Add OFX plugin support and related infrastructure

This commit extends the OFX plugin support in Olive by:

- Initializing and scanning for OFX plugins
- Updating PluginNode to handle OFX plugin parameters and inputs
- Adding necessary methods and properties for OFX plugin integration
- Enhancing NodeFactory to include OFX plugin nodes
- Refactoring and renaming OliveInstance to OlivePluginInstance
- Introducing new classes for parameter handling (ParamInstance)
- Adding PluginJob for rendering OFX plugins
- Adjusting CMakeLists.txt files to include new source files
This commit is contained in:
2025-11-09 17:03:56 +08:00
parent 26e6924cdf
commit 8a7b6cf869
23 changed files with 545 additions and 90 deletions
+16
View File
@@ -29,6 +29,7 @@
#include "block/transition/diptocolor/diptocolortransition.h"
#include "color/displaytransform/displaytransform.h"
#include "color/ociogradingtransformlinear/ociogradingtransformlinear.h"
#include "common/Current.h"
#include "distort/cornerpin/cornerpindistortnode.h"
#include "distort/crop/cropdistortnode.h"
#include "distort/flip/flipdistortnode.h"
@@ -62,6 +63,8 @@
#include "math/trigonometry/trigonometry.h"
#include "output/track/track.h"
#include "output/viewer/viewer.h"
#include "pluginSupport/OliveHost.h"
#include "plugins/Plugin.h"
#include "project/folder/folder.h"
#include "project/footage/footage.h"
#include "project/sequence/sequence.h"
@@ -84,6 +87,19 @@ void NodeFactory::Initialize()
library_.append(created_node);
}
std::shared_ptr<olive::plugin::OliveHost> host=std::make_shared<olive::plugin::OliveHost>();
Current::getInstance().setPluginHost(host);
std::shared_ptr<OFX::Host::ImageEffect::PluginCache> plugin_cache=std::make_shared<OFX::Host::ImageEffect::PluginCache>(*host);
plugin_cache->registerInCache(*OFX::Host::PluginCache::getPluginCache());
OFX::Host::PluginCache::getPluginCache()->scanPluginFiles();
for (auto plugin : OFX::Host::PluginCache::getPluginCache()->getPlugins()) {
plugin::PluginNode *plugin_node=new plugin::PluginNode(dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin*>(plugin));
library_.append(plugin_node);
}
}
void NodeFactory::Destroy()
+4 -2
View File
@@ -19,6 +19,8 @@
#ifndef NODE_H
#define NODE_H
#include "ofxhImageEffectAPI.h"
#include <map>
#include <QMutex>
#include <QObject>
@@ -1124,11 +1126,11 @@ public:
static const QString kEnabledInput;
std::shared_ptr<OFX::Host::ImageEffect::ImageEffectPlugin> getPlugin();
OFX::Host::ImageEffect::ImageEffectPlugin* getPlugin();
protected:
// If is set, this is a plugin node.
std::shared_ptr<OFX::Host::ImageEffect::ImageEffectPlugin> plugin;
OFX::Host::ImageEffect::ImageEffectPlugin* plugin= nullptr;
void InsertInput(const QString &id, NodeValue::Type type,
const QVariant &default_value, InputFlags flags,
+70 -25
View File
@@ -17,44 +17,89 @@
*/
#include "Plugin.h"
#include "render/rendermanager.h"
#include "render/job/pluginjob.h"
olive::plugin::PluginNode::PluginNode(
OFX::Host::ImageEffect::ImageEffectPlugin *plugin)
{
this->plugin = plugin;
auto params = plugin->getDescriptor().getParams();
for (auto param: params) {
NodeValue::Type type;
const std::string &ofxType = param.second->getType();
if (ofxType == kOfxParamTypeInteger) {
type = NodeValue::kInt;
} else if (ofxType == kOfxParamTypeDouble) {
type = NodeValue::kFloat;
} else if (ofxType == kOfxParamTypeBoolean) {
type = NodeValue::kBoolean;
} else if (ofxType == kOfxParamTypeString) {
type = NodeValue::kText;
} else if (ofxType == kOfxParamTypeRGB ||
ofxType == kOfxParamTypeRGBA) {
type = NodeValue::kColor;
} else if (ofxType == kOfxParamTypeChoice) {
type = NodeValue::kCombo;
} else if (ofxType == kOfxParamTypeDouble2D ||
ofxType == kOfxParamTypeInteger2D){
type = NodeValue::kVec2;}
else if (ofxType == kOfxParamTypeDouble3D ||
ofxType == kOfxParamTypeInteger3D){
type = NodeValue::kVec3;
} else if (ofxType == kOfxParamTypeStrChoice){
type = NodeValue::kStrCombo;
}else if (ofxType == kOfxParamTypeBytes
|| ofxType == kOfxParamTypeCustom) {
type = NodeValue::kBinary;
} else {
type = NodeValue::kNone;
}
if (ofxType == kOfxParamTypePushButton) {
// TODO
} else if (ofxType == kOfxParamTypeGroup) {
// TODO
} else if (ofxType == kOfxParamTypePage) {
// TODO
}
AddInput(param.second->getName().data(), type);
}
}
QString olive::plugin::PluginNode::Name() const
{
if (methods.name) {
char buffer[64]={0};
bool ok=methods.name(buffer, 64);
if (ok) {
return QString(buffer);
}
}
return "";
return plugin->getDescriptor()
.getProps()
.getStringProperty(kOfxPropLabel)
.data();
}
QString olive::plugin::PluginNode::Description() const
{
if (methods.description) {
char buffer[1024] = { 0 };
bool ok = methods.description(buffer, 1024);
if (ok) {
return QString(buffer);
}
}
return "";
return plugin->getDescriptor().getProps().getStringProperty(kOfxPropPluginDescription).data();
}
void olive::plugin::PluginNode::Value(const NodeValueRow &value,
const NodeGlobals &globals,
NodeValueTable *table) const
{
methods.value(&node_ctx_functions);
TexturePtr tex = value[kTextureInput].toTexture();
if (tex) {
PluginJob job(,value);
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
}
QString olive::plugin::PluginNode::id() const
{
if (methods.id) {
char buffer[64]={0};
bool ok=methods.id(buffer, 64);
if (ok) {
return QString(buffer);
}
}
return "";
return plugin->getIdentifier().data();
}
+40 -16
View File
@@ -18,36 +18,60 @@
#ifndef PLUGIN_NODES_H
#define PLUGIN_NODES_H
#include "ofxhImageEffectAPI.h"
#include "ofxhPluginCache.h"
#include "node/node.h"
#include "pluginSupport/Plugin.h"
#include "pluginSupport/OlivePlugin.cpp"
namespace olive
{
namespace plugin
{
const QString kTextureInput = QStringLiteral("tex_in");
class PluginNode : public olive::Node{
public:
PluginNode():Node()
{
memset(&methods, 0, sizeof(olive_node_methods));
};
explicit PluginNode(struct olive_node_methods methods):Node()
{
this->methods=methods;
}
void setMethods(struct olive_node_methods methods)
{
this->methods=methods;
}
PluginNode(OFX::Host::ImageEffect::ImageEffectPlugin* plugin) ;
QString Name() const override;
QString id() const override;
QVector<CategoryID> Category() const override;
QString Description() const override;
void AddPushButton();
void AddPage();
Node *copy() const override;
/**
* @brief The main processing function
*
* The node's main purpose is to take values from inputs to set values in outputs. For whatever subclass node you
* create, this is where the code for that goes.
*
* Note that as a video editor, the node graph has to work across time. Depending on the purpose of your node, it may
* output different values depending on the time, and even if not, it will likely be receiving different input
* depending on the time. Most of the difficult work here is handled by NodeInput::get_value() which you should pass
* the `time` parameter to. It will return its value (at that time, if it's keyframed), or pass the time to a
* corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior
* of the NodeParam objects will handle everything related to it automatically.
*/
void Value(const NodeValueRow &value,
const NodeGlobals &globals, NodeValueTable *table) const override;
private:
struct olive_node_methods methods;
/**
* @brief If Value() pushes a ShaderJob, this is the function that will process them.
*/
virtual void ProcessSamples(const NodeValueRow &values,
const SampleBuffer &input, SampleBuffer &output,
int index) const;
/**
* @brief If Value() pushes a GenerateJob, override this function for the image to create
*
* @param frame
*
* The destination buffer. It will already be allocated and ready for writing to.
*/
virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const;
};
+4
View File
@@ -387,6 +387,10 @@ QVector2D NodeTraverser::GenerateResolution() const
video_params_.height());
}
/**
* Resolve Jobs. I need to add a PluginJob here and move the plugin code here.
* @param val
*/
void NodeTraverser::ResolveJobs(NodeValue &val)
{
if (val.type() == NodeValue::kTexture) {
+7 -1
View File
@@ -163,7 +163,13 @@ public:
* Resolves to `int` - the index currently selected
*/
kCombo,
/**
* ComboBox type
*
* Resolves to `QString` - the text of choice currently selected
* This is to support the OpenFX type kOfxParamTypeStrChoice
*/
kStrCombo,
/**
* Video Parameters type
*