Files
oak-editor/docs/zh/plans/riir/M9-oakplugin.md
T
Mike-Solar fd2111d560 refactor(plugin): de-Qt oakplugin and wrap it in a pure C ABI
- 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.
2026-08-07 22:18:36 +08:00

126 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M9 · oakplugin 拆分手册 + facade 装配层裁决
> 内容:`engine/pluginSupport/`OpenFX hostOliveHost、
> 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`
```c
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`
```c
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`
```c
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/ 6plugins/plugin.h 3 等) | 经 oaknode C ABIPluginNode 是节点,留在 oaknodeoakplugin 只经 factory/host 接口交互)——**PluginNode 归属裁决:PluginNode 类随 oaknode 走**(它是节点体系成员),oakplugin 提供 host/instance |
| plugin → render/ 6videoparams 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" # 0R7-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
- hostinit/scan/枚举(照现有 OliveHost 测试的 bundle fixture)。
- instanceShadertoy 类插件(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 ABInode↔instance 的身份路由用新增的
oaknode_node_identity() 注册表实现。
- oliveclip 的纹理为 OakRenderTexture 值句柄,oakrender 因此补了
texture/copier/ticket 一族 C API。
- oaknode 的 transition stubsrc/node/transition/pluginSupport/
桥接 oakplugin 真身头,liboaknode 运行期引用 oakplugin 符号
dynamic_lookup);所有构建 oaknode 的 standalone 树都要把
src/plugin 加进构建,测试二进制必须链接 oakplugin。
验证:build-oakplugin 100/100codec 22/22、audio 40/40、
task 110/110、render 49/49、timeline 121/121(均含 oakplugin
接入后的全量回归)。