refactor(engine): single-lib phase 1 — direct Rust calls across the facade
- unify CHandle in oakcore-rs (all crates re-export it) - facade bridge: 618/624 externs converted to direct module calls - signature-drift fixes surfaced by direct calls (videoparams, seconds, sync estimate, POD unification) - dead node<->render call sites removed; cancelatom -> oakcommon - node bridge/undo -> oakundo direct calls - docs/zh/plans/riir/single-lib.md: design + live status
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
# 单库化(single-lib)· 模块间调用改回直接 Rust 调用
|
||||
|
||||
> 2026-08-10。本计划是 RIIR 拆分计划的**反向修正**:模块拆分阶段为了
|
||||
> 让各 crate 独立链接,把模块间调用压成了 C ABI(`bridge/` + dlsym /
|
||||
> link-time extern)。现在模块已经全部 Rust 化,owner 要求模块间调用
|
||||
> **改回直接 Rust 调用**(一个 `liboakengine` dylib 内联全部模块;
|
||||
> unsafe 只允许留在 OFX 插件边界、引擎对外 C API、以及 shm/wgpu/libc
|
||||
> 等不可避免的位置)。
|
||||
>
|
||||
> 约束(本次任务硬性要求):
|
||||
> 1. **不改变** `oakengine_*` 外部签名与各模块 C ABI 签名
|
||||
> (`app`/`worker`/`cli` 继续工作;`src/plugin` 的 C-ABI 冻结)。
|
||||
> 2. **不触碰** OFX 插件边界(oakplugin 的 suites 保持 C)。
|
||||
> 3. 每个 crate 的 `cargo test`、`src/engine/rust` 的 `cargo test`
|
||||
> 全程保持绿(每步闭环)。
|
||||
> 4. Oak GPL 头、tab 缩进、不做 git 变更。
|
||||
|
||||
## 0. 目标与判据
|
||||
|
||||
终态:
|
||||
|
||||
```
|
||||
liboakengine(一个 dylib,crate 图是 DAG)
|
||||
├── oakcore-rs ← 共享 ABI 类型(CHandle + POD),无依赖的叶子
|
||||
├── oakcommon → oakcore-rs
|
||||
├── oakundo → oakcore-rs
|
||||
├── oaknode → oakcore-rs, oakcommon, 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, oakrender(suites 仍 C)
|
||||
└── oakengine → 全部(facade)
|
||||
```
|
||||
|
||||
完成判据(每条命令可验证):
|
||||
|
||||
1. 模块间、facade→模块的调用 **100% 是编译期 Rust 函数调用**:
|
||||
`grep -rn "extern \"C\"" --include="*.rs" src/{undo,common,timeline,codec,audio,render,task,plugin,node}/rust/src/bridge/` = 0;
|
||||
`grep -rn "dlsym" --include="*.rs"` 只剩 facade 的 `linkage.rs`/`tests/` 注释与
|
||||
OFX host(oakplugin suites)里的必要解析。
|
||||
2. 模块 C ABI(`oakundo_*` … `oaknode_*`)与 `oakengine_*` 依旧从
|
||||
`liboakengine` dylib 导出(`nm -g liboakengine.dylib` 抽查)——
|
||||
外部的 `oaknode_project_init` 等签名一行不改。
|
||||
3. 每个 crate `cargo build` 0 error;每个 crate `cargo test` 绿;
|
||||
`src/engine/rust` `cargo test` 绿。
|
||||
4. unsafe 面收敛:模块 src 中,除
|
||||
`{ffmpeg, ocio, wgpu, libc, shm} → unsafe` 包裹与各自 `ffi.rs` 导出外,
|
||||
无残留;`bridge/` 目录从模块 crate 中消失(或只余测试桩,见 §7)。
|
||||
|
||||
## 1. 现状盘点(2026-08-10 实测)
|
||||
|
||||
### 1.1 crate 依赖现状
|
||||
|
||||
模块 crate 之间**没有 path 依赖**;跨模块调用走各自的 `bridge/`:
|
||||
|
||||
| crate | 跨界机制 | bridge/ 规模(行) | dlsym::call 数 |
|
||||
|---|---|---|---|
|
||||
| oaknode | dlsym(RTLD_DEFAULT) | codec 1270 / common 50340 / core 5298 / render 5134 / timeline 2161 / undo 12964 | 59 |
|
||||
| oakrender | dlsym | codec 6904 / common 7419 / node 5750 | 20 |
|
||||
| oakplugin | dlsym | node 12124 / render 30454 / undo 10943 | 28 |
|
||||
| oaktask | extern "C"(link-time) | codec 9909 / common 5980 / node 26044 / render 12340 / timeline 1291 / undo 2528 | 0 |
|
||||
| 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 | — |
|
||||
|
||||
facade `src/engine/rust/src/bridge/`:9 个文件 2466 行、**624 个
|
||||
`extern "C"` 导入**(node 348 / common 91 / render 36 / timeline 34 /
|
||||
task 33 / audio 31 / codec 24 / undo 22 / plugin 5),由
|
||||
`linkage.rs` 锚定 13 个 `#[no_mangle]` 符号把模块 rlib 拉进 dylib。
|
||||
|
||||
### 1.2 真实调用方向(生产代码,不含 bridge 定义与测试桩)
|
||||
|
||||
按 "`crate::bridge::<b>` 在 `<a>` 生产代码中的出现" 统计(类型别名引用
|
||||
与文档注释已剔除,函数调用计数):
|
||||
|
||||
| 方向 | 生产调用 | 说明 |
|
||||
|---|---|---|
|
||||
| node → render | **3** | `disk_cache_path`(project.rs)、`color_config_create_default`/`color_config_load`(colormanager.rs);其余是 `TextureHandle`/`ColorProcessorHandle`/`CacheHandle` 等**不透明 CHandle 类型别名** |
|
||||
| render → node | **6** | `copier.rs`:`project_deep_copy` / `project_sync_copy` / `ChangeRecord` / `node_abi_available` |
|
||||
| node → codec | 1 | — |
|
||||
| node → timeline | **0** | bridge 是死代码(仅测试用) |
|
||||
| timeline → node | 7 | — |
|
||||
| node → undo | 15 | — |
|
||||
| node → common | 21 | — |
|
||||
| codec → render | 8 | cancelatom(`heard_cancel` 生产、`init`/`cancel` 测试)+ `OakCancelAtom`/`OakRenderTexture` 类型 |
|
||||
| render → codec | **1** | `ffi.rs:931` 的 `codec_abi_available()`,位于必然 Err 的 deferred stub 路径 |
|
||||
| task → node/render/codec | 1 / 6 / 3 | timeline / undo 为 0 |
|
||||
| plugin → node/render/undo | 14 / 38 / 13 | suites 层保持 C(冻结) |
|
||||
| audio → codec/common | 12 / 4 | — |
|
||||
| timeline → undo | 5 | — |
|
||||
| **facade → 各模块** | **393 处调用** | 见 §5 |
|
||||
|
||||
### 1.3 环(Rust crate 禁止循环 path 依赖)
|
||||
|
||||
| 环 | 边 | 处理 |
|
||||
|---|---|---|
|
||||
| **node ↔ render** | node→render 3 fn + render→node copier | §4.1:render→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.2:cancelatom 下沉 oakcommon(原子取消旗标,纯 Rust);render→codec 的 stub 检查直接删除(路径必然 Err) |
|
||||
|
||||
其余方向均无环:node→timeline 0 调用、task→* 单向、plugin→* 单向、
|
||||
audio→* 单向、timeline→node/undo 单向。
|
||||
|
||||
## 2. 目标架构:直接 Rust 调用 + 单一 dylib
|
||||
|
||||
### 2.1 公共面分层(每个模块 crate)
|
||||
|
||||
每个模块 crate 的公共面分两层,对应"机械落地"与"类型化"两档:
|
||||
|
||||
- **Layer 1(本次任务落地):`ffi` 即公共面,调用方直接 Rust 调用。**
|
||||
模块 C ABI 函数是 `pub unsafe extern "C" fn`(`#[no_mangle]` 保持导出)。
|
||||
引擎内部调用不再走 `extern "C"` 导入、不走 dlsym,而是
|
||||
`oaknode::ffi::project::oaknode_project_init()` 这样的**普通 Rust
|
||||
函数调用**——编译期类型检查、链接期直接解析到同 dylib 内的 rlib。
|
||||
调用方在**包装层**(各 crate 的 bridge 改为安全包装 fn)一次性
|
||||
`unsafe {}` 包住,业务代码保持 safe。
|
||||
- **Layer 2(增量、后续):类型化 API。** 各 crate 已有的非 ffi 模块
|
||||
(`project::Project`、`undostack::UndoStack`、`graph::Graph`、
|
||||
`marker::Marker`、`manager::Manager`…)即"types, not CHandle"方向;
|
||||
目前只覆盖部分操作,其余操作仍实现于 `ffi.rs`(CHandle 上)。新代码
|
||||
优先写类型层;把 `ffi.rs` 里的逻辑逐步提取成类型方法属于后续增量,
|
||||
**不在本任务范围内**(本任务只改调用机制,不改实现)。
|
||||
|
||||
### 2.2 类型同一性:共享 ABI 类型下沉 oakcore-rs(本任务的地基)
|
||||
|
||||
直接 Rust 调用要求调用方与被调方**类型同一**。现状是每个 crate 各有一份
|
||||
layout 相同但 Rust 类型不同的 `CHandle`、POD(`OakVideoParams`、
|
||||
`OakAudioParams`、`OakRational`、`OakNodeValue`…)。必须统一:
|
||||
|
||||
- `oakcore-rs` 新增(或接收):
|
||||
- `handle::CHandle`(`{ctx, addref, release, abi_version}`,`#[repr(C)]`,
|
||||
含 `null()`/`is_null()`,`Send + Sync`;`abi_version` 不校验,
|
||||
只作标签——统一后 `null()` 盖 0,各 crate 的 `make_owned` 仍盖各自
|
||||
的 `OAKXXX_ABI_VERSION`);
|
||||
- 跨界 POD:`params::OakVideoParams`、`params::OakAudioParams`、
|
||||
`rational::Rational`(已有)、`value::OakNodeValue` 等。
|
||||
- 各模块 crate:`pub use oakcore_rs::handle::CHandle;`(`handle.rs` 保留
|
||||
`RefBox`/`make_owned`/`guard*`/ABI 版本常量);POD 同理 re-export。
|
||||
各 crate 的 `ffi.rs` **签名不改**(类型名不变,只是指向共享类型,
|
||||
C ABI 层面 layout 不变)。
|
||||
- facade:`pub use oakcore_rs::handle::CHandle;`,`OakVideoParamsPod` 等
|
||||
改为 `pub type OakVideoParamsPod = oakcore_rs::params::OakVideoParams;`。
|
||||
|
||||
> 这是"机械"的底气:统一后 `oaknode::ffi::project::oaknode_project_init()`
|
||||
> 的返回类型就是 facade `OakEngineProject.handle` 的类型,调用点
|
||||
> **一行不用改**。§7 会说明 facade `bridge/` 保留同名安全包装,因此
|
||||
> facade 21k 行业务代码零改动。
|
||||
|
||||
## 3. 每 crate 的 bridge/ 去向
|
||||
|
||||
原则:**生产代码不再经过任何 `bridge/`;bridge/ 从生产路径删除。**
|
||||
|
||||
| crate | 处理 |
|
||||
|---|---|
|
||||
| facade `engine/rust/src/bridge/` | §5:`extern "C"` 块 → 直接调用模块 crate `ffi` 的安全包装(同名同签名) |
|
||||
| oaknode `bridge/{undo,common,codec}` | 直接调用 oakundo/oakcommon/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.2(stub 删除);common → 直接调用 oakcommon |
|
||||
| oakplugin `bridge/{node,render,undo}` | 直接调用各目标 crate ffi;suites 保持 C |
|
||||
| oakcodec `bridge/{common,render}` | common → oakcommon;render → oakrender(cancelatom 移 oakcommon 后改调 oakcommon,见 §4.2) |
|
||||
| oakaudio `bridge/{codec,common,ffmpeg}` | codec/common → 直接调用;ffmpeg → ffmpeg_bridge(C++,保持 extern "C") |
|
||||
| oaktimeline `bridge/{node,undo,common}` | node/undo → 直接调用;common 0 调用 → 删除;`teststubs.rs` 见 §7 |
|
||||
|
||||
**同名 `#[no_mangle]` 冲突**:两个 crate 导出同名 `#[no_mangle]` 符号
|
||||
在单个 dylib 里本来就不允许(重复符号)。现状不会冲突(每个 C ABI 符号
|
||||
唯一归属一个 crate)。内部调用改成直接 Rust 调用后,**外部 C ABI 符号
|
||||
原样保留**(`oaknode_*` 仍由 oaknode crate 导出,供 `app`/`worker`/
|
||||
`cli` 与各 crate 的 C ABI 测试使用);内部调用**绕过**这些符号,走
|
||||
`pub` Rust fn。任何"同符号双实现"都不引入——机制上天然避免。
|
||||
|
||||
## 4. 依赖环处理
|
||||
|
||||
### 4.1 node ↔ render(实施结论:两侧调用均为死代码,删除即破环)
|
||||
|
||||
实施时发现:**两侧的跨模块调用都是死代码**——`oaknode` 的 dlsym 目标
|
||||
(`oakrender_color_config_*`)与 `oakrender` 的 dlsym 目标
|
||||
(`oaknode_project_deep_copy`/`project_sync_copy`)**在对方 crate 中从未
|
||||
实现**(2026-08-10 全量 grep 确认),所以运行时必然 dlsym 失败,走
|
||||
"缺失"分支。破环 = 删除死调用:
|
||||
|
||||
1. `disk_cache_path()`:实现**下沉 oakcommon**(新增
|
||||
`filefunctions::default_disk_cache_path()`,基于既有的
|
||||
`FileFunctions::get_configuration_location()`)。oaknode
|
||||
`project.rs` 与 oakrender `manager.rs` 都直接调 oakcommon。
|
||||
2. `color_config_create_default()`/`color_config_load()`:oakrender 从未
|
||||
实现这两个符号 → node `colormanager.rs` 的调用恒为 `None`(走
|
||||
"标记已加载/保持原状" 分支)。删除调用、保留确定性等价逻辑(行为不变)。
|
||||
3. render 的 `copier.rs`(`project_deep_copy` 等)同样恒失败且无生产
|
||||
调用方——保持现状(dlsym 运行时失败),不引入 crate 依赖。
|
||||
|
||||
**类型别名**:node 里存的 `TextureHandle`/`ColorProcessorHandle`/
|
||||
`CacheHandle` 本就是 `pub type X = CHandle`(统一后 =
|
||||
`oakcore_rs::handle::CHandle`),零依赖。
|
||||
|
||||
结果:node 与 render 之间无任何 crate 依赖、无任何有效调用,环消失。
|
||||
|
||||
### 4.2 codec ↔ render(实施结论:cancelatom 保持 C 边界,render 的 stub 删除)
|
||||
|
||||
- **render → codec**:`ffi.rs:931` 的 `codec_abi_available()` 位于
|
||||
deferred stub(`Err(...)` 恒返回),**已删除**(保留原 Err 文案)。
|
||||
render→codec = 0。
|
||||
- **codec → render**:只有 cancelatom。实施时发现 codec 收到的 atom 句柄
|
||||
是 oakrender `make_owned` 按 **oakrender 的 `RefBox` 布局**装箱的,
|
||||
codec 直接解引用会在不同 crate 的 `RefBox` 布局间读内存(oakcommon
|
||||
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`
|
||||
变为 re-export)。
|
||||
|
||||
结果:codec 与 render 之间无 crate 依赖;codec→render 仅剩 cancelatom
|
||||
一个 link-time C 边界。
|
||||
|
||||
### 4.3 oakcore_*(宿主 liboakcore)与 fb_*(ffmpeg_bridge)
|
||||
|
||||
`oakcore_audioparams_*` / `oakcore_rational_*`(宿主 C++ liboakcore)与
|
||||
`fb_*`(ffmpeg_bridge C++)**不是 Rust crate**,无法变成直接 Rust 调用:
|
||||
保持现状(dylib 链接期 runtime lookup,`build.rs` 的
|
||||
`-Wl,-undefined,dynamic_lookup`)。`bridge/core.rs` 之类保留为 link-time
|
||||
extern(或就地声明),属于"不可避免的 C 边界"。
|
||||
|
||||
## 5. facade bridge → 直接调用(步骤 a,最大但机械)
|
||||
|
||||
`src/engine/rust/src/bridge/*.rs` 从 `extern "C" { ... }` 导入改为
|
||||
**同名同签名的安全包装 fn**:
|
||||
|
||||
```rust
|
||||
// src/bridge/node.rs(改写后)
|
||||
use oakcore_rs::handle::CHandle;
|
||||
/// `oaknode_project_init` — 直接调用 oaknode crate(同 dylib 内 rlib)。
|
||||
pub fn oaknode_project_init() -> CHandle {
|
||||
unsafe { oaknode::ffi::project::oaknode_project_init() }
|
||||
}
|
||||
```
|
||||
|
||||
- 每个 ffi fn 的路径:`oak<mod>::ffi::<子模块>::<fn>`(如
|
||||
`oaknode::ffi::project`、`oaknode::ffi::folder`、`oakcommon::ffi::config`…);
|
||||
实现时以模块 crate 实际 `pub mod` 布局为准(已核对:oaknode ffi 有
|
||||
`project/node/keyframe/…` 子模块)。
|
||||
- **facade 业务代码(node.rs/timeline.rs/… 共 393 处调用)零改动**:
|
||||
它们只 `use crate::bridge::node as n;` 然后 `n::oaknode_project_init()`,
|
||||
包装 fn 同名同签名,链接目标从"extern 导入"变成"直接调用"。
|
||||
- unsafe 收口在包装层:模块 ffi 是 `pub unsafe extern "C" fn`,包装层
|
||||
一处 `unsafe {}`。facade 其余代码保持 safe(现存的散落 `unsafe {}`
|
||||
调用点一并消除)。
|
||||
- `linkage.rs` 保留(锚定符号导出,供外部 C ABI),注释更新。
|
||||
- 现 facade 里 `crate::bridge::common` 的 POD 镜像(`OakVideoParamsPod`)
|
||||
改为 `type` 别名共享类型(§2.2)。
|
||||
|
||||
## 6. 模块 bridge → 直接调用(步骤 b)
|
||||
|
||||
逐方向(每步一个 crate 一个方向,`cargo build`+`cargo test` 闭环):
|
||||
|
||||
1. oaknode:`bridge/undo.rs`、`bridge/common.rs`、`bridge/codec.rs`
|
||||
(→ oakundo/oakcommon/oakcodec 直接调,同 §5 的包装写法);
|
||||
2. oaktimeline:`bridge/node.rs`、`bridge/undo.rs`(→ oaknode/oakundo);
|
||||
3. oakrender:`bridge/node.rs`(→ oaknode,§4.1)、`bridge/common.rs`
|
||||
(→ oakcommon);
|
||||
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);
|
||||
7. oakaudio:`bridge/{codec,common}.rs`;
|
||||
8. oaknode:`bridge/render.rs`(→ oakcommon,§4.1)、`bridge/timeline.rs`
|
||||
(死代码删除,测试迁移见 §7)、`bridge/core.rs`(§4.3 保留 extern)。
|
||||
|
||||
被调方需要被加为 path 依赖的 crate:oaknode 加 `oakundo`/`oakcommon`/
|
||||
`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 已消除)。
|
||||
|
||||
## 7. 测试策略(每 crate 测试保持绿)
|
||||
|
||||
- **每 crate 测试沿用 C ABI 测试为主**(`tests/*.rs` 走 crate 自己的
|
||||
`oak<mod>_*` 导出,`ffi.rs` 不变),**内部 Rust API 测试增量补充**。
|
||||
- **用 `bridge/` 的测试必须迁移**(桥层从生产路径删除后不能留在测试里):
|
||||
- 目标 crate 已 path 依赖的:`oaknode::bridge::undo::…` →
|
||||
`oakundo::ffi::…`(或 oakundo 类型层)直接调;`bridge::common::videoparams_*`
|
||||
→ `oakcommon::…`;`bridge::core::audioparams_*` → `oakcore_rs::…`
|
||||
/ 宿主 liboakcore extern;
|
||||
- 依赖不存在(环/死代码)的:`node::bridge::timeline` 的测试用
|
||||
oaktimeline 自身导出或改写;`node::bridge::render` 的测试改调
|
||||
oakcommon 下沉后的函数;
|
||||
- 专门测 dlsym 机制的测试(如 `node/rust/tests/dbg2_test.rs` 的
|
||||
`bridge::dlsym::resolve`)随机制删除而删除。
|
||||
- **`test-stubs` feature(oakplugin/oakcommon/oaktimeline/oaknode)**:
|
||||
语义变为"编译测试桩 C ABI(替代尚未存在的宿主/兄弟模块实现)"。
|
||||
直接调用落地后,同一二进制内不再同时出现"真实现 + 桩"冲突:
|
||||
facade `cargo test` 的 dev-dependency feature union 按新依赖图调整
|
||||
(凡直接依赖的 crate 用真实现,不再叠 test-stubs)。
|
||||
- facade `tests/`(10 个集成测试)走 `oakengine_*` C ABI,不受影响;
|
||||
`tests/common/mod.rs` 的 `force_link` 更新锚点。
|
||||
|
||||
## 8. unsafe 清单(before / after)
|
||||
|
||||
| 位置 | 现状(实测计数) | 之后 |
|
||||
|---|---|---|
|
||||
| 模块 `bridge/`(dlsym + extern 包装) | node 298 / plugin 167 / timeline 137 / render 45 / codec 50 / task 15 处 `unsafe` 行 | **删除**(或仅测试桩) |
|
||||
| 模块 `ffi.rs` 导出(`unsafe extern "C"`,内含句柄解包) | 各 crate 均有 | **保留**(= 模块 C ABI,外部契约;内部调用在包装层包 unsafe) |
|
||||
| 模块业务代码中散落的 `unsafe` | node ~1020 / plugin ~476 / codec ~533 / render ~277 / task ~306 / timeline ~271 / audio ~165 / common ~230 / undo ~80 行 | 只保留**包裹外部库**(ffmpeg/ocio/wgpu/libc)的调用与必要的句柄解包;bridge 调用产生的 unsafe 随桥层消失 |
|
||||
| oakplugin suites(OFX host) | C 套件 trampoline | **保持 C**(冻结,任务红线) |
|
||||
| facade `engine/rust/src` | 1642 行 `unsafe`(含 ipc/shm 1120+ 行、worker、handle guard、桥层 10 行) | 桥层包装 unsafe 保留;`handle.rs` guard/unbox、`ipc.rs` shm、`worker.rs` 保留(外部 C API 与 shm,属允许项) |
|
||||
| `linkage.rs` / `build.rs` | — | 保留(符号锚定 + `-Wl,-undefined,dynamic_lookup`,宿主 C++ 符号必需) |
|
||||
|
||||
判定:模块 crate 中"非外部库包裹"的 unsafe 清零;facade 中 unsafe 只留
|
||||
{导出 guard、shm/ipc、worker 会话}。
|
||||
|
||||
## 9. 实施顺序(一次一个边界,每步构建+测试闭环)
|
||||
|
||||
1. **地基**:`oakcore-rs` 新增 `handle::CHandle`;各 crate
|
||||
`handle.rs` 改 re-export;facade 改 re-export。逐 crate 验证
|
||||
`cargo build` + `cargo test`(这一步后直接调用才类型同一)。
|
||||
2. **facade bridge → 直接调用**(§5,步骤 a)。
|
||||
3. **环处理**(§4):删除死调用;disk_cache_path/cancelatom 下沉
|
||||
oakcommon;render 的 `codec_abi_available()` stub 检查删除。
|
||||
4. **模块 bridge 逐方向 → 直接调用**(§6,步骤 b)。
|
||||
5. **dlsym 删除**(步骤 c):node/render/plugin 的 `bridge/mod.rs::dlsym`
|
||||
与残留调用清除;`linkage.rs` 注释更新。
|
||||
6. **测试迁移**(§7)与全量验证:每 crate `cargo test` +
|
||||
`src/engine/rust` `cargo test` + 抽查 dylib 导出。
|
||||
|
||||
## 11. 实施状态(2026-08-10 实测)
|
||||
|
||||
已落地(全部构建 0 error、全量 `cargo test` 绿):
|
||||
|
||||
- **地基**:`oakcore_rs::handle::CHandle`(`Clone+Copy+Debug+Default`,
|
||||
`Send+Sync`,`null()` 盖 0)。10 个 crate + facade 全部 re-export;
|
||||
各 crate 的 `impl CHandle`、`unsafe impl Send/Sync` 删除。受影响断言
|
||||
(common/codec/audio/task 的 null-handle 版本/函数指针测试)已同步更新。
|
||||
- **facade bridge**(步骤 a):9 个文件 624 个 `extern "C"` 导入中
|
||||
**618 个改为直接 Rust 调用**(`unsafe { oak<mod>::ffi::<sub>::<fn>(...) }`
|
||||
安全包装,名字签名不变,facade 业务代码 393 处调用点零改动)。
|
||||
保留 8 个 link-time extern:`oakcore_audioparams_*` ×5(宿主 C++)、
|
||||
`oakaudio_manager_start_recording`/`oakcodec_encoder_init`/
|
||||
`oaktask_create_export`(encoding-params C ABI POD,facade 保留自己的
|
||||
POD 镜像,见 §11.1)。
|
||||
- **签名漂移修复**(直接调用把 facade 旧 extern 声明与模块真实签名之间的
|
||||
漂移暴露为编译错误):`videoparams_init_basic` 4→8 参、
|
||||
`init_with_time_base` 4→10 参、`get_bytes_per_channel_for_format`
|
||||
2→1 参、`oakaudio_manager_seconds` 1→2 参、
|
||||
`oakaudio_sync_estimate_stretch_and_offset` 9→12 参(facade 导出现在
|
||||
把引擎的 `min_rate/max_rate/rate_step` 透传给模块,消除了原先
|
||||
"模块自搜默认范围"的 documented deviation)、`get_buffer_size`/
|
||||
`get_time_in_timebase_units`/`get_bytes_per_pixel_for_format` 参数
|
||||
类型修正。POD 统一:`OakNodeValue`→`oaknode::value::OakNodeValue`
|
||||
(`type_` 字段改名 `kind`,1 读 3 构 + 1 测试更新)、
|
||||
`OakUndoCommandVtable`/`OakVideoTicketParams`/`OakRenderVideoParams`/
|
||||
`OffsetResult`/`StretchOffsetResult`/`SourceClip` → 各模块 crate 类型。
|
||||
- **环处理**(§4 实施结论):node↔render 死调用删除;render→codec stub
|
||||
删除;`oakcommon::{filefunctions::default_disk_cache_path, cancelatom}`;
|
||||
render 的 `cancelatom.rs` 改为 re-export。
|
||||
- **模块 bridge**(步骤 b,模式已证明):oaknode `bridge/undo.rs`
|
||||
→ oakundo 直接调用(oakundo 加入 node 依赖;bridge 函数名/签名不变,
|
||||
node 生产代码与测试零改动,全部绿)。
|
||||
|
||||
### 11.1 保留的 C 边界(facade bridge 中 8 个 extern 声明)
|
||||
|
||||
encoding-params POD(`oakcodec_encoding_params` 等)在 4 个 crate 各有
|
||||
镜像(codec/audio/task/facade),字段仅 `[c_char;N]` vs `[u8;N]` 差异,
|
||||
统一到 oakcore-rs 属后续增量(§5 已注明);在此之前,跨越该 POD 的 3 个
|
||||
函数与宿主 `oakcore_*` 保持 link-time extern,与 `fb_*` 同类。
|
||||
|
||||
### 11.2 未完成(后续步骤)
|
||||
|
||||
- **模块 bridge 其余方向**(步骤 b 剩余):oaknode `bridge/{common,codec,
|
||||
core,render,timeline}`、oaktimeline `bridge/{node,undo,common}`、
|
||||
oakcodec `bridge/{common,render}`、oakaudio `bridge/{codec,common,ffmpeg}`、
|
||||
oakrender `bridge/{codec,common,node}`、oaktask `bridge/*`、
|
||||
oakplugin `bridge/*`。每个方向模式与已完成的 node→oakundo 相同
|
||||
(桥函数名不变、函数体改直接调用、目标 crate 加 path 依赖);但
|
||||
各 crate 的 `tests/` 大量直接使用 `bridge::*`(timeline 16 个文件、
|
||||
task 7 个、plugin 8 个、node 6 个),且有 `test-stubs`/`teststubs`
|
||||
桩与真实 crate 的 `#[no_mangle]` 冲突问题——每方向需同步迁移测试并
|
||||
删除对应桩,工作量集中在测试侧。
|
||||
- **dlsym 删除**(步骤 c):node/render/plugin 的 `bridge/mod.rs::dlsym`
|
||||
与残留调用(node 52 处、render 22 处、plugin 28 处)在各自 bridge
|
||||
转换完成后清除;`dbg2_test.rs` 等专测 dlsym 的测试随之删除。
|
||||
- **facade 侧后续**:`linkage.rs` 的 13 个锚定符号注释更新(锚定仍需要);
|
||||
EncodingParamsPOD 等 POD 统一到 oakcore-rs。
|
||||
|
||||
## 10. 风险与回退
|
||||
|
||||
- **共享类型统一**是全局改动:改完一个 crate 编译它,逐 crate 推进;
|
||||
若某 crate 的 `CHandle` 有独有 impl 方法,移入共享 impl 或改为扩展 fn。
|
||||
`abi_version` 统一为 0 标签后,逐 crate 测试确认无断言依赖。
|
||||
- **模块 ffi fn 路径**(`oaknode::ffi::project` 等)以实际 `pub mod`
|
||||
布局为准;包装层用编译错误驱动修正路径。
|
||||
- **宿主符号**(`oakcore_*`/`fb_*`)与 `build.rs` 的
|
||||
`-Wl,-undefined,dynamic_lookup` 不动;这些不是 Rust crate,是允许保留
|
||||
的 C 边界。
|
||||
- **行为零变更**:本计划只改调用机制(extern/dlsym → Rust fn),不改
|
||||
实现;任何"顺带重构"禁止。回退 = 保留 `bridge/` 目录(生产已不引用),
|
||||
不影响外部契约。
|
||||
@@ -54,47 +54,13 @@ pub struct RefBox<T: ?Sized> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
///
|
||||
/// Handles cross the C ABI by value (the C caller copies the 4-field
|
||||
/// struct), so the type is `Copy`/`Clone` — the oaknode crate only derives
|
||||
/// `Clone`, but `Copy` matches the C semantics exactly and lets exports and
|
||||
/// tests pass the same handle around freely. No `Drop`: releasing goes
|
||||
/// through the explicit `free_*`/`release` path, never on scope exit.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
// Handles are passed by value across the C ABI and used from the caller's
|
||||
// thread; the objects behind them synchronize their own state.
|
||||
unsafe impl Send for CHandle {}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: OAKAUDIO_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// True when the handle carries no object.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible. It is `Clone + Copy` (handles cross the C ABI by
|
||||
/// value) and `Send + Sync` (refcounted, shared across threads).
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// `// CPP-PARITY: src/audio/c_api/refcounted.h` (`ref_counted_addref`).
|
||||
unsafe extern "C" fn owned_addref<T: Send + 'static>(ctx: *mut std::ffi::c_void) {
|
||||
|
||||
@@ -93,7 +93,8 @@ fn manager_singleton_and_alive_count() {
|
||||
unsafe { oakaudio_manager_destroy_instance() };
|
||||
let none = unsafe { oakaudio_manager_instance() };
|
||||
assert!(none.ctx.is_null());
|
||||
assert_eq!(none.abi_version, oakaudio::handle::OAKAUDIO_ABI_VERSION);
|
||||
// The empty instance handle is the shared `null()` (no ABI version).
|
||||
assert_eq!(none.abi_version, 0);
|
||||
|
||||
unsafe { oakaudio_manager_create_instance() };
|
||||
let m1 = unsafe { oakaudio_manager_instance() };
|
||||
|
||||
@@ -79,7 +79,8 @@ fn borrowed_release() {
|
||||
fn null_and_guard_ok() {
|
||||
let null = CHandle::null();
|
||||
assert!(null.is_null());
|
||||
assert_eq!(null.abi_version, oakaudio::handle::OAKAUDIO_ABI_VERSION);
|
||||
// The shared `null()` stamps no ABI version (single-lib unification).
|
||||
assert_eq!(null.abi_version, 0);
|
||||
|
||||
assert_eq!(guard(|| Ok(())), OAKAUDIO_OK);
|
||||
|
||||
|
||||
@@ -46,38 +46,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
///
|
||||
/// Handles are `Copy`: passing one by value copies the struct, not the
|
||||
/// reference count — exactly the by-value convention the C ABI documents.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: OAKCODEC_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this is an empty (null) handle.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// Increment the reference count of a boxed `RefBox<T>`.
|
||||
///
|
||||
@@ -293,6 +267,8 @@ mod tests {
|
||||
fn null_handle_helpers() {
|
||||
let h = CHandle::null();
|
||||
assert!(h.is_null());
|
||||
assert_eq!(h.abi_version, OAKCODEC_ABI_VERSION);
|
||||
// The shared `null()` stamps no ABI version (single-lib
|
||||
// unification; `make_owned` stamps the crate version).
|
||||
assert_eq!(h.abi_version, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The cancellation primitive (`olive::CancelAtom`): a thread-safe cancel
|
||||
//! flag shared between a render/encode caller and its worker.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): moved
|
||||
//! here from the oakrender crate so the oakcodec crate can use it without
|
||||
//! depending on oakrender (the oaknode/oakcodec/oakrender call cycle).
|
||||
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
/// A cancellation atom (C++ `CancelAtom`). Reading a set flag also records
|
||||
/// that a consumer heard the cancellation.
|
||||
#[derive(Default)]
|
||||
pub struct CancelAtom {
|
||||
state: Mutex<AtomState>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AtomState {
|
||||
cancelled: bool,
|
||||
heard: bool,
|
||||
}
|
||||
|
||||
fn lock(m: &Mutex<AtomState>) -> MutexGuard<'_, AtomState> {
|
||||
m.lock().unwrap_or_else(|e| e.into_inner())
|
||||
}
|
||||
|
||||
impl CancelAtom {
|
||||
/// A not-cancelled atom.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Set the cancel flag (C++ `CancelAtom::cancel()`).
|
||||
pub fn cancel(&self) {
|
||||
lock(&self.state).cancelled = true;
|
||||
}
|
||||
|
||||
/// Read the cancel flag; reading a set flag records that the
|
||||
/// cancellation was heard (C++ `is_cancelled()`).
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
let mut s = lock(&self.state);
|
||||
if s.cancelled {
|
||||
s.heard = true;
|
||||
}
|
||||
s.cancelled
|
||||
}
|
||||
|
||||
/// Whether any consumer has observed the cancel flag through
|
||||
/// [`CancelAtom::is_cancelled`] (C++ `heard_cancel()`).
|
||||
pub fn heard_cancel(&self) -> bool {
|
||||
lock(&self.state).heard
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fresh_atom_is_not_cancelled() {
|
||||
let a = CancelAtom::new();
|
||||
assert!(!a.is_cancelled());
|
||||
assert!(!a.heard_cancel());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_sets_flag_and_reading_marks_heard() {
|
||||
let a = CancelAtom::new();
|
||||
a.cancel();
|
||||
assert!(!a.heard_cancel(), "not heard until read");
|
||||
assert!(a.is_cancelled());
|
||||
assert!(a.heard_cancel(), "reading a set flag marks it heard");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_cancel_is_idempotent() {
|
||||
let a = CancelAtom::new();
|
||||
a.cancel();
|
||||
a.cancel();
|
||||
assert!(a.is_cancelled());
|
||||
}
|
||||
}
|
||||
@@ -920,3 +920,16 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&b);
|
||||
}
|
||||
}
|
||||
|
||||
/// The default disk cache directory (C++ `DiskManager::
|
||||
/// get_default_disk_cache_path`): `<configuration location>/mediacache`.
|
||||
///
|
||||
/// Single-lib unification: this used to live in the oakrender crate's
|
||||
/// `bridge::common` fallback (see `docs/zh/plans/riir/single-lib.md`);
|
||||
/// oaknode and oakrender both call it directly now.
|
||||
pub fn default_disk_cache_path() -> String {
|
||||
Path::new(&FileFunctions::new().get_configuration_location().unwrap_or_default())
|
||||
.join("mediacache")
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
}
|
||||
|
||||
@@ -59,36 +59,12 @@ pub struct RefBox<T: Sized> {
|
||||
pub refs: AtomicU32,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
#[repr(C)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: OAKCOMMON_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this is an empty handle (`ctx == NULL`).
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// addref thunk: atomically increments the count. Shared by owned and
|
||||
/// borrowed boxes — for a borrowed handle addref only extends the life of
|
||||
@@ -260,7 +236,9 @@ mod tests {
|
||||
assert!(h.ctx.is_null());
|
||||
assert!(h.addref.is_none());
|
||||
assert!(h.release.is_none());
|
||||
assert_eq!(h.abi_version, OAKCOMMON_ABI_VERSION);
|
||||
// The shared `null()` stamps no ABI version (single-lib
|
||||
// unification; `make_owned` stamps the crate version).
|
||||
assert_eq!(h.abi_version, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
pub mod colortransform;
|
||||
pub mod commandlineparser;
|
||||
pub mod cancelatom;
|
||||
pub mod configstore;
|
||||
pub mod debug;
|
||||
pub mod error;
|
||||
|
||||
@@ -126,7 +126,8 @@ fn init_output_null_yields_null_handle() {
|
||||
assert!(h.ctx.is_null());
|
||||
assert!(h.addref.is_none());
|
||||
assert!(h.release.is_none());
|
||||
assert_eq!(h.abi_version, OAKCOMMON_ABI_VERSION);
|
||||
// The shared `null()` stamps no ABI version (single-lib unification).
|
||||
assert_eq!(h.abi_version, 0);
|
||||
}
|
||||
|
||||
/// An empty output name is a valid value: the transform is still an output
|
||||
@@ -189,7 +190,8 @@ fn init_display_null_any_arg_yields_null_handle() {
|
||||
assert!(h.ctx.is_null());
|
||||
assert!(h.addref.is_none());
|
||||
assert!(h.release.is_none());
|
||||
assert_eq!(h.abi_version, OAKCOMMON_ABI_VERSION);
|
||||
// The shared `null()` stamps no ABI version (single-lib unification).
|
||||
assert_eq!(h.abi_version, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+4
@@ -806,7 +806,9 @@ dependencies = [
|
||||
name = "oaknode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -824,12 +826,14 @@ name = "oakplugin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakrender"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"wgpu",
|
||||
|
||||
@@ -327,10 +327,6 @@ pub unsafe extern "C" fn oakengine_audio_estimate_stretch_and_offset(
|
||||
confidence: 0.0,
|
||||
valid: 0,
|
||||
};
|
||||
// The module's rate search is fixed-step; the engine's range
|
||||
// parameters are not part of its C ABI (documented deviation:
|
||||
// the module searches its own default range).
|
||||
let _ = (min_rate, max_rate, rate_step);
|
||||
Error::from_module(a::oakaudio_sync_estimate_stretch_and_offset(
|
||||
reference,
|
||||
reference_len,
|
||||
@@ -340,6 +336,9 @@ pub unsafe extern "C" fn oakengine_audio_estimate_stretch_and_offset(
|
||||
candidate_valid,
|
||||
window_samples,
|
||||
max_offset_windows,
|
||||
min_rate,
|
||||
max_rate,
|
||||
rate_step,
|
||||
&mut result,
|
||||
))?;
|
||||
(*out).rate = result.rate;
|
||||
|
||||
+277
-170
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakaudio C ABI bridge: direct Rust calls into the `oakaudio` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oakaudio`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakaudio C ABI imports, mirroring the oakaudio crate's exports
|
||||
//! (`src/audio/rust/src/ffi.rs`; headers `include/audio/*.h`), plus the
|
||||
//! liboakcore `oakcore_audioparams_*` readers used to convert the
|
||||
@@ -23,182 +50,21 @@ use std::ffi::{c_char, c_double, c_int, c_void};
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `oakaudio_sync_offset_result` mirror — `oak_audio_waveform_offset`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OffsetResult {
|
||||
/// Offset of the candidate relative to the reference, in samples.
|
||||
pub offset_samples: i64,
|
||||
/// Normalized correlation confidence in `[0, 1]`.
|
||||
pub confidence: c_double,
|
||||
/// Whether an offset could be determined.
|
||||
pub valid: c_int,
|
||||
}
|
||||
/// `oakaudio_offsetresult` C ABI POD. Single-lib unification: aliases
|
||||
/// the oakaudio crate's struct (identical layout).
|
||||
pub type OffsetResult = oakaudio::ffi::sync::OffsetResult;
|
||||
|
||||
/// `oakaudio_stretch_offset_result` mirror — `oak_audio_waveform_stretch_offset`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct StretchOffsetResult {
|
||||
/// Playback rate aligning the candidate (`> 1` = speed up).
|
||||
pub rate: c_double,
|
||||
/// Offset in samples.
|
||||
pub offset_samples: i64,
|
||||
/// Normalized correlation confidence in `[0, 1]`.
|
||||
pub confidence: c_double,
|
||||
/// Whether a rate+offset could be determined.
|
||||
pub valid: c_int,
|
||||
}
|
||||
|
||||
/// `oakaudio_sync_source_clip` mirror — `oak_audio_sync_source_clip`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SourceClip {
|
||||
/// Source start time numerator (seconds).
|
||||
pub source_start_time_num: i64,
|
||||
/// Source start time denominator (seconds).
|
||||
pub source_start_time_den: i64,
|
||||
/// Media in point numerator (seconds).
|
||||
pub media_in_num: i64,
|
||||
/// Media in point denominator (seconds).
|
||||
pub media_in_den: i64,
|
||||
/// Whether `source_start_time` is set.
|
||||
pub has_source_start_time: c_int,
|
||||
}
|
||||
/// `oakaudio_stretchoffsetresult` C ABI POD. Single-lib unification: aliases
|
||||
/// the oakaudio crate's struct (identical layout).
|
||||
pub type StretchOffsetResult = oakaudio::ffi::sync::StretchOffsetResult;
|
||||
|
||||
extern "C" {
|
||||
// ---- manager.h --------------------------------------------------------
|
||||
/// `oakaudio_manager_create_instance` — create the singleton.
|
||||
pub fn oakaudio_manager_create_instance() -> c_int;
|
||||
/// `oakaudio_manager_destroy_instance` — destroy the singleton.
|
||||
pub fn oakaudio_manager_destroy_instance();
|
||||
/// `oakaudio_manager_instance` — borrowed handle (empty when none).
|
||||
pub fn oakaudio_manager_instance() -> CHandle;
|
||||
/// `oakaudio_manager_free` — release a manager handle.
|
||||
pub fn oakaudio_manager_free(_self: *mut CHandle);
|
||||
/// `oakaudio_manager_set_output_notify_interval`.
|
||||
pub fn oakaudio_manager_set_output_notify_interval(_self: CHandle, bytes: i64) -> c_int;
|
||||
/// `oakaudio_manager_push_to_output`.
|
||||
pub fn oakaudio_manager_push_to_output(
|
||||
_self: CHandle,
|
||||
rate: c_int,
|
||||
layout: u64,
|
||||
format: c_int,
|
||||
samples: *const c_char,
|
||||
samples_size: i64,
|
||||
error_buf: *mut c_char,
|
||||
error_buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakaudio_manager_clear_buffered_output`.
|
||||
pub fn oakaudio_manager_clear_buffered_output(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_stop_output`.
|
||||
pub fn oakaudio_manager_stop_output(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_reset_output_clock`.
|
||||
pub fn oakaudio_manager_reset_output_clock(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_get_output_device` — module returns the device as
|
||||
/// `c_int`; the facade widens to the engine's int64_t.
|
||||
pub fn oakaudio_manager_get_output_device(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_set_output_device`.
|
||||
pub fn oakaudio_manager_set_output_device(_self: CHandle, device: c_int) -> c_int;
|
||||
/// `oakaudio_manager_get_input_device`.
|
||||
pub fn oakaudio_manager_get_input_device(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_set_input_device`.
|
||||
pub fn oakaudio_manager_set_input_device(_self: CHandle, device: c_int) -> c_int;
|
||||
/// `oakaudio_manager_hard_reset`.
|
||||
pub fn oakaudio_manager_hard_reset(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_start_recording`.
|
||||
pub fn oakaudio_manager_start_recording(
|
||||
_self: CHandle,
|
||||
params: *const EncodingParams,
|
||||
error_buf: *mut c_char,
|
||||
error_buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakaudio_manager_stop_recording`.
|
||||
pub fn oakaudio_manager_stop_recording(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_manager_seconds`.
|
||||
pub fn oakaudio_manager_seconds(_self: CHandle) -> i64;
|
||||
|
||||
// ---- processor.h ------------------------------------------------------
|
||||
/// `oakaudio_processor_init` — new processor, refcount 1.
|
||||
pub fn oakaudio_processor_init() -> CHandle;
|
||||
/// `oakaudio_processor_free` — NULL/empty no-op.
|
||||
pub fn oakaudio_processor_free(_self: *mut CHandle);
|
||||
/// `oakaudio_processor_open`.
|
||||
pub fn oakaudio_processor_open(
|
||||
_self: CHandle,
|
||||
in_rate: c_int,
|
||||
in_layout: u64,
|
||||
in_format: c_int,
|
||||
out_rate: c_int,
|
||||
out_layout: u64,
|
||||
out_format: c_int,
|
||||
speed: c_double,
|
||||
) -> c_int;
|
||||
/// `oakaudio_processor_close`.
|
||||
pub fn oakaudio_processor_close(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_processor_is_open`.
|
||||
pub fn oakaudio_processor_is_open(_self: CHandle) -> c_int;
|
||||
/// `oakaudio_sourceclip` C ABI POD. Single-lib unification: aliases
|
||||
/// the oakaudio crate's struct (identical layout).
|
||||
pub type SourceClip = oakaudio::ffi::sync::SourceClip;
|
||||
|
||||
// ---- sync.h -----------------------------------------------------------
|
||||
/// `oakaudio_sync_estimate_envelope_offset`.
|
||||
pub fn oakaudio_sync_estimate_envelope_offset(
|
||||
reference: *const c_double,
|
||||
reference_len: c_int,
|
||||
candidate: *const c_double,
|
||||
candidate_len: c_int,
|
||||
reference_valid: *const u8,
|
||||
candidate_valid: *const u8,
|
||||
window_samples: u64,
|
||||
max_offset_windows: i64,
|
||||
out: *mut OffsetResult,
|
||||
) -> c_int;
|
||||
/// `oakaudio_sync_estimate_stretch_and_offset`.
|
||||
pub fn oakaudio_sync_estimate_stretch_and_offset(
|
||||
reference: *const c_double,
|
||||
reference_len: c_int,
|
||||
candidate: *const c_double,
|
||||
candidate_len: c_int,
|
||||
reference_valid: *const u8,
|
||||
candidate_valid: *const u8,
|
||||
window_samples: u64,
|
||||
max_offset_windows: i64,
|
||||
out: *mut StretchOffsetResult,
|
||||
) -> c_int;
|
||||
/// `oakaudio_sync_place_by_source_time`.
|
||||
pub fn oakaudio_sync_place_by_source_time(
|
||||
reference: *const SourceClip,
|
||||
candidate: *const SourceClip,
|
||||
reference_timeline_in_num: i64,
|
||||
reference_timeline_in_den: i64,
|
||||
out_num: *mut i64,
|
||||
out_den: *mut i64,
|
||||
out_valid: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakaudio_sync_place_by_waveform_offset`.
|
||||
pub fn oakaudio_sync_place_by_waveform_offset(
|
||||
reference_timeline_in_num: i64,
|
||||
reference_timeline_in_den: i64,
|
||||
candidate_offset_samples: i64,
|
||||
sample_rate: c_int,
|
||||
out_num: *mut i64,
|
||||
out_den: *mut i64,
|
||||
out_valid: *mut c_int,
|
||||
) -> c_int;
|
||||
|
||||
// ---- liboakcore (oakcore_audioparams_*) --------------------------------
|
||||
/// `oakcore_audioparams_create` — new owned params (release with
|
||||
/// [`oakcore_audioparams_free`]).
|
||||
pub fn oakcore_audioparams_create(sample_rate: c_int, channel_layout: u64, format: c_int) -> *mut c_void;
|
||||
/// `oakcore_audioparams_free` — release params created by
|
||||
/// [`oakcore_audioparams_create`] (or returned by the oaknode sequence
|
||||
/// audio-params getter).
|
||||
pub fn oakcore_audioparams_free(params: *mut c_void);
|
||||
/// `oakcore_audioparams_sample_rate` — borrowed params reader.
|
||||
pub fn oakcore_audioparams_sample_rate(params: *const c_void) -> c_int;
|
||||
/// `oakcore_audioparams_channel_layout` — borrowed params reader.
|
||||
pub fn oakcore_audioparams_channel_layout(params: *const c_void) -> u64;
|
||||
/// `oakcore_audioparams_format` — borrowed params reader.
|
||||
pub fn oakcore_audioparams_format(params: *const c_void) -> c_int;
|
||||
}
|
||||
|
||||
/// Opaque mirror of the oakaudio recording-params POD
|
||||
/// (`include/audio/manager.h`). The facade passes the engine's
|
||||
@@ -208,3 +74,244 @@ extern "C" {
|
||||
pub struct EncodingParams {
|
||||
_opaque: [u8; 0],
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn oakcore_audioparams_create(sample_rate: c_int, channel_layout: u64, format: c_int) -> *mut c_void;
|
||||
pub fn oakcore_audioparams_free(params: *mut c_void);
|
||||
pub fn oakcore_audioparams_sample_rate(params: *const c_void) -> c_int;
|
||||
pub fn oakcore_audioparams_channel_layout(params: *const c_void) -> u64;
|
||||
pub fn oakcore_audioparams_format(params: *const c_void) -> c_int;
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_create_instance() -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_create_instance() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_destroy_instance() {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_destroy_instance() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_instance() -> CHandle {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_instance() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_free(_self: *mut CHandle) {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_free(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_set_output_notify_interval(_self: CHandle, bytes: i64) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_set_output_notify_interval(_self, bytes) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_push_to_output(
|
||||
_self: CHandle,
|
||||
rate: c_int,
|
||||
layout: u64,
|
||||
format: c_int,
|
||||
samples: *const c_char,
|
||||
samples_size: i64,
|
||||
error_buf: *mut c_char,
|
||||
error_buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_push_to_output(_self, rate, layout, format, samples, samples_size, error_buf, error_buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_clear_buffered_output(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_clear_buffered_output(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_stop_output(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_stop_output(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_reset_output_clock(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_reset_output_clock(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_get_output_device(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_get_output_device(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_set_output_device(_self: CHandle, device: c_int) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_set_output_device(_self, device) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_get_input_device(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_get_input_device(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_set_input_device(_self: CHandle, device: c_int) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_set_input_device(_self, device) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_hard_reset(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_hard_reset(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
/// `oakaudio_manager_start_recording` — crosses the encoding-params C ABI
|
||||
/// POD (the facade keeps its own opaque mirror; the module's
|
||||
/// `oakaudio::bridge::codec::EncodingParams`). Kept as a link-time
|
||||
/// `extern "C"` declaration against the frozen module C ABI.
|
||||
pub fn oakaudio_manager_start_recording(
|
||||
_self: CHandle,
|
||||
params: *const EncodingParams,
|
||||
error_buf: *mut c_char,
|
||||
error_buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio_start_recording_extern(_self, params, error_buf, error_buf_size) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "oakaudio_manager_start_recording"]
|
||||
pub fn oakaudio_start_recording_extern(
|
||||
_self: CHandle,
|
||||
params: *const EncodingParams,
|
||||
error_buf: *mut c_char,
|
||||
error_buf_size: c_int,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_stop_recording(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_stop_recording(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_manager_seconds(_self: CHandle, out: *mut c_double) -> c_int {
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_seconds(_self, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_processor_init() -> CHandle {
|
||||
unsafe { oakaudio::ffi::processor::oakaudio_processor_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_processor_free(_self: *mut CHandle) {
|
||||
unsafe { oakaudio::ffi::processor::oakaudio_processor_free(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_processor_open(
|
||||
_self: CHandle,
|
||||
in_rate: c_int,
|
||||
in_layout: u64,
|
||||
in_format: c_int,
|
||||
out_rate: c_int,
|
||||
out_layout: u64,
|
||||
out_format: c_int,
|
||||
speed: c_double,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio::ffi::processor::oakaudio_processor_open(_self, in_rate, in_layout, in_format, out_rate, out_layout, out_format, speed) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_processor_close(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::processor::oakaudio_processor_close(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_processor_is_open(_self: CHandle) -> c_int {
|
||||
unsafe { oakaudio::ffi::processor::oakaudio_processor_is_open(_self) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_sync_estimate_envelope_offset(
|
||||
reference: *const c_double,
|
||||
reference_len: c_int,
|
||||
candidate: *const c_double,
|
||||
candidate_len: c_int,
|
||||
reference_valid: *const u8,
|
||||
candidate_valid: *const u8,
|
||||
window_samples: u64,
|
||||
max_offset_windows: i64,
|
||||
out: *mut OffsetResult,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio::ffi::sync::oakaudio_sync_estimate_envelope_offset(reference, reference_len, candidate, candidate_len, reference_valid, candidate_valid, window_samples, max_offset_windows, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_sync_estimate_stretch_and_offset(
|
||||
reference: *const c_double,
|
||||
reference_len: c_int,
|
||||
candidate: *const c_double,
|
||||
candidate_len: c_int,
|
||||
reference_valid: *const u8,
|
||||
candidate_valid: *const u8,
|
||||
window_samples: u64,
|
||||
max_offset_windows: i64,
|
||||
min_rate: c_double,
|
||||
max_rate: c_double,
|
||||
rate_step: c_double,
|
||||
out: *mut StretchOffsetResult,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio::ffi::sync::oakaudio_sync_estimate_stretch_and_offset(reference, reference_len, candidate, candidate_len, reference_valid, candidate_valid, window_samples, max_offset_windows, min_rate, max_rate, rate_step, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_sync_place_by_source_time(
|
||||
reference: *const SourceClip,
|
||||
candidate: *const SourceClip,
|
||||
reference_timeline_in_num: i64,
|
||||
reference_timeline_in_den: i64,
|
||||
out_num: *mut i64,
|
||||
out_den: *mut i64,
|
||||
out_valid: *mut c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio::ffi::sync::oakaudio_sync_place_by_source_time(reference, candidate, reference_timeline_in_num, reference_timeline_in_den, out_num, out_den, out_valid) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakaudio_sync_place_by_waveform_offset(
|
||||
reference_timeline_in_num: i64,
|
||||
reference_timeline_in_den: i64,
|
||||
candidate_offset_samples: i64,
|
||||
sample_rate: c_int,
|
||||
out_num: *mut i64,
|
||||
out_den: *mut i64,
|
||||
out_valid: *mut c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakaudio::ffi::sync::oakaudio_sync_place_by_waveform_offset(reference_timeline_in_num, reference_timeline_in_den, candidate_offset_samples, sample_rate, out_num, out_den, out_valid) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcodec C ABI bridge: direct Rust calls into the `oakcodec` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oakcodec`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcodec C ABI imports, mirroring the oakcodec crate's exports
|
||||
//! (`src/codec/rust/src/ffi/{format,encoder}.rs`; headers
|
||||
//! `include/codec/{format,encoder}.h`). Also carries the
|
||||
@@ -117,76 +144,171 @@ impl EncodingParamsPOD {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// ---- include/codec/format.h (encoding metadata) ------------------------
|
||||
/// `oakcodec_encoding_format_count`.
|
||||
pub fn oakcodec_encoding_format_count() -> c_int;
|
||||
/// `oakcodec_encoding_format_name` (two-stage string).
|
||||
pub fn oakcodec_encoding_format_name(format: c_int, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_format_extension` (two-stage string).
|
||||
pub fn oakcodec_encoding_format_extension(
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_count() -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_count() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_name(format: c_int, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_name(format, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_extension(
|
||||
format: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoding_format_video_codec_count`.
|
||||
pub fn oakcodec_encoding_format_video_codec_count(format: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_format_video_codec_at`.
|
||||
pub fn oakcodec_encoding_format_video_codec_at(format: c_int, index: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_format_audio_codec_count`.
|
||||
pub fn oakcodec_encoding_format_audio_codec_count(format: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_format_audio_codec_at`.
|
||||
pub fn oakcodec_encoding_format_audio_codec_at(format: c_int, index: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_format_subtitle_codec_count`.
|
||||
pub fn oakcodec_encoding_format_subtitle_codec_count(format: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_format_subtitle_codec_at`.
|
||||
pub fn oakcodec_encoding_format_subtitle_codec_at(format: c_int, index: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_codec_name` (two-stage string).
|
||||
pub fn oakcodec_encoding_codec_name(codec: c_int, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_codec_is_still_image`.
|
||||
pub fn oakcodec_encoding_codec_is_still_image(codec: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_codec_is_lossless`.
|
||||
pub fn oakcodec_encoding_codec_is_lossless(codec: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_pix_fmt_count`.
|
||||
pub fn oakcodec_encoding_pix_fmt_count(format: c_int, codec: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_pix_fmt_at` (two-stage string).
|
||||
pub fn oakcodec_encoding_pix_fmt_at(
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_extension(format, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_video_codec_count(format: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_video_codec_count(format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_video_codec_at(format: c_int, index: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_video_codec_at(format, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_audio_codec_count(format: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_audio_codec_count(format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_audio_codec_at(format: c_int, index: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_audio_codec_at(format, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_subtitle_codec_count(format: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_subtitle_codec_count(format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_format_subtitle_codec_at(format: c_int, index: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_format_subtitle_codec_at(format, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_codec_name(codec: c_int, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_codec_name(codec, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_codec_is_still_image(codec: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_codec_is_still_image(codec) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_codec_is_lossless(codec: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_codec_is_lossless(codec) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_pix_fmt_count(format: c_int, codec: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_pix_fmt_count(format, codec) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_pix_fmt_at(
|
||||
format: c_int,
|
||||
codec: c_int,
|
||||
index: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoding_pix_fmt_index`.
|
||||
pub fn oakcodec_encoding_pix_fmt_index(codec: c_int, pix_fmt: *const c_char) -> c_int;
|
||||
/// `oakcodec_encoding_sample_format_count`.
|
||||
pub fn oakcodec_encoding_sample_format_count(format: c_int, codec: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_sample_format_at`.
|
||||
pub fn oakcodec_encoding_sample_format_at(format: c_int, codec: c_int, index: c_int) -> c_int;
|
||||
/// `oakcodec_encoding_filename_contains_digit_placeholder` (0 for NULL).
|
||||
pub fn oakcodec_encoding_filename_contains_digit_placeholder(filename: *const c_char) -> c_int;
|
||||
/// `oakcodec_encoding_image_sequence_digit_count` (0 when none).
|
||||
pub fn oakcodec_encoding_image_sequence_digit_count(filename: *const c_char) -> c_int;
|
||||
/// `oakcodec_encoding_filename_remove_digit_placeholder` (two-stage).
|
||||
pub fn oakcodec_encoding_filename_remove_digit_placeholder(
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_pix_fmt_at(format, codec, index, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_pix_fmt_index(codec: c_int, pix_fmt: *const c_char) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_pix_fmt_index(codec, pix_fmt) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_sample_format_count(format: c_int, codec: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_sample_format_count(format, codec) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_sample_format_at(format: c_int, codec: c_int, index: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_sample_format_at(format, codec, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_filename_contains_digit_placeholder(filename: *const c_char) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_filename_contains_digit_placeholder(filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_image_sequence_digit_count(filename: *const c_char) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_image_sequence_digit_count(filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_filename_remove_digit_placeholder(
|
||||
filename: *const c_char,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoding_generate_matrix` — writes 16 `f64` (the engine
|
||||
/// surface uses `f32`; the facade converts).
|
||||
pub fn oakcodec_encoding_generate_matrix(
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::format::oakcodec_encoding_filename_remove_digit_placeholder(filename, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoding_generate_matrix(
|
||||
method: c_int,
|
||||
src_width: c_int,
|
||||
src_height: c_int,
|
||||
dst_width: c_int,
|
||||
dst_height: c_int,
|
||||
out_matrix: *mut f64,
|
||||
) -> c_int;
|
||||
|
||||
// ---- include/codec/encoder.h -------------------------------------------
|
||||
/// `oakcodec_encoder_init` — encoder over a params POD (refcount 1).
|
||||
pub fn oakcodec_encoder_init(params: *const EncodingParamsPOD) -> CHandle;
|
||||
/// `oakcodec_encoder_free` — NULL/empty no-op.
|
||||
pub fn oakcodec_encoder_free(encoder: *mut CHandle);
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoding_generate_matrix(method, src_width, src_height, dst_width, dst_height, out_matrix) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
/// `oakcodec_encoder_init` — crosses the encoding-params C ABI POD
|
||||
/// (`oakcodec_encoding_params`; the facade keeps its own POD mirror).
|
||||
/// Kept as a link-time `extern "C"` declaration against the frozen module
|
||||
/// C ABI.
|
||||
pub fn oakcodec_encoder_init(params: *const EncodingParamsPOD) -> CHandle {
|
||||
unsafe { oakcodec_encoder_init_extern(params) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "oakcodec_encoder_init"]
|
||||
pub fn oakcodec_encoder_init_extern(params: *const EncodingParamsPOD) -> CHandle;
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcodec_encoder_free(encoder: *mut CHandle) {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_free(encoder) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcommon C ABI bridge: direct Rust calls into the `oakcommon` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oakcommon`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcommon C ABI imports, mirroring the oakcommon crate's exports
|
||||
//! (`src/common/rust/src/ffi.rs`; headers `include/common/*.h`). Only the
|
||||
//! families the facade wraps: config, videoparams, colortransform, xml
|
||||
@@ -27,316 +54,686 @@ use crate::handle::CHandle;
|
||||
pub type ConfigErrorHandler =
|
||||
Option<unsafe extern "C" fn(title: *const c_char, message: *const c_char, userdata: *mut c_void)>;
|
||||
|
||||
extern "C" {
|
||||
// ---- config.h -------------------------------------------------------
|
||||
/// `oakcommon_config_load` — reset to defaults, then read config.ini.
|
||||
pub fn oakcommon_config_load() -> c_int;
|
||||
/// `oakcommon_config_save` — write config.ini (temp file + rename).
|
||||
pub fn oakcommon_config_save() -> c_int;
|
||||
/// `oakcommon_config_reset_defaults` — drop custom keys.
|
||||
pub fn oakcommon_config_reset_defaults() -> c_int;
|
||||
/// `oakcommon_config_set` — set a string entry.
|
||||
pub fn oakcommon_config_set(group: *const c_char, key: *const c_char, value: *const c_char);
|
||||
/// `oakcommon_config_get` — read an entry as string (two-stage).
|
||||
pub fn oakcommon_config_get(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_load() -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_load() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_save() -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_save() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_reset_defaults() -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_reset_defaults() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_set(group: *const c_char, key: *const c_char, value: *const c_char) {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_set(group, key, value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_get(
|
||||
group: *const c_char,
|
||||
key: *const c_char,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_config_get_int` — INT entry with fallback.
|
||||
pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int;
|
||||
/// `oakcommon_config_get_int64` — INT64 entry with fallback.
|
||||
pub fn oakcommon_config_get_int64(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get(group, key, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_int(group, key, fallback) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_get_int64(
|
||||
group: *const c_char,
|
||||
key: *const c_char,
|
||||
fallback: i64,
|
||||
) -> i64;
|
||||
/// `oakcommon_config_get_double` — DOUBLE entry with fallback.
|
||||
pub fn oakcommon_config_get_double(group: *const c_char, key: *const c_char, fallback: f64) -> f64;
|
||||
/// `oakcommon_config_get_bool` — BOOL entry with fallback.
|
||||
pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int;
|
||||
/// `oakcommon_config_set_int` — set an INT entry.
|
||||
pub fn oakcommon_config_set_int(group: *const c_char, key: *const c_char, value: c_int);
|
||||
/// `oakcommon_config_set_int64` — set an INT64 entry.
|
||||
pub fn oakcommon_config_set_int64(group: *const c_char, key: *const c_char, value: i64);
|
||||
/// `oakcommon_config_set_double` — set a DOUBLE entry.
|
||||
pub fn oakcommon_config_set_double(group: *const c_char, key: *const c_char, value: f64);
|
||||
/// `oakcommon_config_set_bool` — set a BOOL entry.
|
||||
pub fn oakcommon_config_set_bool(group: *const c_char, key: *const c_char, value: c_int);
|
||||
/// `oakcommon_config_entry_type` — the entry's declared type.
|
||||
pub fn oakcommon_config_entry_type(group: *const c_char, key: *const c_char) -> c_int;
|
||||
/// `oakcommon_config_set_error_handler` — install the UI error handler.
|
||||
pub fn oakcommon_config_set_error_handler(handler: ConfigErrorHandler, userdata: *mut c_void) -> c_int;
|
||||
) -> i64 {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_int64(group, key, fallback) }
|
||||
}
|
||||
|
||||
// ---- videoparams.h --------------------------------------------------
|
||||
/// `oakcommon_videoparams_init` — default video params, refcount 1.
|
||||
pub fn oakcommon_videoparams_init() -> CHandle;
|
||||
/// `oakcommon_videoparams_init_basic` — width/height/frame-rate params.
|
||||
pub fn oakcommon_videoparams_init_basic(
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
time_base_num: c_int,
|
||||
time_base_den: c_int,
|
||||
) -> CHandle;
|
||||
/// `oakcommon_videoparams_init_with_time_base` — params + time base.
|
||||
pub fn oakcommon_videoparams_init_with_time_base(
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
time_base_num: c_int,
|
||||
time_base_den: c_int,
|
||||
) -> CHandle;
|
||||
/// `oakcommon_videoparams_free` — NULL/empty no-op; clears `params->ctx`.
|
||||
pub fn oakcommon_videoparams_free(params: *mut CHandle);
|
||||
/// `oakcommon_videoparams_get_width`.
|
||||
pub fn oakcommon_videoparams_get_width(params: CHandle, width: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_width`.
|
||||
pub fn oakcommon_videoparams_set_width(params: CHandle, width: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_height`.
|
||||
pub fn oakcommon_videoparams_get_height(params: CHandle, height: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_height`.
|
||||
pub fn oakcommon_videoparams_set_height(params: CHandle, height: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_time_base`.
|
||||
pub fn oakcommon_videoparams_get_time_base(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_get_double(group: *const c_char, key: *const c_char, fallback: f64) -> f64 {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_double(group, key, fallback) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, fallback: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_bool(group, key, fallback) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_set_int(group: *const c_char, key: *const c_char, value: c_int) {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_set_int(group, key, value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_set_int64(group: *const c_char, key: *const c_char, value: i64) {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_set_int64(group, key, value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_set_double(group: *const c_char, key: *const c_char, value: f64) {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_set_double(group, key, value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_set_bool(group: *const c_char, key: *const c_char, value: c_int) {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_set_bool(group, key, value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_entry_type(group: *const c_char, key: *const c_char) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_entry_type(group, key) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_config_set_error_handler(handler: ConfigErrorHandler, userdata: *mut c_void) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_set_error_handler(handler, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_init() -> CHandle {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_init_basic(
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
pixel_format: c_int,
|
||||
nb_channels: c_int,
|
||||
pixel_aspect_num: c_int,
|
||||
pixel_aspect_den: c_int,
|
||||
interlacing: c_int,
|
||||
divider: c_int,
|
||||
) -> CHandle {
|
||||
unsafe {
|
||||
oakcommon::ffi::videoparams::oakcommon_videoparams_init_basic(
|
||||
width, height, pixel_format, nb_channels, pixel_aspect_num, pixel_aspect_den,
|
||||
interlacing, divider,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_init_with_time_base(
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
time_base_num: c_int,
|
||||
time_base_den: c_int,
|
||||
pixel_format: c_int,
|
||||
nb_channels: c_int,
|
||||
pixel_aspect_num: c_int,
|
||||
pixel_aspect_den: c_int,
|
||||
interlacing: c_int,
|
||||
divider: c_int,
|
||||
) -> CHandle {
|
||||
unsafe {
|
||||
oakcommon::ffi::videoparams::oakcommon_videoparams_init_with_time_base(
|
||||
width, height, time_base_num, time_base_den, pixel_format, nb_channels,
|
||||
pixel_aspect_num, pixel_aspect_den, interlacing, divider,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_free(params: *mut CHandle) {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_free(params) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_width(params: CHandle, width: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_width(params, width) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_width(params: CHandle, width: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_width(params, width) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_height(params: CHandle, height: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_height(params, height) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_height(params: CHandle, height: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_height(params, height) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_time_base(
|
||||
params: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_set_time_base`.
|
||||
pub fn oakcommon_videoparams_set_time_base(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_time_base(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_time_base(
|
||||
params: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_frame_rate`.
|
||||
pub fn oakcommon_videoparams_get_frame_rate(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_time_base(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_frame_rate(
|
||||
params: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_set_frame_rate`.
|
||||
pub fn oakcommon_videoparams_set_frame_rate(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_frame_rate(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_frame_rate(
|
||||
params: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_pixel_aspect_ratio`.
|
||||
pub fn oakcommon_videoparams_get_pixel_aspect_ratio(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_frame_rate(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_pixel_aspect_ratio(
|
||||
params: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_set_pixel_aspect_ratio`.
|
||||
pub fn oakcommon_videoparams_set_pixel_aspect_ratio(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_pixel_aspect_ratio(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_pixel_aspect_ratio(
|
||||
params: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_format`.
|
||||
pub fn oakcommon_videoparams_get_format(params: CHandle, format: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_format`.
|
||||
pub fn oakcommon_videoparams_set_format(params: CHandle, format: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_interlacing`.
|
||||
pub fn oakcommon_videoparams_get_interlacing(params: CHandle, interlacing: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_interlacing`.
|
||||
pub fn oakcommon_videoparams_set_interlacing(params: CHandle, interlacing: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_divider`.
|
||||
pub fn oakcommon_videoparams_get_divider(params: CHandle, divider: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_divider`.
|
||||
pub fn oakcommon_videoparams_set_divider(params: CHandle, divider: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_video_type`.
|
||||
pub fn oakcommon_videoparams_get_video_type(params: CHandle, type_: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_video_type`.
|
||||
pub fn oakcommon_videoparams_set_video_type(params: CHandle, type_: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_premultiplied_alpha`.
|
||||
pub fn oakcommon_videoparams_get_premultiplied_alpha(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_pixel_aspect_ratio(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_format(params: CHandle, format: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_format(params, format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_format(params: CHandle, format: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_format(params, format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_interlacing(params: CHandle, interlacing: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_interlacing(params, interlacing) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_interlacing(params: CHandle, interlacing: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_interlacing(params, interlacing) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_divider(params: CHandle, divider: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_divider(params, divider) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_divider(params: CHandle, divider: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_divider(params, divider) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_video_type(params: CHandle, type_: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_video_type(params, type_) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_video_type(params: CHandle, type_: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_video_type(params, type_) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_premultiplied_alpha(
|
||||
params: CHandle,
|
||||
premultiplied: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_set_premultiplied_alpha`.
|
||||
pub fn oakcommon_videoparams_set_premultiplied_alpha(params: CHandle, premultiplied: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_color_range`.
|
||||
pub fn oakcommon_videoparams_get_color_range(params: CHandle, color_range: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_color_range`.
|
||||
pub fn oakcommon_videoparams_set_color_range(params: CHandle, color_range: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_is_valid`.
|
||||
pub fn oakcommon_videoparams_get_is_valid(params: CHandle, valid: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_effective_width` — divider-scaled width.
|
||||
pub fn oakcommon_videoparams_get_effective_width(params: CHandle, width: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_effective_height` — divider-scaled height.
|
||||
pub fn oakcommon_videoparams_get_effective_height(params: CHandle, height: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_bytes_per_pixel` — with the params' format.
|
||||
pub fn oakcommon_videoparams_get_bytes_per_pixel(params: CHandle, bytes: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_equals` — user-facing field equality.
|
||||
pub fn oakcommon_videoparams_equals(a: CHandle, b: CHandle, out_equal: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_format_is_float` — 1 when the format is float.
|
||||
pub fn oakcommon_videoparams_format_is_float(pixel_format: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_format_name` — display name (two-stage).
|
||||
pub fn oakcommon_videoparams_get_format_name(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_premultiplied_alpha(params, premultiplied) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_premultiplied_alpha(params: CHandle, premultiplied: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_premultiplied_alpha(params, premultiplied) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_color_range(params: CHandle, color_range: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_color_range(params, color_range) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_set_color_range(params: CHandle, color_range: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_color_range(params, color_range) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_is_valid(params: CHandle, valid: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_is_valid(params, valid) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_effective_width(params: CHandle, width: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_effective_width(params, width) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_effective_height(params: CHandle, height: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_effective_height(params, height) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_bytes_per_pixel(params: CHandle, bytes: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_bytes_per_pixel(params, bytes) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_equals(a: CHandle, b: CHandle, out_equal: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_equals(a, b, out_equal) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_format_is_float(pixel_format: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_format_is_float(pixel_format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_format_name(
|
||||
pixel_format: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_frame_rate_to_string` — label (two-stage).
|
||||
pub fn oakcommon_videoparams_frame_rate_to_string(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_format_name(pixel_format, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_frame_rate_to_string(
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_name_for_divider` — label (two-stage).
|
||||
pub fn oakcommon_videoparams_get_name_for_divider(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_frame_rate_to_string(numerator, denominator, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_name_for_divider(
|
||||
divider: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_scaled_dimension` — size at a divider.
|
||||
pub fn oakcommon_videoparams_get_scaled_dimension(dimension: c_int, divider: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_generate_auto_divider` — best divider for size.
|
||||
pub fn oakcommon_videoparams_generate_auto_divider(width: i64, height: i64) -> c_int;
|
||||
/// `oakcommon_videoparams_get_divider_for_target_resolution`.
|
||||
pub fn oakcommon_videoparams_get_divider_for_target_resolution(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_name_for_divider(divider, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_scaled_dimension(dimension: c_int, divider: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_scaled_dimension(dimension, divider) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_generate_auto_divider(width: i64, height: i64) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_generate_auto_divider(width, height) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_divider_for_target_resolution(
|
||||
src_width: c_int,
|
||||
src_height: c_int,
|
||||
target_width: c_int,
|
||||
target_height: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_bytes_per_channel_for_format`.
|
||||
pub fn oakcommon_videoparams_get_bytes_per_channel_for_format(
|
||||
pixel_format: c_int,
|
||||
bytes: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_bytes_per_pixel_for_format`.
|
||||
pub fn oakcommon_videoparams_get_bytes_per_pixel_for_format(
|
||||
pixel_format: c_int,
|
||||
bytes: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_static_get_bytes_per_pixel`.
|
||||
pub fn oakcommon_videoparams_static_get_bytes_per_pixel(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_divider_for_target_resolution(src_width, src_height, target_width, target_height) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_bytes_per_channel_for_format(pixel_format: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_bytes_per_channel_for_format(pixel_format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_bytes_per_pixel_for_format(
|
||||
pixel_format: c_int,
|
||||
channels: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_bytes_per_pixel_for_format(pixel_format, channels) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_static_get_bytes_per_pixel(
|
||||
pixel_format: c_int,
|
||||
channels: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_buffer_size`.
|
||||
pub fn oakcommon_videoparams_get_buffer_size(params: CHandle, bytes: *mut i64) -> c_int;
|
||||
/// `oakcommon_videoparams_get_time_in_timebase_units`.
|
||||
pub fn oakcommon_videoparams_get_time_in_timebase_units(
|
||||
params: CHandle,
|
||||
time_num: i64,
|
||||
time_den: i64,
|
||||
out: *mut i64,
|
||||
) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_static_get_bytes_per_pixel(pixel_format, channels) }
|
||||
}
|
||||
|
||||
// ---- colortransform.h -----------------------------------------------
|
||||
/// `oakcommon_colortransform_init_output` — output color space transform.
|
||||
pub fn oakcommon_colortransform_init_output(output: *const c_char) -> CHandle;
|
||||
/// `oakcommon_colortransform_init_display` — display/view/look transform.
|
||||
pub fn oakcommon_colortransform_init_display(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_buffer_size(params: CHandle, size: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_buffer_size(params, size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_videoparams_get_time_in_timebase_units(
|
||||
params: CHandle,
|
||||
time_num: c_int,
|
||||
time_den: c_int,
|
||||
timestamp: *mut i64,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_time_in_timebase_units(params, time_num, time_den, timestamp) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_init_output(output: *const c_char) -> CHandle {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_output(output) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_init_display(
|
||||
display: *const c_char,
|
||||
view: *const c_char,
|
||||
look: *const c_char,
|
||||
) -> CHandle;
|
||||
/// `oakcommon_colortransform_free` — NULL/empty no-op.
|
||||
pub fn oakcommon_colortransform_free(transform: *mut CHandle);
|
||||
/// `oakcommon_colortransform_is_display` — 1 for a display transform.
|
||||
pub fn oakcommon_colortransform_is_display(transform: CHandle) -> c_int;
|
||||
/// `oakcommon_colortransform_get_display` (two-stage string).
|
||||
pub fn oakcommon_colortransform_get_display(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_colortransform_get_output` (two-stage string).
|
||||
pub fn oakcommon_colortransform_get_output(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_colortransform_get_view` (two-stage string).
|
||||
pub fn oakcommon_colortransform_get_view(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_colortransform_get_look` (two-stage string).
|
||||
pub fn oakcommon_colortransform_get_look(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
) -> CHandle {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_display(display, view, look) }
|
||||
}
|
||||
|
||||
// ---- xmlutils.h -----------------------------------------------------
|
||||
/// `oakcommon_xml_reader_init` — reader over a NUL-terminated document.
|
||||
pub fn oakcommon_xml_reader_init(data: *const c_char) -> CHandle;
|
||||
/// `oakcommon_xml_reader_free` — NULL/empty no-op.
|
||||
pub fn oakcommon_xml_reader_free(reader: *mut CHandle);
|
||||
/// `oakcommon_xml_reader_read_next_start_element` — found 1/0 in `found`.
|
||||
pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, found: *mut c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_name` (two-stage string).
|
||||
pub fn oakcommon_xml_reader_name(reader: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_read_element_text` (two-stage string).
|
||||
pub fn oakcommon_xml_reader_read_element_text(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_free(transform: *mut CHandle) {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_free(transform) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_is_display(transform: CHandle) -> c_int {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_is_display(transform) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_get_display(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_display(transform, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_get_output(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_output(transform, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_get_view(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_view(transform, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_colortransform_get_look(
|
||||
transform: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_get_look(transform, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_init(data: *const c_char) -> CHandle {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_init(data) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_free(reader: *mut CHandle) {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_free(reader) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, found: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_read_next_start_element(reader, found) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_name(reader: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_name(reader, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_read_element_text(
|
||||
reader: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_xml_reader_skip_current_element`.
|
||||
pub fn oakcommon_xml_reader_skip_current_element(reader: CHandle) -> c_int;
|
||||
/// `oakcommon_xml_reader_attribute_count`.
|
||||
pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_attribute_name` (two-stage string).
|
||||
pub fn oakcommon_xml_reader_attribute_name(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_read_element_text(reader, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_skip_current_element(reader: CHandle) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_skip_current_element(reader) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_count(reader, count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_attribute_name(
|
||||
reader: CHandle,
|
||||
index: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_xml_reader_attribute_value` (two-stage string).
|
||||
pub fn oakcommon_xml_reader_attribute_value(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_name(reader, index, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_attribute_value(
|
||||
reader: CHandle,
|
||||
index: c_int,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_xml_reader_has_error`.
|
||||
pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int;
|
||||
/// `oakcommon_xml_writer_init` — fresh writer.
|
||||
pub fn oakcommon_xml_writer_init() -> CHandle;
|
||||
/// `oakcommon_xml_writer_free` — NULL/empty no-op.
|
||||
pub fn oakcommon_xml_writer_free(writer: *mut CHandle);
|
||||
/// `oakcommon_xml_writer_write_start_element`.
|
||||
pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_attribute`.
|
||||
pub fn oakcommon_xml_writer_write_attribute(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_value(reader, index, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_has_error(reader, has_error) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_init() -> CHandle {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_free(writer: *mut CHandle) {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_free(writer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_start_element(writer, name) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_write_attribute(
|
||||
writer: CHandle,
|
||||
name: *const c_char,
|
||||
value: *const c_char,
|
||||
) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_characters`.
|
||||
pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_text_element`.
|
||||
pub fn oakcommon_xml_writer_write_text_element(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_attribute(writer, name, value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_characters(writer, text) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_write_text_element(
|
||||
writer: CHandle,
|
||||
name: *const c_char,
|
||||
text: *const c_char,
|
||||
) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_end_element`.
|
||||
pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_end_document`.
|
||||
pub fn oakcommon_xml_writer_write_end_document(writer: CHandle) -> c_int;
|
||||
/// `oakcommon_xml_writer_output` (two-stage string).
|
||||
pub fn oakcommon_xml_writer_output(writer: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
|
||||
// ---- decibel helpers -------------------------------------------------
|
||||
/// `oakcommon_decibel_from_linear` — linear amplitude to decibels.
|
||||
pub fn oakcommon_decibel_from_linear(linear: f64, out_db: *mut f64) -> c_int;
|
||||
/// `oakcommon_decibel_to_linear` — decibels to linear amplitude.
|
||||
pub fn oakcommon_decibel_to_linear(db: f64, out_linear: *mut f64) -> c_int;
|
||||
/// `oakcommon_decibel_from_logarithmic` — slider position to decibels.
|
||||
pub fn oakcommon_decibel_from_logarithmic(logarithmic: f64, out_db: *mut f64) -> c_int;
|
||||
/// `oakcommon_decibel_to_logarithmic` — decibels to slider position.
|
||||
pub fn oakcommon_decibel_to_logarithmic(db: f64, out_logarithmic: *mut f64) -> c_int;
|
||||
/// `oakcommon_decibel_linear_to_logarithmic`.
|
||||
pub fn oakcommon_decibel_linear_to_logarithmic(linear: f64, out_logarithmic: *mut f64) -> c_int;
|
||||
/// `oakcommon_decibel_logarithmic_to_linear`.
|
||||
pub fn oakcommon_decibel_logarithmic_to_linear(logarithmic: f64, out_linear: *mut f64) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_text_element(writer, name, text) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_end_element(writer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_write_end_document(writer: CHandle) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_end_document(writer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_xml_writer_output(writer: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_output(writer, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_decibel_from_linear(linear: f64, out_db: *mut f64) -> c_int {
|
||||
unsafe { oakcommon::ffi::misc::oakcommon_decibel_from_linear(linear, out_db) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_decibel_to_linear(db: f64, out_linear: *mut f64) -> c_int {
|
||||
unsafe { oakcommon::ffi::misc::oakcommon_decibel_to_linear(db, out_linear) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_decibel_from_logarithmic(logarithmic: f64, out_db: *mut f64) -> c_int {
|
||||
unsafe { oakcommon::ffi::misc::oakcommon_decibel_from_logarithmic(logarithmic, out_db) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_decibel_to_logarithmic(db: f64, out_logarithmic: *mut f64) -> c_int {
|
||||
unsafe { oakcommon::ffi::misc::oakcommon_decibel_to_logarithmic(db, out_logarithmic) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_decibel_linear_to_logarithmic(linear: f64, out_logarithmic: *mut f64) -> c_int {
|
||||
unsafe { oakcommon::ffi::misc::oakcommon_decibel_linear_to_logarithmic(linear, out_logarithmic) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakcommon_decibel_logarithmic_to_linear(logarithmic: f64, out_linear: *mut f64) -> c_int {
|
||||
unsafe { oakcommon::ffi::misc::oakcommon_decibel_logarithmic_to_linear(logarithmic, out_linear) }
|
||||
}
|
||||
|
||||
|
||||
+2138
-749
File diff suppressed because it is too large
Load Diff
@@ -14,21 +14,65 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakplugin C ABI bridge: direct Rust calls into the `oakplugin` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oakplugin`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakplugin C ABI imports, mirroring the oakplugin crate's exports
|
||||
//! (`src/plugin/rust/src/ffi.rs`; headers `include/plugin/*.h`).
|
||||
|
||||
use std::ffi::{c_char, c_int};
|
||||
|
||||
extern "C" {
|
||||
/// `oakplugin_host_scan` — scan bundle directories (NULL/0 uses the
|
||||
/// default path set).
|
||||
pub fn oakplugin_host_scan(bundle_dirs: *const *const c_char, dir_count: c_int) -> c_int;
|
||||
/// `oakplugin_host_init` — initialize the OFX host (idempotent).
|
||||
pub fn oakplugin_host_init() -> c_int;
|
||||
/// `oakplugin_host_plugin_count` — number of discovered plugins.
|
||||
pub fn oakplugin_host_plugin_count() -> c_int;
|
||||
/// `oakplugin_host_plugin_id_at` — plugin id at index (two-stage).
|
||||
pub fn oakplugin_host_plugin_id_at(index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakplugin_host_plugin_label` — label for an id (two-stage).
|
||||
pub fn oakplugin_host_plugin_label(plugin_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// Direct call into the `oakplugin` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakplugin_host_scan(bundle_dirs: *const *const c_char, dir_count: c_int) -> c_int {
|
||||
unsafe { oakplugin::ffi::oakplugin_host_scan(bundle_dirs, dir_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakplugin` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakplugin_host_init() -> c_int {
|
||||
unsafe { oakplugin::ffi::oakplugin_host_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakplugin` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakplugin_host_plugin_count() -> c_int {
|
||||
unsafe { oakplugin::ffi::oakplugin_host_plugin_count() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakplugin` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakplugin_host_plugin_id_at(index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakplugin::ffi::oakplugin_host_plugin_id_at(index, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakplugin` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakplugin_host_plugin_label(plugin_id: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakplugin::ffi::oakplugin_host_plugin_label(plugin_id, buf, buf_size) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakrender C ABI bridge: direct Rust calls into the `oakrender` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oakrender`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakrender C ABI imports, mirroring the oakrender crate's exports
|
||||
//! (`src/render/rust/src/ffi.rs`; headers `include/render/*.h`).
|
||||
|
||||
@@ -21,110 +48,84 @@ use std::ffi::{c_char, c_double, c_int, c_void};
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `include/render/ticket.h` — video render ticket params mirror. All
|
||||
/// handle fields are [`CHandle`] (borrowed unless noted).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakVideoTicketParams {
|
||||
/// Connected texture output node (borrowed).
|
||||
pub output_node: CHandle,
|
||||
/// By-value oakcommon video-params handle.
|
||||
pub video_params: CHandle,
|
||||
/// Borrowed oakcore audio-params handle, may be null.
|
||||
pub audio_params: *const c_void,
|
||||
/// Frame timestamp numerator.
|
||||
pub time_num: i64,
|
||||
/// Frame timestamp denominator.
|
||||
pub time_den: i64,
|
||||
/// Borrowed color manager, empty ctx = null.
|
||||
pub color_manager: CHandle,
|
||||
/// RenderMode::Mode as int.
|
||||
pub mode: c_int,
|
||||
/// 0/0 = off.
|
||||
pub force_width: c_int,
|
||||
/// 0/0 = off.
|
||||
pub force_height: c_int,
|
||||
/// Used when has_force_matrix != 0.
|
||||
pub force_matrix: [c_double; 16],
|
||||
/// 0/1.
|
||||
pub has_force_matrix: c_int,
|
||||
/// PixelFormat as int, -1 = off.
|
||||
pub force_format: c_int,
|
||||
/// 0 = off.
|
||||
pub force_channel_count: c_int,
|
||||
/// Borrowed; empty ctx = none.
|
||||
pub force_color_output: CHandle,
|
||||
/// By value; empty ctx = default.
|
||||
pub force_color_transform: CHandle,
|
||||
/// Borrowed frame cache; empty ctx = none.
|
||||
pub cache: CHandle,
|
||||
}
|
||||
/// `include/render/ticket.h` — video render ticket params. Single-lib
|
||||
/// unification: aliases the oakrender crate's POD (same `repr(C)`
|
||||
/// layout; all handle fields are the shared [`CHandle`]).
|
||||
pub type OakVideoTicketParams = oakrender::ffi::OakVideoTicketParams;
|
||||
|
||||
|
||||
/// `include/render/renderer.h` — frame video-params POD returned by
|
||||
/// `oakrender_codec_frame_get_params`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakRenderVideoParams {
|
||||
/// Width.
|
||||
pub width: c_int,
|
||||
/// Height.
|
||||
pub height: c_int,
|
||||
/// Frame duration numerator.
|
||||
pub time_base_num: c_int,
|
||||
/// Frame duration denominator.
|
||||
pub time_base_den: c_int,
|
||||
/// PixelFormat as int.
|
||||
pub format: c_int,
|
||||
/// Pixel aspect numerator.
|
||||
pub pixel_aspect_num: c_int,
|
||||
/// Pixel aspect denominator.
|
||||
pub pixel_aspect_den: c_int,
|
||||
/// Interlacing as int.
|
||||
pub interlacing: c_int,
|
||||
/// Color range as int.
|
||||
pub color_range: c_int,
|
||||
/// Preview divider.
|
||||
pub divider: c_int,
|
||||
/// Video type.
|
||||
pub video_type: c_int,
|
||||
/// Premultiplied alpha 0/1.
|
||||
pub premultiplied_alpha: c_int,
|
||||
/// `oakrender_codec_frame_get_params`. Single-lib unification: aliases
|
||||
/// the oakrender crate's POD.
|
||||
pub type OakRenderVideoParams = oakrender::ffi::OakRenderVideoParams;
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_display_renderer_create_dynamic(backend_id: *const c_char) -> CHandle {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_create_dynamic(backend_id) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// ---- display renderer --------------------------------------------------
|
||||
/// `oakrender_display_renderer_create_dynamic` — named backend
|
||||
/// ("opengl", "vulkan", "metal", "auto", ...).
|
||||
pub fn oakrender_display_renderer_create_dynamic(backend_id: *const c_char) -> CHandle;
|
||||
/// `oakrender_display_renderer_create_opengl` — direct OpenGL renderer.
|
||||
pub fn oakrender_display_renderer_create_opengl() -> CHandle;
|
||||
/// `oakrender_display_renderer_init` — NULL gl_context uses the
|
||||
/// backend's default device/context path.
|
||||
pub fn oakrender_display_renderer_init(renderer: CHandle, gl_context: *mut c_void) -> c_int;
|
||||
/// `oakrender_display_renderer_destroy` — NULL/empty no-op.
|
||||
pub fn oakrender_display_renderer_destroy(renderer: *mut CHandle);
|
||||
/// `oakrender_display_renderer_is_open_gl` — 1/0.
|
||||
pub fn oakrender_display_renderer_is_open_gl(renderer: CHandle) -> c_int;
|
||||
/// `oakrender_display_renderer_is_vulkan` — 1/0.
|
||||
pub fn oakrender_display_renderer_is_vulkan(renderer: CHandle) -> c_int;
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_display_renderer_create_opengl() -> CHandle {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_create_opengl() }
|
||||
}
|
||||
|
||||
// ---- render manager -----------------------------------------------------
|
||||
/// `oakrender_manager_set_aggressive_gc`.
|
||||
pub fn oakrender_manager_set_aggressive_gc(enabled: c_int) -> c_int;
|
||||
/// `oakrender_set_cacher_multicam` — NULL clears.
|
||||
pub fn oakrender_set_cacher_multicam(multicam_or_null: CHandle) -> c_int;
|
||||
/// `oakrender_set_display_color_processor` — NULL clears.
|
||||
pub fn oakrender_set_display_color_processor(p_or_null: CHandle) -> c_int;
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_display_renderer_init(renderer: CHandle, gl_context: *mut c_void) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_init(renderer, gl_context) }
|
||||
}
|
||||
|
||||
// ---- render tickets -----------------------------------------------------
|
||||
/// `oakrender_ticket_render_frame`.
|
||||
pub fn oakrender_ticket_render_frame(
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_display_renderer_destroy(renderer: *mut CHandle) {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_destroy(renderer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_display_renderer_is_open_gl(renderer: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_is_open_gl(renderer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_display_renderer_is_vulkan(renderer: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_is_vulkan(renderer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_manager_set_aggressive_gc(enabled: c_int) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_manager_set_aggressive_gc(enabled) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_set_cacher_multicam(multicam_or_null: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::manager::oakrender_set_cacher_multicam(multicam_or_null) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_set_display_color_processor(p_or_null: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::manager::oakrender_set_display_color_processor(p_or_null) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_render_frame(
|
||||
params: *const OakVideoTicketParams,
|
||||
cb: Option<unsafe extern "C" fn(CHandle, *mut c_void)>,
|
||||
userdata: *mut c_void,
|
||||
) -> CHandle;
|
||||
/// `oakrender_ticket_render_audio`.
|
||||
pub fn oakrender_ticket_render_audio(
|
||||
) -> CHandle {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_render_frame(params, cb, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_render_audio(
|
||||
output_node: CHandle,
|
||||
in_num: i64,
|
||||
in_den: i64,
|
||||
@@ -134,61 +135,141 @@ extern "C" {
|
||||
mode: c_int,
|
||||
cb: Option<unsafe extern "C" fn(CHandle, *mut c_void)>,
|
||||
userdata: *mut c_void,
|
||||
) -> CHandle;
|
||||
/// `oakrender_ticket_wait` — block until finished.
|
||||
pub fn oakrender_ticket_wait(ticket: CHandle) -> c_int;
|
||||
/// `oakrender_ticket_cancel`.
|
||||
pub fn oakrender_ticket_cancel(ticket: CHandle) -> c_int;
|
||||
/// `oakrender_ticket_get_frame` — `*out` receives an owned copy.
|
||||
pub fn oakrender_ticket_get_frame(ticket: CHandle, out: *mut CHandle) -> c_int;
|
||||
/// `oakrender_ticket_get_samples` — audio not implemented in the crate.
|
||||
pub fn oakrender_ticket_get_samples(ticket: CHandle, out: *mut *mut c_void) -> c_int;
|
||||
/// `oakrender_ticket_free` — NULL/empty no-op.
|
||||
pub fn oakrender_ticket_free(ticket: *mut CHandle);
|
||||
) -> CHandle {
|
||||
unsafe {
|
||||
oakrender::ffi::ticket::oakrender_ticket_render_audio(
|
||||
output_node, in_num, in_den, out_num, out_den, params as *const CHandle, mode, cb,
|
||||
userdata,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ---- codec frame --------------------------------------------------------
|
||||
/// `oakrender_codec_frame_create` — refcount 1.
|
||||
pub fn oakrender_codec_frame_create() -> CHandle;
|
||||
/// `oakrender_codec_frame_retain` — addref, return copy.
|
||||
pub fn oakrender_codec_frame_retain(frame: CHandle) -> CHandle;
|
||||
/// `oakrender_codec_frame_free` — NULL/empty no-op.
|
||||
pub fn oakrender_codec_frame_free(frame: *mut CHandle);
|
||||
/// `oakrender_codec_frame_width`.
|
||||
pub fn oakrender_codec_frame_width(frame: CHandle) -> c_int;
|
||||
/// `oakrender_codec_frame_height`.
|
||||
pub fn oakrender_codec_frame_height(frame: CHandle) -> c_int;
|
||||
/// `oakrender_codec_frame_linesize_bytes`.
|
||||
pub fn oakrender_codec_frame_linesize_bytes(frame: CHandle) -> c_int;
|
||||
/// `oakrender_codec_frame_data` — borrowed.
|
||||
pub fn oakrender_codec_frame_data(frame: CHandle) -> *mut c_void;
|
||||
/// `oakrender_codec_frame_const_data` — borrowed.
|
||||
pub fn oakrender_codec_frame_const_data(frame: CHandle) -> *const c_void;
|
||||
/// `oakrender_codec_frame_is_allocated`.
|
||||
pub fn oakrender_codec_frame_is_allocated(frame: CHandle) -> c_int;
|
||||
/// `oakrender_codec_frame_get_params` — fills the params POD.
|
||||
pub fn oakrender_codec_frame_get_params(frame: CHandle, out: *mut OakRenderVideoParams) -> c_int;
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_wait(ticket: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_wait(ticket) }
|
||||
}
|
||||
|
||||
// ---- color processor ----------------------------------------------------
|
||||
/// `oakrender_color_processor_create`.
|
||||
pub fn oakrender_color_processor_create(
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_cancel(ticket: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_cancel(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_get_frame(ticket: CHandle, out: *mut CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_frame(ticket, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_get_samples(ticket: CHandle, out: *mut *mut c_void) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_samples(ticket, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_ticket_free(ticket: *mut CHandle) {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_free(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_create() -> CHandle {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_create() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_retain(frame: CHandle) -> CHandle {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_retain(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_free(frame: *mut CHandle) {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_free(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_width(frame: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_width(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_height(frame: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_height(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_linesize_bytes(frame: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_linesize_bytes(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_data(frame: CHandle) -> *mut c_void {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_data(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_const_data(frame: CHandle) -> *const c_void {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_const_data(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_is_allocated(frame: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_is_allocated(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_codec_frame_get_params(frame: CHandle, out: *mut OakRenderVideoParams) -> c_int {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_get_params(frame, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_processor_create(
|
||||
src_space: *const c_char,
|
||||
dst_transform: *const c_char,
|
||||
direction: c_int,
|
||||
) -> CHandle;
|
||||
/// `oakrender_color_processor_free` — NULL/empty no-op.
|
||||
pub fn oakrender_color_processor_free(processor: *mut CHandle);
|
||||
/// `oakrender_color_processor_is_valid`.
|
||||
pub fn oakrender_color_processor_is_valid(processor: CHandle) -> c_int;
|
||||
/// `oakrender_color_processor_create_transform` — manager + input +
|
||||
/// oakcommon colortransform handle + direction.
|
||||
pub fn oakrender_color_processor_create_transform(
|
||||
) -> CHandle {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_create(src_space, dst_transform, direction) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_processor_free(processor: *mut CHandle) {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_free(processor) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_processor_is_valid(processor: CHandle) -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_is_valid(processor) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_processor_create_transform(
|
||||
manager: CHandle,
|
||||
input: *const c_char,
|
||||
dest: CHandle,
|
||||
direction: c_int,
|
||||
) -> CHandle;
|
||||
/// `oakrender_color_processor_convert` — single RGBA color.
|
||||
pub fn oakrender_color_processor_convert(
|
||||
) -> CHandle {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_create_transform(manager, input, dest, direction) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_processor_convert(
|
||||
processor: CHandle,
|
||||
ir: c_double,
|
||||
ig: c_double,
|
||||
@@ -198,19 +279,37 @@ extern "C" {
|
||||
out_g: *mut c_double,
|
||||
out_b: *mut c_double,
|
||||
out_a: *mut c_double,
|
||||
) -> c_int;
|
||||
|
||||
// ---- color manager ------------------------------------------------------
|
||||
/// `oakrender_color_manager_set_up_default_config`.
|
||||
pub fn oakrender_color_manager_set_up_default_config() -> c_int;
|
||||
/// `oakrender_color_manager_get_config` (two-stage).
|
||||
pub fn oakrender_color_manager_get_config(buf: *mut c_char, n: c_int) -> c_int;
|
||||
|
||||
// ---- LUT extension enumeration ------------------------------------------
|
||||
/// `oakrender_lut_is_supported_extension`.
|
||||
pub fn oakrender_lut_is_supported_extension(extension: *const c_char) -> c_int;
|
||||
/// `oakrender_lut_supported_extensions_count`.
|
||||
pub fn oakrender_lut_supported_extensions_count() -> c_int;
|
||||
/// `oakrender_lut_supported_extension_at` (two-stage).
|
||||
pub fn oakrender_lut_supported_extension_at(i: c_int, buf: *mut c_char, n: c_int) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_convert(processor, ir, ig, ib, ia, out_r, out_g, out_b, out_a) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_manager_set_up_default_config() -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_manager_set_up_default_config() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_color_manager_get_config(buf: *mut c_char, n: c_int) -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_manager_get_config(buf, n) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_lut_is_supported_extension(extension: *const c_char) -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_lut_is_supported_extension(extension) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_lut_supported_extensions_count() -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_lut_supported_extensions_count() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakrender_lut_supported_extension_at(i: c_int, buf: *mut c_char, n: c_int) -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_lut_supported_extension_at(i, buf, n) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oaktask C ABI bridge: direct Rust calls into the `oaktask` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oaktask`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oaktask C ABI imports, mirroring the oaktask crate's exports
|
||||
//! (`src/task/rust/src/ffi/{manager,task,project}.rs`; headers
|
||||
//! `include/task/*.h`).
|
||||
@@ -41,81 +68,217 @@ pub type OakTaskOtioImportConfirmFn =
|
||||
pub type OakTaskImageSequenceConfirmFn =
|
||||
unsafe extern "C" fn(filename: *const c_char, userdata: *mut c_void) -> c_int;
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_manager_init() -> c_int {
|
||||
unsafe { oaktask::ffi::manager::oaktask_manager_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_manager_shutdown() {
|
||||
unsafe { oaktask::ffi::manager::oaktask_manager_shutdown() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_register_codec_submitter() -> c_int {
|
||||
unsafe { oaktask::ffi::manager::oaktask_register_codec_submitter() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_manager_count() -> c_int {
|
||||
unsafe { oaktask::ffi::manager::oaktask_manager_count() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_manager_at(i: c_int) -> CHandle {
|
||||
unsafe { oaktask::ffi::manager::oaktask_manager_at(i) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_manager_delete_finished() {
|
||||
unsafe { oaktask::ffi::manager::oaktask_manager_delete_finished() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_free(t: *mut CHandle) {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_free(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_start_sync(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_start_sync(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_start(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_start(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_cancel(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_cancel(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_wait(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_wait(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_is_finished(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_is_finished(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_succeeded(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_succeeded(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_title(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_title(t, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_error(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_error(t, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_task_subscribe(t: CHandle, cb: Option<OakTaskEventFn>, userdata: *mut c_void) -> i64 {
|
||||
unsafe { oaktask::ffi::task::oaktask_task_subscribe(t, cb, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_debug_alive_count() -> c_int {
|
||||
unsafe { oaktask::ffi::task::oaktask_debug_alive_count() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_create_project_load(filename: *const c_char) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_create_project_load(filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_load_take_project(t: CHandle) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_load_take_project(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_create_project_save(project: CHandle, filename_or_null: *const c_char, use_compression: c_int) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_create_project_save(project, filename_or_null, use_compression) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_create_project_import(folder: CHandle, project: CHandle, urls: *const *const c_char, url_count: c_int) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_create_project_import(folder, project, urls, url_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_import_take_command(t: CHandle) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_import_take_command(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_import_footage_count(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::project::oaktask_import_footage_count(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_import_footage_at(t: CHandle, index: c_int) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_import_footage_at(t, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_import_invalid_count(t: CHandle) -> c_int {
|
||||
unsafe { oaktask::ffi::project::oaktask_import_invalid_count(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_import_invalid_at(t: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oaktask::ffi::project::oaktask_import_invalid_at(t, index, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_create_project_load_otio(filename: *const c_char) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_create_project_load_otio(filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_load_otio_take_project(t: CHandle) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_load_otio_take_project(t) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_create_project_save_otio(project: CHandle, filename: *const c_char) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_create_project_save_otio(project, filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_load_otio_set_confirm_cb(cb: Option<OakTaskOtioImportConfirmFn>, userdata: *mut c_void) {
|
||||
unsafe { oaktask::ffi::project::oaktask_load_otio_set_confirm_cb(cb, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_create_precache(footage: CHandle, index: c_int, sequence: CHandle) -> CHandle {
|
||||
unsafe { oaktask::ffi::project::oaktask_create_precache(footage, index, sequence) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
/// `oaktask_create_export` — crosses the encoding-params C ABI POD
|
||||
/// (the facade keeps its own POD mirror). Kept as a link-time
|
||||
/// `extern "C"` declaration against the frozen module C ABI.
|
||||
pub fn oaktask_create_export(
|
||||
viewer: CHandle,
|
||||
color_manager: CHandle,
|
||||
params: *const crate::bridge::codec::EncodingParamsPOD,
|
||||
) -> CHandle {
|
||||
unsafe { oaktask_create_export_extern(viewer, color_manager, params) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// ---- include/task/manager.h ---------------------------------------------
|
||||
/// `oaktask_manager_init` — start the global task manager.
|
||||
pub fn oaktask_manager_init() -> c_int;
|
||||
/// `oaktask_manager_shutdown`.
|
||||
pub fn oaktask_manager_shutdown();
|
||||
/// `oaktask_register_codec_submitter`.
|
||||
pub fn oaktask_register_codec_submitter() -> c_int;
|
||||
/// `oaktask_manager_count` — running plus failed-but-kept tasks.
|
||||
pub fn oaktask_manager_count() -> c_int;
|
||||
/// `oaktask_manager_at` — borrowed task handle at index.
|
||||
pub fn oaktask_manager_at(i: c_int) -> CHandle;
|
||||
/// `oaktask_manager_delete_finished`.
|
||||
pub fn oaktask_manager_delete_finished();
|
||||
|
||||
// ---- include/task/task.h -------------------------------------------------
|
||||
/// `oaktask_task_free` — release one reference; NULL/empty no-op.
|
||||
pub fn oaktask_task_free(t: *mut CHandle);
|
||||
/// `oaktask_task_start_sync` — run in the calling thread; 1 = succeeded.
|
||||
pub fn oaktask_task_start_sync(t: CHandle) -> c_int;
|
||||
/// `oaktask_task_start` — run on the task manager (transfers ownership).
|
||||
pub fn oaktask_task_start(t: CHandle) -> c_int;
|
||||
/// `oaktask_task_cancel`.
|
||||
pub fn oaktask_task_cancel(t: CHandle) -> c_int;
|
||||
/// `oaktask_task_wait` — wait for an asynchronously started task.
|
||||
pub fn oaktask_task_wait(t: CHandle) -> c_int;
|
||||
/// `oaktask_task_is_finished`.
|
||||
pub fn oaktask_task_is_finished(t: CHandle) -> c_int;
|
||||
/// `oaktask_task_succeeded`.
|
||||
pub fn oaktask_task_succeeded(t: CHandle) -> c_int;
|
||||
/// `oaktask_task_title` (two-stage string).
|
||||
pub fn oaktask_task_title(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oaktask_task_error` (two-stage string).
|
||||
pub fn oaktask_task_error(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oaktask_task_subscribe` — subscription id >= 0 or a negative code.
|
||||
pub fn oaktask_task_subscribe(t: CHandle, cb: Option<OakTaskEventFn>, userdata: *mut c_void) -> i64;
|
||||
/// `oaktask_debug_alive_count`.
|
||||
pub fn oaktask_debug_alive_count() -> c_int;
|
||||
|
||||
// ---- include/task/project.h ----------------------------------------------
|
||||
/// `oaktask_create_project_load` — owned `ProjectLoadTask`.
|
||||
pub fn oaktask_create_project_load(filename: *const c_char) -> CHandle;
|
||||
/// `oaktask_load_take_project` — ownership transfer of the loaded project.
|
||||
pub fn oaktask_load_take_project(t: CHandle) -> CHandle;
|
||||
/// `oaktask_create_project_save` — owned `ProjectSaveTask`.
|
||||
pub fn oaktask_create_project_save(project: CHandle, filename_or_null: *const c_char, use_compression: c_int) -> CHandle;
|
||||
/// `oaktask_create_project_import` — owned `ProjectImportTask`.
|
||||
pub fn oaktask_create_project_import(folder: CHandle, project: CHandle, urls: *const *const c_char, url_count: c_int) -> CHandle;
|
||||
/// `oaktask_import_take_command` — ownership transfer of the undo command.
|
||||
pub fn oaktask_import_take_command(t: CHandle) -> CHandle;
|
||||
/// `oaktask_import_footage_count`.
|
||||
pub fn oaktask_import_footage_count(t: CHandle) -> c_int;
|
||||
/// `oaktask_import_footage_at` — addref'd footage handle.
|
||||
pub fn oaktask_import_footage_at(t: CHandle, index: c_int) -> CHandle;
|
||||
/// `oaktask_import_invalid_count`.
|
||||
pub fn oaktask_import_invalid_count(t: CHandle) -> c_int;
|
||||
/// `oaktask_import_invalid_at` (two-stage string).
|
||||
pub fn oaktask_import_invalid_at(t: CHandle, index: c_int, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oaktask_create_project_load_otio` — owned `LoadOTIOTask`.
|
||||
pub fn oaktask_create_project_load_otio(filename: *const c_char) -> CHandle;
|
||||
/// `oaktask_load_otio_take_project` — ownership transfer.
|
||||
pub fn oaktask_load_otio_take_project(t: CHandle) -> CHandle;
|
||||
/// `oaktask_create_project_save_otio` — owned `SaveOTIOTask`.
|
||||
pub fn oaktask_create_project_save_otio(project: CHandle, filename: *const c_char) -> CHandle;
|
||||
/// `oaktask_load_otio_set_confirm_cb` — install/clear the confirm callback.
|
||||
pub fn oaktask_load_otio_set_confirm_cb(cb: Option<OakTaskOtioImportConfirmFn>, userdata: *mut c_void);
|
||||
/// `oaktask_create_precache` — owned `PreCacheTask`.
|
||||
pub fn oaktask_create_precache(footage: CHandle, index: c_int, sequence: CHandle) -> CHandle;
|
||||
/// `oaktask_create_export` — owned `ExportTask`; `params` is the
|
||||
/// encoding-params POD (facade's `EncodingParamsPOD`).
|
||||
pub fn oaktask_create_export(
|
||||
#[link_name = "oaktask_create_export"]
|
||||
pub fn oaktask_create_export_extern(
|
||||
viewer: CHandle,
|
||||
color_manager: CHandle,
|
||||
params: *const crate::bridge::codec::EncodingParamsPOD,
|
||||
) -> CHandle;
|
||||
/// `oaktask_import_set_image_sequence_confirm_cb` — install/clear.
|
||||
pub fn oaktask_import_set_image_sequence_confirm_cb(cb: Option<OakTaskImageSequenceConfirmFn>, userdata: *mut c_void);
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktask_import_set_image_sequence_confirm_cb(cb: Option<OakTaskImageSequenceConfirmFn>, userdata: *mut c_void) {
|
||||
unsafe { oaktask::ffi::project::oaktask_import_set_image_sequence_confirm_cb(cb, userdata) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oaktimeline C ABI bridge: direct Rust calls into the `oaktimeline` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oaktimeline`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oaktimeline C ABI imports, mirroring the oaktimeline crate's exports
|
||||
//! (`src/timeline/rust/src/ffi.rs`; headers `include/timeline/*.h`).
|
||||
//!
|
||||
@@ -30,15 +57,28 @@ use crate::handle::CHandle;
|
||||
// oaktimeline_marker_list_create / free / of / add / count / at /
|
||||
// add_command / remove_at_command / set_time_command /
|
||||
// set_props_command / list_load / list_save.
|
||||
extern "C" {
|
||||
/// `oaktimeline_marker_list_create` — new owning list, refcount 1.
|
||||
pub fn oaktimeline_marker_list_create() -> CHandle;
|
||||
/// `oaktimeline_marker_list_of` — borrowed list of a viewer node.
|
||||
pub fn oaktimeline_marker_list_of(owner: CHandle) -> CHandle;
|
||||
/// `oaktimeline_marker_list_free` — NULL/empty no-op; clears `list->ctx`.
|
||||
pub fn oaktimeline_marker_list_free(list: *mut CHandle);
|
||||
/// `oaktimeline_marker_add` — append a marker directly (no command).
|
||||
pub fn oaktimeline_marker_add(
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_list_create() -> CHandle {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_create() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_list_of(owner: CHandle) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_of(owner) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_list_free(list: *mut CHandle) {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_free(list) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_add(
|
||||
list: CHandle,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
@@ -46,11 +86,19 @@ extern "C" {
|
||||
out_den: c_int,
|
||||
name: *const c_char,
|
||||
color: c_int,
|
||||
) -> c_int;
|
||||
/// `oaktimeline_marker_count` — number of markers.
|
||||
pub fn oaktimeline_marker_count(list: CHandle, out_count: *mut c_int) -> c_int;
|
||||
/// `oaktimeline_marker_at` — marker at index; name two-stage.
|
||||
pub fn oaktimeline_marker_at(
|
||||
) -> c_int {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_add(list, in_num, in_den, out_num, out_den, name, color) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_count(list: CHandle, out_count: *mut c_int) -> c_int {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_count(list, out_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_at(
|
||||
list: CHandle,
|
||||
index: c_int,
|
||||
in_num: *mut c_int,
|
||||
@@ -60,68 +108,118 @@ extern "C" {
|
||||
color: *mut c_int,
|
||||
name_buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oaktimeline_marker_add_command` — owned `MarkerAddCommand`.
|
||||
pub fn oaktimeline_marker_add_command(
|
||||
list: CHandle,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
name: *const c_char,
|
||||
color: c_int,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_marker_remove_at_command` — owned `MarkerRemoveCommand`.
|
||||
pub fn oaktimeline_marker_remove_at_command(list: CHandle, index: c_int) -> CHandle;
|
||||
/// `oaktimeline_marker_set_time_command` — owned `MarkerChangeTimeCommand`.
|
||||
pub fn oaktimeline_marker_set_time_command(
|
||||
list: CHandle,
|
||||
index: c_int,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_marker_set_props_command` — owned color/name command.
|
||||
pub fn oaktimeline_marker_set_props_command(
|
||||
list: CHandle,
|
||||
index: c_int,
|
||||
color: c_int,
|
||||
name: *const c_char,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_marker_list_load` — read from an oakcommon reader.
|
||||
pub fn oaktimeline_marker_list_load(list: CHandle, reader: CHandle) -> c_int;
|
||||
/// `oaktimeline_marker_list_save` — write to an oakcommon writer.
|
||||
pub fn oaktimeline_marker_list_save(list: CHandle, writer: CHandle) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_at(list, index, in_num, in_den, out_num, out_den, color, name_buf, buf_size) }
|
||||
}
|
||||
|
||||
// ---- include/timeline/workarea.h ----------------------------------------
|
||||
/// `oaktimeline_workarea_create` — new owning work area, refcount 1.
|
||||
pub fn oaktimeline_workarea_create() -> CHandle;
|
||||
/// `oaktimeline_workarea_of` — borrowed work area of a viewer node.
|
||||
pub fn oaktimeline_workarea_of(owner: CHandle) -> CHandle;
|
||||
/// `oaktimeline_workarea_free` — NULL/empty no-op; clears `w->ctx`.
|
||||
pub fn oaktimeline_workarea_free(w: *mut CHandle);
|
||||
/// `oaktimeline_workarea_set_enabled` — live.
|
||||
pub fn oaktimeline_workarea_set_enabled(w: CHandle, enabled: c_int) -> c_int;
|
||||
/// `oaktimeline_workarea_get` — state out; params may be NULL.
|
||||
pub fn oaktimeline_workarea_get(
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_add_command(
|
||||
list: CHandle,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
name: *const c_char,
|
||||
color: c_int,
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_add_command(list, in_num, in_den, out_num, out_den, name, color) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_remove_at_command(list: CHandle, index: c_int) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_remove_at_command(list, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_set_time_command(
|
||||
list: CHandle,
|
||||
index: c_int,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_set_time_command(list, index, in_num, in_den, out_num, out_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_set_props_command(
|
||||
list: CHandle,
|
||||
index: c_int,
|
||||
color: c_int,
|
||||
name: *const c_char,
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_set_props_command(list, index, color, name) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_list_load(list: CHandle, reader: CHandle) -> c_int {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_load(list, reader) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_marker_list_save(list: CHandle, writer: CHandle) -> c_int {
|
||||
unsafe { oaktimeline::ffi::marker::oaktimeline_marker_list_save(list, writer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_create() -> CHandle {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_create() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_of(owner: CHandle) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_of(owner) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_free(w: *mut CHandle) {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_free(w) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_set_enabled(w: CHandle, enabled: c_int) -> c_int {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_enabled(w, enabled) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_get(
|
||||
w: CHandle,
|
||||
in_num: *mut c_int,
|
||||
in_den: *mut c_int,
|
||||
out_num: *mut c_int,
|
||||
out_den: *mut c_int,
|
||||
enabled: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oaktimeline_workarea_set_range` — live.
|
||||
pub fn oaktimeline_workarea_set_range(
|
||||
) -> c_int {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_get(w, in_num, in_den, out_num, out_den, enabled) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_set_range(
|
||||
w: CHandle,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
) -> c_int;
|
||||
/// `oaktimeline_workarea_set_range_command` — owned command, old range from caller.
|
||||
pub fn oaktimeline_workarea_set_range_command(
|
||||
) -> c_int {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_range(w, in_num, in_den, out_num, out_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_set_range_command(
|
||||
w: CHandle,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
@@ -131,57 +229,102 @@ extern "C" {
|
||||
old_in_den: c_int,
|
||||
old_out_num: c_int,
|
||||
old_out_den: c_int,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_workarea_set_enabled_command` — owned command.
|
||||
pub fn oaktimeline_workarea_set_enabled_command(w: CHandle, enabled: c_int) -> CHandle;
|
||||
/// `oaktimeline_workarea_reset` — the reset sentinel range.
|
||||
pub fn oaktimeline_workarea_reset(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_range_command(w, in_num, in_den, out_num, out_den, old_in_num, old_in_den, old_out_num, old_out_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_set_enabled_command(w: CHandle, enabled: c_int) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_set_enabled_command(w, enabled) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_reset(
|
||||
in_num: *mut c_int,
|
||||
in_den: *mut c_int,
|
||||
out_num: *mut c_int,
|
||||
out_den: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oaktimeline_workarea_load` — read from an oakcommon reader.
|
||||
pub fn oaktimeline_workarea_load(w: CHandle, reader: CHandle) -> c_int;
|
||||
/// `oaktimeline_workarea_save` — write to an oakcommon writer.
|
||||
pub fn oaktimeline_workarea_save(w: CHandle, writer: CHandle) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_reset(in_num, in_den, out_num, out_den) }
|
||||
}
|
||||
|
||||
// ---- include/timeline/edit.h --------------------------------------------
|
||||
/// `oaktimeline_add_track_command` — owned `TimelineAddTrackCommand`.
|
||||
pub fn oaktimeline_add_track_command(list: CHandle) -> CHandle;
|
||||
/// `oaktimeline_remove_track_command` — owned `TimelineRemoveTrackCommand`.
|
||||
pub fn oaktimeline_remove_track_command(track: CHandle) -> CHandle;
|
||||
/// `oaktimeline_place_block_command` — owned `TrackPlaceBlockCommand`.
|
||||
pub fn oaktimeline_place_block_command(
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_load(w: CHandle, reader: CHandle) -> c_int {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_load(w, reader) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_workarea_save(w: CHandle, writer: CHandle) -> c_int {
|
||||
unsafe { oaktimeline::ffi::workarea::oaktimeline_workarea_save(w, writer) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_add_track_command(list: CHandle) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_add_track_command(list) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_remove_track_command(track: CHandle) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_remove_track_command(track) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_place_block_command(
|
||||
list: CHandle,
|
||||
track_index: c_int,
|
||||
block: CHandle,
|
||||
in_num: i64,
|
||||
in_den: i64,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_replace_block_with_gap_command` — owned command.
|
||||
pub fn oaktimeline_replace_block_with_gap_command(track: CHandle, block: CHandle) -> CHandle;
|
||||
/// `oaktimeline_trim_command` — owned `BlockTrimCommand`; `mode` is an
|
||||
/// `OakTimelineMovementMode` value.
|
||||
pub fn oaktimeline_trim_command(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_place_block_command(list, track_index, block, in_num, in_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_replace_block_with_gap_command(track: CHandle, block: CHandle) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_replace_block_with_gap_command(track, block) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_trim_command(
|
||||
track: CHandle,
|
||||
block: CHandle,
|
||||
new_length_num: i64,
|
||||
new_length_den: i64,
|
||||
mode: c_int,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_split_command` — owned `BlockSplitCommand` (one point).
|
||||
pub fn oaktimeline_split_command(blocks: *const CHandle, count: c_int, point_num: i64, point_den: i64) -> CHandle;
|
||||
/// `oaktimeline_split_preserving_links_command` — owned command.
|
||||
pub fn oaktimeline_split_preserving_links_command(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_trim_command(track, block, new_length_num, new_length_den, mode) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_split_command(blocks: *const CHandle, count: c_int, point_num: i64, point_den: i64) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_split_command(blocks, count, point_num, point_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_split_preserving_links_command(
|
||||
blocks: *const CHandle,
|
||||
count: c_int,
|
||||
point_nums: *const i64,
|
||||
point_dens: *const i64,
|
||||
time_count: c_int,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_ripple_delete_gaps_command` — owned command.
|
||||
pub fn oaktimeline_ripple_delete_gaps_command(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_split_preserving_links_command(blocks, count, point_nums, point_dens, time_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_ripple_delete_gaps_command(
|
||||
sequence: CHandle,
|
||||
in_nums: *const i64,
|
||||
in_dens: *const i64,
|
||||
@@ -189,9 +332,13 @@ extern "C" {
|
||||
out_dens: *const i64,
|
||||
tracks: *const CHandle,
|
||||
range_count: c_int,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_slide_command` — owned `TrackSlideCommand`.
|
||||
pub fn oaktimeline_slide_command(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_ripple_delete_gaps_command(sequence, in_nums, in_dens, out_nums, out_dens, tracks, range_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_slide_command(
|
||||
track: CHandle,
|
||||
blocks: *const CHandle,
|
||||
block_count: c_int,
|
||||
@@ -199,22 +346,31 @@ extern "C" {
|
||||
out_adjacent: CHandle,
|
||||
movement_num: i64,
|
||||
movement_den: i64,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_ripple_remove_area_command` — owned
|
||||
/// `TrackRippleRemoveAreaCommand`.
|
||||
pub fn oaktimeline_ripple_remove_area_command(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_slide_command(track, blocks, block_count, in_adjacent, out_adjacent, movement_num, movement_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_ripple_remove_area_command(
|
||||
track: CHandle,
|
||||
in_num: i64,
|
||||
in_den: i64,
|
||||
out_num: i64,
|
||||
out_den: i64,
|
||||
) -> CHandle;
|
||||
/// `oaktimeline_insert_gaps_command` — owned `TrackListInsertGaps`.
|
||||
pub fn oaktimeline_insert_gaps_command(
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_ripple_remove_area_command(track, in_num, in_den, out_num, out_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oaktimeline_insert_gaps_command(
|
||||
list: CHandle,
|
||||
point_num: i64,
|
||||
point_den: i64,
|
||||
length_num: i64,
|
||||
length_den: i64,
|
||||
) -> CHandle;
|
||||
) -> CHandle {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_insert_gaps_command(list, point_num, point_den, length_num, length_den) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakundo C ABI bridge: direct Rust calls into the `oakundo` crate.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): every
|
||||
//! call below is a compile-time Rust call into `oakundo`'s `ffi` (the
|
||||
//! `#[no_mangle]` exports stay in the dylib for the external C ABI;
|
||||
//! internal callers bypass them). Handles cross as the shared
|
||||
//! [`crate::handle::CHandle`]. Exceptions that keep an `extern "C"`
|
||||
//! declaration (resolved at link time against the sibling crate in the
|
||||
//! same dylib) are the host `oakcore_*` symbols and the encoding-params
|
||||
//! C ABI POD crossings (the facade keeps its own POD mirrors there).
|
||||
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakundo C ABI imports, mirroring the oakundo crate's exports
|
||||
//! (`src/undo/rust/src/ffi.rs`; headers `include/undo/*.h`).
|
||||
|
||||
@@ -21,82 +48,161 @@ use std::ffi::{c_char, c_int};
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
extern "C" {
|
||||
/// `oakundo_command_init` — vtable-backed command, refcount 1.
|
||||
pub fn oakundo_command_init(
|
||||
|
||||
/// `include/undo/undocommand.h` — callback table backing a
|
||||
/// caller-defined undo command. Single-lib unification: aliases the
|
||||
/// oakundo crate's vtable POD.
|
||||
pub type OakUndoCommandVtable = oakundo::undocommand::OakUndoCommandVtable;
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_init(
|
||||
vtable: *const OakUndoCommandVtable,
|
||||
userdata: *mut std::ffi::c_void,
|
||||
) -> CHandle;
|
||||
/// `oakundo_command_init_multi` — empty multi command, refcount 1.
|
||||
pub fn oakundo_command_init_multi() -> CHandle;
|
||||
/// `oakundo_command_multi_add_child` (stack takes one child ref).
|
||||
pub fn oakundo_command_multi_add_child(multi: CHandle, child: CHandle) -> c_int;
|
||||
/// `oakundo_command_multi_child_count`.
|
||||
pub fn oakundo_command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int;
|
||||
/// `oakundo_command_multi_child` (returned handle carries own ref).
|
||||
pub fn oakundo_command_multi_child(
|
||||
) -> CHandle {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_init_multi() -> CHandle {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init_multi() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_multi_add_child(multi: CHandle, child: CHandle) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_multi_child_count(multi: CHandle, out_count: *mut c_int) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_child_count(multi, out_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_multi_child(
|
||||
multi: CHandle,
|
||||
index: c_int,
|
||||
out_child: *mut CHandle,
|
||||
) -> c_int;
|
||||
/// `oakundo_command_redo_now`.
|
||||
pub fn oakundo_command_redo_now(command: CHandle) -> c_int;
|
||||
/// `oakundo_command_undo_now`.
|
||||
pub fn oakundo_command_undo_now(command: CHandle) -> c_int;
|
||||
/// `oakundo_command_free` — NULL/empty no-op; clears `command->ctx`.
|
||||
pub fn oakundo_command_free(command: *mut CHandle);
|
||||
/// `oakundo_undostack_init` — fresh stack, refcount 1.
|
||||
pub fn oakundo_undostack_init() -> CHandle;
|
||||
/// `oakundo_undostack_free` — NULL/empty no-op; clears `stack->ctx`.
|
||||
pub fn oakundo_undostack_free(stack: *mut CHandle);
|
||||
/// `oakundo_undostack_push` — redo then record; drops redoable tail.
|
||||
pub fn oakundo_undostack_push(stack: CHandle, command: CHandle, name: *const c_char) -> c_int;
|
||||
/// `oakundo_undostack_push_pre_executed` — record without redoing.
|
||||
pub fn oakundo_undostack_push_pre_executed(
|
||||
) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_child(multi, index, out_child) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_redo_now(command: CHandle) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_undo_now(command: CHandle) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_undo_now(command) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_command_free(command: *mut CHandle) {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_free(command) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_init() -> CHandle {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_free(stack: *mut CHandle) {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_free(stack) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_push(stack: CHandle, command: CHandle, name: *const c_char) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_push(stack, command, name) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_push_pre_executed(
|
||||
stack: CHandle,
|
||||
command: CHandle,
|
||||
name: *const c_char,
|
||||
) -> c_int;
|
||||
/// `oakundo_undostack_undo`.
|
||||
pub fn oakundo_undostack_undo(stack: CHandle) -> c_int;
|
||||
/// `oakundo_undostack_redo`.
|
||||
pub fn oakundo_undostack_redo(stack: CHandle) -> c_int;
|
||||
/// `oakundo_undostack_jump` (clamped to 0; `index` is i64).
|
||||
pub fn oakundo_undostack_jump(stack: CHandle, index: i64) -> c_int;
|
||||
/// `oakundo_undostack_clear`.
|
||||
pub fn oakundo_undostack_clear(stack: CHandle) -> c_int;
|
||||
/// `oakundo_undostack_can_undo`.
|
||||
pub fn oakundo_undostack_can_undo(stack: CHandle, out_value: *mut c_int) -> c_int;
|
||||
/// `oakundo_undostack_can_redo`.
|
||||
pub fn oakundo_undostack_can_redo(stack: CHandle, out_value: *mut c_int) -> c_int;
|
||||
/// `oakundo_undostack_count`.
|
||||
pub fn oakundo_undostack_count(stack: CHandle, out_count: *mut i64) -> c_int;
|
||||
/// `oakundo_undostack_index`.
|
||||
pub fn oakundo_undostack_index(stack: CHandle, out_index: *mut i64) -> c_int;
|
||||
/// `oakundo_undostack_command_text` (two-stage string getter).
|
||||
pub fn oakundo_undostack_command_text(
|
||||
) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_push_pre_executed(stack, command, name) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_undo(stack: CHandle) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_undo(stack) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_redo(stack: CHandle) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_redo(stack) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_jump(stack: CHandle, index: i64) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_jump(stack, index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_clear(stack: CHandle) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_clear(stack) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_can_undo(stack: CHandle, out_value: *mut c_int) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_can_undo(stack, out_value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_can_redo(stack: CHandle, out_value: *mut c_int) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_can_redo(stack, out_value) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_count(stack: CHandle, out_count: *mut i64) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_count(stack, out_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_index(stack: CHandle, out_index: *mut i64) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_index(stack, out_index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_command_text(
|
||||
stack: CHandle,
|
||||
row: i64,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakundo_undostack_command_is_done`.
|
||||
pub fn oakundo_undostack_command_is_done(
|
||||
) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_command_text(stack, row, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
pub fn oakundo_undostack_command_is_done(
|
||||
stack: CHandle,
|
||||
row: i64,
|
||||
out_value: *mut c_int,
|
||||
) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_command_is_done(stack, row, out_value) }
|
||||
}
|
||||
|
||||
/// `include/undo/undocommand.h` — callback table backing a
|
||||
/// caller-defined undo command.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakUndoCommandVtable {
|
||||
/// Redo callback (NULL = no-op).
|
||||
pub redo: Option<unsafe extern "C" fn(userdata: *mut std::ffi::c_void)>,
|
||||
/// Undo callback (NULL = no-op).
|
||||
pub undo: Option<unsafe extern "C" fn(userdata: *mut std::ffi::c_void)>,
|
||||
/// Destruction callback releasing `userdata`.
|
||||
pub free_fn: Option<unsafe extern "C" fn(userdata: *mut std::ffi::c_void)>,
|
||||
}
|
||||
|
||||
@@ -40,63 +40,13 @@ use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
/// ABI-neutral mirror of the module handle struct
|
||||
/// (`{ctx, addref, release, abi_version}`). Structurally identical to
|
||||
/// every `Oak<Mod><Type>` value handle in `include/<mod>/*.h`, so the
|
||||
/// facade can copy a handle across the module boundary without knowing
|
||||
/// the module's concrete type names.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub const fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this is the empty (zero) handle.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
|
||||
/// Take an additional reference through the handle's `addref` and
|
||||
/// return the (now refcount-incremented) copy.
|
||||
///
|
||||
/// # Safety
|
||||
/// `self` must be a live handle returned by a module function.
|
||||
pub unsafe fn addref(&self) -> Self {
|
||||
let mut copy = *self;
|
||||
if let Some(addref) = copy.addref {
|
||||
let _ = &mut copy;
|
||||
unsafe {
|
||||
addref(copy.ctx);
|
||||
}
|
||||
}
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
// Module handles follow the shared_ptr-like convention of
|
||||
// `include/common/handle.h`: they are opaque, refcounted and safe to
|
||||
// share across threads (the module crates themselves use them behind
|
||||
// mutexes). The facade therefore declares them Send + Sync.
|
||||
unsafe impl Send for CHandle {}
|
||||
unsafe impl Sync for CHandle {}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// by every module crate, so the facade can pass a handle straight into a
|
||||
/// module's `pub` Rust functions without an `extern "C"` declaration.
|
||||
/// `Clone + Copy + Send + Sync` come from the shared type.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// Engine opaque handle types, one per `typedef struct OakEngine*` in
|
||||
/// `engine/include/oakengine/*.h`. All are thin newtype wrappers around a
|
||||
|
||||
@@ -33,20 +33,11 @@ use crate::undo::push_or_run;
|
||||
|
||||
/// `engine/include/oakengine/node.h` — POD mirror of `oak_node_value`.
|
||||
///
|
||||
/// Layout-identical to the module's `oaknode_value`, so the facade hands
|
||||
/// the engine POD straight to the oaknode bridge.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakNodeValue {
|
||||
/// `oak_node_value_type`.
|
||||
pub type_: c_int,
|
||||
/// INT/COMBO value, BOOL 0/1, RATIONAL numerator.
|
||||
pub num: i64,
|
||||
/// RATIONAL denominator.
|
||||
pub den: i64,
|
||||
/// FLOAT f[0]; VEC2/3/4 f[0..n-1]; COLOR r,g,b,a.
|
||||
pub f: [f64; 4],
|
||||
}
|
||||
/// Single-lib unification: aliases the oaknode crate's POD (the module
|
||||
/// C ABI struct `oak_node_value`), so the facade can pass it straight
|
||||
/// into `oaknode::ffi` functions without an `extern "C"` declaration.
|
||||
/// The field is named `kind` on the shared type (was `type_`).
|
||||
pub type OakNodeValue = oaknode::value::OakNodeValue;
|
||||
|
||||
/// `engine/include/oakengine/footage.h` — POD mirror of
|
||||
/// `oak_footage_video_info` (olive::VideoParams stream description).
|
||||
@@ -5584,7 +5575,7 @@ pub unsafe extern "C" fn oakengine_node_value_split_to_tracks(
|
||||
let count = oakengine_node_value_keyframe_track_count(c_type).min(track_count);
|
||||
for i in 0..count as usize {
|
||||
let mut t = OakNodeValue {
|
||||
type_: c_type,
|
||||
kind: c_type,
|
||||
num: 0,
|
||||
den: 0,
|
||||
f: [0.0; 4],
|
||||
@@ -5604,7 +5595,7 @@ pub unsafe extern "C" fn oakengine_node_value_split_to_tracks(
|
||||
t.f[0] = n.f[0];
|
||||
}
|
||||
_ => {
|
||||
t.type_ = c_type;
|
||||
t.kind = c_type;
|
||||
t.f = n.f;
|
||||
}
|
||||
}
|
||||
@@ -5627,7 +5618,7 @@ pub unsafe extern "C" fn oakengine_node_value_combine_tracks(
|
||||
return Err(Error::Invalid);
|
||||
}
|
||||
let mut out = OakNodeValue {
|
||||
type_: c_type,
|
||||
kind: c_type,
|
||||
num: 0,
|
||||
den: 0,
|
||||
f: [0.0; 4],
|
||||
|
||||
@@ -4794,7 +4794,7 @@ pub unsafe extern "C" fn oakengine_track_block_at_time(
|
||||
unsafe fn track_nearest_boxed(
|
||||
track: *const OakEngineTrack,
|
||||
timestamp: i64,
|
||||
via: unsafe extern "C" fn(CHandle, c_int, c_int, *mut CHandle) -> c_int,
|
||||
via: fn(CHandle, c_int, c_int, *mut CHandle) -> c_int,
|
||||
) -> *mut OakEngineBlock {
|
||||
guard_ptr(|| unsafe {
|
||||
if track.is_null() {
|
||||
|
||||
@@ -75,7 +75,7 @@ fn force_oakundo_command_link() -> usize {
|
||||
/// A float POD value.
|
||||
fn float_value(x: f64) -> OakNodeValue {
|
||||
OakNodeValue {
|
||||
type_: 2, // OAK_NODE_VALUE_FLOAT
|
||||
kind: 2, // OAK_NODE_VALUE_FLOAT
|
||||
num: 0,
|
||||
den: 0,
|
||||
f: [x, 0.0, 0.0, 0.0],
|
||||
@@ -229,7 +229,7 @@ fn project_node_keyframe_lifecycle() {
|
||||
unsafe { oakengine_node_get_input(value, c"value_in".as_ptr(), &mut out) },
|
||||
0
|
||||
);
|
||||
assert_eq!(out.type_, 2);
|
||||
assert_eq!(out.kind, 2);
|
||||
assert!((out.f[0] - 3.5).abs() < 1e-6);
|
||||
|
||||
// ---- connect / disconnect -------------------------------------------
|
||||
@@ -265,7 +265,7 @@ fn project_node_keyframe_lifecycle() {
|
||||
unsafe { oakengine_node_get_input_at_time(value, c"value_in".as_ptr(), -1, -1, 0, 0, &mut at) },
|
||||
0
|
||||
);
|
||||
assert_eq!(at.type_, 2);
|
||||
assert_eq!(at.kind, 2);
|
||||
assert!((at.f[0] - 0.5).abs() < 1e-6);
|
||||
|
||||
// ---- project save → fresh load round-trip ---------------------------
|
||||
|
||||
Generated
+334
@@ -2,6 +2,168 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
@@ -9,6 +171,178 @@ version = "0.1.0"
|
||||
[[package]]
|
||||
name = "oaknode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakundo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ocio-rs"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3492534019b59e29dba06014f907dd12824537ed4d293d4108c4bfc669de7fd"
|
||||
dependencies = [
|
||||
"ocio-sys",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ocio-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63251d72d848de5eda39d59cd6490260cf031738ebd518ea37d76b5aae614ec"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b"
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
@@ -14,6 +14,8 @@ panic = "unwind"
|
||||
|
||||
[dependencies]
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakcommon = { path = "../../common/rust" }
|
||||
oakundo = { path = "../../undo/rust" }
|
||||
|
||||
[features]
|
||||
# In-crate stubs for the oakundo C ABI (and other module bridges) so
|
||||
|
||||
@@ -14,19 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakundo C ABI imports. Undo commands are created through the C ABI
|
||||
//! vtable (`oakundo_command_init` with Rust closures as userdata) — no
|
||||
//! C++ UndoCommand subclassing exists on this side. Symbols resolve via
|
||||
//! `dlsym(RTLD_DEFAULT)` (see [`super`]).
|
||||
//! oakundo C ABI calls — now direct Rust calls into the oakundo crate
|
||||
//! (single-lib unification, see `docs/zh/plans/riir/single-lib.md`).
|
||||
//! Undo commands are created through the C ABI vtable
|
||||
//! (`oakundo_command_init` with Rust closures as userdata) — no C++
|
||||
//! UndoCommand subclassing exists on this side.
|
||||
//!
|
||||
//! ## Test stubs (`--features test-stubs`)
|
||||
//!
|
||||
//! `cargo test` builds without liboakundo, so the feature compiles
|
||||
//! in-crate `#[no_mangle]` implementations of the undo C ABI
|
||||
//! (see [`stub`]) that run Rust closures directly. `dlsym` then resolves
|
||||
//! the stub symbols from the test binary's global scope, so the undoable
|
||||
//! exports run end-to-end in tests. Real module builds (feature off)
|
||||
//! resolve the actual oakundo library.
|
||||
//! With the direct dependency, the real oakundo rlib is linked into
|
||||
//! every build and test; the `test-stubs` feature still compiles
|
||||
//! in-crate `#[no_mangle]` implementations of the undo C ABI (see
|
||||
//! [`stub`]) for environments that link without oakundo. Do not enable
|
||||
//! the feature in a binary that also links oakundo (duplicate symbols).
|
||||
|
||||
use std::ffi::c_int;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -34,17 +34,9 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `OakUndoCommandVtable` (include/undo/undocommand.h) — the callback
|
||||
/// table backing a caller-defined undo command.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Vtable {
|
||||
/// Execute the redo.
|
||||
pub redo: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Execute the undo.
|
||||
pub undo: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Release `userdata` (invoked when the command is destroyed).
|
||||
pub free_fn: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
}
|
||||
/// table backing a caller-defined undo command. Single-lib unification:
|
||||
/// aliases the oakundo crate's vtable POD (identical layout).
|
||||
pub type Vtable = oakundo::undocommand::OakUndoCommandVtable;
|
||||
|
||||
/// Rust closure state behind a vtable command's `userdata` pointer.
|
||||
///
|
||||
@@ -130,11 +122,13 @@ pub fn command_init(vtable: &Vtable, userdata: *mut std::ffi::c_void) -> Option<
|
||||
/// `oakundo_command_init` (vtable command).
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub fn command_init(vtable: &Vtable, userdata: *mut std::ffi::c_void) -> Option<CHandle> {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn(*const Vtable, *mut std::ffi::c_void) -> CHandle;
|
||||
dlsym::call::<F, CHandle>("oakundo_command_init", |f| unsafe {
|
||||
f(vtable as *const Vtable, userdata)
|
||||
})
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
let h = unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) };
|
||||
if h.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(h)
|
||||
}
|
||||
}
|
||||
|
||||
/// `oakundo_command_init_multi`.
|
||||
@@ -146,9 +140,13 @@ pub fn command_init_multi() -> Option<CHandle> {
|
||||
/// `oakundo_command_init_multi`.
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub fn command_init_multi() -> Option<CHandle> {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn() -> CHandle;
|
||||
dlsym::call::<F, CHandle>("oakundo_command_init_multi", |f| unsafe { f() })
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
let h = unsafe { oakundo::ffi::command::oakundo_command_init_multi() };
|
||||
if h.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(h)
|
||||
}
|
||||
}
|
||||
|
||||
/// `oakundo_command_multi_add_child`.
|
||||
@@ -160,11 +158,8 @@ pub fn command_multi_add_child(multi: CHandle, child: CHandle) -> Option<c_int>
|
||||
/// `oakundo_command_multi_add_child`.
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub fn command_multi_add_child(multi: CHandle, child: CHandle) -> Option<c_int> {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn(CHandle, CHandle) -> c_int;
|
||||
dlsym::call::<F, c_int>("oakundo_command_multi_add_child", |f| unsafe {
|
||||
f(multi, child)
|
||||
})
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
Some(unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) })
|
||||
}
|
||||
|
||||
/// `oakundo_command_redo_now`.
|
||||
@@ -176,9 +171,8 @@ pub fn command_redo_now(command: CHandle) -> Option<c_int> {
|
||||
/// `oakundo_command_redo_now`.
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub fn command_redo_now(command: CHandle) -> Option<c_int> {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn(CHandle) -> c_int;
|
||||
dlsym::call::<F, c_int>("oakundo_command_redo_now", |f| unsafe { f(command) })
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
Some(unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) })
|
||||
}
|
||||
|
||||
/// `oakundo_command_undo_now`.
|
||||
@@ -190,9 +184,8 @@ pub fn command_undo_now(command: CHandle) -> Option<c_int> {
|
||||
/// `oakundo_command_undo_now`.
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub fn command_undo_now(command: CHandle) -> Option<c_int> {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn(CHandle) -> c_int;
|
||||
dlsym::call::<F, c_int>("oakundo_command_undo_now", |f| unsafe { f(command) })
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
Some(unsafe { oakundo::ffi::command::oakundo_command_undo_now(command) })
|
||||
}
|
||||
|
||||
/// `oakundo_command_free`.
|
||||
@@ -204,22 +197,14 @@ pub fn command_free(command: *mut CHandle) {
|
||||
/// `oakundo_command_free`.
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub fn command_free(command: *mut CHandle) {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn(*mut CHandle);
|
||||
if let Some(f) = dlsym::call::<F, ()>("oakundo_command_free", |f| unsafe {
|
||||
f(command)
|
||||
}) {
|
||||
let _ = f;
|
||||
}
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
unsafe { oakundo::ffi::command::oakundo_command_free(command) }
|
||||
}
|
||||
|
||||
/// `oakundo_stack_push` (facade-owned stack).
|
||||
pub fn stack_push(stack: CHandle, command: CHandle, text: *const std::ffi::c_char) -> Option<c_int> {
|
||||
use crate::bridge::dlsym;
|
||||
type F = unsafe extern "C" fn(CHandle, CHandle, *const std::ffi::c_char) -> c_int;
|
||||
dlsym::call::<F, c_int>("oakundo_stack_push", |f| unsafe {
|
||||
f(stack, command, text)
|
||||
})
|
||||
// Direct call into the oakundo crate (single-lib unification).
|
||||
Some(unsafe { oakundo::ffi::undostack::oakundo_undostack_push(stack, command, text) })
|
||||
}
|
||||
|
||||
/// In-crate implementations of the undo C ABI for `cargo test`
|
||||
|
||||
@@ -55,19 +55,11 @@ impl ColorManager {
|
||||
}
|
||||
|
||||
/// Load the built-in default config (C++ `ColorManager::init()`).
|
||||
/// The config load itself goes through the oakrender color C ABI;
|
||||
/// when oakrender is absent (cargo test) the manager still marks the
|
||||
/// config loaded with the built-in defaults so pure-graph consumers
|
||||
/// can query state.
|
||||
/// The oakrender color C ABI never exported the config-loading
|
||||
/// symbols, so this always took the "mark loaded with the built-in
|
||||
/// defaults" path (single-lib: the render call is removed and the
|
||||
/// deterministic equivalent kept).
|
||||
pub fn initialize(&mut self) -> crate::error::Result<()> {
|
||||
match crate::bridge::render::color_config_create_default() {
|
||||
Some(Err(())) => {
|
||||
return Err(crate::error::Error::Failed(
|
||||
"OCIO config creation failed".to_string(),
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.config_loaded = true;
|
||||
Ok(())
|
||||
}
|
||||
@@ -79,30 +71,18 @@ impl ColorManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// (Re)load the config from `config_filename` via the oakrender
|
||||
/// color C ABI (`oakrender_color_manager_*`); E_FAILED on OCIO
|
||||
/// (Re)load the config from `config_filename`; E_FAILED on OCIO
|
||||
/// errors. Missing/invalid files keep the previous config (C++
|
||||
/// `update_config_from_filename()`).
|
||||
/// `update_config_from_filename()`). The oakrender color C ABI never
|
||||
/// implemented the load, so the file-loaded path always kept the
|
||||
/// previous state (single-lib: the render call is removed).
|
||||
pub fn update_config_from_filename(&mut self) -> crate::error::Result<()> {
|
||||
if self.config_filename.is_empty() {
|
||||
// Empty filename selects the bundled default.
|
||||
self.config_loaded = true;
|
||||
return Ok(());
|
||||
}
|
||||
match crate::bridge::render::color_config_load(&self.config_filename) {
|
||||
Some(Ok(())) => {
|
||||
self.config_loaded = true;
|
||||
Ok(())
|
||||
}
|
||||
Some(Err(())) => {
|
||||
// Invalid file: keep the previous config (C++ tolerance).
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
// oakrender absent (tests): keep the previous state.
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Enumerate colorspaces of the active config (two-stage lists are
|
||||
|
||||
@@ -37,45 +37,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: OAKNODE_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// True when `ctx` is null.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
// CHandle is the C-side value handle (passed by value, copyable across
|
||||
// threads); `ctx` is an opaque box pointer. The addref/release functions
|
||||
// are atomic, so sharing the box between threads is the host's
|
||||
// dispatching contract (same rationale as the oakplugin crate's
|
||||
// handle.rs).
|
||||
unsafe impl Send for CHandle {}
|
||||
unsafe impl Sync for CHandle {}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// addref 的实现:原子 +1。拥有型与借用型共用——借用型只延长盒子
|
||||
/// 的寿命,不延长被借用对象。
|
||||
|
||||
@@ -311,11 +311,9 @@ impl Project {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Default location: ask oakrender via the C ABI.
|
||||
match crate::bridge::render::disk_cache_path() {
|
||||
Some(path) => path,
|
||||
None => String::new(),
|
||||
}
|
||||
// Default location: the shared disk-cache directory (single-lib:
|
||||
// lives in oakcommon, used by oaknode and oakrender alike).
|
||||
oakcommon::filefunctions::default_disk_cache_path()
|
||||
}
|
||||
|
||||
/// Copy all settings from `src` into `self` (C++
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The shared ABI value-handle type (single-lib unification).
|
||||
//!
|
||||
//! Every module crate used to define its own `CHandle` with an identical
|
||||
//! `{ctx, addref, release, abi_version}` layout but a distinct Rust type,
|
||||
//! so cross-module calls had to cross an `extern "C"`/dlsym boundary.
|
||||
//! With the module-to-module calls going back to direct Rust calls (see
|
||||
//! `docs/zh/plans/riir/single-lib.md`), one canonical handle type lives
|
||||
//! here in `oakcore-rs` (the crate every module already depends on) and
|
||||
//! every crate re-exports it. The C layout is unchanged, so the frozen
|
||||
//! module C ABIs (`Oak<Mod><Type>*` handles in `include/<mod>/*.h`) are
|
||||
//! unaffected.
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
/// ABI value handle mirroring the C handle struct
|
||||
/// (`{ctx, addref, release, abi_version}`) from `include/common/handle.h`.
|
||||
///
|
||||
/// `ctx` points to an opaque refcounted box; `addref`/`release` are the
|
||||
/// box's atomic increment/decrement (release destroys at zero);
|
||||
/// `abi_version` is a tag stamped by each crate's `make_owned` (0 for
|
||||
/// empty handles). Structurally identical to every `Oak<Mod><Type>` value
|
||||
/// handle, so a handle can cross any module boundary by value.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub const fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
}
|
||||
} /// Whether this is the empty (zero) handle.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
|
||||
/// Take an additional reference through the handle's `addref` and
|
||||
/// return the (now refcount-incremented) copy.
|
||||
///
|
||||
/// # Safety
|
||||
/// `self` must be a live handle returned by a module function.
|
||||
pub unsafe fn addref(&self) -> Self {
|
||||
let mut copy = *self;
|
||||
if let Some(addref) = copy.addref {
|
||||
let _ = &mut copy;
|
||||
unsafe {
|
||||
addref(copy.ctx);
|
||||
}
|
||||
}
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
/// The empty handle is the natural default (some crates derive `Default`
|
||||
/// on structs holding a handle).
|
||||
impl Default for CHandle {
|
||||
fn default() -> Self {
|
||||
Self::null()
|
||||
}
|
||||
}
|
||||
|
||||
// Handles follow the shared_ptr-like convention of
|
||||
// `include/common/handle.h`: they are opaque, refcounted and safe to
|
||||
// share across threads (the module crates use them behind mutexes).
|
||||
unsafe impl Send for CHandle {}
|
||||
unsafe impl Sync for CHandle {}
|
||||
@@ -25,6 +25,10 @@ mod rational;
|
||||
mod samplefmt;
|
||||
mod timerange;
|
||||
|
||||
/// Shared ABI value-handle type (see [`handle::CHandle`]).
|
||||
pub mod handle;
|
||||
|
||||
pub use handle::CHandle;
|
||||
pub use rational::Rational;
|
||||
pub use samplefmt::{PixelFormat, SampleFormat};
|
||||
pub use timerange::{TimeRange, TimeRangeList};
|
||||
|
||||
Generated
+5
@@ -18,11 +18,16 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||
|
||||
[[package]]
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "oakplugin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -17,7 +17,9 @@ crate-type = ["staticlib", "rlib"]
|
||||
panic = "unwind"
|
||||
|
||||
[dependencies]
|
||||
# 共享 ABI 类型(CHandle 等,单库化统一,见 docs/zh/plans/riir/single-lib.md)。
|
||||
# 只允许零依赖起步。确需引入的 crate 必须在 README 登记理由。
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
|
||||
[features]
|
||||
# oakrender 测试桩(库内 no_mangle 符号 + 状态访问器):cargo test
|
||||
|
||||
@@ -53,44 +53,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
/// C 句柄的 Rust 镜像。`#[repr(C)]`,与 C 头文件布局一致。
|
||||
///
|
||||
/// 生命周期:`*_init`/`*_create` 返回计数 1 的拥有型句柄;
|
||||
/// `*_free(&h)` 释放一次并清空 `ctx`;`free(NULL)`/空句柄是 no-op。
|
||||
/// 值型(Clone/Copy:C 侧按值传句柄,复制后再 addref 是调用方
|
||||
/// 契约)。
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct CHandle {
|
||||
/// 不透明盒子指针(`RefBox<T>` 擦型后的 `*mut c_void`)。
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// 原子 +1。
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// 原子 -1,归零销毁。
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// [`OAKPLUGIN_ABI_VERSION`]。
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
// CHandle 是 C 侧值型句柄(按值传、可跨线程复制);`ctx` 是
|
||||
// 不透明盒子指针,跨线程搬运是宿主分发语义(multithread suite
|
||||
// 允许插件线程回调任意 suite)。
|
||||
unsafe impl Send for CHandle {}
|
||||
unsafe impl Sync for CHandle {}
|
||||
|
||||
impl CHandle {
|
||||
/// 空句柄(`ctx == NULL`)。
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: OAKPLUGIN_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否为空调用面(`ctx` 为空)。
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible. `Send + Sync` come from the shared type.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// addref 的实现:原子 +1。拥有型与借用型共用——借用型只延长盒子
|
||||
/// 的寿命,不延长被借用对象。
|
||||
|
||||
Generated
+150
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.6"
|
||||
@@ -94,6 +100,12 @@ dependencies = [
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.4.2"
|
||||
@@ -163,6 +175,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
@@ -184,12 +205,28 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
@@ -369,6 +406,19 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
@@ -487,6 +537,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.31.0"
|
||||
@@ -502,6 +558,26 @@ dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "25.0.1"
|
||||
@@ -546,6 +622,17 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
@@ -554,6 +641,7 @@ version = "0.1.0"
|
||||
name = "oakrender"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"wgpu",
|
||||
@@ -671,6 +759,27 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
@@ -761,6 +870,12 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
@@ -890,6 +1005,20 @@ dependencies = [
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
@@ -973,6 +1102,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "25.0.2"
|
||||
@@ -1297,3 +1432,18 @@ dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b"
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
@@ -15,6 +15,7 @@ panic = "unwind"
|
||||
|
||||
[dependencies]
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakcommon = { path = "../../common/rust" }
|
||||
# wgpu: portable GPU backend (Metal/Vulkan/GL/DX12 in one safe API) — the
|
||||
# direct replacement for the C++ liboakgl2/liboakvulkan backend plugins.
|
||||
# Version 25 (2025 stable line); the only GPU dependency.
|
||||
|
||||
@@ -16,79 +16,11 @@
|
||||
|
||||
//! The cancellation primitive (`olive::CancelAtom`): a thread-safe cancel
|
||||
//! flag shared between a render/encode caller and its worker.
|
||||
//!
|
||||
//! Single-lib unification (see `docs/zh/plans/riir/single-lib.md`): the
|
||||
//! implementation moved to oakcommon; this module re-exports it so the
|
||||
//! render ffi's `oakrender_cancelatom_*` exports (and their C-ABI
|
||||
//! consumers, e.g. oakcodec) keep working unchanged.
|
||||
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
/// A cancellation atom (C++ `CancelAtom`). Reading a set flag also records
|
||||
/// that a consumer heard the cancellation.
|
||||
#[derive(Default)]
|
||||
pub struct CancelAtom {
|
||||
state: Mutex<AtomState>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AtomState {
|
||||
cancelled: bool,
|
||||
heard: bool,
|
||||
}
|
||||
|
||||
fn lock(m: &Mutex<AtomState>) -> MutexGuard<'_, AtomState> {
|
||||
m.lock().unwrap_or_else(|e| e.into_inner())
|
||||
}
|
||||
|
||||
impl CancelAtom {
|
||||
/// A not-cancelled atom.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Set the cancel flag (C++ `CancelAtom::cancel()`).
|
||||
pub fn cancel(&self) {
|
||||
lock(&self.state).cancelled = true;
|
||||
}
|
||||
|
||||
/// Read the cancel flag; reading a set flag records that the
|
||||
/// cancellation was heard (C++ `is_cancelled()`).
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
let mut s = lock(&self.state);
|
||||
if s.cancelled {
|
||||
s.heard = true;
|
||||
}
|
||||
s.cancelled
|
||||
}
|
||||
|
||||
/// Whether any consumer has observed the cancel flag through
|
||||
/// [`CancelAtom::is_cancelled`] (C++ `heard_cancel()`).
|
||||
pub fn heard_cancel(&self) -> bool {
|
||||
lock(&self.state).heard
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fresh_atom_is_not_cancelled() {
|
||||
let a = CancelAtom::new();
|
||||
assert!(!a.is_cancelled());
|
||||
assert!(!a.heard_cancel());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_sets_flag_and_reading_marks_heard() {
|
||||
let a = CancelAtom::new();
|
||||
a.cancel();
|
||||
assert!(!a.heard_cancel(), "not heard until read");
|
||||
assert!(a.is_cancelled());
|
||||
assert!(a.heard_cancel(), "reading a set flag marks it heard");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_cancel_is_idempotent() {
|
||||
let a = CancelAtom::new();
|
||||
a.cancel();
|
||||
a.cancel();
|
||||
assert!(a.is_cancelled());
|
||||
}
|
||||
}
|
||||
/// Shared cancellation atom (oakcommon).
|
||||
pub use oakcommon::cancelatom::CancelAtom;
|
||||
|
||||
@@ -926,13 +926,8 @@ pub mod cache {
|
||||
if !std::path::Path::new(&filename).exists() {
|
||||
return Err(crate::error::Error::NotFound);
|
||||
}
|
||||
// Payload decode belongs to the oakcodec crate (EXR/JPEG).
|
||||
// Without it the file exists but cannot be decoded.
|
||||
if !crate::bridge::codec::codec_abi_available() {
|
||||
return Err(crate::error::Error::Failed(
|
||||
"oakcodec C ABI not present (frame decode pending)".into(),
|
||||
));
|
||||
}
|
||||
// Payload decode belongs to the oakcodec crate (EXR/JPEG),
|
||||
// deferred; without it the file exists but cannot be decoded.
|
||||
Err(crate::error::Error::Failed(
|
||||
"oakcodec frame decode bridge pending".into(),
|
||||
))
|
||||
|
||||
@@ -42,42 +42,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs.
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
// CHandle is a by-value handle (copied across threads per the shared_ptr
|
||||
// semantics documented in the public headers); `ctx` is an opaque box
|
||||
// pointer, and moving the struct itself never dereferences it.
|
||||
unsafe impl Send for CHandle {}
|
||||
unsafe impl Sync for CHandle {}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: OAKRENDER_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// True when `ctx` is null.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible. `Send + Sync` come from the shared type.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// Global live-object count (owned handles + cancel-atom boxes).
|
||||
static ALIVE_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
@@ -132,9 +132,10 @@ impl RenderManager {
|
||||
}
|
||||
|
||||
/// The default disk cache directory (C++ `DiskManager::
|
||||
/// get_default_disk_cache_path`).
|
||||
/// get_default_disk_cache_path`); shared with oaknode via oakcommon
|
||||
/// (single-lib unification).
|
||||
pub fn disk_cache_path() -> String {
|
||||
crate::bridge::common::default_disk_cache_path()
|
||||
oakcommon::filefunctions::default_disk_cache_path()
|
||||
}
|
||||
|
||||
/// Bytes consumed by the default disk cache folder (direct filesystem
|
||||
|
||||
Generated
+135
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.6"
|
||||
@@ -94,6 +100,12 @@ dependencies = [
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.4.2"
|
||||
@@ -163,6 +175,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
@@ -184,12 +205,28 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
@@ -369,6 +406,19 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
@@ -514,6 +564,26 @@ dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "25.0.1"
|
||||
@@ -558,6 +628,17 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
@@ -576,6 +657,7 @@ dependencies = [
|
||||
name = "oakrender"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"wgpu",
|
||||
@@ -702,6 +784,18 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.41.0"
|
||||
@@ -815,6 +909,12 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
@@ -944,6 +1044,20 @@ dependencies = [
|
||||
"syn 3.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
@@ -1027,6 +1141,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "25.0.2"
|
||||
@@ -1357,3 +1477,18 @@ name = "zmij"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b"
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
@@ -33,29 +33,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
// Handles are shared between the calling thread and the manager worker
|
||||
// threads (same ownership model as a C++ shared_ptr). The raw pointer and
|
||||
// function-pointer fields are inherently `!Send`/`!Sync`; the box behind
|
||||
// `ctx` is either `Send + Sync` (task state, atomics) or a plain pointer
|
||||
// (borrowed handles), both of which are safe to share through the
|
||||
// refcounted handle.
|
||||
unsafe impl Send for CHandle {}
|
||||
unsafe impl Sync for CHandle {}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible. `Send + Sync` come from the shared type.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
unsafe extern "C" fn noop_addref(_ctx: *mut std::ffi::c_void) {}
|
||||
|
||||
@@ -101,24 +84,6 @@ unsafe extern "C" fn borrowed_release<T: 'static>(ctx: *mut std::ffi::c_void) {
|
||||
}
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle. `ctx` is null but the fn pointers and ABI version
|
||||
/// are stamped so callers can unconditionally call `release`.
|
||||
pub fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: Some(noop_addref),
|
||||
release: Some(noop_release),
|
||||
abi_version: OAKTASK_ABI_VERSION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the handle is empty (`ctx == NULL`).
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
/// Owned handle with count 1; empty on allocation failure.
|
||||
pub fn make_owned<T: Send + 'static>(value: T) -> CHandle {
|
||||
let b = Box::new(RefBox { refs: AtomicU32::new(1), value });
|
||||
|
||||
@@ -53,20 +53,15 @@ fn abi_version_is_one() {
|
||||
assert_eq!(OAKTASK_ABI_VERSION, 1);
|
||||
}
|
||||
|
||||
/// Given a null handle, `CHandle::null()` has a null ctx, non-null
|
||||
/// addref/release, and the stamped ABI version.
|
||||
/// Given a null handle, `CHandle::null()` has a null ctx, no addref/
|
||||
/// release fn pointers and no ABI version (single-lib unification).
|
||||
#[test]
|
||||
fn null_handle_contract() {
|
||||
let h = CHandle::null();
|
||||
assert!(h.ctx.is_null());
|
||||
assert!(h.addref.is_some(), "null handle addref must be callable");
|
||||
assert!(h.release.is_some(), "null handle release must be callable");
|
||||
assert_eq!(h.abi_version, OAKTASK_ABI_VERSION);
|
||||
// The empty handle is a no-op for both ops (never touches memory).
|
||||
unsafe {
|
||||
h.addref.unwrap()(h.ctx);
|
||||
h.release.unwrap()(h.ctx);
|
||||
}
|
||||
assert!(h.addref.is_none(), "null handle addref is empty");
|
||||
assert!(h.release.is_none(), "null handle release is empty");
|
||||
assert_eq!(h.abi_version, 0);
|
||||
// `is_null` reflects the ctx.
|
||||
assert!(h.is_null());
|
||||
}
|
||||
@@ -91,7 +86,11 @@ fn handle_size_and_owned_release() {
|
||||
}
|
||||
// The boxed value was dropped; a null handle still works afterwards.
|
||||
let null_h = CHandle::null();
|
||||
unsafe {
|
||||
null_h.release.unwrap()(null_h.ctx);
|
||||
// The shared null() carries no fn pointers; releasing goes through
|
||||
// the `if let Some` path (a no-op for empty handles).
|
||||
if let Some(release) = null_h.release {
|
||||
unsafe {
|
||||
release(null_h.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,20 +38,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// Generic `addref` implementation: increments the box's reference count.
|
||||
///
|
||||
@@ -82,23 +74,6 @@ unsafe extern "C" fn release_box<T: 'static>(ptr: *mut c_void) {
|
||||
}
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this is the empty (all-null) handle.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
/// Owned handle with count 1; empty on allocation failure.
|
||||
pub fn make_owned<T: Send + 'static>(value: T) -> CHandle {
|
||||
let boxed = Box::new(RefBox {
|
||||
|
||||
+15
-64
@@ -48,63 +48,14 @@ use crate::undostack::UndoStack;
|
||||
/// [`crate::handle`].
|
||||
|
||||
/// `include/undo/undocommand.h` handle type — `OakUndoCommand`
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakUndoCommand {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// OAKUNDO_ABI_VERSION.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
/// (`{ctx, addref, release, abi_version}`). Single-lib unification:
|
||||
/// aliases the shared [`CHandle`] (identical layout; the C ABI is
|
||||
/// unchanged).
|
||||
pub type OakUndoCommand = CHandle;
|
||||
|
||||
/// `include/undo/undostack.h` handle type — `OakUndoStack`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakUndoStack {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// OAKUNDO_ABI_VERSION.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
/// Field-copy [`OakUndoStack`] into a [`CHandle`].
|
||||
fn chandle_from_stack(stack: OakUndoStack) -> CHandle {
|
||||
CHandle {
|
||||
ctx: stack.ctx,
|
||||
addref: stack.addref,
|
||||
release: stack.release,
|
||||
abi_version: stack.abi_version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Field-copy a [`CHandle`] into an [`OakUndoStack`].
|
||||
fn stack_from_chandle(handle: CHandle) -> OakUndoStack {
|
||||
OakUndoStack {
|
||||
ctx: handle.ctx,
|
||||
addref: handle.addref,
|
||||
release: handle.release,
|
||||
abi_version: handle.abi_version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Field-copy a [`CHandle`] into an [`OakUndoCommand`].
|
||||
fn command_from_chandle(handle: CHandle) -> OakUndoCommand {
|
||||
OakUndoCommand {
|
||||
ctx: handle.ctx,
|
||||
addref: handle.addref,
|
||||
release: handle.release,
|
||||
abi_version: handle.abi_version,
|
||||
}
|
||||
}
|
||||
/// `include/undo/undostack.h` handle type — `OakUndoStack`. Single-lib
|
||||
/// unification: aliases the shared [`CHandle`].
|
||||
pub type OakUndoStack = CHandle;
|
||||
|
||||
/// Lock the stack behind `stack` and run `f` on it. `E_INVALID` for an
|
||||
/// empty handle. A poisoned mutex is recovered (its inner value is
|
||||
@@ -112,7 +63,7 @@ fn command_from_chandle(handle: CHandle) -> OakUndoCommand {
|
||||
fn with_stack<R>(stack: OakUndoStack, f: impl FnOnce(&mut UndoStack) -> Result<R>) -> Result<R> {
|
||||
// Keep a local handle so `get`'s returned reference lives for the
|
||||
// whole call (its lifetime ties to the `&CHandle` argument).
|
||||
let ch = chandle_from_stack(stack);
|
||||
let ch = stack;
|
||||
let m = unsafe { crate::handle::get::<Mutex<UndoStack>>(&ch) }.ok_or(Error::Invalid)?;
|
||||
let mut guard = m.lock().unwrap_or_else(|e| e.into_inner());
|
||||
f(&mut guard)
|
||||
@@ -143,21 +94,21 @@ pub mod command {
|
||||
vtable: *const OakUndoCommandVtable,
|
||||
userdata: *mut c_void,
|
||||
) -> OakUndoCommand {
|
||||
command_from_chandle(guard_handle(|| unsafe {
|
||||
guard_handle(|| unsafe {
|
||||
if vtable.is_null() {
|
||||
return Ok(CHandle::null());
|
||||
}
|
||||
let table = *vtable;
|
||||
Ok(command_from_owned(UndoCommand::from_vtable(table, userdata)))
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// `oakundo_command_init_multi`: empty multi command, refcount 1.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oakundo_command_init_multi() -> OakUndoCommand {
|
||||
command_from_chandle(guard_handle(|| unsafe {
|
||||
guard_handle(|| unsafe {
|
||||
Ok(command_from_owned(UndoCommand::multi()))
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// `oakundo_command_multi_add_child` (stack takes one child ref).
|
||||
@@ -216,7 +167,7 @@ pub mod command {
|
||||
}
|
||||
let child = parent.multi_child(index as usize)?;
|
||||
let ptr = child as *const UndoCommand as *mut UndoCommand;
|
||||
*out_child = command_from_chandle(command_from_borrowed(ptr));
|
||||
*out_child = command_from_borrowed(ptr);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -272,9 +223,9 @@ pub mod undostack {
|
||||
/// `oakundo_undostack_init`: fresh stack, refcount 1.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oakundo_undostack_init() -> OakUndoStack {
|
||||
stack_from_chandle(guard_handle(|| {
|
||||
guard_handle(|| {
|
||||
Ok(make_owned(Mutex::new(UndoStack::new())))
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// `oakundo_undostack_free`: NULL/empty no-op; clears `stack->ctx`.
|
||||
|
||||
@@ -34,36 +34,12 @@ pub struct RefBox<T: ?Sized> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
/// `#[repr(C)]` mirror of the public handle structs
|
||||
/// (`{ctx, addref, release, abi_version}`).
|
||||
#[repr(C)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut std::ffi::c_void,
|
||||
/// Atomic increment.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// Atomic decrement; destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
|
||||
impl CHandle {
|
||||
/// The empty handle.
|
||||
pub fn null() -> Self {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this is the empty (zero) handle.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
}
|
||||
/// The shared ABI value-handle type (single-lib unification, see
|
||||
/// `docs/zh/plans/riir/single-lib.md`): one canonical
|
||||
/// `{ctx, addref, release, abi_version}` type in `oakcore-rs`, re-exported
|
||||
/// here so the crate's `ffi.rs` signatures and handle scaffolding stay
|
||||
/// source-compatible.
|
||||
pub use oakcore_rs::handle::CHandle;
|
||||
|
||||
/// Owned handle with count 1; empty on allocation failure.
|
||||
pub fn make_owned<T: Send + 'static>(value: T) -> CHandle {
|
||||
|
||||
@@ -38,6 +38,7 @@ use oakundo::ffi::undostack::{
|
||||
oakundo_undostack_redo, oakundo_undostack_undo,
|
||||
};
|
||||
use oakundo::ffi::{OakUndoCommand, OakUndoStack};
|
||||
use oakundo::handle::CHandle;
|
||||
use oakundo::handle::OAKUNDO_ABI_VERSION;
|
||||
use oakundo::undocommand::OakUndoCommandVtable;
|
||||
|
||||
@@ -103,7 +104,7 @@ unsafe fn make_cmd(probe: *mut Probe) -> OakUndoCommand {
|
||||
|
||||
/// An empty (all-zero) command handle.
|
||||
fn empty_cmd() -> OakUndoCommand {
|
||||
OakUndoCommand {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
@@ -113,7 +114,7 @@ fn empty_cmd() -> OakUndoCommand {
|
||||
|
||||
/// An empty (all-zero) stack handle.
|
||||
fn empty_stack() -> OakUndoStack {
|
||||
OakUndoStack {
|
||||
CHandle {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
|
||||
Reference in New Issue
Block a user