Files
oak-editor/docs/zh/plans/riir/04-interfaces.md
T
Mike-Solar 774eda75fe docs(riir): design inter-module C ABI interfaces and split out oakstorage
- riir.md: split project file read/write into standalone oakstorage
  module (pluggable backend, DB-replaceable); add Mermaid data flow
  diagram of all modules; adjust batch table and milestones
- riir/04-interfaces.md: new provides/consumes contract matrix for
  all modules
- riir/M10-oakstorage.md: new manual with frozen C API (typed opaque
  handles, manual vtable for storage backends, URI addressing)
- riir/01: codify pure-C OO interface rules (typed handles instead of
  void*, init/free pairs, manual vtables, no C++ objects or member
  calls across shared library boundaries); upper layers issue commands
  only, no module-to-module event subscriptions (async task callbacks
  excepted)
- sync 00/02/03 and M2-M9 manuals: remove subscribe APIs, replace
  void* with typed handles, update tests accordingly
2026-08-05 14:48:08 +08:00

8.9 KiB
Raw Blame History

04 · 模块间接口设计(provides / consumes 全表)

本文是各模块手册(M1–M10)C API 的汇总视图:每个模块对外提供哪些 接口族、消费哪些模块的哪些接口族、边界上流什么数据。逐函数签名以各 M 手册的"冻结 C API"节为准;本文管"模块与模块之间的契约关系",管不到 逐函数细节。

全部接口遵守 01-adapter-pattern.md §0 的铁律:纯 C、面向对象—— 有类型的不透明句柄(禁止 void * 当对象)、init_*/free_* 构造析构、 首参 self 的普通函数当成员函数、多态用手工函数指针表、C++ 对象与成员 函数一律不跨动态库边界。

1. 接口关系总表

行 = 消费方,列 = 提供方;单元格 = 消费的接口族(详见各提供方手册)。

消费 ↓ \ 提供 → oakcommon oakundo oaknode oaktimeline oakcodec oakaudio oakrender oakstorage oaktask oakplugin oakcore
facadesrc/capi 工具/类型 undo 全族 node/project/footage/serializer(clipboard) 族 timeline 全族 decoder/frame/proxy 族 audio 全族 renderer/playback/preview 族 open/save/probe 族 task/manager 全族 plugin 全族 rational/timecode
oaktask 工具 command 句柄 footage/project/sequence/folder 族 conform/proxy 族 导出用 render 族 load/save/otio 委托
oakrender videoparams/colortransformM3.5 下沉) command 句柄 node 遍历/取值、project、colormanager decoder/frame 族 音频参数 plugin 实例句柄
oakplugin 工具 command 句柄 node 参数读写 帧缓冲/纹理句柄
oakaudio 工具 frame/解码(1 处) videoparams(下沉后消失) samplebuffer
oakcodec videoparams/subtitleparams(下沉) footage 流信息(3 处) rational
oaktimeline timelinecommon 枚举(下沉) command 句柄 track/block/sequence 族(32 处)
oaknode 枚举/常量/工具 undocommand.h4 处) marker/workarea2 处,M4 反向) decoder/frame/proxy8 处,M5 反向) audio 参数(4 处,M6 反向) colorprocessor/rendermanager/jobM7 反向,02 §4 裁决 A rational/bezier
oakundo 工具
oakstorage 工具 project/root/序列化建图取图
oakcommon

(空格 = 无依赖。"N 处"数据来自 02 的 include 扫描。oakcore 与 ffmpeg_bridge 为现成独立库,不参与拆分顺序。)

2. 逐模块接口契约

2.1 oakcommonM1)— 纯下沉,无业务对象

  • 提供include/oakcommon/types.h 的全模块共用 POD(时间戳/区间/ 枚举常量,含 M3.5 下沉的 OakVideoParams/OakSubtitleParams/ OakColorTransform);工具函数(全 _s 静态式,无句柄)。
  • 消费:无(叶子)。
  • 边界数据:纯 POD 值,无所有权问题。

2.2 oakundo(M2)— 手工虚表的第一个用户

  • 提供OakUndoCommand / OakUndoStack 两类句柄。命令的多态 (redo/undo 行为)经 回调函数指针 实现 oakundo_command_create(name, redo, undo, free_fn, userdata)), 即铁律 §0.4 的手工虚表;消费侧不构造 C++ 子类
  • 消费oakcommon。
  • 边界数据:命令句柄(owned)。无事件——push/undo/redo 的调用方 知道栈索引变化,通知由调用方(facade 适配层)发出(见 §3)。

2.3 oaknodeM3)— 最大提供方

  • 提供OakNodeNode/NodeGroup/NodeKeyframe/NodeFactory/NodeTraverser/ Project/Folder/Sequence/Track/TrackList/Block/Footage/ColorManager 句柄族。逐族清单见 M3 §2。无订阅接口——所有修改经命令函数完成, 调用方知道影响(§3)。
  • 消费oakcommon、oakundo;对 render/codec/audio/timeline 的引用按 02 §3/§4 的反向切割表在各模块就位后改经其 C ABI。
  • 边界数据:节点句柄(borrowed 为主,工程拥有节点)、 oak_node_value POD、id 字符串(buf/size)。

2.4 oaktimelineM4

  • 提供marker/workarea/timeline 编辑原语句柄族(OakTimelineMarker 等),timeline 专用 undo 命令经 oakundo 的回调式命令注册,不自带 命令子类。
  • 消费:oaknode32 处,全部经句柄族)、oakundo、oakcommon。

2.5 oakcodecM5

  • 提供OakCodecDecoder/Encoder/Frame/ProxyManager 句柄族; 帧以 OakCodecFrame * 不透明句柄跨边界(owned,配对 free), 像素数据经 oakcodec_frame_data(frame, plane, &linesize) 取出指针 borrowed,生命周期随 frame)。
  • 消费oakcommon、oaknodefootage 流信息)、oakcore、ffmpeg_bridge。

2.6 oakaudioM6

  • 提供OakAudioManager/Processor/Synchronizer 句柄族;波形/电平 数据以 POD 数组 + count 出参。
  • 消费oakcoresamplebuffer)、oakcodec1 处)。

2.7 oakrenderM7

  • 提供OakRenderRenderer/Ticket/Cache/ColorProcessor 句柄族; 渲染结果帧为 owned 句柄;渲染 ticket 是异步命令(后台线程), 进度/完成回调是它的返回通道——这是 §3 允许回调的唯一情形 (线程语义按 riir.md §6.2 钉死)。
  • 消费oaknode、oakcodec、oakcommon、oakundo1 处)、oakbackend GPU 插件,经 renderbackend_c.h 手工虚表——现有先例)。

2.8 oaktaskM8)— 编排者

  • 提供OakTaskTask 句柄 + 任务工厂族 + TaskManager 查询函数。 任务是异步命令:进度/完成回调即其返回通道(§3 唯一例外), 无其他事件。load/save/import/otio 任务工厂保留,但实现改为委托 oakstorage(见 M10 §4);任务结果(Project、Footage 列表)以 有类型句柄返回(oaktask_import_take_commandvoid * 返回 按铁律 §0.1 改为 OakUndoCommand *)。
  • 消费oakstorage、oaknode、oakcodec、oakrender、oaktimeline。

2.9 oakpluginM9

  • 提供OFX 插件加载/实例句柄族(OakPluginHost/Instance)。
  • 消费oaknode、oakrender、oakundo。

2.10 oakstorageM10,新拆)— 工程持久化

  • 提供OakStorageProject(打开的工程会话)、OakStorageBackend (手工虚函数表,后端注册用)两类句柄 + oakstorage_open/save/probe 静态函数。URI 寻址file://…/*.ove 走内建 ove-xml 后端;未来 oakdb:// 走数据库后端——替换数据库 = 新增一个后端实现并注册, 消费侧零改动。
  • 消费:oaknode(反序列化建图 / 序列化取图)、oakcommon。
  • 边界数据:工程句柄(owned)、XML 字节流(buf/size)、后端表。 无事件——open/save 是同步命令,成败与结果全在返回值里,调用方 (oaktask/facade)知道影响,由它发通知(§3)。
  • 详见 M10-oakstorage.md

3. 通知的统一约定(2026-08 修订:上层对下层只有命令)

铁律:上层调下层只发命令,不调订阅。 上层调用下层时必须知道该调用的 影响——改了什么、结果是什么,全部由返回值/出参告知,调用方自己决定后续 动作。因此:

  • 模块间 C ABI 一律不提供 subscribe/unsubscribe 类接口。 下层不持有 上层的函数指针,不反向通知。各模块手册里原有的 oak<mod>_subscribe 设计全部作废(M2/M3/M10 已改)。
  • 变更通知由命令发起方负责。 例:app 经 facade 调 undo 命令后, facade 知道栈索引变了,由 facade 经既有 oakengine_event 通道通知 app 侧——通知的起点永远是最靠近调用者的那一层。
  • 唯一例外:异步任务。 后台执行的单元(oaktask 的任务、oakrender 的 渲染 ticket)本质上是"提交时拿不到结果"的命令,允许进度/完成回调—— 回调即该命令的返回通道,线程语义按 01 §4 / riir.md §6.2 钉死。 同步接口不得配回调。

4. 错误与所有权(横向统一)

  • 返回码:0 = OK,负值 OAK<MOD>_E_*(值与 oakengine 现有对齐); 细节经 oak<mod>_last_error(buf, size)(线程局部)。
  • 所有权注释三档:/* owned */init/take 返回,必须配对 free)、 /* borrowed */(访问器返回,禁 free)、/* retained */register 类,配对 unregister)。句柄默认 owned。
  • 每个模块提供 oak<mod>_debug_alive_count()(测试专用,钉死泄漏)。