Files
oak-editor/docs/zh/modularization-plan

Olive/Oak 模块化与多进程渲染:显式加载 + 纯 C 接口方案

状态:详细实施计划
范围:仅制定方案,不涉及代码变更。
核心目标

  1. 所有业务模块编译为动态库,主进程显式加载dlopen/LoadLibrary),通过纯 C 接口交互。
  2. 渲染引擎拆分为独立可执行文件 olive-renderer,采用**"用完即弃"**的进程模型:每帧(或每几帧)启动一个新进程,渲染完成后立即退出,最大限度避免锁和状态同步问题。

目录索引

文件 内容
README.md 本文档:总体架构、设计哲学、目录索引
09-c-api-design.md 先读此文件:C API 设计规范、显式加载器、内存管理、错误处理、类型映射总纲。所有其他库的 C API 都遵循此规范。
01-olivecore.md libolivecore.so:基础数据类型库(Rational, Color, TimeRange, PixelFormat, SampleBuffer 等)
02-olivecodec.md libolivecodec.so:编解码库(Decoder, Encoder, Frame, Stream
03-oliveplugin.md liboliveplugin.soOFX 插件宿主支持
04-oliveaudio.md liboliveaudio.so:音频播放与处理
05-olivenode.md libolivenode.so:节点图系统(Node, NodeGraph, Project, Param, Keyframe, Timeline, Undo
06-oliverender.md liboliverender.so:渲染引擎抽象(RenderContext, RenderJob, RenderResult
07-oliveui.md liboliveui.soUI 层(Widget, Panel, Window, Dialog
08-olive-renderer.md olive-renderer 可执行文件:多进程渲染的"用完即弃"模型详细设计
10-implementation-roadmap.md 10 周小步快跑实施路线图,含每周任务、验收标准、回退策略
11-ipc-protocol.md 渲染子进程的 IPC 协议(命令行参数、stdin JSON、stdout NDJSON、共享内存)

总体架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                         olive-editor(主进程,GUI                           │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    ModuleLoader(显式加载管理器)                      │   │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │   │
│  │  │dlopen    │ │dlopen    │ │dlopen    │ │dlopen    │ │dlopen    │  │   │
│  │  │olivecore │ │olivecodec│ │olivenode │ │oliverender││oliveui   │  │   │
│  │  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘  │   │
│  │       │            │            │            │            │         │   │
│  │       └────────────┴────────────┴────────────┘            │         │   │
│  │                        纯 C 接口交互                        │         │   │
│  │                                                             ▼         │   │
│  │                                                    ┌──────────────┐   │   │
│  │                                                    │ QProcess     │   │   │
│  │                                                    │ 启动/等待/回收 │   │   │
│  │                                                    └──────┬───────┘   │   │
│  └───────────────────────────────────────────────────────────┼───────────┘   │
│                                                              │               │
├──────────────────────────────────────────────────────────────┼───────────────┤
│                                                              │               │
│  ┌───────────────────────────────────────────────────────────┘               │
│  │   olive-renderer(子进程,无 GUI"用完即弃"                              │
│  │                                                                             │
│  │  启动参数:--node-graph=/tmp/g.xml --time=1001/30000 --output-shm=/o_123    │
│  │                                                                             │
│  │  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  │ 1. 初始化 Qt Core                                                   │   │
│  │  │ 2. 初始化 OpenGL 离屏上下文                                          │   │
│  │  │ 3. 加载节点图 XML                                                   │   │
│  │  │ 4. 执行渲染(RenderProcessor + OpenGLRenderer                      │   │
│  │  │ 5. 将帧数据写入共享内存                                              │   │
│  │  │ 6. 输出 JSON 结果到 stdout                                           │   │
│  │  │ 7. 清理并退出(return 0                                            │   │
│  │  └─────────────────────────────────────────────────────────────────────┘   │
│  └────────────────────────────────────────────────────────────────────────────┘
│
│  所有动态库共享的基础依赖:QtCore, FFmpeg, OpenColorIO 等(由操作系统加载器解析)
└─────────────────────────────────────────────────────────────────────────────┘

核心设计哲学

1. 显式加载 + 纯 C 接口

  • 主进程不链接任何业务动态库olive-editormain.cppcore.cpp 中没有任何对业务模块的 #include(除 C API 头文件外)。
  • 所有跨模块边界的交互通过纯 C 函数完成,使用**不透明指针(Opaque Pointer**封装 C++ 对象。
  • 动态库内部可以继续使用 C++、Qt、STL、虚函数、模板等任意特性,但对外仅暴露 C 接口。

为什么用 C 接口而非 C++ 类?

  • C++ 的 ABI(虚表布局、name mangling、异常传播)在不同编译器/版本间不兼容。
  • C 接口的符号名干净(无 mangling),dlsym 可直接查找。
  • 未来如果需要,C 接口可被 Python、Rust、C# 等语言直接绑定。

2. "用完即弃"的渲染进程

  • 每一帧(或每 N 帧)渲染任务 = 一个独立的操作系统进程
  • 进程启动时接收完整的渲染参数和节点图,渲染完成后立即 exit(0)
  • 不存在常驻渲染进程,因此不需要:心跳检测、崩溃恢复、状态同步、读写锁、graph_ref 缓存、复杂的取消机制。
  • 主进程如果需要取消渲染,直接 QProcess::kill() 即可。

可能的问题与回退

  • 若进程启动开销(QProcess::start() + OpenGL 上下文初始化)导致实时预览帧率不足,可回退为**"批处理模式"**:每 3–5 帧共享一个进程,或预先启动一个进程池(但进程池内的进程仍不共享状态,每个进程只处理一个批次后自杀)。详见 08-olive-renderer.md

3. 小步快跑

  • 每个模块的改造都是独立、可回退、可并行的。
  • 不改现有 C++ 类定义,只在其上层新增 C 封装层api/<module>_api.cpp)。
  • 保留原有 OBJECT 库编译方式,通过 CMake 选项 -DOLIVE_DYNAMIC_MODULES=ON 切换。
  • 每完成一个模块,就通过该模块的单元测试验证,再进入下一个模块。

快速开始(阅读顺序)

  1. 先读 09-c-api-design.md:理解 C API 的约定、显式加载器、内存管理规则。
  2. 再读 08-olive-renderer.md:理解最核心的架构变革——多进程渲染。
  3. 然后按任意顺序阅读 01-07-:各业务模块的具体 C API 设计和实施步骤。
  4. 最后读 10-implementation-roadmap.md:10 周实施计划,了解如何排期和验收。
  5. 参考 11-ipc-protocol.md:渲染子进程的通信协议细节。