- de-Qt src/plugin/src (olivehost/oliveplugininstance/oliveclip/
paraminstance/image/pluginprogressreporter); QMessageBox/
QApplication replaced by facade callbacks
- new C ABI in include/plugin/{error,host,instance}.h with
refcounted OakPluginInstance value handle
- paraminstance bridges via oaknode C ABI (OakNodeNode value handle,
oaknode_node_identity registry); undo via oakundo C ABI
- oliveclip textures are OakRenderTexture value handles; oakrender
gains texture/copier/ticket C API additions
- oaknode gains get_input_at_time/set_input_at_time_undoable/
node_identity/sequence_from_node/sequence_set_default_parameters/
find_input_footage
- move avframeptr.h to src/common/src (shared by codec and render)
- node transition pluginSupport stubs bridge the real oakplugin
headers; all oaknode-building standalone trees add src/plugin and
link oakplugin into their test binaries
- plugin tests self-sufficient (ipc shim, OfxHost force_load,
PRE_TEST discovery, OCIO env); timeline standalone gains
render/c_api
- restore ffmpegdecoder.cpp in src/codec/src/ffmpeg/CMakeLists.txt
(dropped in 3d004c081, caused jump-to-0 in decoder/encoder tests)
All six standalone trees green: codec 22, audio 40, task 110,
render 49, timeline 121, plugin 100.
5.3 KiB
M9 · oakplugin 拆分手册 + facade 装配层裁决
内容:
engine/pluginSupport/(OpenFX host:OliveHost、 OlivePluginInstance、PluginNode、PluginProgressReporter)。 依赖:node 6、render 6、common 6、core 2、undo 2、coreengine 2。 拆分顺序第 9 位(最后拆的实体模块)。文末 §4 是 liboakengine 装配层的最终裁决。
1. 目标形态
oakplugin/
include/oakplugin/{host.h, instance.h, progress.h, types.h, export.h}
src/
tests/ # oakplugin_gtest
2. 冻结 C API
2.1 oakplugin/host.h
OAKPL_API int oakplugin_host_init(void);
OAKPL_API void oakplugin_host_shutdown(void);
OAKPL_API int oakplugin_host_scan(const char *const *bundle_dirs,
int dir_count);
OAKPL_API int oakplugin_host_plugin_count(void);
OAKPL_API int oakplugin_host_plugin_id_at(int i, char *buf, int n);
OAKPL_API int oakplugin_host_plugin_label(const char *plugin_id,
char *buf, int n);
2.2 oakplugin/instance.h
typedef struct OakPluginInstance OakPluginInstance;
OAKPL_API OakPluginInstance *oakplugin_instance_create(
const char *plugin_id);
OAKPL_API void oakplugin_instance_free(OakPluginInstance *i);
OAKPL_API int oakplugin_instance_set_param(OakPluginInstance *i,
const char *param_id, const oak_node_value *v);
OAKPL_API int oakplugin_instance_get_param(OakPluginInstance *i,
const char *param_id, oak_node_value *out);
OAKPL_API int oakplugin_instance_render(OakPluginInstance *i,
OakCodecFrame *dst, const OakCodecFrame *src, int64_t ts);
/* 进度回调:instance_render 是异步命令(渲染中进行),进度/取消回调
* 即其返回通道——04 §3 唯一例外情形(R6 已把 cancelled 信号改成 C
* 回调,沿用该机制)。非异步接口一律不配回调。 */
OAKPL_API void oakplugin_instance_set_progress_cb(OakPluginInstance *i,
oakplugin_progress_fn fn, void *userdata);
OAKPL_API void oakplugin_instance_cancel(OakPluginInstance *i);
2.3 oakplugin/progress.h
typedef struct OakPluginProgress OakPluginProgress; /* 报告器句柄 */
OAKPL_API OakPluginProgress *oakplugin_progress_create_dialog(
const char *message, const char *title); /* UI 侧实现 */
OAKPL_API void oakplugin_progress_free(OakPluginProgress *p);
3. 切割点
| 现状 | 处理 |
|---|---|
| plugin → node/ 6(plugins/plugin.h 3 等) | 经 oaknode C ABI(PluginNode 是节点,留在 oaknode;oakplugin 只经 factory/host 接口交互)——PluginNode 归属裁决:PluginNode 类随 oaknode 走(它是节点体系成员),oakplugin 提供 host/instance |
| plugin → render/ 6(videoparams 3 等) | videoparams 已下沉;其余经 oakrender C ABI |
| plugin → undo/ 2 | oakundo 适配类 |
| plugin → coreengine.h 2 | 插件注册点内聚进 oakplugin_host_init |
4. facade 装配层最终裁决(liboakengine 的终态)
M1-M9 全部完成后,engine/src/capi + coreengine + tool/ +
ui/ 残余构成 liboakengine。裁决(选定):
facade 直链各模块,不绕 C ABI 自调。即:facade 的 oakengine_*
实现可以继续直接调用各模块的 C++ 内部(链接 oaknode/oakrender 等
的静态或共享库),不要求 facade 经各模块的公共 C ABI 兜圈。
理由:facade 与 app 的边界(oakengine_*)已经纯 C 且 nm=0,模块间
边界是给"模块互相调用"用的;facade 是装配层,自家人不绕远路。
但:coreengine.h 被 node/render/task/plugin 引用的 5+2+2+2
处必须内聚(各模块的初始化改由各自的 oak<mod>_init 完成,
coreengine 只做编排调用)。
终态验证:
nm -D --defined-only liboakengine.so | grep -c " T _Z" # 0(R7-B)
nm -D --defined-only liboaknode.so | grep -c " T _Z" # 0(每模块同查)
ldd liboakengine.so | grep oak # 只见 oak* 模块库
全量构建 0 error;全量 ctest 绿
5. 测试(映射 03 §2/§3)
- host:init/scan/枚举(照现有 OliveHost 测试的 bundle fixture)。
- instance:Shadertoy 类插件(CI 里可用的)创建/参数/渲染一帧非空。
- progress:回调触发与 cancel。
oakplugin_debug_alive_count()泄漏断言。
6. 实施现状(2026-08-05)
已完成。src/plugin/src/ 六个类(olivehost/oliveplugininstance/ oliveclip/paraminstance/image/pluginprogressreporter)全部去Qt, QMessageBox/QApplication 依赖删除,改为 §4 裁决的 facade 回调 装配。C ABI 落在 include/plugin/{error,host,instance}.h, OakPluginInstance 为引用计数值句柄(ctx/addref/release/ abi_version)。
偏离手册之处:
- paraminstance 不直接持有 Node*,改持 OakNodeNode 值句柄,参数 读写全部经 oaknode C ABI;node↔instance 的身份路由用新增的 oaknode_node_identity() 注册表实现。
- oliveclip 的纹理为 OakRenderTexture 值句柄,oakrender 因此补了 texture/copier/ticket 一族 C API。
- oaknode 的 transition stub(src/node/transition/pluginSupport/) 桥接 oakplugin 真身头,liboaknode 运行期引用 oakplugin 符号 (dynamic_lookup);所有构建 oaknode 的 standalone 树都要把 src/plugin 加进构建,测试二进制必须链接 oakplugin。
验证:build-oakplugin 100/100;codec 22/22、audio 40/40、 task 110/110、render 49/49、timeline 121/121(均含 oakplugin 接入后的全量回归)。