diff --git a/app/common/Current.h b/app/common/Current.h index b2076e351..aee702922 100644 --- a/app/common/Current.h +++ b/app/common/Current.h @@ -51,6 +51,10 @@ public: { currentAudioParams_ = params; } + bool interactive() + { + return true; + } private: static Current current; olive::VideoParams currentVideoParams_; diff --git a/app/main.cpp b/app/main.cpp index 90f5e28a2..68c0005a4 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -24,6 +24,7 @@ * Use the navigation above to find documentation on classes or source files. */ +#include "OliveHost.h" extern "C" { #include #include @@ -52,7 +53,6 @@ extern "C" { #ifdef USE_CRASHPAD #include "common/crashpadinterface.h" #endif // USE_CRASHPAD -#include "OlivePlugin.cpp" int decompress_project(const QString &project) { if (project.isEmpty()) { diff --git a/app/node/node.h b/app/node/node.h index c4b356ac2..b2f05d95f 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -1124,7 +1124,12 @@ public: static const QString kEnabledInput; + std::shared_ptr getPlugin(); protected: + + // If is set, this is a plugin node. + std::shared_ptr plugin; + void InsertInput(const QString &id, NodeValue::Type type, const QVariant &default_value, InputFlags flags, int index); diff --git a/app/pluginSupport/OliveClip.cpp b/app/pluginSupport/OliveClip.cpp index 7edd1e2af..b41ec7cc7 100644 --- a/app/pluginSupport/OliveClip.cpp +++ b/app/pluginSupport/OliveClip.cpp @@ -118,5 +118,28 @@ OFX::Host::ImageEffect::Image * olive::plugin::OliveClipInstance::getImage(OfxTime time, const OfxRectD *optionalBounds) { + return &image_; +} +OfxRectD +olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const +{ + if (regionOfDefinitions_.contains(time)) { + return regionOfDefinitions_[time]; + } + OfxRectD regionOfDefinition; + regionOfDefinition.x1=regionOfDefinition.y1=0; + regionOfDefinition.x2=params_.width(); + regionOfDefinition.y2=params_.height(); + return regionOfDefinition; +} +void olive::plugin::OliveClipInstance::setRegionOfDefinition( + OfxRectD regionOfDefinition, OfxTime time) +{ + regionOfDefinitions_[time] = regionOfDefinition; +} +void olive::plugin::OliveClipInstance::setDefaultRegionOfDefinition( + OfxRectD regionOfDefinition) +{ + defaultRegionOfDefinitions_ = regionOfDefinition; } \ No newline at end of file diff --git a/app/pluginSupport/OliveClip.h b/app/pluginSupport/OliveClip.h index 94ba596e0..833402257 100644 --- a/app/pluginSupport/OliveClip.h +++ b/app/pluginSupport/OliveClip.h @@ -25,6 +25,8 @@ #define OLIVECLIP_H #include "ofxhClip.h" #include "render/videoparams.h" + +#include namespace olive { namespace plugin @@ -37,6 +39,11 @@ public: { params_ = params; } + OFX::Host::ImageEffect::Image& getOutputImage() + { + return image_; + } + const std::string &getUnmappedBitDepth() const override; const std::string &getUnmappedComponents() const override; const std::string &getPremult() const override; @@ -50,10 +57,21 @@ public: bool getContinuousSamples() const override; OFX::Host::ImageEffect::Image* getImage(OfxTime time, const OfxRectD *optionalBounds) override; OfxRectD getRegionOfDefinition(OfxTime time) const override; - const std::string &findSupportedComp(const std::string &s) const override; + + void setRegionOfDefinition(OfxRectD regionOfDefinition, OfxTime time); + void olive::plugin::OliveClipInstance::setDefaultRegionOfDefinition( + OfxRectD regionOfDefinition); +# ifdef OFX_SUPPORTS_OPENGLRENDER + OFX::Host::ImageEffect::Texture* loadTexture(OfxTime time, const char *format, const OfxRectD *optionalBounds) { return NULL; }; +# endif private: VideoParams params_; + QMap regionOfDefinitions_; + + OfxRectD defaultRegionOfDefinitions_; + + OFX::Host::ImageEffect::Image image_; }; } } diff --git a/app/pluginSupport/OliveHost.cpp b/app/pluginSupport/OliveHost.cpp index 8477cb4fd..d0a0e1355 100644 --- a/app/pluginSupport/OliveHost.cpp +++ b/app/pluginSupport/OliveHost.cpp @@ -25,6 +25,9 @@ #include #include #include "OliveHost.h" + +#include "OliveInstance.h" +#include "common/Current.h" using namespace OFX::Host; using namespace olive::plugin; void loadPlugins(QString path) @@ -79,7 +82,7 @@ OFX::Host::ImageEffect::Instance* OliveHost::newInstance(void* clientData, OFX::Host::ImageEffect::ImageEffectPlugin* plugin, OFX::Host::ImageEffect::Descriptor& desc, const std::string& context){ - //ImageEffect::Instance* instance=new ImageEffect::Instance(clientData,plugin,desc,context); + ImageEffect::Instance* instance=new OliveInstance(plugin,desc,context,Current::getInstance().interactive()); instances_.append(instance); return instance; }; diff --git a/app/pluginSupport/OliveInstance.cpp b/app/pluginSupport/OliveInstance.cpp index 0c0030fe8..f653aeeaf 100644 --- a/app/pluginSupport/OliveInstance.cpp +++ b/app/pluginSupport/OliveInstance.cpp @@ -147,6 +147,12 @@ void OliveInstance::getRenderScaleRecursive(double &x, double &y) const x = 1.0; y = 1.0; } +OFX::Host::Param::Instance * +OliveInstance::newParam(const std::string &name, + OFX::Host::Param::Descriptor &Descriptor) +{ + +} OFX::Host::ImageEffect::ClipInstance *OliveInstance::newClipInstance( OFX::Host::ImageEffect::Instance *plugin, diff --git a/app/pluginSupport/OliveInstance.h b/app/pluginSupport/OliveInstance.h index 30265f56c..5e2e0178d 100644 --- a/app/pluginSupport/OliveInstance.h +++ b/app/pluginSupport/OliveInstance.h @@ -20,6 +20,8 @@ #include "ofxImageEffect.h" #include #include "ofxhImageEffect.h" +#include "render/videoparams.h" + #include #include #include @@ -49,6 +51,10 @@ public: return kOfxImageFieldNone; }; + void setVideoParam(VideoParams params) + { + this->params_=params; + } OFX::Host::ImageEffect::ClipInstance *newClipInstance( OFX::Host::ImageEffect::Instance *plugin, OFX::Host::ImageEffect::ClipDescriptor *descriptor, @@ -88,9 +94,61 @@ public: /// renderScale void getRenderScaleRecursive(double &x, double &y) const override; + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for Param::SetInstance + + /// make a parameter instance + /// + /// Client host code needs to implement this + virtual OFX::Host::Param::Instance* newParam(const std::string& name, OFX::Host::Param::Descriptor& Descriptor); + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditBegin + /// + /// Client host code needs to implement this + virtual OfxStatus editBegin(const std::string& name); + + /// Triggered when the plug-in calls OfxParameterSuiteV1::paramEditEnd + /// + /// Client host code needs to implement this + virtual OfxStatus editEnd(); + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for Progress::ProgressI + + /// Start doing progress. + virtual void progressStart(const std::string &message, const std::string &messageid); + + /// finish yer progress + virtual void progressEnd(); + + /// set the progress to some level of completion, returns + /// false if you should abandon processing, true to continue + virtual bool progressUpdate(double t); + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // overridden for TimeLine::TimeLineI + + /// get the current time on the timeline. This is not necessarily the same + /// time as being passed to an action (eg render) + virtual double timeLineGetTime(); + + /// set the timeline to a specific time + virtual void timeLineGotoTime(double t); + + /// get the first and last times available on the effect's timeline + virtual void timeLineGetBounds(double &t1, double &t2); private: QList persistentErrors_; - + VideoParams params_; }; } } \ No newline at end of file diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 530a06ccd..bdec1ceed 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -28,6 +28,8 @@ #include "node/block/transition/transition.h" #include "node/project.h" #include "rendermanager.h" +#include "pluginSupport/OliveClip.h" +#include "pluginSupport/OliveHost.h" namespace olive { @@ -157,6 +159,7 @@ void RenderProcessor::Run() SetCancelPointer(ticket_->GetCancelAtom()); + VideoParams params=ticket_->property("vparam").value(); SetCacheVideoParams(ticket_->property("vparam").value()); SetCacheAudioParams(ticket_->property("aparam").value()); @@ -165,6 +168,92 @@ void RenderProcessor::Run() return; } + // if is a plugin + Node *node=ticket_->property("node").value(); + if (node && node->getPlugin()) { + std::shared_ptr plugin + = node->getPlugin(); + std::unique_ptr instance(plugin->createInstance(kOfxImageEffectContextFilter, NULL)); + + OfxStatus stat; + stat = instance->createInstanceAction(); + if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + ticket_->Finish(); + return; + } + // now we need to to call getClipPreferences on the instance so that it does the clip component/depth + // logic and caches away the components and depth on each clip. + bool ok = instance->getClipPreferences(); + if (!ok) { + ticket_->Finish(); + return; + } + + // current render scale of 1 + OfxPointD renderScale; + renderScale.x = renderScale.y = 1.0; + + // The render window is in pixel coordinates + // ie: render scale and a PAR of not 1 + OfxRectI renderWindow; + renderWindow.x1 = renderWindow.y1 = 0; + renderWindow.x2 = ticket_->property("size").value().width(); + renderWindow.y2 = ticket_->property("size").value().height(); + + /// RoI is in canonical coords, + OfxRectD regionOfInterest; + regionOfInterest.x1 = regionOfInterest.y1 = 0; + regionOfInterest.x2 = renderWindow.x2 * instance->getProjectPixelAspectRatio(); + regionOfInterest.y2 = renderWindow.y2 * instance->getProjectPixelAspectRatio(); + + OfxRectD regionOfDefinition; + regionOfDefinition.x1 = regionOfDefinition.y1 = 0; + regionOfDefinition.x2 = params.width(); + regionOfDefinition.y2 = params.height(); + + + int numFramesToRender=ticket_->property("time").value().toDouble() + * params.frame_rate().toDouble(); + stat = instance->beginRenderAction(0, numFramesToRender, 1.0, false, renderScale, /*sequential=*/true, /*interactive=*/false + ); + if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) { + ticket_->Finish(); + return; + } + + plugin::OliveClipInstance *clip=dynamic_cast(instance->getClip("Output")); + for(int t = 0; t <= numFramesToRender; ++t) + { + // call get region of interest on each of the inputs + OfxTime frame = t; + + // get the RoI for each input clip + // the regions of interest for each input clip are returned in a std::map + // on a real host, these will be the regions of each input clip that the + // effect needs to render a given frame (clipped to the RoD). + // + // In our example we are doing full frame fetches regardless. + std::map rois; + stat = instance->getRegionOfInterestAction(frame, renderScale, + regionOfInterest, rois); + assert(stat == kOfxStatOK || stat == kOfxStatReplyDefault); + + // render a frame + stat = instance->renderAction(t,kOfxImageFieldBoth,renderWindow, renderScale, /*sequential=*/true, /*interactive=*/false, /*draft=*/false); + assert(stat == kOfxStatOK); + + // get the output image buffer + OFX::Host::ImageEffect::Image *outputImage = clip->getOutputImage(); + + std::ostringstream ss; + ss << "Output." << t << ".ppm"; + exportToPPM(ss.str(), outputImage); + } + + instance->endRenderAction(0, numFramesToRender, 1.0, false, renderScale, /*sequential=*/true, /*interactive=*/false + ); + } + switch (type) { case RenderManager::kTypeVideo: { rational time = ticket_->property("time").value();