# 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.so`:OFX 插件宿主支持 | | `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.so`:UI 层(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-editor` 的 `main.cpp` 和 `core.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/_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`**:渲染子进程的通信协议细节。