diff --git a/TODO-zh.md b/TODO-zh.md index dad0986ff..cba41ad2d 100644 --- a/TODO-zh.md +++ b/TODO-zh.md @@ -3,9 +3,11 @@ 下面是 README 里 OpenFX TODO 的中文翻译与详细说明。每条都尽量解释“是什么、为什么需要、该往哪里改”。 1) 实现插件发现与加载流程 -- 现状:`app/pluginSupport/OliveHost.cpp` 里只创建了 Host 和 PluginCache,但没有扫描路径/加载 OFX 插件。 -- 为什么需要:没有完整的发现/加载,就无法让用户看到插件或实例化插件。 -- 可能改动:补全 `loadPlugins()`,遍历指定目录(如 OFX 标准路径),调用 OpenFX 的插件缓存加载逻辑,注册可用插件并让 UI/节点系统可用。 +- 现状:`app/node/factory.cpp` 自己临时创建 Host/PluginCache 并扫描,`loadPlugins()` 只是一段占位逻辑。 +- 为什么需要:没有统一的发现/加载入口,插件扫描路径和实例化流程很容易分叉,后续维护困难。 +- 已完成: + - 在 `app/pluginSupport/OliveHost.cpp` 实现 `loadPlugins()`:创建 Host/PluginCache,注册到 OFX 全局缓存,设置 host path,按需追加路径并扫描插件文件。 + - `app/node/factory.cpp` 统一通过 `loadPlugins()` 初始化插件,再从全局缓存取插件注册到节点库。 2) 输出剪辑图像的缓冲区管理(Output Clip) - 现状:`OliveClipInstance::getImage()` 返回空的 OFX Image,没有分配像素内存,也没有设置 `kOfxImagePropData`。 diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 5d0400bba..4ef8b72f2 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -88,12 +88,7 @@ void NodeFactory::Initialize() library_.append(created_node); } - std::shared_ptr host=std::make_shared(); - Current::getInstance().setPluginHost(host); - std::shared_ptr plugin_cache=std::make_shared(*host); - plugin_cache->registerInCache(*OFX::Host::PluginCache::getPluginCache()); - OFX::Host::PluginCache::getPluginCache()->scanPluginFiles(); - + olive::plugin::loadPlugins(QString()); for (auto plugin : OFX::Host::PluginCache::getPluginCache()->getPlugins()) { plugin::PluginNode *plugin_node=new plugin::PluginNode(dynamic_cast(plugin)); diff --git a/app/pluginSupport/OliveHost.cpp b/app/pluginSupport/OliveHost.cpp index 40268d223..89f521651 100644 --- a/app/pluginSupport/OliveHost.cpp +++ b/app/pluginSupport/OliveHost.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include "OliveHost.h" @@ -41,13 +42,64 @@ class PluginNode; } } +namespace { +void AddPluginPath(OFX::Host::PluginCache *cache, const QString &path, bool recurse = true) +{ + if (!cache || path.isEmpty()) { + return; + } + QDir dir(path); + if (!dir.exists()) { + return; + } + cache->addFileToPath(dir.canonicalPath().toStdString(), recurse); +} + +void AddPluginPathsFromEnv(OFX::Host::PluginCache *cache, const char *env_var) +{ + QString raw = qEnvironmentVariable(env_var); + if (raw.isEmpty()) { + return; + } + const QChar separator = QDir::listSeparator(); + const QStringList paths = raw.split(separator, Qt::SkipEmptyParts); + for (const QString &path : paths) { + AddPluginPath(cache, path); + } +} +} + void olive::plugin::loadPlugins(QString path) { - std::shared_ptr host=std::make_shared(); + std::shared_ptr host = std::make_shared(); Current::getInstance().setPluginHost(host); - std::shared_ptr imageEffectPluginCache - =std::make_shared(*host); + std::shared_ptr imageEffectPluginCache = + std::make_shared(*host); + Current::getInstance().setPluginCache(imageEffectPluginCache); + + imageEffectPluginCache->registerInCache( + *OFX::Host::PluginCache::getPluginCache()); + OFX::Host::PluginCache *cache = OFX::Host::PluginCache::getPluginCache(); + cache->setPluginHostPath("Olive"); + + const QString home_path = QDir::homePath(); + AddPluginPath(cache, QDir(home_path).filePath(".OFX/Plugins")); + AddPluginPath(cache, QDir(home_path).filePath(".local/share/OFX/Plugins")); + AddPluginPath(cache, QDir(home_path).filePath(".local/share/olive/ofx/Plugins")); + + const QString app_dir = QCoreApplication::applicationDirPath(); + AddPluginPath(cache, QDir(app_dir).filePath("../OFX/Plugins")); + AddPluginPath(cache, QDir(app_dir).filePath("../share/olive/ofx/Plugins")); + AddPluginPath(cache, QDir(app_dir).filePath("../lib/olive/ofx/Plugins")); + + AddPluginPathsFromEnv(cache, "OLIVE_OFX_PLUGIN_PATH"); + AddPluginPathsFromEnv(cache, "OLIVE_PLUGIN_PATH"); + + if (!path.isEmpty()) { + AddPluginPath(cache, path, true); + } + cache->scanPluginFiles(); } OliveHost::~OliveHost() { diff --git a/app/pluginSupport/OlivePluginInstance.cpp b/app/pluginSupport/OlivePluginInstance.cpp index 7513425fe..5306ad548 100644 --- a/app/pluginSupport/OlivePluginInstance.cpp +++ b/app/pluginSupport/OlivePluginInstance.cpp @@ -410,6 +410,7 @@ bool OlivePluginInstance::progressUpdate(double t) return !progress_cancelled_; } +#ifdef OFX_SUPPORTS_OPENGLRENDER OfxStatus OlivePluginInstance::contextAttachedAction() { if (!open_gl_enabled_) { @@ -425,6 +426,7 @@ OfxStatus OlivePluginInstance::contextDetachedAction() } return kOfxStatOK; } +#endif double OlivePluginInstance::timeLineGetTime() { diff --git a/app/render/plugin/pluginrenderer.cpp b/app/render/plugin/pluginrenderer.cpp index 6f5bf8cdd..8397ea0a6 100644 --- a/app/render/plugin/pluginrenderer.cpp +++ b/app/render/plugin/pluginrenderer.cpp @@ -341,10 +341,12 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin:: return; } +#ifdef OFX_SUPPORTS_OPENGLRENDER if (use_opengl) { instance->contextAttachedAction(); AttachOutputTexture(destination); } +#endif OliveClipInstance *clip=dynamic_cast(instance->getClip("Output")); if (!clip) { @@ -412,8 +414,10 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin:: } } else { if (!destination || !destination->id().isValid()) { +#ifdef OFX_SUPPORTS_OPENGLRENDER DetachOutputTexture(); instance->contextDetachedAction(); +#endif instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, renderScale, true, interactive); return; @@ -432,8 +436,10 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin:: } else { AVFramePtr frame_ptr = ReadbackTextureToFrame(destination, destination_params); +#ifdef OFX_SUPPORTS_OPENGLRENDER DetachOutputTexture(); instance->contextDetachedAction(); +#endif if (frame_ptr) { AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params);