core: merge oak-common into oak-core
CI / Build & test (Linux) (push) Successful in 24m6s
CI / Build & test (Windows) (push) Successful in 31m14s

oak-common is gone; its modules (configstore, xmlutils, ocioutils,
oiioutils, colormath, colortransform, videoparams, ffmpegutils, ...)
now live in oak-core alongside the value types. The render value/GPU
types moved too: backend (wgpu context + DisplayRenderer), color
(ColorProcessor over ocio-rs), texture, frame, and the commonutil
config helpers.

Fix-ups to make the merged tree build and pass tests:

- oak-core Cargo.toml: wgpu back to 25 (the moved backend code is
  written against that API generation); add the toml/quick-xml/image
  deps oak-common carried.
- lib.rs: drop the duplicate 'pub mod error;'.
- error.rs: unified OAKCORE_* codes; restore Error::new() and
  From<OcioError> from oak-common's error type.
- backend.rs/color.rs: oak_core::/oak_render:: self-references
  rewritten to crate::; the shaderfx-dependent GPU effect test moved
  to oak-render's shaderfx tests (shaderfx depends on oak-node and
  cannot live in oak-core).
- oak-render's error module re-exports oak_core::error::{Error,
  Result}; the OAKRENDER_* codes stay as the public-code contract.
- oak-node jobs.rs: ColorProcessor imported from oak_core::color.
- Integration tests repointed at oak_core::{texture, frame, backend,
  color, colormath}.
- the display-ICC regression test treats an empty OAK_DISPLAY_ICC as
  unset, matching displayicc::env_override_icc.
This commit is contained in:
2026-09-03 17:42:20 +08:00
parent 49fed365a4
commit 4babbf5de8
150 changed files with 3052 additions and 4030 deletions
+1 -1
View File
@@ -18,7 +18,7 @@
```
oakcore(已有,不动)
oakcommon ─ oakundo ─ oaknode ─ oaktimeline ─ oakcodec ─ oakrender ─ oaktask ─ oakplugin
oak_core ─ oakundo ─ oaknode ─ oaktimeline ─ oakcodec ─ oakrender ─ oaktask ─ oakplugin
│ │
└────────────── oakstorage(工程持久化, ┘
后端可插拔:文件→数据库)
@@ -58,7 +58,7 @@ OAKMOD_API <ret> oakmod_clazz_<func>_s(/* 参数 */);
3. 多个构造重载用后缀区分:`oakmod_clazz_init`(默认)、
`oakmod_clazz_init_from_file``oakmod_clazz_init_copy` 等。
4. 命名全小写,模块前缀 `oak<mod>_`oakundo/oaknode/oaktimeline/
oakcodec/oakrender/oaktask/oakaudio/oakplugin/oakcommon/oakstorage)。
oakcodec/oakrender/oaktask/oakaudio/oakplugin/oak_core/oakstorage)。
5. 导出宏 `OAKMOD_API``oakengine/export.h` 样式
`__attribute__((visibility("default")))`),模块编译加
`-fvisibility=hidden`——每个模块**出生即 visibility 干净**
@@ -36,7 +36,7 @@
| 序 | 模块 | 内容(engine/ 下目录) | 主要切割点 |
|---|---|---|---|
| M0 | oakcore | `core/`(已完成,不动) | — |
| M1 | oakcommon | `common/`41 文件工具集)+ `config/` | common→render/node/undo/codec/plugin 的 12 次反向 include(清单见 M1 §3 |
| M1 | oak_core | `common/`41 文件工具集)+ `config/` | common→render/node/undo/codec/plugin 的 12 次反向 include(清单见 M1 §3 |
| M2 | oakundo | `undo/`undocommand/undostack | undo→node/project.h 1 处(M2 §3 |
| M3 | oaknode | `node/`(图、工厂、keyframe、nodeundo、traverser | node→render 47、node→codec 8、node→timeline 5、node→audio 4、node→undo 4M3 §3,最大的活) |
| M3a | **oakstorage** | `node/project/serializer` 落盘路径 + `task/project/{load,save,loadotio,saveotio}` 文件 IO(**工程持久化单列**,后端可插拔:当前 XML 文件,未来数据库) | storage→node(序列化建图取图,经 oaknode C ABI);手册 M10 |
@@ -52,15 +52,15 @@
**M3.5(伴随 M3 的类型下沉)**`render/videoparams.h`
`render/subtitleparams.h``render/colortransform.h` 是纯数据类型,
codec/node 都重度引用——下沉到 **oakcommon**(或独立 oakmedia 目录,
执行时二选一,默认并 oakcommon),切断 codec→render 的大头。
codec/node 都重度引用——下沉到 **oak_core**(或独立 oakmedia 目录,
执行时二选一,默认并 oak_core),切断 codec→render 的大头。
## 3. 依赖环处理总表
| 环 | 数据 | 处理 |
|---|---|---|
| node ↔ render | 47/38 | M3 时 node 侧 47 次引用经 oakrender **尚未存在**——因此 M3 拆分时 node→render 的引用先经"前向 C ABI"处理:把 node 用到的 render 类(ColorProcessor/RenderManager/footagejob/pluginjob/videoparams)的 C API 定义在 **oaknode 手册里但由 M7 实现**?**否**——正确顺序见 §4 说明 |
| node ↔ timeline | 5/32 | node→timeline 5 次(timelinecommon×2、marker/workarea/timelineundogeneral 各1):枚举/常量头下沉 oakcommon,其余经 M4 反向 C ABI |
| node ↔ timeline | 5/32 | node→timeline 5 次(timelinecommon×2、marker/workarea/timelineundogeneral 各1):枚举/常量头下沉 oak_core,其余经 M4 反向 C ABI |
| node ↔ codec | 8/3 | node→codec 8decoder/frame/encoder/proxymanager):M5 反向 C ABI |
| node ↔ audio | 4/4 | M6 反向 C ABI |
| render ↔ codec | 9/11 | M3.5 类型下沉后剩 ~3renderer.h/framemanager.h),M5 时处理 |
+10 -10
View File
@@ -14,7 +14,7 @@
行 = 消费方,列 = 提供方;单元格 = 消费的接口族(详见各提供方手册)。
| 消费 ↓ \ 提供 → | oakcommon | oakundo | oaknode | oaktimeline | oakcodec | oakaudio | oakrender | oakstorage | oaktask | oakplugin | oakcore |
| 消费 ↓ \ 提供 → | oak_core | oakundo | oaknode | oaktimeline | oakcodec | oakaudio | oakrender | oakstorage | oaktask | oakplugin | oakcore |
|---|---|---|---|---|---|---|---|---|---|---|---|
| **facade**src/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 委托** | — | — | — |
@@ -26,16 +26,16 @@
| **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** | — | — | — | — | — | — | — | — | — | — | — |
| **oak_core** | — | — | — | — | — | — | — | — | — | — | — |
(空格 = 无依赖。"N 处"数据来自 02 的 include 扫描。oakcore 与
ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
## 2. 逐模块接口契约
### 2.1 oakcommonM1)— 纯下沉,无业务对象
### 2.1 oak_coreM1)— 纯下沉,无业务对象
- **提供**`include/oakcommon/types.h` 的全模块共用 POD(时间戳/区间/
- **提供**`include/oak_core/types.h` 的全模块共用 POD(时间戳/区间/
枚举常量,含 M3.5 下沉的 `OakVideoParams`/`OakSubtitleParams`/
`OakColorTransform`);工具函数(全 `_s` 静态式,无句柄)。
- **消费**:无(叶子)。
@@ -47,7 +47,7 @@ ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
redo/undo 行为)经 **回调函数指针** 实现
`oakundo_command_create(name, redo, undo, free_fn, userdata)`),
即铁律 §0.4 的手工虚表;消费侧**不构造 C++ 子类**。
- **消费**oakcommon
- **消费**oak_core
- **边界数据**:命令句柄(owned)。无事件——push/undo/redo 的调用方
知道栈索引变化,通知由调用方(facade 适配层)发出(见 §3)。
@@ -57,7 +57,7 @@ ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
Project/Folder/Sequence/Track/TrackList/Block/Footage/ColorManager`
句柄族。逐族清单见 M3 §2。无订阅接口——所有修改经命令函数完成,
调用方知道影响(§3)。
- **消费**oakcommon、oakundo;对 render/codec/audio/timeline 的引用按
- **消费**oak_core、oakundo;对 render/codec/audio/timeline 的引用按
02 §3/§4 的反向切割表在各模块就位后改经其 C ABI。
- **边界数据**:节点句柄(borrowed 为主,工程拥有节点)、
`oak_node_value` POD、id 字符串(buf/size)。
@@ -67,7 +67,7 @@ ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
- **提供**marker/workarea/timeline 编辑原语句柄族(`OakTimelineMarker`
等),timeline 专用 undo 命令**经 oakundo 的回调式命令**注册,不自带
命令子类。
- **消费**oaknode32 处,全部经句柄族)、oakundo、oakcommon
- **消费**oaknode32 处,全部经句柄族)、oakundo、oak_core
### 2.5 oakcodecM5
@@ -75,7 +75,7 @@ ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
帧以 `OakCodecFrame *` 不透明句柄跨边界(owned,配对 free),
像素数据经 `oakcodec_frame_data(frame, plane, &linesize)` 取出指针
borrowed,生命周期随 frame)。
- **消费**oakcommon、oaknodefootage 流信息)、oakcore、ffmpeg_bridge。
- **消费**oak_core、oaknodefootage 流信息)、oakcore、ffmpeg_bridge。
### 2.6 oakaudioM6
@@ -89,7 +89,7 @@ ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
渲染结果帧为 owned 句柄;渲染 ticket 是**异步命令**(后台线程),
进度/完成回调是它的返回通道——这是 §3 允许回调的唯一情形
(线程语义按 riir.md §6.2 钉死)。
- **消费**oaknode、oakcodec、oakcommon、oakundo1 处)、oakbackend
- **消费**oaknode、oakcodec、oak_core、oakundo1 处)、oakbackend
GPU 插件,经 `renderbackend_c.h` 手工虚表——现有先例)。
### 2.8 oaktaskM8)— 编排者
@@ -114,7 +114,7 @@ ffmpeg_bridge 为现成独立库,不参与拆分顺序。)
静态函数。**URI 寻址**`file://…/*.ove` 走内建 ove-xml 后端;未来
`oakdb://` 走数据库后端——替换数据库 = 新增一个后端实现并注册,
消费侧零改动。
- **消费**oaknode(反序列化建图 / 序列化取图)、oakcommon
- **消费**oaknode(反序列化建图 / 序列化取图)、oak_core
- **边界数据**:工程句柄(owned)、XML 字节流(buf/size)、后端表。
无事件——open/save 是同步命令,成败与结果全在返回值里,调用方
oaktask/facade)知道影响,由它发通知(§3)。
+49 -49
View File
@@ -1,4 +1,4 @@
# M1 · oakcommon 拆分手册
# M1 · oak_core 拆分手册
> 内容:`engine/common/`41 文件通用工具集)+ `engine/config/`。
> 依赖:oakcore(2)。被依赖:几乎全员(node 31、render 24、
@@ -8,99 +8,99 @@
## 1. 目标形态
```
oakcommon/
include/oakcommon/ # 公共头(C ABI + 允许直引的纯头工具)
oak_core/
include/oak_core/ # 公共头(C ABI + 允许直引的纯头工具)
src/ # 现有 .cpp 原样迁入
tests/ # oakcommon_gtest
tests/ # oak_core_gtest
```
- **纯头工具**lerp.h、define.h、decibel.h、tohex.h、digit.h、
memorypool.h、threadsafemap.h、range.h 等无 .cpp 的):作为
oakcommon 公共头直接提供给其他模块 include——拆分阶段允许
oak_core 公共头直接提供给其他模块 include——拆分阶段允许
(不产生链接依赖)。RIIR 阶段这些会改写成各语言自有实现。
- **config/config.h**:单头配置存取,被全模块引用(10+)。
它是 Qt 依赖(QSettings 包装),按 §2 冻结 C ABI。
## 2. 冻结 C API(有 .cpp 实现的函数族)
命名前缀 `oakcommon_`。以下按头分组(签名机械规则见 01 §3,
命名前缀 `oak_core_`。以下按头分组(签名机械规则见 01 §3,
此处冻结函数清单与特殊约定):
### 2.1 `oakcommon/config.h`(对应 config/config.h
### 2.1 `oak_core/config.h`(对应 config/config.h
```c
void oakcommon_config_set(const char *group, const char *key,
void oak_core_config_set(const char *group, const char *key,
const char *value_utf8);
int oakcommon_config_get(const char *group, const char *key,
int oak_core_config_get(const char *group, const char *key,
char *buf, int buf_size); /* 两段式 */
int oakcommon_config_get_int(const char *group, const char *key,
int oak_core_config_get_int(const char *group, const char *key,
int fallback);
double oakcommon_config_get_double(const char *group, const char *key,
double oak_core_config_get_double(const char *group, const char *key,
double fallback);
void oakcommon_config_set_int(const char *group, const char *key, int v);
void oak_core_config_set_int(const char *group, const char *key, int v);
```
### 2.2 `oakcommon/xml.h`(对应 common/xmlutils.h8 次被引)
### 2.2 `oak_core/xml.h`(对应 common/xmlutils.h8 次被引)
```c
/* XMLAttributeLoop/xml_read_next_start_element 的 C 化:
* 以迭代器句柄包装 QXmlStreamReader */
typedef struct OakCommonXmlReader OakCommonXmlReader;
OakCommonXmlReader *oakcommon_xml_reader_init(const char *utf8, int len);
void oakcommon_xml_reader_free(OakCommonXmlReader *r);
int oakcommon_xml_read_next_start_element(OakCommonXmlReader *r);
int oakcommon_xml_reader_name(OakCommonXmlReader *r, char *buf, int n);
int oakcommon_xml_reader_attr(OakCommonXmlReader *r, const char *attr,
typedef struct oak_coreXmlReader oak_coreXmlReader;
oak_coreXmlReader *oak_core_xml_reader_init(const char *utf8, int len);
void oak_core_xml_reader_free(oak_coreXmlReader *r);
int oak_core_xml_read_next_start_element(oak_coreXmlReader *r);
int oak_core_xml_reader_name(oak_coreXmlReader *r, char *buf, int n);
int oak_core_xml_reader_attr(oak_coreXmlReader *r, const char *attr,
char *buf, int n);
int oakcommon_xml_reader_read_element_text(OakCommonXmlReader *r,
int oak_core_xml_reader_read_element_text(oak_coreXmlReader *r,
char *buf, int n);
void oakcommon_xml_reader_skip_current(OakCommonXmlReader *r);
void oak_core_xml_reader_skip_current(oak_coreXmlReader *r);
```
写出侧 `oakcommon_xml_writer_*`init_to_string/write_attribute/
写出侧 `oak_core_xml_writer_*`init_to_string/write_attribute/
write_text_element/free 得字符串,两段式)。
### 2.3 `oakcommon/files.h`common/filefunctions.hrender 7 次)
### 2.3 `oak_core/files.h`common/filefunctions.hrender 7 次)
```c
int oakcommon_file_exists(const char *path); /* 1/0 */
int oakcommon_file_size(const char *path); /* -1 失败 */
int oakcommon_file_read_all(const char *path, char *buf, int n); /* 两段式 */
int oakcommon_file_write_all(const char *path, const char *data, int n);
int oakcommon_dir_mkpath(const char *path);
int oakcommon_get_config_path(char *buf, int n);
int oakcommon_get_temp_path(char *buf, int n);
int oak_core_file_exists(const char *path); /* 1/0 */
int oak_core_file_size(const char *path); /* -1 失败 */
int oak_core_file_read_all(const char *path, char *buf, int n); /* 两段式 */
int oak_core_file_write_all(const char *path, const char *data, int n);
int oak_core_dir_mkpath(const char *path);
int oak_core_get_config_path(char *buf, int n);
int oak_core_get_temp_path(char *buf, int n);
```
### 2.4 `oakcommon/ocio.h`、`oakcommon/oii.h`、`oakcommon/ffmpeg.h`
### 2.4 `oak_core/ocio.h`、`oak_core/oii.h`、`oak_core/ffmpeg.h`
ocioutils/oiioutils/ffmpegutils,按 01 §3 机械 POD 化;
OAK/OIIO/FFmpeg 类型全部句柄化或拍平字段。)
### 2.5 `oakcommon/misc.h`
### 2.5 `oak_core/misc.h`
`jobtime``double oakcommon_jobtime_now(void)`)、`current`
`oakcommon_current_get/set` 线程局部当前对象句柄)。
`jobtime``double oak_core_jobtime_now(void)`)、`current`
`oak_core_current_get/set` 线程局部当前对象句柄)。
## 3. 切割点(common 的 12 次反向 include,逐条)
| 现状 | 处理 |
|---|---|
| common → render/ 7 次(播放钟/自动滚动等引 render 类型) | 涉及文件(playbackaudioclock/autoscroll 等)**上移出 oakcommon**:它们不是底层工具,归 oakrenderM7 |
| common → render/ 7 次(播放钟/自动滚动等引 render 类型) | 涉及文件(playbackaudioclock/autoscroll 等)**上移出 oak_core**:它们不是底层工具,归 oakrenderM7 |
| common → node/ 3 次 | 同上,归 oaknodeM3 |
| common → undo/ 1 次 | 同上,归 oakundoM2 |
| common → codec/ 1 次 | 同上,归 oakcodecM5 |
| common → pluginSupport/ 1 次 | 同上,归 oakpluginM9 |
判据:切完后 `grep -rn '#include "' oakcommon/src | grep -vE
'"(oakcommon|olive/core)'` 为空(只剩 oakcore 与 Qt/系统头)。
判据:切完后 `grep -rn '#include "' oak_core/src | grep -vE
'"(oak_core|olive/core)'` 为空(只剩 oakcore 与 Qt/系统头)。
## 4. 测试(映射 03 §2
- configset/get 往返、int/double fallback、两段式 buf。
- xmlreader 解析样例串、attr/text 读取、skip、writer 产出解析回读。
- files:临时目录建/写/读/尺寸/删除。
- 每函数 1 正常 + 1 错误路径;`oakcommon_debug_alive_count()` 泄漏断言。
- 每函数 1 正常 + 1 错误路径;`oak_core_debug_alive_count()` 泄漏断言。
## 实施现状(2026-08-05
@@ -110,10 +110,10 @@ M1 已落地并可独立构建、测试全绿(127 个用例:126 通过,1
### 最终目录结构
- `src/common/src/` — 去 Qt 化 C++ 实现(`olive::` 命名空间),target
`oakcommon`SHARED)。
`oak_core`SHARED)。
- `src/common/c_api/` — 纯 C ABI 包装,通过 `target_sources` 合并进
`oakcommon`,不单独成库。
- `src/common/tests/` — gtesttarget `oakcommon-gtest`
`oak_core`,不单独成库。
- `src/common/tests/` — gtesttarget `oak_core-gtest`
`gtest_discover_tests`
- `include/common/`(仓库根)— 公共 C 头:`commandlineparser.h`
`current.h``debug.h``dropworkflowbehavior.h``error.h`
@@ -124,18 +124,18 @@ M1 已落地并可独立构建、测试全绿(127 个用例:126 通过,1
### 独立构建与测试
```sh
cmake -S src/common/standalone -B build-oakcommon
cmake --build build-oakcommon -j
ctest --test-dir build-oakcommon --output-on-failure
cmake -S src/common/standalone -B build-oak_core
cmake --build build-oak_core -j
ctest --test-dir build-oak_core --output-on-failure
```
driver 通过 `find_package(... CONFIG)` 使用 Homebrew 的 OCIO/OIIO/GTest
(顶层 `cmake/FindOpenColorIO.cmake`/`FindOpenImageIO.cmake` 面向
`.so`,macOS 下不适用),并把 config target 映射到 oakcommon
`.so`,macOS 下不适用),并把 config target 映射到 oak_core
CMakeLists 消费的 `${OCIO_LIBRARIES}` 等变量。driver 中额外处理了两点:
`olivecore``third_party/openfx/include` 头路径(顶层靠全局
include);禁用 OpenTimelineIO`/opt/otio` 的 dylib 用 `@loader_path`
安装名,构建树内无法加载,且 oakcommon 不需要 OTIO)。
安装名,构建树内无法加载,且 oak_core 不需要 OTIO)。
### 实际依赖
@@ -150,16 +150,16 @@ include);禁用 OpenTimelineIO`/opt/otio` 的 dylib 用 `@loader_path`
`fb_find_best_pix_fmt_of_list`ffmpeg_bridge 导出符号)。
- `pixelformat.h`/`sampleformat.h` 本身是 header-only,只需头路径
`core/include``ffmpeg_bridge/include`,因这两个 target 的
include 目录是 PRIVATE,在 oakcommon 里显式补为 PUBLIC)。
include 目录是 PRIVATE,在 oak_core 里显式补为 PUBLIC)。
- 未按计划只链 oakcore 头;OLIVECORE_BUILD_TESTS 在独立构建中关闭。
### 与计划的主要差异
- 接口未按 §2 冻结清单逐条实现,而是按实际使用面包装:C ABI 头放在
仓库根 `include/common/`,命名 `oakcommon_<模块>_<动词>`,两段式
仓库根 `include/common/`,命名 `oak_core_<模块>_<动词>`,两段式
buffer(先查询尺寸再拷入)约定统一。
- `xmlutils` 用 expat 实现(事件预先解析成队列);C API 的
`oakcommon_xml_reader_read_element_text` 因底层是消费型读取,在
`oak_core_xml_reader_read_element_text` 因底层是消费型读取,在
handle 内缓存最近一次文本以兼容两段式调用。
- 被移除/上移的类(播放钟、autoscroll 等反向 include 涉及项)见
`notes.md`
@@ -5,7 +5,7 @@
> 与 `engine/task/project/{load,save,loadotio,saveotio}` 的**文件 IO 部分**。
> **不含**剪贴板序列化(copy/paste 的节点图 XML 留在 oaknode 的
> serializer 族,见 M3)。
> 依赖:oaknodeproject/root/序列化建图取图)、oakcommon
> 依赖:oaknodeproject/root/序列化建图取图)、oak_core
> 被依赖:oaktaskload/save 任务委托)、facade。
> 拆分顺序:M3aoaknode 之后、oakserialize 同批)。
>
@@ -9,7 +9,7 @@
## 0. 形态决策(2026-08,已定)
- **A 方案(用户拍板)**app / oak-cli / oak-worker 只依赖
oakcommon / oakundo / oaknode / oaktimeline / oakcodec / oakaudio /
oak_core / oakundo / oaknode / oaktimeline / oakcodec / oakaudio /
oakrender / oaktask / oakplugin / oakstorage 的 rlib;不链接
liboakengine(连 rlib 形态都不用)。
- **oakengine 保留为纯 cdylib**:只给 OFX 插件和未来的外部消费者
+4 -4
View File
@@ -132,21 +132,21 @@ ctest --test-dir build-oakundo --output-on-failure
### 实际依赖
- Oak 内部:仅 oakcommon 的头文件宏(`define.h`
- Oak 内部:仅 oak_core 的头文件宏(`define.h`
`DISABLE_COPY_MOVE`),纯头文件,按 include 路径引用
`${OAK_REPO_ROOT}/src/common/src`),**不链接** oakcommon
`${OAK_REPO_ROOT}/src/common/src`),**不链接** oak_core
不依赖 olivecore/ffmpeg_bridge。
- 第三方:GTest(仅测试)。无 Qt。
### 与计划的主要差异
- 接口未按 §2 冻结清单逐条实现,而是对齐 oakcommon 的既有契约:
- 接口未按 §2 冻结清单逐条实现,而是对齐 oak_core 的既有契约:
C ABI 头放在仓库根 `include/undo/`,命名 `oakundo_<族>_<动词>`
查询类函数返回 int 错误码 + out 参数(计划中的
`int64_t oakundo_undostack_count(...)` 直接返回值形式改为
`int ...(OakUndoStack *, int64_t *out)`);字符串两段式 buffer 约定。
- 句柄族名:`OakUndoCommand`/`OakUndoStack`init/free 语义与
oakcommon 一致(init 失败返回 NULL 且内部 try/catch 兜底,
oak_core 一致(init 失败返回 NULL 且内部 try/catch 兜底,
free(NULL) 为 no-op)。
- §2.2 的 `OakUndoObjectParent`QObject 挂载点)、
`oakundo_undostack_update_actions``oakundo_undostack_undo_action/
+7 -7
View File
@@ -61,9 +61,9 @@ project.h、timeline.h 的对应函数就是模板,参数命名前缀换
| 现状(次数) | 处理 |
|---|---|
| node → render/ 47colorprocessor 8、videoparams 5、footagejob 4、rendermanager 3、pluginjob 3 等) | videoparams/colortransform 随 M3.5 下沉 oakcommon;其余 **M7 时**改经 oakrender C ABI02 §4 裁决 A:M3 暂不断链,禁止新增) |
| node → render/ 47colorprocessor 8、videoparams 5、footagejob 4、rendermanager 3、pluginjob 3 等) | videoparams/colortransform 随 M3.5 下沉 oak_core;其余 **M7 时**改经 oakrender C ABI02 §4 裁决 A:M3 暂不断链,禁止新增) |
| node → codec/ 8decoder 4、frame 2、encoder 1、proxymanager 1 | M5 时改经 oakcodec C ABIM5 手册已含 frame/decoder 家族) |
| node → timeline/ 5timelinecommon 2、marker 1、workarea 1、timelineundogeneral 1 | timelinecommon 的枚举/常量下沉 oakcommon/types.hmarker/workarea 引用(均在 node/project/ 序列化路径)M4 时改经 oaktimeline C ABI |
| node → timeline/ 5timelinecommon 2、marker 1、workarea 1、timelineundogeneral 1 | timelinecommon 的枚举/常量下沉 oak_core/types.hmarker/workarea 引用(均在 node/project/ 序列化路径)M4 时改经 oaktimeline C ABI |
| node → audio/ 4 | M6 时改经 oakaudio C ABI |
| node → undo/ 4undocommand.h | M2 后改 include oakundo 公共头 + 适配类 |
@@ -117,15 +117,15 @@ driver 照 src/common/standalone 模式:EXPAT/OpenColorIO/OpenImageIO
用 Homebrew 的 config 包(`find_package(... CONFIG)`)并映射到
`${OCIO_LIBRARIES}` 等变量;`add_subdirectory` 引入真实 in-repo
targetcore→olivecore、ffmpeg_bridge、src/undo→oakundo、
src/common→oakcommon,各自 BUILD_TESTS 关闭),不再链接预构建
src/common→oak_core,各自 BUILD_TESTS 关闭),不再链接预构建
dylib;禁用 OpenTimelineIO`/opt/otio``@loader_path` 问题,
oaknode 不需要)。
### 实际依赖
- Oak 内部:oakcommonXML/Current/工具)、oakundoUndoCommand/
- Oak 内部:oak_coreXML/Current/工具)、oakundoUndoCommand/
UndoStack)、olivecore`olive::core::Rational/Color/Bezier`
C ABI 包装,真实符号)、ffmpeg_bridge(经 oakcommon 间接)。
C ABI 包装,真实符号)、ffmpeg_bridge(经 oak_core 间接)。
- 第三方:EXPAT、OpenColorIO、OpenImageIO、Imath(头)、FFmpeg
(经 ffmpeg_bridge 间接)、GTest(仅测试)。
- **transition stub 机制**(裁决 A):对尚未拆分的
@@ -133,7 +133,7 @@ oaknode 不需要)。
头文件由 `src/node/transition/` 的过渡 stub/转发头提供(engine 头
仍是 Qt 版),符号经 `-undefined dynamic_lookup`macOS)留到
运行时解析。测试进程启动时必须能解析这些符号:oaknode-gtest
链接真实 targetolivecore/oakcommon/oakundo + OCIO/OIIO/Imath
链接真实 targetolivecore/oak_core/oakundo + OCIO/OIIO/Imath
dylib)并 `-Wl,-force_load` 预构建的
`build/third_party/openfx/HostSupport/libOfxHost.a`OFX 符号与
typeinfo,否则二进制启动即崩,PRE_TEST 发现模式也会挂;路径用
@@ -145,7 +145,7 @@ oaknode 不需要)。
### 与冻结 C API 的主要差异
- 函数族命名与约定照 oakcommon/oakundo 既有契约:`oaknode_<族>_<动词>`
- 函数族命名与约定照 oak_core/oakundo 既有契约:`oaknode_<族>_<动词>`
int 错误码 + out 参数,字符串两段式 bufferundoable 变体成对
`_undoable` 后缀,部分经 `OakUndoCommand *` 尾参)。
- §2 冻结表中**跳过/未实现**的函数族:
@@ -61,11 +61,11 @@ OAKTL_API int oaktimeline_workarea_set_range_undoable(
OAKTL_API int oaktimeline_workarea_set_enabled_undoable(
OakTimelineWorkarea *w, int enabled, OakUndoCommand *command);
OAKTL_API void oaktimeline_workarea_reset(int64_t *in_ts, int64_t *out_ts);
/* load/save 经 oakcommon_xml 句柄在 oaknode 序列化路径调用 */
/* load/save 经 oak_core_xml 句柄在 oaknode 序列化路径调用 */
OAKTL_API int oaktimeline_workarea_load(OakTimelineWorkarea *w,
OakCommonXmlReader *r);
oak_coreXmlReader *r);
OAKTL_API int oaktimeline_workarea_save(const OakTimelineWorkarea *w,
OakCommonXmlWriter *x);
oak_coreXmlWriter *x);
```
### 2.3 `oaktimeline/edit.h`timeline undo 命令族的语义入口)
@@ -120,7 +120,7 @@ OAKTL_API int64_t oaktimeline_nearest_block_ts(OakNodeTrack *track,
- 构建测试:`cmake -S src/timeline/standalone -B build-oaktimeline &&
cmake --build build-oaktimeline -j && ctest --test-dir
build-oaktimeline`——117/117(本模块 21 用例 + oaknode 回归 96)。
全量回归:oakcommon 193、oaknode 96、oakrender 42、oakcodec 18、
全量回归:oak_core 193、oaknode 96、oakrender 42、oakcodec 18、
oakaudio 36 全绿。
- C API 与 §2 冻结表的差异:marker/workarea 的增删改统一为
`_command` 工厂形态(返回 OakUndoCommand,调用方 redo/push),
+1 -1
View File
@@ -83,7 +83,7 @@ proxy:照 `oakengine/proxy.h` 模板(get_or_start/state/cancel)。
| 现状 | 处理 |
|---|---|
| codec → render/ 11 | videoparams/subtitleparams/colortransform 已随 M3.5 下沉 oakcommon;剩 renderer.h(2)、framemanager.h(1) → framemanager 是 codec 内部缓存编排,**随 codec 一起走**(从 render/ 移入 oakcodec/src,纯文件移动,它本来就主要服务 codec) |
| codec → render/ 11 | videoparams/subtitleparams/colortransform 已随 M3.5 下沉 oak_core;剩 renderer.h(2)、framemanager.h(1) → framemanager 是 codec 内部缓存编排,**随 codec 一起走**(从 render/ 移入 oakcodec/src,纯文件移动,它本来就主要服务 codec) |
| codec → task/ 5taskmanager/conform/proxy 编排) | proxy/conform 对 TaskManager 的引用改为 01 §4 回调注册(`oakcodec_set_task_submit_cb`),Task 对象创建上移 oaktaskM8),oakcodec 只调回调 |
| codec → node/ 3 | 经 oaknode C ABIM3 已就位) |
+3 -3
View File
@@ -179,7 +179,7 @@ oakengine_ipc_* 悬置符号。
### 实际依赖与链接形态
- Oak 内部:oaknode、oakcommon、oakundo、olivecore、ffmpeg_bridge
- Oak 内部:oaknode、oak_core、oakundo、olivecore、ffmpeg_bridge
(真实 target`add_subdirectory` 引入)。
- 第三方:OpenColorIO、OpenImageIO、Imath/OpenEXR(头)、OpenGL/
CoreVideo/Metal/QuartzCore framework、GTest(仅测试)。
@@ -209,10 +209,10 @@ oakengine_ipc_* 悬置符号。
**56** 个,**0 个悬置**」:25 个由 liboakrender 解析
PlaybackCache/FrameHashCache/DiskManager/RenderManager/
ColorProcessor/PreviewAutoCacher/LUTLibrary 等),其余 31 个由
oakcommonVideoParams/XmlStream*/SubtitleParams/QtUtils)、
oak_coreVideoParams/XmlStream*/SubtitleParams/QtUtils)、
oakundoUndoCommand/UndoStack/MultiUndoCommand vtable)解析。
- 公共头位于 `include/render/`(非 §1 的 `include/oakrender/`),
函数前缀 `oakrender_`,与 oaknode/oakcommon 的既有契约一致
函数前缀 `oakrender_`,与 oaknode/oak_core 的既有契约一致
(§1 目标形态中的 `oakrender/include/oakrender/` 未采用)。
- C API 命名照 R7-A §A.2 的 display.h 重写版改前缀
`oakrender_display_*`/`oakrender_codec_frame_*``OakCodecFrame`
+16 -16
View File
@@ -4,7 +4,7 @@
CancelableObject只在render和task处有🚰,移入对应模块。
## 从 oakcommonsrc/common)移除的类(2026-08-05
## 从 oak_coresrc/common)移除的类(2026-08-05
判据:不严重依赖 common 其他类,且只有一个非 common 模块使用它
tests/gtest 不计入使用方)。以下类已从 `src/common/` 移除,
@@ -12,7 +12,7 @@ CancelableObject只在render和task处有🚰,移入对应模块。
| 类 | 唯一使用方 | 应放到 |
|---|---|---|
| `Html`html.h/.cpp | engine/node | oaknodeM3)。注意它依赖 common 的 xmlutils,迁移时需连同 XML 辅助或改为调用 oakcommon C API |
| `Html`html.h/.cpp | engine/node | oaknodeM3)。注意它依赖 common 的 xmlutils,迁移时需连同 XML 辅助或改为调用 oak_core C API |
| `JobTime`jobtime.h/.cpp | engine/render | oakrenderM7 |
| `OTIOUtils`otioutils.h | engine/task | oaktaskM8 |
| `PlaybackAudioClock`playbackaudioclock.h | engine/audio | oakaudioM6 |
@@ -27,15 +27,15 @@ CancelableObject只在render和task处有🚰,移入对应模块。
另:`power.h``memorypool.h``threadsafemap.h` 当前没有任何
common 模块外的使用方(零用户),不满足移除判据,暂保留在
oakcommon;后续若确认无用途可直接删除。
oak_core;后续若确认无用途可直接删除。
## oakcommon 去Qt化的删除与语义变更(2026-08-05)
## oak_core 去Qt化的删除与语义变更(2026-08-05)
去Qt化过程中以下函数被删除或语义变化,迁移调用方时需注意:
- `CommandLineParser::print_help()`:不再自动读取
`QCoreApplication::applicationName()/applicationVersion()`,需先调
`set_app_info()`C API`oakcommon_commandlineparser_set_app_info`),
`set_app_info()`C API`oak_core_commandlineparser_set_app_info`),
否则打印默认 `"oak"` + 空版本。
- `FileFunctions::get_unique_file_identifier`:哈希由 SHA-1 改为
FNV-1a 64-bit,旧缓存 key 全部失效(需一次重建)。
@@ -51,7 +51,7 @@ oakcommon;后续若确认无用途可直接删除。
`olive::XmlStreamReader/Writer` 替代(不支持 XML 命名空间)。
- `OIIOUtils::frame_to_buffer/buffer_to_frame`:未进 C APIC++ 侧签名
拍平为 `(const void *data, int64_t linesize_bytes, OIIO::ImageBuf *)`
engine/codec/frame.cpp 迁移时传成员即可。`OakCommonPixelFormat` 枚举
engine/codec/frame.cpp 迁移时传成员即可。`oak_corePixelFormat` 枚举
目前定义在 include/common/ocioutils.hoiioutils 复用,后续可抽成
独立的 include/common/pixelformat.h。
- `MemoryPool`:删除 QTimer 每 5 秒自动回收空 arena,改为公有
@@ -67,7 +67,7 @@ oakcommon;后续若确认无用途可直接删除。
`create_horizontal/vertical_line``set_combo_box_data`
`word_wrap_string``flip_control_and_shift_modifiers`
`get_formatted_date_time``to_q_color``core::qHash`
`Q_DECLARE_METATYPE` 宏组)未迁入 oakcommonapp 层继续用 Qt 版。
`Q_DECLARE_METATYPE` 宏组)未迁入 oak_coreapp 层继续用 Qt 版。
`ptr_to_value/value_to_ptr` 载体由 QVariant 改为 `uintptr_t`
迁移时调用点需同步改(renderprocessor.cpp、rendermanager.cpp、
previewautocacher.cpp、src/capi/worker.cpp)。`get_parent_of_type`
@@ -283,7 +283,7 @@ ColorManager)去Qt化过程中的删除与语义变化,迁移调用方时需
- oaknode↔oaktimeline 运行期互相解析(add_default_nodes →
TimelineAddTrackCommand),双方 dylib dynamic_lookup,测试二进制
必须同时链两个库(各 standalone 驱动已接线)。
- oakcommon xml C API 新增 get_native 借用访问器(C++ only),
- oak_core xml C API 新增 get_native 借用访问器(C++ only),
oaktimeline 的 load/save 经它取回 XmlStreamReader/Writer。
## oakplugin 去Qt化的删除与语义变更(2026-08-05)
@@ -348,8 +348,8 @@ ColorManager)去Qt化过程中的删除与语义变化,迁移调用方时需
OAK_TIMELINE_WAVEFORMS_*,值与 olive::Timeline 枚举保持兼容)。
- tracklist.h/block.h 里 timelinecommon.h 的死引用删除;
src/node/transition/timeline/ 四个 stub 头删除。
- oakcommon xml C API 新增 oakcommon_xml_reader_wrap_native/
oakcommon_xml_writer_wrap_nativeC++ only 借用包装),
- oak_core xml C API 新增 oak_core_xml_reader_wrap_native/
oak_core_xml_writer_wrap_nativeC++ only 借用包装),
XmlReaderState/XmlWriterState 支持 owning/borrowed 双模式。
- liboaknode 对 liboaktimeline 的 C++ 符号引用降为 0(nm 验证)。
@@ -404,7 +404,7 @@ Rust 重写驱动(RIIR 后调用方只能走 C ABI,接线自动发生且被
- 已切:oaknode→oaktimeline81431d180)、oaknode→oakrender
5a564f30c,缓存体系/色彩/单例全部 C ABI 化)。
- olive::Variant 从 oaknode 下沉到 oakcommonsrc/common/src/
- olive::Variant 从 oaknode 下沉到 oak_coresrc/common/src/
variant.{h,cpp})——它本是跨模块值类型。
- 冻结时点的残留(nm 可查):
- render→node 41 个 C++ 符号:ProjectCopier 深拷贝族、
@@ -415,15 +415,15 @@ Rust 重写驱动(RIIR 后调用方只能走 C ABI,接线自动发生且被
oaknode_project_deep_copy/sync_copytraverser 改 hook 制)。
- node/render→plugin 的 OFX C++ 符号:随 M11DeepSeek 实现中)
落地消解。
- 各模块→oakcommon 的 XmlStreamReader/FileFunctions/VideoParams
C++ 调用:随 oakcommon Rust 化消解。
- 各模块→oak_core 的 XmlStreamReader/FileFunctions/VideoParams
C++ 调用:随 oak_core Rust 化消解。
- 文档化例外:Texture 的 Variant 载荷(Rust 侧不存在此问题)、
UndoCommand 跨模块继承、oakgl2/oakvulkan 后端插件接口。
- ④(隐藏 C++ API)同步搁置:模块 Rust 化后 C++ 符号自然消失。
## oakcommon Rust 测试:ffmpeg_bridge 符号依赖(2026-08-08
## oak_core Rust 测试:ffmpeg_bridge 符号依赖(2026-08-08
`oakcommon_ffmpegutils_get_compatible_bridge_pixel_format` 在非测试构建
`oak_core_ffmpegutils_get_compatible_bridge_pixel_format` 在非测试构建
中会经 `find_best_pix_fmt_of_list` 引用 ffmpeg_bridge 的
`fb_find_best_pix_fmt_of_list` 符号。集成测试二进制不链接 libffmpeg_bridge
实验证实直接调用该 FFI 导出会在链接期报 `_fb_find_best_pix_fmt_of_list`
@@ -441,7 +441,7 @@ test-stubs 约定一致):
(成功路径 + null out-param 的 E_INVALID 路径),需带
`--features test-stubs` 运行;不带 flag 时该文件整体为空(cfg 门控)。
## oakcommon Rustocioutils/oiioutils 吸收 oakoci2026-08-08 接手笔记)
## oak_core Rustocioutils/oiioutils 吸收 oakoci2026-08-08 接手笔记)
### 基线
+41 -41
View File
@@ -22,15 +22,15 @@
```
liboakengine(一个 dylibcrate 图是 DAG
├── oakcore-rs ← 共享 ABI 类型(CHandle + POD),无依赖的叶子
├── oakcommon → oakcore-rs
├── oak_core → oakcore-rs
├── oakundo → oakcore-rs
├── oaknode → oakcore-rs, oakcommon, oakundo, oakcodec
├── oaknode → oakcore-rs, oak_core, oakundo, oakcodec
├── oaktimeline → oakcore-rs, oakundo, oaknode
├── oakcodec → oakcore-rs, oakrender codec→render 直接调)
├── oakaudio → oakcore-rs, oakcommon, oakcodec
├── oakrender → oakcore-rs, oakcommon, oaknode render→node 直接调)
├── oaktask → oakcore-rs, oakcommon, oakundo, oakcodec, oaknode, oakrender
├── oakplugin → oakcore-rs, oakcommon, oakundo, oaknode, oakrendersuites 仍 C
├── oakaudio → oakcore-rs, oak_core, oakcodec
├── oakrender → oakcore-rs, oak_core, oaknode render→node 直接调)
├── oaktask → oakcore-rs, oak_core, oakundo, oakcodec, oaknode, oakrender
├── oakplugin → oakcore-rs, oak_core, oakundo, oaknode, oakrendersuites 仍 C
└── oakengine → 全部(facade
```
@@ -64,7 +64,7 @@ liboakengine(一个 dylibcrate 图是 DAG
| oakcodec | extern "C" | common 15657 / render 7262+test_stubs 27176 | 0 |
| oakaudio | extern "C" | codec 6683 / common 1665 / ffmpeg 7812 | 0 |
| oaktimeline | extern "C" | common / node 11742 / undo 2780+teststubs 52921 | 0 |
| oakundo / oakcommon | — | 无 bridge | — |
| oakundo / oak_core | — | 无 bridge | — |
facade `src/engine/rust/src/bridge/`9 个文件 2466 行、**624 个
`extern "C"` 导入**node 348 / common 91 / render 36 / timeline 34 /
@@ -97,8 +97,8 @@ task 33 / audio 31 / codec 24 / undo 22 / plugin 5),由
| 环 | 边 | 处理 |
|---|---|---|
| **node ↔ render** | node→render 3 fn + render→node copier | §4.1render→node 保留直接依赖;node→render 的 3 个函数下沉 oakcommon(实现本就在 oakcommon 侧:`default_disk_cache_path` 已是 render/bridge/common.rs 内的纯 Rust 实现;OCIO config 由 oakcommon `ocioutils::OcioConfig` 提供) |
| **codec ↔ render** | codec→render cancelatom + render→codec stub | §4.2cancelatom 下沉 oakcommon(原子取消旗标,纯 Rust);render→codec 的 stub 检查直接删除(路径必然 Err) |
| **node ↔ render** | node→render 3 fn + render→node copier | §4.1render→node 保留直接依赖;node→render 的 3 个函数下沉 oak_core(实现本就在 oak_core 侧:`default_disk_cache_path` 已是 render/bridge/common.rs 内的纯 Rust 实现;OCIO config 由 oak_core `ocioutils::OcioConfig` 提供) |
| **codec ↔ render** | codec→render cancelatom + render→codec stub | §4.2cancelatom 下沉 oak_core(原子取消旗标,纯 Rust);render→codec 的 stub 检查直接删除(路径必然 Err) |
其余方向均无环:node→timeline 0 调用、task→* 单向、plugin→* 单向、
audio→* 单向、timeline→node/undo 单向。
@@ -155,13 +155,13 @@ layout 相同但 Rust 类型不同的 `CHandle`、POD`OakVideoParams`、
| crate | 处理 |
|---|---|
| facade `engine/rust/src/bridge/` | §5`extern "C"` 块 → 直接调用模块 crate `ffi` 的安全包装(同名同签名) |
| oaknode `bridge/{undo,common,codec}` | 直接调用 oakundo/oakcommon/oakcodec 的 ffi`bridge/` 删除 |
| oaknode `bridge/{undo,common,codec}` | 直接调用 oakundo/oak_core/oakcodec 的 ffi`bridge/` 删除 |
| oaknode `bridge/{render,timeline,core}` | render/timeline 见 §4(环/死代码);core → oakcore-rs / 宿主 liboakcore(保持 link-time extern,见 §4.3 |
| oaktask `bridge/*` | 直接调用各目标 crate ffi`bridge/` 删除 |
| oakrender `bridge/node` | 直接调用 oaknode ffi(§4.1 |
| oakrender `bridge/{codec,common}` | codec → §4.2stub 删除);common → 直接调用 oakcommon |
| oakrender `bridge/{codec,common}` | codec → §4.2stub 删除);common → 直接调用 oak_core |
| oakplugin `bridge/{node,render,undo}` | 直接调用各目标 crate ffisuites 保持 C |
| oakcodec `bridge/{common,render}` | common → oakcommonrender → oakrendercancelatom 移 oakcommon 后改调 oakcommon,见 §4.2 |
| oakcodec `bridge/{common,render}` | common → oak_corerender → oakrendercancelatom 移 oak_core 后改调 oak_core,见 §4.2 |
| oakaudio `bridge/{codec,common,ffmpeg}` | codec/common → 直接调用;ffmpeg → ffmpeg_bridgeC++,保持 extern "C" |
| oaktimeline `bridge/{node,undo,common}` | node/undo → 直接调用;common 0 调用 → 删除;`teststubs.rs` 见 §7 |
@@ -182,10 +182,10 @@ layout 相同但 Rust 类型不同的 `CHandle`、POD`OakVideoParams`、
实现**2026-08-10 全量 grep 确认),所以运行时必然 dlsym 失败,走
"缺失"分支。破环 = 删除死调用:
1. `disk_cache_path()`:实现**下沉 oakcommon**(新增
1. `disk_cache_path()`:实现**下沉 oak_core**(新增
`filefunctions::default_disk_cache_path()`,基于既有的
`FileFunctions::get_configuration_location()`)。oaknode
`project.rs` 与 oakrender `manager.rs` 都直接调 oakcommon
`project.rs` 与 oakrender `manager.rs` 都直接调 oak_core
2. `color_config_create_default()`/`color_config_load()`oakrender 从未
实现这两个符号 → node `colormanager.rs` 的调用恒为 `None`(走
"标记已加载/保持原状" 分支)。删除调用、保留确定性等价逻辑(行为不变)。
@@ -205,12 +205,12 @@ layout 相同但 Rust 类型不同的 `CHandle`、POD`OakVideoParams`、
render→codec = 0。
- **codec → render**:只有 cancelatom。实施时发现 codec 收到的 atom 句柄
是 oakrender `make_owned` 按 **oakrender 的 `RefBox` 布局**装箱的,
codec 直接解引用会在不同 crate 的 `RefBox` 布局间读内存(oakcommon
codec 直接解引用会在不同 crate 的 `RefBox` 布局间读内存(oak_core
value-first、其余 refs-first),**不安全**。因此 cancelatom 的读取保持
经 oakrender 的 C 导出(codec `bridge::render` 的 link-time extern
`oakcore_*`/`fb_*` 同类,属"不可避免的 C 边界");实现体下沉
oakcommon`cancelatom::CancelAtom`oakrender 的
`oakrender_cancelatom_*` 导出改包 oakcommon`render/cancelatom.rs`
oak_core`cancelatom::CancelAtom`oakrender 的
`oakrender_cancelatom_*` 导出改包 oak_core`render/cancelatom.rs`
变为 re-export)。
结果:codec 与 render 之间无 crate 依赖;codec→render 仅剩 cancelatom
@@ -239,7 +239,7 @@ pub fn oaknode_project_init() -> CHandle {
```
- 每个 ffi fn 的路径:`oak<mod>::ffi::<子模块>::<fn>`(如
`oaknode::ffi::project``oaknode::ffi::folder``oakcommon::ffi::config`…);
`oaknode::ffi::project``oaknode::ffi::folder``oak_core::ffi::config`…);
实现时以模块 crate 实际 `pub mod` 布局为准(已核对:oaknode ffi 有
`project/node/keyframe/…` 子模块)。
- **facade 业务代码(node.rs/timeline.rs/… 共 393 处调用)零改动**:
@@ -257,24 +257,24 @@ pub fn oaknode_project_init() -> CHandle {
逐方向(每步一个 crate 一个方向,`cargo build`+`cargo test` 闭环):
1. oaknode`bridge/undo.rs``bridge/common.rs``bridge/codec.rs`
(→ oakundo/oakcommon/oakcodec 直接调,同 §5 的包装写法);
(→ oakundo/oak_core/oakcodec 直接调,同 §5 的包装写法);
2. oaktimeline`bridge/node.rs``bridge/undo.rs`(→ oaknode/oakundo);
3. oakrender`bridge/node.rs`(→ oaknode,§4.1)、`bridge/common.rs`
(→ oakcommon);
(→ oak_core);
4. oaktask`bridge/{node,render,codec,undo,common}.rs`
5. oakplugin`bridge/{node,render,undo}.rs`suites 不动);
6. oakcodec`bridge/common.rs`(→ oakcommon)、`bridge/render.rs`
(→ oakcommon cancelatom,§4.2);
6. oakcodec`bridge/common.rs`(→ oak_core)、`bridge/render.rs`
(→ oak_core cancelatom,§4.2);
7. oakaudio`bridge/{codec,common}.rs`
8. oaknode`bridge/render.rs`(→ oakcommon,§4.1)、`bridge/timeline.rs`
8. oaknode`bridge/render.rs`(→ oak_core,§4.1)、`bridge/timeline.rs`
(死代码删除,测试迁移见 §7)、`bridge/core.rs`(§4.3 保留 extern)。
被调方需要被加为 path 依赖的 crateoaknode 加 `oakundo`/`oakcommon`/
被调方需要被加为 path 依赖的 crateoaknode 加 `oakundo`/`oak_core`/
`oakcodec`oaktimeline 加 `oakundo`/`oaknode`oakrender 加
`oakcommon`/`oaknode`oaktask 加 `oakundo`/`oakcommon`/`oakcodec`/
`oaknode`/`oakrender`oakplugin 加 `oakcore-rs`/`oakcommon`/`oakundo`/
`oaknode`/`oakrender`oakcodec 加 `oakcommon`oakaudio 加
`oakcommon`/`oakcodec`。**不产生任何环**(§1.3 已消除)。
`oak_core`/`oaknode`oaktask 加 `oakundo`/`oak_core`/`oakcodec`/
`oaknode`/`oakrender`oakplugin 加 `oakcore-rs`/`oak_core`/`oakundo`/
`oaknode`/`oakrender`oakcodec 加 `oak_core`oakaudio 加
`oak_core`/`oakcodec`。**不产生任何环**(§1.3 已消除)。
## 7. 测试策略(每 crate 测试保持绿)
@@ -283,14 +283,14 @@ pub fn oaknode_project_init() -> CHandle {
- **用 `bridge/` 的测试必须迁移**(桥层从生产路径删除后不能留在测试里):
- 目标 crate 已 path 依赖的:`oaknode::bridge::undo::…`
`oakundo::ffi::…`(或 oakundo 类型层)直接调;`bridge::common::videoparams_*`
`oakcommon::…``bridge::core::audioparams_*``oakcore_rs::…`
`oak_core::…``bridge::core::audioparams_*``oakcore_rs::…`
/ 宿主 liboakcore extern
- 依赖不存在(环/死代码)的:`node::bridge::timeline` 的测试用
oaktimeline 自身导出或改写;`node::bridge::render` 的测试改调
oakcommon 下沉后的函数;
oak_core 下沉后的函数;
- 专门测 dlsym 机制的测试(如 `node/rust/tests/dbg2_test.rs`
`bridge::dlsym::resolve`)随机制删除而删除。
- **`test-stubs` featureoakplugin/oakcommon/oaktimeline/oaknode**
- **`test-stubs` featureoakplugin/oak_core/oaktimeline/oaknode**
语义变为"编译测试桩 C ABI(替代尚未存在的宿主/兄弟模块实现)"。
直接调用落地后,同一二进制内不再同时出现"真实现 + 桩"冲突:
facade `cargo test` 的 dev-dependency feature union 按新依赖图调整
@@ -319,7 +319,7 @@ pub fn oaknode_project_init() -> CHandle {
`cargo build` + `cargo test`(这一步后直接调用才类型同一)。
2. **facade bridge → 直接调用**(§5,步骤 a)。
3. **环处理**(§4):删除死调用;disk_cache_path/cancelatom 下沉
oakcommonrender 的 `codec_abi_available()` stub 检查删除。
oak_corerender 的 `codec_abi_available()` stub 检查删除。
4. **模块 bridge 逐方向 → 直接调用**(§6,步骤 b)。
5. **dlsym 删除**(步骤 c):node/render/plugin 的 `bridge/mod.rs::dlsym`
与残留调用清除;`linkage.rs` 注释更新。
@@ -354,7 +354,7 @@ pub fn oaknode_project_init() -> CHandle {
`OakUndoCommandVtable`/`OakVideoTicketParams`/`OakRenderVideoParams`/
`OffsetResult`/`StretchOffsetResult`/`SourceClip` → 各模块 crate 类型。
- **环处理**(§4 实施结论):node↔render 死调用删除;render→codec stub
删除;`oakcommon::{filefunctions::default_disk_cache_path, cancelatom}`
删除;`oak_core::{filefunctions::default_disk_cache_path, cancelatom}`
render 的 `cancelatom.rs` 改为 re-export。
- **模块 bridge**(步骤 b,模式已证明):oaknode `bridge/undo.rs`
→ oakundo 直接调用(oakundo 加入 node 依赖;bridge 函数名/签名不变,
@@ -372,18 +372,18 @@ encoding-params POD`oakcodec_encoding_params` 等)在 4 个 crate 各有
本轮完成的方向(每步 `cargo build` + 该 crate `cargo test` 绿):
- **oaknode `bridge/{undo,common,codec}` → 直接调用**(上轮已做 undo,
本轮完成 common + codec):oakcommon/oakcodec 加入 node 依赖;common
桥 31 个 dlsym 包装改为 `oakcommon::ffi::*` 直接调用,`test-stubs`
本轮完成 common + codec):oak_core/oakcodec 加入 node 依赖;common
桥 31 个 dlsym 包装改为 `oak_core::ffi::*` 直接调用,`test-stubs`
特性与库内 XML 桩删除;codec 桥的 `decoder_probe` 改为直接调用
`oakcodec::ffi::decoder::oakcodec_decoder_probe`(签名修正为真实
单参返回 CHandlefootage.rs 调用点同步)。node dlsym 52→20。
- **oakrender `bridge/common` → 直接调用**config/configuration_location/
disk_cache_path 改调 `oakcommon::ffi``oakcommon::filefunctions`
disk_cache_path 改调 `oak_core::ffi``oak_core::filefunctions`
`bridge/codec.rs` 全死代码(0 生产调用、0 测试引用)**删除**;
`bridge/node.rs`(copier 深拷贝)是死方向(oaknode 未实现该 C ABI
`oakrender_project_copier_*` 是冻结导出)——保留 dlsym 并记录。
render dlsym 22→4。
- **oakaudio `bridge/{codec,common}` → 直接调用**oakcodec/oakcommon
- **oakaudio `bridge/{codec,common}` → 直接调用**oakcodec/oak_core
加入 audio 依赖;codec 桥的 `*mut c_void` 句柄约定与真实
`CHandle`/`OakCodecAudioStreamInfo`/`oakcodec_encoding_params` 对齐
(类型别名统一),调用点(waveform/manager)同步;common 桥改直接
@@ -394,7 +394,7 @@ encoding-params POD`oakcodec_encoding_params` 等)在 4 个 crate 各有
断言改为探针错误路径(完整解码依赖宿主 ffmpeg_bridgeRust 测试
二进制不链接)。
- **oakcodec `test-stubs` 特性拆分**(为 node 测试二进制提供宿主符号):
`src/bridge/test_stubs.rs` 的 oakcommon_* 桩保持 `#[cfg(test)]`
`src/bridge/test_stubs.rs` 的 oak_core_* 桩保持 `#[cfg(test)]`
codec 自身测试用),oakcore_*/oakrender_* 桩改为
`#[cfg(any(test, feature="test-stubs"))]`node 的 dev-dependencies
`features=["test-stubs"]` 依赖 oakcodec,解决 node 测试链接
@@ -429,16 +429,16 @@ encoding-params POD`oakcodec_encoding_params` 等)在 4 个 crate 各有
容错路径(`texture_is_dummy` 空句柄 0、`instance_render` 空 dst 被
插件层 E_INVALID 拒绝、`render_job` 同);OFX suites 层未触碰。
- **oaktimeline `bridge/{node,undo,common}` → 直接调用**oaknode/
oakundo/oakcommon 加入依赖;81 个桥函数直接调用。`teststubs.rs`
oakundo/oak_core 加入依赖;81 个桥函数直接调用。`teststubs.rs`
1658 行)改为纯 Rust mock(去 `#[no_mangle]`),桥函数加
`#[cfg(any(test, feature="test-stubs"))]` mock 变体 / 真实变体,
测试二进制(cfg(test) 对依赖关)经 `--features test-stubs` 解析
`bridge::teststubs`——与真实 crate 导出共存无冲突。修复桥签名漂移:
`oakcommon_xml_reader_read_next_start_element` 2 参(found 标志,
`oak_core_xml_reader_read_next_start_element` 2 参(found 标志,
调用点 ffi.rs/tests 同步);`oakundo_stack_push`→真实
`oakundo_undostack_push`。260 测试绿。
- **oaktask `bridge/*` → 直接调用**240 个桥函数):oaknode/oakundo/
oakcommon/oakcodec/oakrender/oaktimeline 加入依赖(oakrender 由可选
oak_core/oakcodec/oakrender/oaktimeline 加入依赖(oakrender 由可选
转必选,`real-oakrender` 特性改为标记)。镜像类型对齐真实 crate:
`OakCancelAtom`/`OakRenderTicket`/`OakRenderCache`/`OakColorProcessor`
等 → CHandle 别名,`OakCodecEncodingParams`/`OakCodecProxyParams`/