refactor(engine): single-lib phase 3 — plugin/timeline/task/codec bridges converted
- oakplugin bridges -> direct (dlsym 28->0; OFX suites untouched) - oaktimeline bridges -> direct (teststubs slimmed to pure-Rust mocks) - oaktask bridges -> direct; facade EncodingParamsPOD -> oakcodec alias - dlsym total 102->24 (all in documented dead/host directions) - All crates build+test green; dylib exports unchanged
This commit is contained in:
@@ -415,19 +415,64 @@ encoding-params POD(`oakcodec_encoding_params` 等)在 4 个 crate 各有
|
||||
`oakcodec_decoder_probe` 直接调用,测试的 `is_err()` 断言仍成立
|
||||
(真实 codec 对不存在文件返回错误句柄)。
|
||||
|
||||
### 11.4 未完成(后续步骤)
|
||||
### 11.4 第三轮完成(2026-08-10)
|
||||
|
||||
- **模块 bridge 其余方向**(步骤 b 剩余):oakplugin `bridge/{node,
|
||||
render,undo}`(28 处 dlsym + 状态化 test-stubs 迁移)、oaktimeline
|
||||
`bridge/{node,undo,common}`(teststubs.rs 52921 行 + 16 个测试文件)、
|
||||
oaktask `bridge/*`(7 文件 + tests/common 的 C ABI 桩)、oakcodec
|
||||
`bridge/common`(`OakVideoParams` 类型从桩句柄对齐到真实 CHandle,
|
||||
波及 frame.rs 等内部类型)。每个方向模式已由 node/render/audio 证明;
|
||||
工作量集中在测试侧(桩删除 + 迁移 + 类型对齐)。
|
||||
- **dlsym 删除**(步骤 c):node 20 处、render 4 处(均在死/宿主方向
|
||||
bridge)、plugin 28 处,在各自 bridge 转换完成后清除。
|
||||
- **facade 侧后续**:`linkage.rs` 注释更新;EncodingParamsPOD 等 POD
|
||||
统一到 oakcore-rs。
|
||||
本轮完成的方向(每步 `cargo build` + 该 crate `cargo test` 绿):
|
||||
|
||||
- **oakplugin `bridge/{node,render,undo}` → 直接调用**(28 处 dlsym → 0):
|
||||
oaknode/oakrender/oakundo 加入依赖;28 个桥函数直接调 `oaknode::ffi`/
|
||||
`oakrender::ffi`/`oakundo::ffi`。`Value` 桥接用布局一致的指针 cast
|
||||
(避免 49 处 `r#type`→`kind` 改名);`VideoParams` 别名到
|
||||
`oakrender::ffi::OakRenderVideoParams`。`test-stubs` 特性保留,桩改为
|
||||
纯 Rust(无 `#[no_mangle]`,与真实 crate 导出不冲突);`dlsym` 模块
|
||||
删除。测试迁移:两个"符号缺失"单测改为空/NULL 句柄经真实 crate 的
|
||||
容错路径(`texture_is_dummy` 空句柄 0、`instance_render` 空 dst 被
|
||||
插件层 E_INVALID 拒绝、`render_job` 同);OFX suites 层未触碰。
|
||||
- **oaktimeline `bridge/{node,undo,common}` → 直接调用**:oaknode/
|
||||
oakundo/oakcommon 加入依赖;81 个桥函数直接调用。`teststubs.rs`
|
||||
(1658 行)改为纯 Rust mock(去 `#[no_mangle]`),桥函数加
|
||||
`#[cfg(any(test, feature="test-stubs"))]` mock 变体 / 真实变体,
|
||||
测试二进制(cfg(test) 对依赖关)经 `--features test-stubs` 解析
|
||||
`bridge::teststubs`——与真实 crate 导出共存无冲突。修复桥签名漂移:
|
||||
`oakcommon_xml_reader_read_next_start_element` 2 参(found 标志,
|
||||
调用点 ffi.rs/tests 同步);`oakundo_stack_push`→真实
|
||||
`oakundo_undostack_push`。260 测试绿。
|
||||
- **oaktask `bridge/*` → 直接调用**(240 个桥函数):oaknode/oakundo/
|
||||
oakcommon/oakcodec/oakrender/oaktimeline 加入依赖(oakrender 由可选
|
||||
转必选,`real-oakrender` 特性改为标记)。镜像类型对齐真实 crate:
|
||||
`OakCancelAtom`/`OakRenderTicket`/`OakRenderCache`/`OakColorProcessor`
|
||||
等 → CHandle 别名,`OakCodecEncodingParams`/`OakCodecProxyParams`/
|
||||
`OakCodecTaskRequest`/`OakRenderVideoTicketParams`/`OakUndoCommandVtable`
|
||||
→ 真实 crate 类型;`from_chandle`/`to_chandle` 助手删除(恒等)。
|
||||
测试侧:encoding-params 结构从 `[c_char;N]`→`[u8;N]`,`write_cstr`
|
||||
改 u8,`fake_atom` 等 fixtures 仍可用(真实 crate 的 cancel 路径由
|
||||
task 内部创建真实 atom)。90 测试绿。
|
||||
- **oakcodec `bridge/{common,render}` 句柄类型对齐**:`OakVideoParams`/
|
||||
`OakAudioParams`/`OakSubtitleParams`/`OakNodeBlock`/`OakRenderTexture`/
|
||||
`OakCancelAtom`/`OakRenderRenderer`/`OakCodecFrame` → CHandle 别名
|
||||
(删除其上的 `unsafe impl Send/Sync` 与固有 impl);共享
|
||||
`oakcore_rs::handle::CHandle` 增补 `PartialEq, Eq`(codec 的
|
||||
`CodecStream` 派生比较)。
|
||||
- **facade EncodingParamsPOD 统一**(步骤 c 的 POD 部分):facade 的
|
||||
`EncodingParamsPOD`(41 字段 c_char 镜像)→ 别名
|
||||
`oakcodec::ffi::encoder::oakcodec_encoding_params`(u8);`zeroed()`
|
||||
→ `zeroed_encoding_params()` 自由函数;`write_field`/`field_str` 改
|
||||
u8;`oakcodec_encoder_init`/`oaktask_create_export`/
|
||||
`oakaudio_manager_start_recording` 三个 encoding-params link-time
|
||||
extern 全部改直接调用(audio 的 `EncodingParams` 同别名后打通)。
|
||||
facade bridge 仅剩宿主 `oakcore_audioparams_*` extern(C++ lib,非
|
||||
Rust crate)。
|
||||
|
||||
### 11.5 未完成(后续步骤)
|
||||
|
||||
- **dlsym 残留**(node 20、render 4):全在死/宿主方向——node
|
||||
`bridge/core.rs`(`oakcore_audioparams_*` 宿主符号)、
|
||||
`bridge/render.rs`+`bridge/timeline.rs`(死方向,node 测试
|
||||
`ffi_timeline_test` 使用)、render `bridge/node.rs`(copier 死方向,
|
||||
`copier_test` 使用)。这些是文档化的"保留 dlsym"(死/宿主),转换
|
||||
需同步迁移对应测试;`linkage.rs` 锚定注释可更新。
|
||||
- `oakcodec::bridge::render` 的 cancel-atom C 边界(设计 §4.2)保持。
|
||||
- OFX suites 层保持 C(冻结,未触碰)。
|
||||
|
||||
## 10. 风险与回退
|
||||
|
||||
|
||||
@@ -35,74 +35,28 @@
|
||||
|
||||
use std::ffi::{c_char, c_int, c_void};
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `OakVideoParams` — refcounted video-parameter handle.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakVideoParams {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version (see [`OAKCODEC_ABI_VERSION`]).
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakVideoParams = CHandle;
|
||||
|
||||
|
||||
/// `OakAudioParams` — refcounted audio-parameter handle.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakAudioParams {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakAudioParams = CHandle;
|
||||
|
||||
|
||||
/// `OakSubtitleParams` — refcounted subtitle-parameter handle.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakSubtitleParams {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakSubtitleParams = CHandle;
|
||||
|
||||
|
||||
/// `OakNodeBlock` — opaque node-block handle (owned elsewhere; codec
|
||||
/// only stores and forwards it).
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakNodeBlock {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakNodeBlock = CHandle;
|
||||
|
||||
|
||||
// The handle structs are opaque refcounted handles pointing into a C
|
||||
// library; the boxed objects are independently synchronized there, so
|
||||
// moving a handle between threads is sound.
|
||||
unsafe impl Send for OakVideoParams {}
|
||||
unsafe impl Sync for OakVideoParams {}
|
||||
unsafe impl Send for OakAudioParams {}
|
||||
unsafe impl Sync for OakAudioParams {}
|
||||
unsafe impl Send for OakSubtitleParams {}
|
||||
unsafe impl Sync for OakSubtitleParams {}
|
||||
unsafe impl Send for OakNodeBlock {}
|
||||
unsafe impl Sync for OakNodeBlock {}
|
||||
|
||||
extern "C" {
|
||||
/// `oakcommon_videoparams_init`.
|
||||
|
||||
@@ -23,71 +23,25 @@
|
||||
|
||||
use std::ffi::{c_char, c_int, c_void};
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `OakRenderTexture` — refcounted GPU texture handle.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakRenderTexture {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakRenderTexture = CHandle;
|
||||
|
||||
|
||||
/// `OakCancelAtom` — refcounted cancellation atom handle.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakCancelAtom {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakCancelAtom = CHandle;
|
||||
|
||||
|
||||
/// `OakRenderRenderer` — refcounted display-renderer handle.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakRenderRenderer {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakRenderRenderer = CHandle;
|
||||
|
||||
|
||||
/// `OakCodecFrame` — refcounted CPU-frame handle shared with oakrender.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct OakCodecFrame {
|
||||
/// Opaque object pointer.
|
||||
pub ctx: *mut c_void,
|
||||
/// Atomically increments the reference count.
|
||||
pub addref: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// Decrements the count, destroys at zero.
|
||||
pub release: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// ABI version.
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakCodecFrame = CHandle;
|
||||
|
||||
|
||||
// Refcounted opaque handles; thread-safe in the C library.
|
||||
unsafe impl Send for OakRenderTexture {}
|
||||
unsafe impl Sync for OakRenderTexture {}
|
||||
unsafe impl Send for OakCancelAtom {}
|
||||
unsafe impl Sync for OakCancelAtom {}
|
||||
unsafe impl Send for OakRenderRenderer {}
|
||||
unsafe impl Sync for OakRenderRenderer {}
|
||||
unsafe impl Send for OakCodecFrame {}
|
||||
unsafe impl Sync for OakCodecFrame {}
|
||||
|
||||
/// `oakrender_video_params` — flattened POD of `olive::VideoParams`
|
||||
/// passed into oakrender; see `include/render/renderer.h`.
|
||||
|
||||
Generated
+12
@@ -830,6 +830,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"oakcore-rs",
|
||||
"oaknode",
|
||||
"oakrender",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -846,15 +849,24 @@ dependencies = [
|
||||
name = "oaktask"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oaknode",
|
||||
"oakotio",
|
||||
"oakrender",
|
||||
"oaktimeline",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oaktimeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oaknode",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -66,14 +66,9 @@ pub type SourceClip = oakaudio::ffi::sync::SourceClip;
|
||||
|
||||
|
||||
|
||||
/// Opaque mirror of the oakaudio recording-params POD
|
||||
/// (`include/audio/manager.h`). The facade passes the engine's
|
||||
/// `OakEngineEncodingParams*` through untouched — both are the same C ABI
|
||||
/// mirror of `olive::EncodingParams`.
|
||||
#[repr(C)]
|
||||
pub struct EncodingParams {
|
||||
_opaque: [u8; 0],
|
||||
}
|
||||
/// `oakaudio` recording-params POD — single-lib unification: aliases the
|
||||
/// oakaudio crate's type (itself the oakcodec `oakcodec_encoding_params`).
|
||||
pub type EncodingParams = oakaudio::bridge::codec::EncodingParams;
|
||||
|
||||
extern "C" {
|
||||
pub fn oakcore_audioparams_create(sample_rate: c_int, channel_layout: u64, format: c_int) -> *mut c_void;
|
||||
@@ -188,17 +183,7 @@ pub fn oakaudio_manager_start_recording(
|
||||
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;
|
||||
unsafe { oakaudio::ffi::manager::oakaudio_manager_start_recording(_self, params, error_buf, error_buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakaudio` crate (single-lib unification; the
|
||||
|
||||
@@ -52,97 +52,21 @@ use std::ffi::{c_char, c_int};
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `include/codec/encoder.h` — the encoding-params POD, a complete mirror
|
||||
/// of `olive::EncodingParams`. The facade's `OakEngineEncodingParams`
|
||||
/// handle is a heap box over exactly this struct, so every engine getter/
|
||||
/// setter reads/writes a field and `encoder_init`/recording can consume
|
||||
/// the pointer directly.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct EncodingParamsPOD {
|
||||
/// Output filename (NUL-terminated).
|
||||
pub filename: [c_char; 1024],
|
||||
/// Output container format id.
|
||||
pub format: c_int,
|
||||
/// Whether video is enabled (1/0).
|
||||
pub video_enabled: c_int,
|
||||
/// Video codec id.
|
||||
pub video_codec: c_int,
|
||||
/// Video width in pixels.
|
||||
pub video_width: c_int,
|
||||
/// Video height in pixels.
|
||||
pub video_height: c_int,
|
||||
/// Frame duration numerator.
|
||||
pub video_time_base_num: c_int,
|
||||
/// Frame duration denominator.
|
||||
pub video_time_base_den: c_int,
|
||||
/// Delivery pixel format (`OakPixelFormat`).
|
||||
pub video_pixel_format: c_int,
|
||||
/// Interlacing mode (`OAKCODEC_INTERLACE_*`).
|
||||
pub video_interlacing: c_int,
|
||||
/// Pixel aspect ratio numerator.
|
||||
pub video_pixel_aspect_num: c_int,
|
||||
/// Pixel aspect ratio denominator.
|
||||
pub video_pixel_aspect_den: c_int,
|
||||
/// Video bit rate in bits per second (0 = codec default).
|
||||
pub video_bit_rate: i64,
|
||||
/// Minimum video bit rate.
|
||||
pub video_min_bit_rate: i64,
|
||||
/// Maximum video bit rate.
|
||||
pub video_max_bit_rate: i64,
|
||||
/// Video buffer size in bytes.
|
||||
pub video_buffer_size: i64,
|
||||
/// Encoder threads (0 = auto).
|
||||
pub video_threads: c_int,
|
||||
/// Encoded pixel format name ("yuv420p", NUL-terminated).
|
||||
pub video_pix_fmt: [c_char; 64],
|
||||
/// Whether video is an image sequence (1/0).
|
||||
pub video_is_image_sequence: c_int,
|
||||
/// Scaling method (`OAKCODEC_ENCODING_SCALING_*`).
|
||||
pub video_scaling_method: c_int,
|
||||
/// Whether audio is enabled (1/0).
|
||||
pub audio_enabled: c_int,
|
||||
/// Audio codec id.
|
||||
pub audio_codec: c_int,
|
||||
/// Audio sample rate in Hz.
|
||||
pub audio_sample_rate: c_int,
|
||||
/// Audio channel layout mask.
|
||||
pub audio_channel_layout: u64,
|
||||
/// Audio sample format (`SampleFormat::Format`).
|
||||
pub audio_sample_format: c_int,
|
||||
/// Audio bit rate in bits per second.
|
||||
pub audio_bit_rate: i64,
|
||||
/// Whether subtitles are enabled (1/0).
|
||||
pub subtitles_enabled: c_int,
|
||||
/// Subtitle codec id.
|
||||
pub subtitles_codec: c_int,
|
||||
/// Whether subtitles are a sidecar file (1/0).
|
||||
pub subtitles_are_sidecar: c_int,
|
||||
/// Sidecar subtitle format (`ExportFormat::Format`).
|
||||
pub subtitles_sidecar_format: c_int,
|
||||
/// Output OCIO colorspace name (empty = reference space).
|
||||
pub color_transform_output: [c_char; 256],
|
||||
/// Export length in seconds (rational), numerator.
|
||||
pub export_length_num: c_int,
|
||||
/// Export length in seconds (rational), denominator.
|
||||
pub export_length_den: c_int,
|
||||
/// Whether a custom export range is set (1/0).
|
||||
pub has_custom_range: c_int,
|
||||
/// Custom range in point numerator (seconds).
|
||||
pub custom_range_in_num: i64,
|
||||
/// Custom range in point denominator (seconds).
|
||||
pub custom_range_in_den: i64,
|
||||
/// Custom range out point numerator (seconds).
|
||||
pub custom_range_out_num: i64,
|
||||
/// Custom range out point denominator (seconds).
|
||||
pub custom_range_out_den: i64,
|
||||
/// `olive::EncodingParams` — single-lib unification: aliases the oakcodec
|
||||
/// crate's POD (`oakcodec_encoding_params`, identical `#[repr(C)]` layout;
|
||||
/// the engine's `OakEngineEncodingParams` handle is a heap box over exactly
|
||||
/// this struct, so every engine getter/setter reads/writes a field and
|
||||
/// `encoder_init`/recording can consume the pointer directly).
|
||||
pub type EncodingParamsPOD = oakcodec::ffi::encoder::oakcodec_encoding_params;
|
||||
|
||||
|
||||
/// Zeroed encoding-params POD (all fields 0 / NUL). The codec crate's
|
||||
/// struct has no zeroed constructor; this facade helper provides it.
|
||||
pub fn zeroed_encoding_params() -> EncodingParamsPOD {
|
||||
// All-C fields: all-zero is a valid value.
|
||||
unsafe { std::mem::zeroed() }
|
||||
}
|
||||
|
||||
impl EncodingParamsPOD {
|
||||
/// Zeroed POD: all tracks disabled, format unset.
|
||||
pub fn zeroed() -> Self {
|
||||
unsafe { std::mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
/// `#[no_mangle]` export stays for the external C ABI).
|
||||
@@ -298,12 +222,7 @@ pub fn oakcodec_encoding_generate_matrix(
|
||||
/// 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;
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_init(params) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification; the
|
||||
|
||||
@@ -256,24 +256,15 @@ pub fn oaktask_create_precache(footage: CHandle, index: c_int, sequence: CHandle
|
||||
|
||||
/// 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.
|
||||
/// `oaktask_create_export` — direct call into the `oaktask` crate
|
||||
/// (single-lib unification; the encoding-params POD is the shared
|
||||
/// oakcodec type).
|
||||
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" {
|
||||
#[link_name = "oaktask_create_export"]
|
||||
pub fn oaktask_create_export_extern(
|
||||
viewer: CHandle,
|
||||
color_manager: CHandle,
|
||||
params: *const crate::bridge::codec::EncodingParamsPOD,
|
||||
) -> CHandle;
|
||||
unsafe { oaktask::ffi::project::oaktask_create_export(viewer, color_manager, params) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oaktask` crate (single-lib unification; the
|
||||
|
||||
@@ -38,7 +38,7 @@ use std::collections::HashMap;
|
||||
use std::ffi::{c_char, c_int, c_void};
|
||||
|
||||
use crate::bridge::codec as k;
|
||||
use crate::bridge::codec::EncodingParamsPOD;
|
||||
use crate::bridge::codec::{EncodingParamsPOD, zeroed_encoding_params};
|
||||
use crate::common::OakVideoParamsPod;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::handle::{guard, guard_int, string_result};
|
||||
@@ -59,7 +59,7 @@ struct ParamsBox {
|
||||
|
||||
impl ParamsBox {
|
||||
fn new() -> Self {
|
||||
let mut pod = EncodingParamsPOD::zeroed();
|
||||
let mut pod = zeroed_encoding_params();
|
||||
pod.format = -1; // unset (POD 0 is a valid format, DNxHD)
|
||||
ParamsBox {
|
||||
pod,
|
||||
@@ -89,23 +89,15 @@ unsafe fn params_mut(ptr: *mut OakEngineEncodingParams) -> Result<&'static mut P
|
||||
}
|
||||
|
||||
/// Read a NUL-terminated fixed array field as a `String`.
|
||||
fn field_str(field: &[c_char]) -> String {
|
||||
let bytes: Vec<u8> = field
|
||||
.iter()
|
||||
.take_while(|c| **c != 0)
|
||||
.map(|c| *c as u8)
|
||||
.collect();
|
||||
fn field_str(field: &[u8]) -> String {
|
||||
let bytes: Vec<u8> = field.iter().take_while(|c| **c != 0).copied().collect();
|
||||
String::from_utf8_lossy(&bytes).into_owned()
|
||||
}
|
||||
|
||||
/// Write a string into a fixed array field (truncated, NUL-terminated).
|
||||
fn write_field(field: &mut [c_char], value: &str) {
|
||||
fn write_field(field: &mut [u8], value: &str) {
|
||||
for (i, slot) in field.iter_mut().enumerate() {
|
||||
*slot = if i < value.len() {
|
||||
value.as_bytes()[i] as c_char
|
||||
} else {
|
||||
0
|
||||
};
|
||||
*slot = if i < value.len() { value.as_bytes()[i] } else { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,7 +1067,7 @@ pub unsafe extern "C" fn oakengine_encoding_start_audio_recording(
|
||||
}
|
||||
let rc = crate::bridge::audio::oakaudio_manager_start_recording(
|
||||
m,
|
||||
&p.pod as *const EncodingParamsPOD as *const c_void as *const crate::bridge::audio::EncodingParams,
|
||||
&p.pod as *const oakaudio::bridge::codec::EncodingParams,
|
||||
errbuf,
|
||||
errbuf_size,
|
||||
);
|
||||
|
||||
@@ -43,7 +43,7 @@ use std::ffi::{c_char, c_int, c_void};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use crate::bridge::codec::EncodingParamsPOD;
|
||||
use crate::bridge::codec::{EncodingParamsPOD, zeroed_encoding_params};
|
||||
use crate::bridge::node as n;
|
||||
use crate::bridge::task as t;
|
||||
use crate::codec::OakEngineEncodingParams;
|
||||
@@ -622,7 +622,7 @@ pub unsafe extern "C" fn oakengine_task_create_export(
|
||||
/// them is behaviorally identical to the original for the export task; all
|
||||
/// other POD fields stay zeroed.
|
||||
fn export_params_pod(params: *const OakEngineEncodingParams) -> Result<EncodingParamsPOD> {
|
||||
let mut pod = EncodingParamsPOD::zeroed();
|
||||
let mut pod = zeroed_encoding_params();
|
||||
|
||||
// filename (two-stage; writes NUL-terminated into `buf`)
|
||||
let mut buf = [0 as c_char; 1024];
|
||||
@@ -633,7 +633,7 @@ fn export_params_pod(params: *const OakEngineEncodingParams) -> Result<EncodingP
|
||||
return Err(Error::Invalid);
|
||||
}
|
||||
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
|
||||
unsafe { std::ptr::copy_nonoverlapping(buf.as_ptr(), pod.filename.as_mut_ptr(), len) };
|
||||
unsafe { std::ptr::copy_nonoverlapping(buf.as_ptr() as *const u8, pod.filename.as_mut_ptr(), len) };
|
||||
|
||||
pod.format = unsafe { crate::codec::oakengine_encoding_params_format(params) };
|
||||
pod.video_enabled = unsafe { crate::codec::oakengine_encoding_params_video_enabled(params) };
|
||||
|
||||
@@ -37,7 +37,7 @@ use std::ffi::c_void;
|
||||
/// 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)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct CHandle {
|
||||
/// Opaque box pointer.
|
||||
pub ctx: *mut c_void,
|
||||
|
||||
Generated
+1621
-1
File diff suppressed because it is too large
Load Diff
@@ -18,13 +18,18 @@ panic = "unwind"
|
||||
|
||||
[dependencies]
|
||||
# 共享 ABI 类型(CHandle 等,单库化统一,见 docs/zh/plans/riir/single-lib.md)。
|
||||
# 模块桥改直接 Rust 调用(单库化,见 docs/zh/plans/riir/single-lib.md);
|
||||
# 只允许零依赖起步。确需引入的 crate 必须在 README 登记理由。
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakundo = { path = "../../undo/rust" }
|
||||
oaknode = { path = "../../node/rust" }
|
||||
oakrender = { path = "../../render/rust" }
|
||||
|
||||
[features]
|
||||
# oakrender 测试桩(库内 no_mangle 符号 + 状态访问器):cargo test
|
||||
# --features test-stubs 时桥直连桩,像素路径可在无 liboakrender 的
|
||||
# 环境下跑通;真实链路仍走 dlsym 解析。
|
||||
# 测试桩(库内状态访问器):cargo test --features test-stubs 时桥直连
|
||||
# 桩,像素路径可在无真实 GL/GPU 的环境下跑通。桩的 C ABI 符号不再
|
||||
# no_mangle(真实 oaknode/oakrender/oakundo 已作为 path 依赖链接,
|
||||
# 避免重复符号);真实链路走直接 Rust 调用。
|
||||
test-stubs = []
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -14,64 +14,21 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! bridge:oak 其余模块的 C ABI 导入。
|
||||
//! bridge:oak 其余模块的 C ABI 调用——直接 Rust 调用(单库化,见
|
||||
//! `docs/zh/plans/riir/single-lib.md`)。
|
||||
//!
|
||||
//! 每个子模块(node/render/undo)只声明对应公共头的子集并包一层
|
||||
//! 极薄的 safe 封装。链接在模块 dylib 装配时完成(liboaknode/
|
||||
//! liboakrender/liboakundo)。
|
||||
//! 每个子模块(node/render/undo)调用对应 crate 的 `ffi` 导出(同名
|
||||
//! `#[no_mangle]` 符号仍从 dylib 导出供外部 C ABI 使用;内部调用绕过
|
||||
//! 它们)。句柄全部是共享的 [`crate::handle::CHandle`]。
|
||||
//!
|
||||
//! ## 双态实现(所有子模块统一)
|
||||
//!
|
||||
//! - 默认:`dlsym(RTLD_DEFAULT)` 运行时解析(本模块被 force_load
|
||||
//! 进宿主进程,符号在全局作用域;cargo test 无这些库时符号缺失
|
||||
//! → 可解释错误,测试可走通至桥边界);
|
||||
//! - `--features test-stubs`:库内 no_mangle 桩 + 状态访问器
|
||||
//! (各子模块的 [`node::stub`]/[`render::stub`]/[`undo::stub`])——
|
||||
//! 桥路径在 cargo test 里全链路可跑。两种形态的调用面完全一致。
|
||||
//!
|
||||
//! [`dlsym`] 是三个子模块共享的解析实现(macOS/Linux 的 RTLD_DEFAULT
|
||||
//! 取值不同;函数指针按调用方签名转换)。
|
||||
//! - 默认:直接调用 oaknode/oakrender/oakundo 的 ffi;
|
||||
//! - `--features test-stubs`:桥走库内状态桩(各子模块的
|
||||
//! [`node::stub`]/[`render::stub`]/[`undo::stub`],纯 Rust、无
|
||||
//! `#[no_mangle]`,与真实 crate 的导出不冲突)——像素路径可在无
|
||||
//! 真实 GL/GPU 的环境下跑通。两种形态的调用面完全一致。
|
||||
|
||||
pub mod node;
|
||||
pub mod render;
|
||||
pub mod undo;
|
||||
|
||||
/// 共享的 dlsym 运行时解析(`#[cfg(not(feature = "test-stubs"))]`)。
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
pub(crate) mod dlsym {
|
||||
use std::ffi::{c_char, c_void};
|
||||
|
||||
/// RTLD_DEFAULT(macOS: -2;Linux: 0)。
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(crate) const RTLD_DEFAULT: *mut c_void = -2isize as *mut c_void;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) const RTLD_DEFAULT: *mut c_void = 0isize as *mut c_void;
|
||||
|
||||
extern "C" {
|
||||
fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
||||
}
|
||||
|
||||
/// 解析全局作用域符号;缺失返回 None。
|
||||
pub(crate) fn resolve(name: &str) -> Option<*mut c_void> {
|
||||
let c = std::ffi::CString::new(name).ok()?;
|
||||
let p = unsafe { dlsym(RTLD_DEFAULT, c.as_ptr()) };
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析并按签名调用;符号缺失返回 None。
|
||||
///
|
||||
/// # Safety
|
||||
/// 调用方保证 `T` 与符号的真实函数类型一致。
|
||||
pub(crate) fn call<T, R>(name: &str, f: impl FnOnce(T) -> R) -> Option<R>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
let p = resolve(name)?;
|
||||
let f_ptr: T = unsafe { std::mem::transmute_copy(&p) };
|
||||
Some(f(f_ptr))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +28,11 @@
|
||||
//!
|
||||
//! ## 双态实现(同 [`crate::bridge::render`])
|
||||
//!
|
||||
//! - 默认:`dlsym(RTLD_DEFAULT)` 运行时解析(cargo test 无 liboaknode
|
||||
//! 时符号缺失 → 错误码/空句柄,桥路径可解释地失败);
|
||||
//! - `--features test-stubs`:库内桩([`stub`])——节点值、undo 命令
|
||||
//! 全链路可在 cargo test 跑通。两种形态的调用面完全一致。
|
||||
//! - 默认:直接 Rust 调用 oaknode 的 `ffi`(单库化,见
|
||||
//! `docs/zh/plans/riir/single-lib.md`);
|
||||
//! - `--features test-stubs`:库内状态桩([`stub`],纯 Rust、无
|
||||
//! `#[no_mangle]`,与真实 oaknode 的导出不冲突)——节点值、undo
|
||||
//! 命令全链路可在 cargo test 跑通。两种形态的调用面完全一致。
|
||||
|
||||
use std::ffi::c_char;
|
||||
|
||||
@@ -177,9 +178,7 @@ pub(crate) unsafe fn node_from_identity(id: usize) -> NodeHandle {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(usize) -> NodeHandle;
|
||||
crate::bridge::dlsym::call::<F, NodeHandle>("oaknode_node_from_identity", |f| unsafe { f(id) })
|
||||
.unwrap_or_else(CHandle::null)
|
||||
unsafe { oaknode::ffi::node::oaknode_node_from_identity(id) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,11 +200,14 @@ pub(crate) unsafe fn set_input_undoable(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(NodeHandle, *const c_char, *const Value, *mut CommandHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oaknode_node_set_input_undoable", |f| {
|
||||
unsafe { f(node, input, value, out) }
|
||||
})
|
||||
.unwrap_or(-30001)
|
||||
unsafe {
|
||||
oaknode::ffi::node::oaknode_node_set_input_undoable(
|
||||
node,
|
||||
input,
|
||||
value as *const oaknode::value::OakNodeValue,
|
||||
out,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +228,14 @@ pub(crate) unsafe fn set_input_string_undoable(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(NodeHandle, *const c_char, *const c_char, *mut CommandHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oaknode_node_set_input_string_undoable", |f| {
|
||||
unsafe { f(node, input, value, out) }
|
||||
})
|
||||
.unwrap_or(-30001)
|
||||
unsafe {
|
||||
oaknode::ffi::node::oaknode_node_set_input_string_undoable(
|
||||
node,
|
||||
input,
|
||||
value,
|
||||
out,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,16 +394,16 @@ pub mod stub {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 默认模式单测(无桩;dlsym 缺失的可解释失败路径)----------------------
|
||||
// ---- 默认模式单测(无桩;空/NULL 句柄经真实 crate 的可解释失败路径)----------------------
|
||||
|
||||
#[cfg(all(test, not(feature = "test-stubs")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// cargo test 无 liboaknode:符号缺失 → 空句柄/负错误码;空句柄
|
||||
/// 与空指针参数被拒。
|
||||
/// 空/NULL 句柄经真实 oaknode 容错:未登记身份 → 空句柄;空句柄
|
||||
/// 与空指针参数被拒(OAKNODE_E_INVALID)。
|
||||
#[test]
|
||||
fn dlsym_missing_error_paths() {
|
||||
fn empty_handle_error_paths() {
|
||||
let mut cmd = CommandHandle::null();
|
||||
unsafe {
|
||||
assert!(node_from_identity(0xDEAD).is_null(), "未登记身份 → 空句柄");
|
||||
|
||||
@@ -26,45 +26,19 @@
|
||||
//!
|
||||
//! ## 双态实现
|
||||
//!
|
||||
//! - 默认:`dlsym(RTLD_DEFAULT)` 运行时解析(本模块被 force_load
|
||||
//! 进宿主进程,符号在全局作用域;cargo test 无 liboakrender 时
|
||||
//! 符号缺失 → 可解释错误,测试可走通至渲染边界);
|
||||
//! - `--features test-stubs`:库内 no_mangle 桩 + 状态访问器
|
||||
//! ([`stub`])——像素路径在 cargo test 里全链路可跑。
|
||||
//! 两种形态的调用面(`texture_get_frame` 等)完全一致。
|
||||
//! - 默认:直接 Rust 调用 oakrender 的 `ffi`(单库化,见
|
||||
//! `docs/zh/plans/riir/single-lib.md`);
|
||||
//! - `--features test-stubs`:库内状态桩 + 状态访问器([`stub`],纯
|
||||
//! Rust、无 `#[no_mangle]`,与真实 oakrender 的导出不冲突)——像素
|
||||
//! 路径在 cargo test 里全链路可跑。两种形态的调用面
|
||||
//! (`texture_get_frame` 等)完全一致。
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
/// oakrender 视频参数(include/render/renderer.h:78,字段逐字一致)。
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct VideoParams {
|
||||
/// 宽。
|
||||
pub width: i32,
|
||||
/// 高。
|
||||
pub height: i32,
|
||||
/// 帧时长分子(如 1001/30000 秒)。
|
||||
pub time_base_num: i32,
|
||||
/// 帧时长分母。
|
||||
pub time_base_den: i32,
|
||||
/// `olive::PixelFormat::Format`(invalid=-1, u8=0, u10=1, u16=2,
|
||||
/// f16=3, f32=4)。
|
||||
pub format: i32,
|
||||
/// 像素比分子。
|
||||
pub pixel_aspect_num: i32,
|
||||
/// 像素比分母。
|
||||
pub pixel_aspect_den: i32,
|
||||
/// `olive::VideoParams::Interlacing`。
|
||||
pub interlacing: i32,
|
||||
/// `olive::VideoParams::ColorRange`。
|
||||
pub color_range: i32,
|
||||
/// 预览分辨率除数(1 = 全分辨率)。
|
||||
pub divider: i32,
|
||||
/// `olive::VideoParams::Type`(0 = video)。
|
||||
pub video_type: i32,
|
||||
/// 预乘 alpha(0/1)。
|
||||
pub premultiplied_alpha: i32,
|
||||
}
|
||||
/// `oakrender_video_params` POD — single-lib unification: aliases the
|
||||
/// oakrender crate's struct (identical layout; include/render/renderer.h:78).
|
||||
pub type VideoParams = oakrender::ffi::OakRenderVideoParams;
|
||||
|
||||
|
||||
/// olive::PixelFormat::Format 的 f32 值。
|
||||
pub const PIXEL_FORMAT_F32: i32 = 4;
|
||||
@@ -90,11 +64,7 @@ pub(crate) unsafe fn texture_get_frame(texture: TextureHandle, out: *mut FrameHa
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle, *mut FrameHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_texture_get_frame", |f| {
|
||||
unsafe { f(texture, out) }
|
||||
})
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_get_frame(texture, out) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +76,7 @@ pub(crate) unsafe fn texture_is_dummy(texture: TextureHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_texture_is_dummy", |f| unsafe { f(texture) })
|
||||
.unwrap_or(1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_is_dummy(texture) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,9 +88,7 @@ pub(crate) unsafe fn frame_width(frame: FrameHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(FrameHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_codec_frame_width", |f| unsafe { f(frame) })
|
||||
.unwrap_or(0)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_width(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,9 +100,7 @@ pub(crate) unsafe fn frame_height(frame: FrameHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(FrameHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_codec_frame_height", |f| unsafe { f(frame) })
|
||||
.unwrap_or(0)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_height(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,9 +112,7 @@ pub(crate) unsafe fn frame_data(frame: FrameHandle) -> *mut c_void {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(FrameHandle) -> *mut c_void;
|
||||
crate::bridge::dlsym::call::<F, *mut c_void>("oakrender_codec_frame_data", |f| unsafe { f(frame) })
|
||||
.unwrap_or(std::ptr::null_mut())
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_data(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,9 +124,7 @@ pub(crate) unsafe fn frame_get_params(frame: FrameHandle, out: *mut VideoParams)
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(FrameHandle, *mut VideoParams) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_codec_frame_get_params", |f| unsafe { f(frame, out) })
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_get_params(frame, out) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,9 +136,7 @@ pub(crate) unsafe fn frame_allocate(frame: FrameHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(FrameHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_codec_frame_allocate", |f| unsafe { f(frame) })
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_allocate(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,13 +148,7 @@ pub(crate) unsafe fn frame_free(frame: *mut FrameHandle) {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(*mut FrameHandle);
|
||||
if let Some(f) = crate::bridge::dlsym::call::<F, ()>("oakrender_codec_frame_free", |f| {
|
||||
unsafe { f(frame) }
|
||||
}) {
|
||||
// 调用已完成;返回值忽略。
|
||||
let _ = f;
|
||||
}
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_free(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,11 +163,7 @@ pub(crate) unsafe fn frame_linesize_bytes(frame: FrameHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(FrameHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_codec_frame_linesize_bytes", |f| {
|
||||
unsafe { f(frame) }
|
||||
})
|
||||
.unwrap_or(0)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_linesize_bytes(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,11 +179,7 @@ pub(crate) unsafe fn renderer_create_dynamic(backend: *const std::ffi::c_char) -
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(*const std::ffi::c_char) -> RendererHandle;
|
||||
crate::bridge::dlsym::call::<F, RendererHandle>("oakrender_display_renderer_create_dynamic", |f| {
|
||||
unsafe { f(backend) }
|
||||
})
|
||||
.unwrap_or_else(RendererHandle::null)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_create_dynamic(backend) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,11 +196,7 @@ pub(crate) unsafe fn renderer_init(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(RendererHandle, *mut std::ffi::c_void) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_renderer_init", |f| {
|
||||
unsafe { f(renderer, gl_context) }
|
||||
})
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_init(renderer, gl_context) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,11 +209,7 @@ pub(crate) unsafe fn renderer_is_open_gl(renderer: RendererHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(RendererHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_renderer_is_open_gl", |f| {
|
||||
unsafe { f(renderer) }
|
||||
})
|
||||
.unwrap_or(0)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_is_open_gl(renderer) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,12 +223,7 @@ pub(crate) unsafe fn renderer_destroy(renderer: *mut RendererHandle) {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(*mut RendererHandle);
|
||||
if let Some(f) = crate::bridge::dlsym::call::<F, ()>("oakrender_display_renderer_destroy", |f| {
|
||||
unsafe { f(renderer) }
|
||||
}) {
|
||||
let _ = f;
|
||||
}
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_renderer_destroy(renderer) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,11 +246,11 @@ pub(crate) unsafe fn texture_create(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(RendererHandle, *const VideoParams, *const std::ffi::c_void, i32) -> TextureHandle;
|
||||
crate::bridge::dlsym::call::<F, TextureHandle>("oakrender_display_texture_create", |f| {
|
||||
unsafe { f(renderer, params, pixels, linesize) }
|
||||
})
|
||||
.unwrap_or_else(TextureHandle::null)
|
||||
unsafe {
|
||||
oakrender::ffi::renderer::oakrender_display_texture_create(
|
||||
renderer, params, pixels, linesize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,9 +263,7 @@ pub(crate) unsafe fn texture_id(texture: TextureHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_texture_id", |f| unsafe { f(texture) })
|
||||
.unwrap_or(0)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_id(texture) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,11 +275,7 @@ pub(crate) unsafe fn texture_get_params(texture: TextureHandle, out: *mut VideoP
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle, *mut VideoParams) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_texture_get_params", |f| {
|
||||
unsafe { f(texture, out) }
|
||||
})
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_get_params(texture, out) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,11 +293,7 @@ pub(crate) unsafe fn texture_download(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle, *mut std::ffi::c_void, i32) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_texture_download", |f| {
|
||||
unsafe { f(texture, pixels, linesize) }
|
||||
})
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_download(texture, pixels, linesize) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,11 +306,7 @@ pub(crate) unsafe fn texture_retain(texture: TextureHandle) -> TextureHandle {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle) -> TextureHandle;
|
||||
crate::bridge::dlsym::call::<F, TextureHandle>("oakrender_display_texture_retain", |f| {
|
||||
unsafe { f(texture) }
|
||||
})
|
||||
.unwrap_or_else(TextureHandle::null)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_retain(texture) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,12 +319,7 @@ pub(crate) unsafe fn texture_free(texture: *mut TextureHandle) {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(*mut TextureHandle);
|
||||
if let Some(f) = crate::bridge::dlsym::call::<F, ()>("oakrender_display_texture_free", |f| {
|
||||
unsafe { f(texture) }
|
||||
}) {
|
||||
let _ = f;
|
||||
}
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_free(texture) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,11 +337,7 @@ pub(crate) unsafe fn texture_upload(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(TextureHandle, *const std::ffi::c_void, i32) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_texture_upload", |f| {
|
||||
unsafe { f(texture, pixels, linesize) }
|
||||
})
|
||||
.unwrap_or(-1)
|
||||
unsafe { oakrender::ffi::renderer::oakrender_display_texture_upload(texture, pixels, linesize) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,11 +357,11 @@ pub(crate) unsafe fn renderer_download_from_texture(
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(RendererHandle, i32, *const VideoParams, *mut std::ffi::c_void, i32) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakrender_display_renderer_download_from_texture", |f| {
|
||||
unsafe { f(renderer, texture_id, params, dst, linesize) }
|
||||
})
|
||||
.unwrap_or(-1)
|
||||
unsafe {
|
||||
oakrender::ffi::renderer::oakrender_display_renderer_download_from_texture(
|
||||
renderer, texture_id, params, dst, linesize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -949,26 +857,27 @@ pub mod stub {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 默认模式单测(无桩;dlsym 缺失的可解释失败路径)----------------------
|
||||
// ---- 默认模式单测(无桩;空/NULL 句柄经真实 crate 的可解释失败路径)----------------------
|
||||
|
||||
#[cfg(all(test, not(feature = "test-stubs")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// cargo test 无 liboakrender:符号缺失 → 明确错误码/空指针/占位
|
||||
/// 判定(1),全部生命周期函数对空句柄容错不崩。
|
||||
/// 空/NULL 句柄经真实 oakrender 全部容错不崩:返回
|
||||
/// `OAKRENDER_E_INVALID`(-70001)或空值。
|
||||
#[test]
|
||||
fn dlsym_missing_error_paths() {
|
||||
fn empty_handle_error_paths() {
|
||||
let mut frame = FrameHandle::null();
|
||||
let tex = TextureHandle::null();
|
||||
unsafe {
|
||||
assert_eq!(texture_get_frame(tex, &mut frame), -1);
|
||||
assert_eq!(texture_is_dummy(tex), 1, "符号缺失 → 视为占位");
|
||||
assert_eq!(texture_get_frame(tex, &mut frame), -70001);
|
||||
// 空句柄不是占位纹理:真实 oakrender 返回 0。
|
||||
assert_eq!(texture_is_dummy(tex), 0);
|
||||
assert_eq!(frame_width(frame), 0);
|
||||
assert_eq!(frame_height(frame), 0);
|
||||
assert!(frame_data(frame).is_null());
|
||||
assert_eq!(frame_get_params(frame, &mut VideoParams::default()), -1);
|
||||
assert_eq!(frame_allocate(frame), -1);
|
||||
assert_eq!(frame_get_params(frame, &mut VideoParams::default()), -70001);
|
||||
assert_eq!(frame_allocate(frame), -70001);
|
||||
frame_free(&mut frame); // 空句柄 no-op
|
||||
frame_free(std::ptr::null_mut()); // NULL no-op
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
//!
|
||||
//! ## 双态实现(同 [`crate::bridge::render`])
|
||||
//!
|
||||
//! - 默认:`dlsym(RTLD_DEFAULT)` 运行时解析;
|
||||
//! - `--features test-stubs`:库内桩([`stub`])——命令表 + undo/redo
|
||||
//! - 默认:直接 Rust 调用 oakundo 的 `ffi`(单库化,见
|
||||
//! `docs/zh/plans/riir/single-lib.md`);
|
||||
//! - `--features test-stubs`:库内状态桩([`stub`],纯 Rust、无
|
||||
//! `#[no_mangle]`,与真实 oakundo 的导出不冲突)——命令表 + undo/redo
|
||||
//! 语义在 cargo test 里全链路可跑。两种形态的调用面完全一致。
|
||||
|
||||
use crate::handle::CHandle;
|
||||
@@ -46,9 +48,7 @@ pub(crate) unsafe fn command_init_multi() -> CommandHandle {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn() -> CommandHandle;
|
||||
crate::bridge::dlsym::call::<F, CommandHandle>("oakundo_command_init_multi", |f| unsafe { f() })
|
||||
.unwrap_or_else(CHandle::null)
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init_multi() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,9 +60,7 @@ pub(crate) unsafe fn command_redo_now(command: CommandHandle) -> i32 {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(CommandHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakundo_command_redo_now", |f| unsafe { f(command) })
|
||||
.unwrap_or(-40001)
|
||||
unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,11 +72,7 @@ pub(crate) unsafe fn command_multi_add_child(multi: CommandHandle, child: Comman
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(CommandHandle, CommandHandle) -> i32;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakundo_command_multi_add_child", |f| unsafe {
|
||||
f(multi, child)
|
||||
})
|
||||
.unwrap_or(-40001)
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,12 +84,7 @@ pub(crate) unsafe fn command_free(command: *mut CommandHandle) {
|
||||
}
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
{
|
||||
type F = unsafe fn(*mut CommandHandle);
|
||||
if let Some(f) = crate::bridge::dlsym::call::<F, ()>("oakundo_command_free", |f| {
|
||||
unsafe { f(command) }
|
||||
}) {
|
||||
let _ = f;
|
||||
}
|
||||
unsafe { oakundo::ffi::command::oakundo_command_free(command) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,23 +353,23 @@ pub mod stub {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 默认模式单测(无桩;dlsym 缺失的可解释失败路径)----------------------
|
||||
// ---- 默认模式单测(无桩;空/NULL 句柄经真实 crate 的可解释失败路径)----------------------
|
||||
|
||||
#[cfg(all(test, not(feature = "test-stubs")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// cargo test 无 liboakundo:符号缺失 → 空句柄/负错误码,命令
|
||||
/// 生命周期函数对空句柄/NULL 容错不崩。
|
||||
/// 空/NULL 句柄经真实 oakundo 全部容错不崩:`init_multi` 产生
|
||||
/// 真实命令,空句柄操作返回 `OAKUNDO_E_INVALID`(-20001)。
|
||||
#[test]
|
||||
fn dlsym_missing_error_paths() {
|
||||
fn empty_handle_error_paths() {
|
||||
unsafe {
|
||||
let mut m = command_init_multi();
|
||||
assert!(m.is_null(), "无 liboakundo 时 init_multi 应返回空句柄");
|
||||
assert_eq!(command_redo_now(CommandHandle::null()), -40001);
|
||||
assert!(!m.is_null(), "init_multi 应产生真实命令句柄");
|
||||
assert_eq!(command_redo_now(CommandHandle::null()), -20001);
|
||||
assert_eq!(
|
||||
command_multi_add_child(CommandHandle::null(), CommandHandle::null()),
|
||||
-40001
|
||||
-20001
|
||||
);
|
||||
command_free(&mut m); // 空句柄 no-op
|
||||
command_free(std::ptr::null_mut()); // NULL no-op
|
||||
|
||||
@@ -208,7 +208,9 @@ fn instance_render_one_frame() {
|
||||
});
|
||||
}
|
||||
|
||||
/// render 无桩(默认构建):桥符号缺失 → 明确失败码而非崩溃。
|
||||
/// render 默认构建(真实 oakrender 链接):NULL 输出纹理在触达
|
||||
/// oakrender 之前被插件层校验拒绝(E_INVALID),不崩溃。真实纹理
|
||||
/// 路径需要 GL/GPU,属集成测试范畴。
|
||||
#[cfg(not(feature = "test-stubs"))]
|
||||
#[test]
|
||||
fn instance_render_one_frame() {
|
||||
@@ -217,8 +219,8 @@ fn instance_render_one_frame() {
|
||||
if h.is_null() {
|
||||
return;
|
||||
}
|
||||
let dst = fake_texture(0xA1);
|
||||
assert_eq!(unsafe { oakplugin_instance_render(h, dst, CHandle::null(), 0.0) }, -90003);
|
||||
let dst = CHandle::null();
|
||||
assert_eq!(unsafe { oakplugin_instance_render(h, dst, CHandle::null(), 0.0) }, -90001);
|
||||
unsafe { oakplugin_instance_free(&mut h) };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -207,11 +207,12 @@ fn render_job_graceful_without_bridge() {
|
||||
if h.is_null() {
|
||||
return;
|
||||
}
|
||||
let dst = fake_texture(0xA1);
|
||||
// NULL 输出纹理在触达 oakrender 前被插件层校验拒绝(E_INVALID)。
|
||||
let dst = CHandle::null();
|
||||
let r = unsafe {
|
||||
oakplugin_instance_render_job(h, dst, 0.0, 0, 0, std::ptr::null(), CHandle::null(), std::ptr::null(), 0, std::ptr::null(), 0, CHandle::null())
|
||||
};
|
||||
assert_eq!(r, -90003, "无 liboakrender 时输出纹理无 CPU 帧 → E_FAILED");
|
||||
assert_eq!(r, -90001, "NULL 输出纹理 → E_INVALID(不崩溃)");
|
||||
unsafe { oakplugin_instance_free(&mut h) };
|
||||
});
|
||||
}
|
||||
|
||||
Generated
+215
-3
@@ -8,6 +8,15 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.6"
|
||||
@@ -38,6 +47,24 @@ version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash 2.1.3",
|
||||
"shlex 1.3.0",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
@@ -113,7 +140,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
"shlex 2.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -128,6 +164,17 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.58"
|
||||
@@ -199,6 +246,12 @@ dependencies = [
|
||||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -211,6 +264,31 @@ version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6380599799e175191eb7ffe82c97f36a2a90a36cbc54c738a903e5287d7f516a"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"ffmpeg-sys-next",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-sys-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b939bf79dd5949412a4b81cfe21a07f48ea21b47fcbb5f57816c8c2de5ae30b"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
"num_cpus",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.10"
|
||||
@@ -295,6 +373,12 @@ dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
|
||||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.16.0"
|
||||
@@ -400,6 +484,12 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
@@ -429,6 +519,15 @@ dependencies = [
|
||||
"hashbrown 0.17.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
@@ -564,6 +663,12 @@ dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
@@ -602,7 +707,7 @@ dependencies = [
|
||||
"log",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"spirv",
|
||||
"strum",
|
||||
"thiserror 2.0.20",
|
||||
@@ -618,6 +723,16 @@ dependencies = [
|
||||
"jni-sys 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -628,6 +743,24 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcodec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ffmpeg-next",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
@@ -643,6 +776,16 @@ dependencies = [
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "oaknode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakotio"
|
||||
version = "0.1.0"
|
||||
@@ -667,9 +810,31 @@ dependencies = [
|
||||
name = "oaktask"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oaknode",
|
||||
"oakotio",
|
||||
"oakrender",
|
||||
"oaktimeline",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oaktimeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oaknode",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakundo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -835,6 +1000,35 @@ dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "renderdoc-sys"
|
||||
version = "1.1.0"
|
||||
@@ -847,6 +1041,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.23"
|
||||
@@ -903,6 +1103,12 @@ dependencies = [
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
@@ -1070,6 +1276,12 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@@ -1196,7 +1408,7 @@ dependencies = [
|
||||
"portable-atomic",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
"thiserror 2.0.20",
|
||||
"wgpu-core-deps-apple",
|
||||
|
||||
@@ -21,7 +21,7 @@ crate-type = ["staticlib", "rlib"]
|
||||
# `--test`) also compiles the stub-based tests, which cannot coexist with
|
||||
# the real oakrender exports in one binary (duplicate `#[no_mangle]`
|
||||
# symbols), so always pass the `--test` filter when the feature is on.
|
||||
real-oakrender = ["dep:oakrender"]
|
||||
real-oakrender = []
|
||||
|
||||
[profile.release]
|
||||
# FFI discipline: panics must be catchable at every exported entry.
|
||||
@@ -29,6 +29,11 @@ panic = "unwind"
|
||||
|
||||
[dependencies]
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakundo = { path = "../../undo/rust" }
|
||||
oakcommon = { path = "../../common/rust" }
|
||||
oakcodec = { path = "../../codec/rust" }
|
||||
oaknode = { path = "../../node/rust" }
|
||||
oaktimeline = { path = "../../timeline/rust" }
|
||||
|
||||
# Pure-Rust OpenTimelineIO JSON binding (serde model of the OTIO JSON format
|
||||
# covering exactly the object graph the C++ loadotio/saveotio tasks use).
|
||||
@@ -36,8 +41,8 @@ oakcore-rs = { path = "../../oakcore-rs" }
|
||||
# LoadOTIOTask/SaveOTIOTask parse/serialize through this crate.
|
||||
oakotio = { path = "../../bindings/oakotio" }
|
||||
|
||||
# Optional: only built when the `real-oakrender` feature is on, which links
|
||||
# the real oakrender crate into the integration-test binary. The library
|
||||
# itself never references it (all render access goes through the C ABI in
|
||||
# `bridge/render.rs`); plain `cargo test`/`cargo build` do not compile it.
|
||||
oakrender = { path = "../../render/rust", optional = true }
|
||||
# oakrender is a regular path dependency (single-lib: bridge/render.rs calls
|
||||
# its ffi directly). The `real-oakrender` marker feature keeps the
|
||||
# render-real integration test's cargo invocation working (it links the
|
||||
# real oakrender — now always — and skips the ticket stubs).
|
||||
oakrender = { path = "../../render/rust" }
|
||||
|
||||
+150
-183
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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. The task module reaches the codec side through
|
||||
//! `include/codec/task.h` (the task submitter), `include/codec/decoder.h`
|
||||
//! (conform/proxy work) and `include/codec/encoder.h` (export). Signatures
|
||||
@@ -36,27 +52,8 @@ pub const OAKCODEC_E_INVALID: c_int = -50001;
|
||||
pub const OAKCODEC_E_FAILED: c_int = -50003;
|
||||
|
||||
/// Mirror of `OakCodecTaskRequest` (`include/codec/task.h`).
|
||||
#[repr(C)]
|
||||
pub struct OakCodecTaskRequest {
|
||||
/// `OakCodecTaskKind` as int.
|
||||
pub kind: c_int,
|
||||
/// Source media filename.
|
||||
pub input_filename: *const c_char,
|
||||
/// Final destination path.
|
||||
pub output_filename: *const c_char,
|
||||
/// Stream inside the source media.
|
||||
pub stream_index: c_int,
|
||||
/// conform: target sample rate.
|
||||
pub sample_rate: c_int,
|
||||
/// conform: target channel layout mask.
|
||||
pub channel_layout: u64,
|
||||
/// conform: target sample format (enum as int).
|
||||
pub sample_format: c_int,
|
||||
/// proxy: target width, 0 = unspecified/divider.
|
||||
pub proxy_width: c_int,
|
||||
/// proxy: target height, 0 = unspecified/divider.
|
||||
pub proxy_height: c_int,
|
||||
}
|
||||
pub type OakCodecTaskRequest = oakcodec::task::OakCodecTaskRequest;
|
||||
|
||||
|
||||
/// `oakcodec_task_submit_fn` callback typedef.
|
||||
pub type OakCodecTaskSubmitFn =
|
||||
@@ -72,147 +69,74 @@ pub type OakEncoder = CHandle;
|
||||
pub type OakDecoder = CHandle;
|
||||
|
||||
/// Mirror of `OakCodecProxyParams` (`include/codec/proxy.h`).
|
||||
#[repr(C)]
|
||||
pub struct OakCodecProxyParams {
|
||||
/// Target width.
|
||||
pub width: c_int,
|
||||
/// Target height.
|
||||
pub height: c_int,
|
||||
/// Resolution divider.
|
||||
pub divider: c_int,
|
||||
/// Proxy format version.
|
||||
pub version: c_int,
|
||||
/// CRF for the proxy encode.
|
||||
pub crf: c_int,
|
||||
/// Whether audio is included.
|
||||
pub include_audio: c_int,
|
||||
/// Output container extension.
|
||||
pub extension: [c_char; 32],
|
||||
/// ffmpeg preset name.
|
||||
pub preset: [c_char; 32],
|
||||
}
|
||||
pub type OakCodecProxyParams = oakcodec::ffi::proxy::oakcodec_proxy_params;
|
||||
|
||||
|
||||
/// Mirror of `oakcodec_encoding_params` (`include/codec/encoder.h`) — the
|
||||
/// export task fills this to open the encoder. Layout mirrors the header
|
||||
/// verbatim (a zeroed struct = all tracks disabled).
|
||||
#[repr(C)]
|
||||
pub struct OakCodecEncodingParams {
|
||||
/// Output filename.
|
||||
pub filename: [c_char; 1024],
|
||||
/// Export format id (`olive::ExportFormat::Format`).
|
||||
pub format: c_int,
|
||||
/// Whether video is exported.
|
||||
pub video_enabled: c_int,
|
||||
/// Video codec id.
|
||||
pub video_codec: c_int,
|
||||
/// Output width.
|
||||
pub video_width: c_int,
|
||||
/// Output height.
|
||||
pub video_height: c_int,
|
||||
/// Frame duration rational numerator.
|
||||
pub video_time_base_num: c_int,
|
||||
/// Frame duration rational denominator.
|
||||
pub video_time_base_den: c_int,
|
||||
/// Delivery pixel format (`OakPixelFormat` as int).
|
||||
pub video_pixel_format: c_int,
|
||||
/// Interlacing (`OAKCODEC_INTERLACE_*`).
|
||||
pub video_interlacing: c_int,
|
||||
/// Pixel aspect ratio numerator.
|
||||
pub video_pixel_aspect_num: c_int,
|
||||
/// Pixel aspect ratio denominator.
|
||||
pub video_pixel_aspect_den: c_int,
|
||||
/// Video bit rate (bit/s, 0 = default).
|
||||
pub video_bit_rate: i64,
|
||||
/// Minimum video bit rate.
|
||||
pub video_min_bit_rate: i64,
|
||||
/// Maximum video bit rate.
|
||||
pub video_max_bit_rate: i64,
|
||||
/// Video buffer size (bytes).
|
||||
pub video_buffer_size: i64,
|
||||
/// Video threads (0 = auto).
|
||||
pub video_threads: c_int,
|
||||
/// Encoded pixel format name ("yuv420p").
|
||||
pub video_pix_fmt: [c_char; 64],
|
||||
/// Whether the output is an image sequence.
|
||||
pub video_is_image_sequence: c_int,
|
||||
/// Scaling method (`OAKCODEC_ENCODING_SCALING_*`).
|
||||
pub video_scaling_method: c_int,
|
||||
/// Whether audio is exported.
|
||||
pub audio_enabled: c_int,
|
||||
/// Audio codec id.
|
||||
pub audio_codec: c_int,
|
||||
/// Audio sample rate.
|
||||
pub audio_sample_rate: c_int,
|
||||
/// Audio channel layout mask.
|
||||
pub audio_channel_layout: u64,
|
||||
/// Audio sample format (`olive::core::SampleFormat::Format` as int).
|
||||
pub audio_sample_format: c_int,
|
||||
/// Audio bit rate.
|
||||
pub audio_bit_rate: i64,
|
||||
/// Whether subtitles are exported.
|
||||
pub subtitles_enabled: c_int,
|
||||
/// Subtitle codec id.
|
||||
pub subtitles_codec: c_int,
|
||||
/// Whether subtitles go to a sidecar file.
|
||||
pub subtitles_are_sidecar: c_int,
|
||||
/// Sidecar subtitle format.
|
||||
pub subtitles_sidecar_format: c_int,
|
||||
/// Output OCIO colorspace name (empty = reference space).
|
||||
pub color_transform_output: [c_char; 256],
|
||||
/// Export length in seconds (rational).
|
||||
pub export_length_num: c_int,
|
||||
/// Export length denominator.
|
||||
pub export_length_den: c_int,
|
||||
/// Whether a custom export range is in effect.
|
||||
pub has_custom_range: c_int,
|
||||
/// Custom range in (seconds, rational).
|
||||
pub custom_range_in_num: i64,
|
||||
/// Custom range in denominator.
|
||||
pub custom_range_in_den: i64,
|
||||
/// Custom range out numerator.
|
||||
pub custom_range_out_num: i64,
|
||||
/// Custom range out denominator.
|
||||
pub custom_range_out_den: i64,
|
||||
}
|
||||
pub type OakCodecEncodingParams = oakcodec::ffi::encoder::oakcodec_encoding_params;
|
||||
|
||||
extern "C" {
|
||||
/// `oakcodec_set_task_submit_cb` — install the task submitter (`None`
|
||||
/// unregisters, matching the header's `cb == NULL`).
|
||||
pub fn oakcodec_set_task_submit_cb(
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_set_task_submit_cb(
|
||||
cb: Option<OakCodecTaskSubmitFn>,
|
||||
userdata: *mut c_void,
|
||||
);
|
||||
/// `oakcodec_task_submit_is_registered`.
|
||||
pub fn oakcodec_task_submit_is_registered() -> c_int;
|
||||
) {
|
||||
unsafe { oakcodec::ffi::task::oakcodec_set_task_submit_cb(cb, userdata) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_init`.
|
||||
pub fn oakcodec_decoder_init() -> OakDecoder;
|
||||
/// `oakcodec_decoder_free`.
|
||||
pub fn oakcodec_decoder_free(decoder: *mut OakDecoder);
|
||||
/// `oakcodec_decoder_open`.
|
||||
pub fn oakcodec_decoder_open(
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_task_submit_is_registered() -> c_int {
|
||||
unsafe { oakcodec::ffi::task::oakcodec_task_submit_is_registered() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_init() -> OakDecoder {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_free(decoder: *mut OakDecoder) {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_free(decoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_open(
|
||||
decoder: OakDecoder,
|
||||
filename: *const c_char,
|
||||
stream_index: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_decoder_close`.
|
||||
pub fn oakcodec_decoder_close(decoder: OakDecoder) -> c_int;
|
||||
/// `oakcodec_decoder_is_open`.
|
||||
pub fn oakcodec_decoder_is_open(decoder: OakDecoder) -> c_int;
|
||||
/// `oakcodec_decoder_decode_audio`.
|
||||
pub fn oakcodec_decoder_decode_audio(
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_open(decoder, filename, stream_index) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_close(decoder: OakDecoder) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_close(decoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_is_open(decoder: OakDecoder) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_is_open(decoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_decode_audio(
|
||||
decoder: OakDecoder,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
sample_rate: c_int,
|
||||
channel_layout: c_uint,
|
||||
channel_layout: u64,
|
||||
buf: *mut f32,
|
||||
buf_frames: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_decoder_conform_audio` — the whole-stream conform pass.
|
||||
pub fn oakcodec_decoder_conform_audio(
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_decode_audio(decoder, in_num, in_den, out_num, out_den, sample_rate, channel_layout, buf, buf_frames) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_conform_audio(
|
||||
decoder: OakDecoder,
|
||||
output_filenames: *const *const c_char,
|
||||
filename_count: c_int,
|
||||
@@ -220,65 +144,108 @@ extern "C" {
|
||||
channel_layout: u64,
|
||||
sample_format: c_int,
|
||||
cancelled: OakCancelAtom,
|
||||
) -> c_int;
|
||||
/// `oakcodec_decoder_last_error`.
|
||||
pub fn oakcodec_decoder_last_error(decoder: OakDecoder, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_conform_audio(decoder, output_filenames, filename_count, sample_rate, channel_layout, sample_format, cancelled) }
|
||||
}
|
||||
|
||||
// --- decoder.h: image-sequence heuristics ---
|
||||
/// `oakcodec_decoder_get_image_sequence_digit_count`.
|
||||
pub fn oakcodec_decoder_get_image_sequence_digit_count(filename: *const c_char) -> c_int;
|
||||
/// `oakcodec_decoder_get_image_sequence_index`.
|
||||
pub fn oakcodec_decoder_get_image_sequence_index(filename: *const c_char) -> i64;
|
||||
/// `oakcodec_decoder_transform_image_sequence_file_name` (two-stage).
|
||||
pub fn oakcodec_decoder_transform_image_sequence_file_name(
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_last_error(decoder: OakDecoder, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_last_error(decoder, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_get_image_sequence_digit_count(filename: *const c_char) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_get_image_sequence_digit_count(filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_get_image_sequence_index(filename: *const c_char) -> i64 {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_get_image_sequence_index(filename) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_decoder_transform_image_sequence_file_name(
|
||||
filename: *const c_char,
|
||||
number: i64,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_transform_image_sequence_file_name(filename, number, buf, buf_size) }
|
||||
}
|
||||
|
||||
// --- encoder.h extras ---
|
||||
/// `oakcodec_encoder_get_desired_pixel_format`.
|
||||
pub fn oakcodec_encoder_get_desired_pixel_format(encoder: OakEncoder) -> c_int;
|
||||
/// `oakcodec_encoding_generate_matrix` (row-major 4x4).
|
||||
pub fn oakcodec_encoding_generate_matrix(
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_get_desired_pixel_format(encoder: OakEncoder) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_get_desired_pixel_format(encoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
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;
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoding_generate_matrix(method, src_width, src_height, dst_width, dst_height, out_matrix) }
|
||||
}
|
||||
|
||||
// --- proxy.h ---
|
||||
/// `oakcodec_proxy_find_ffmpeg` (buf/size getter).
|
||||
pub fn oakcodec_proxy_find_ffmpeg(configured_path: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcodec_proxy_params_default`.
|
||||
pub fn oakcodec_proxy_params_default(out: *mut OakCodecProxyParams) -> c_int;
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_proxy_find_ffmpeg(configured_path: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::proxy::oakcodec_proxy_find_ffmpeg(configured_path, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// `oakcodec_encoder_init`.
|
||||
pub fn oakcodec_encoder_init(params: *const OakCodecEncodingParams) -> OakEncoder;
|
||||
/// `oakcodec_encoder_free`.
|
||||
pub fn oakcodec_encoder_free(encoder: *mut OakEncoder);
|
||||
/// `oakcodec_encoder_open`.
|
||||
pub fn oakcodec_encoder_open(encoder: OakEncoder) -> c_int;
|
||||
/// `oakcodec_encoder_write_video`.
|
||||
pub fn oakcodec_encoder_write_video(encoder: OakEncoder, frame: OakFrame) -> c_int;
|
||||
/// `oakcodec_encoder_write_audio`.
|
||||
pub fn oakcodec_encoder_write_audio(
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_proxy_params_default(out: *mut OakCodecProxyParams) -> c_int {
|
||||
unsafe { oakcodec::ffi::proxy::oakcodec_proxy_params_default(out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_init(params: *const OakCodecEncodingParams) -> OakEncoder {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_init(params) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_free(encoder: *mut OakEncoder) {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_free(encoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_open(encoder: OakEncoder) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_open(encoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_write_video(encoder: OakEncoder, frame: OakFrame) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_write_video(encoder, frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_write_audio(
|
||||
encoder: OakEncoder,
|
||||
samples: *const f32,
|
||||
frame_count: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoder_write_subtitle`.
|
||||
pub fn oakcodec_encoder_write_subtitle(
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_write_audio(encoder, samples, frame_count) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_write_subtitle(
|
||||
encoder: OakEncoder,
|
||||
text: *const c_char,
|
||||
in_seconds: f64,
|
||||
out_seconds: f64,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoder_flush`.
|
||||
pub fn oakcodec_encoder_flush(encoder: OakEncoder) -> c_int;
|
||||
/// `oakcodec_encoder_last_error`.
|
||||
pub fn oakcodec_encoder_last_error(encoder: OakEncoder, buf: *mut c_char, buf_size: c_int) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_write_subtitle(encoder, text, in_seconds, out_seconds) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_flush(encoder: OakEncoder) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_flush(encoder) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcodec` crate (single-lib unification).
|
||||
pub fn oakcodec_encoder_last_error(encoder: OakEncoder, buf: *mut c_char, buf_size: c_int) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_last_error(encoder, buf, buf_size) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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 / oakcore C ABI imports. The task module reaches the shared
|
||||
//! value types through `include/common/videoparams.h`,
|
||||
//! `include/common/colortransform.h` and the oakcore audio-params C ABI.
|
||||
@@ -45,12 +61,13 @@ pub const OAKCOMMON_VIDEO_TYPE_STILL: c_int = 1;
|
||||
/// `OAKCOMMON_VIDEO_TYPE_IMAGE_SEQUENCE` (`include/common/videoparams.h`).
|
||||
pub const OAKCOMMON_VIDEO_TYPE_IMAGE_SEQUENCE: c_int = 2;
|
||||
|
||||
extern "C" {
|
||||
// --- videoparams.h ---
|
||||
/// `oakcommon_videoparams_init`.
|
||||
pub fn oakcommon_videoparams_init() -> OakVideoParams;
|
||||
/// `oakcommon_videoparams_init_basic`.
|
||||
pub fn oakcommon_videoparams_init_basic(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_init() -> OakVideoParams {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_init() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_init_basic(
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
pixel_format: c_int,
|
||||
@@ -59,88 +76,146 @@ extern "C" {
|
||||
pixel_aspect_den: c_int,
|
||||
interlacing: c_int,
|
||||
divider: c_int,
|
||||
) -> OakVideoParams;
|
||||
/// `oakcommon_videoparams_free`.
|
||||
pub fn oakcommon_videoparams_free(params: *mut OakVideoParams);
|
||||
/// `oakcommon_videoparams_get_width`.
|
||||
pub fn oakcommon_videoparams_get_width(params: OakVideoParams, width: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_height`.
|
||||
pub fn oakcommon_videoparams_get_height(params: OakVideoParams, height: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_format`.
|
||||
pub fn oakcommon_videoparams_get_format(params: OakVideoParams, format: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_format`.
|
||||
pub fn oakcommon_videoparams_set_format(params: OakVideoParams, format: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_get_time_base`.
|
||||
pub fn oakcommon_videoparams_get_time_base(
|
||||
) -> OakVideoParams {
|
||||
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).
|
||||
pub fn oakcommon_videoparams_free(params: *mut OakVideoParams) {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_free(params) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_get_width(params: OakVideoParams, 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).
|
||||
pub fn oakcommon_videoparams_get_height(params: OakVideoParams, 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).
|
||||
pub fn oakcommon_videoparams_get_format(params: OakVideoParams, 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).
|
||||
pub fn oakcommon_videoparams_set_format(params: OakVideoParams, format: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_format(params, format) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_get_time_base(
|
||||
params: OakVideoParams,
|
||||
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).
|
||||
pub fn oakcommon_videoparams_set_time_base(
|
||||
params: OakVideoParams,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_frame_rate_as_time_base` — frame rate flipped
|
||||
/// to a frame duration rational.
|
||||
pub fn oakcommon_videoparams_frame_rate_as_time_base(
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_time_base(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_frame_rate_as_time_base(
|
||||
params: OakVideoParams,
|
||||
out_num: *mut c_int,
|
||||
out_den: *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_frame_rate_as_time_base(params, out_num, out_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_set_frame_rate(
|
||||
params: OakVideoParams,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_video_type`.
|
||||
pub fn oakcommon_videoparams_get_video_type(params: OakVideoParams, out_type: *mut c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_video_type`.
|
||||
pub fn oakcommon_videoparams_set_video_type(params: OakVideoParams, video_type: c_int) -> c_int;
|
||||
/// `oakcommon_videoparams_set_start_time`.
|
||||
pub fn oakcommon_videoparams_set_start_time(params: OakVideoParams, start: i64) -> c_int;
|
||||
/// `oakcommon_videoparams_set_duration`.
|
||||
pub fn oakcommon_videoparams_set_duration(params: OakVideoParams, duration: i64) -> c_int;
|
||||
/// `oakcommon_videoparams_get_is_valid`.
|
||||
pub fn oakcommon_videoparams_get_is_valid(params: OakVideoParams, out_valid: *mut 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_frame_rate(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_get_video_type(params: OakVideoParams, out_type: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_video_type(params, out_type) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_set_video_type(params: OakVideoParams, video_type: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_video_type(params, video_type) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_set_start_time(params: OakVideoParams, start: i64) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_start_time(params, start) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_set_duration(params: OakVideoParams, duration: i64) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_duration(params, duration) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_get_is_valid(params: OakVideoParams, out_valid: *mut c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_is_valid(params, out_valid) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_get_frame_rate(
|
||||
params: OakVideoParams,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_videoparams_get_duration`.
|
||||
pub fn oakcommon_videoparams_get_duration(params: OakVideoParams, duration: *mut i64) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_frame_rate(params, numerator, denominator) }
|
||||
}
|
||||
|
||||
// --- colortransform.h ---
|
||||
/// `oakcommon_colortransform_init_display`.
|
||||
pub fn oakcommon_colortransform_init_display(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_videoparams_get_duration(params: OakVideoParams, duration: *mut i64) -> c_int {
|
||||
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_duration(params, duration) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_colortransform_init_display(
|
||||
display: *const c_char,
|
||||
view: *const c_char,
|
||||
look: *const c_char,
|
||||
) -> OakColorTransform;
|
||||
/// `oakcommon_colortransform_init_output`.
|
||||
pub fn oakcommon_colortransform_init_output(
|
||||
output: *const c_char,
|
||||
display: *const c_char,
|
||||
view: *const c_char,
|
||||
look: *const c_char,
|
||||
) -> OakColorTransform;
|
||||
/// `oakcommon_colortransform_free`.
|
||||
pub fn oakcommon_colortransform_free(transform: *mut OakColorTransform);
|
||||
) -> OakColorTransform {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_display(display, view, look) }
|
||||
}
|
||||
|
||||
// --- config.h ---
|
||||
/// `oakcommon_config_get` (buf/size getter; returns needed size).
|
||||
pub fn oakcommon_config_get(
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_colortransform_init_output(output: *const c_char) -> OakColorTransform {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_output(output) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_colortransform_free(transform: *mut OakColorTransform) {
|
||||
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_free(transform) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
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`.
|
||||
pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, default: c_int) -> c_int;
|
||||
/// `oakcommon_config_get_bool`.
|
||||
pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, default: c_int) -> c_int;
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get(group, key, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, default: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_int(group, key, default) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, default: c_int) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_bool(group, key, default) }
|
||||
}
|
||||
|
||||
|
||||
+788
-333
File diff suppressed because it is too large
Load Diff
+166
-258
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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. The task module reaches the render side through
|
||||
//! `include/render/cancelatom.h` (task cancellation), `include/render/ticket.h`
|
||||
//! (frame/audio render tickets), `include/render/copier.h` (export project
|
||||
@@ -37,166 +53,27 @@ use crate::bridge::node::{OakNodeColorManager, OakNodeNode, OakNodeProject};
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// Mirror of `OakCancelAtom` (`include/render/cancelatom.h`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakCancelAtom {
|
||||
/// Opaque pointer to the reference-counted object.
|
||||
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 (`OAKRENDER_ABI_VERSION`).
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakCancelAtom = oakrender::ffi::OakCancelAtom;
|
||||
|
||||
impl OakCancelAtom {
|
||||
/// The empty (null) atom.
|
||||
pub fn null() -> Self {
|
||||
OakCancelAtom {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the atom is empty (`ctx == NULL`).
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ctx.is_null()
|
||||
}
|
||||
|
||||
/// Adopt the fields of a generic `CHandle` (layout-identical) — the task
|
||||
/// module stores the atom as a `CHandle` for its public API.
|
||||
pub fn from_chandle(h: CHandle) -> Self {
|
||||
OakCancelAtom {
|
||||
ctx: h.ctx,
|
||||
addref: h.addref,
|
||||
release: h.release,
|
||||
abi_version: h.abi_version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert back to a generic `CHandle` (layout-identical).
|
||||
pub fn to_chandle(&self) -> CHandle {
|
||||
CHandle {
|
||||
ctx: self.ctx,
|
||||
addref: self.addref,
|
||||
release: self.release,
|
||||
abi_version: self.abi_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror of `OakRenderTicket` (`include/render/ticket.h`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakRenderTicket {
|
||||
/// Opaque pointer to the reference-counted object.
|
||||
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 (`OAKRENDER_ABI_VERSION`).
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakRenderTicket = oakrender::ffi::OakRenderTicket;
|
||||
|
||||
|
||||
/// Mirror of `OakRenderCache` (`include/render/cache.h`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakRenderCache {
|
||||
/// Opaque pointer to the reference-counted object.
|
||||
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 (`OAKRENDER_ABI_VERSION`).
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakRenderCache = oakrender::ffi::OakRenderCache;
|
||||
|
||||
impl OakRenderCache {
|
||||
/// The empty (null) cache handle.
|
||||
pub fn null() -> Self {
|
||||
OakRenderCache {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to the layout-identical generic `CHandle`.
|
||||
pub fn to_chandle(&self) -> CHandle {
|
||||
CHandle {
|
||||
ctx: self.ctx,
|
||||
addref: self.addref,
|
||||
release: self.release,
|
||||
abi_version: self.abi_version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adopt the fields of a generic `CHandle` (layout-identical).
|
||||
pub fn from_chandle(h: CHandle) -> Self {
|
||||
OakRenderCache {
|
||||
ctx: h.ctx,
|
||||
addref: h.addref,
|
||||
release: h.release,
|
||||
abi_version: h.abi_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror of `OakRenderProjectCopier` (`include/render/copier.h`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakRenderProjectCopier {
|
||||
/// Opaque pointer to the reference-counted object.
|
||||
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 (`OAKRENDER_ABI_VERSION`).
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakRenderProjectCopier = oakrender::ffi::OakRenderProjectCopier;
|
||||
|
||||
|
||||
/// Mirror of `OakColorProcessor` (`include/render/color.h`).
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OakColorProcessor {
|
||||
/// Opaque pointer to the reference-counted object.
|
||||
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 (`OAKRENDER_ABI_VERSION`).
|
||||
pub abi_version: u32,
|
||||
}
|
||||
pub type OakColorProcessor = oakrender::ffi::OakColorProcessor;
|
||||
|
||||
impl OakColorProcessor {
|
||||
/// Convert to the layout-identical generic `CHandle`.
|
||||
pub fn to_chandle(&self) -> CHandle {
|
||||
CHandle {
|
||||
ctx: self.ctx,
|
||||
addref: self.addref,
|
||||
release: self.release,
|
||||
abi_version: self.abi_version,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adopt the fields of a generic `CHandle` (layout-identical).
|
||||
pub fn from_chandle(h: CHandle) -> Self {
|
||||
OakColorProcessor {
|
||||
ctx: h.ctx,
|
||||
addref: h.addref,
|
||||
release: h.release,
|
||||
abi_version: h.abi_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror of `oakrender_ticket_finished_fn` (`include/render/ticket.h`).
|
||||
///
|
||||
@@ -208,64 +85,45 @@ impl OakColorProcessor {
|
||||
pub type OakRenderTicketFinishedFn = unsafe extern "C" fn(ticket: OakRenderTicket, userdata: *mut c_void);
|
||||
|
||||
/// Mirror of `oakrender_video_ticket_params` (`include/render/ticket.h`).
|
||||
#[repr(C)]
|
||||
pub struct OakRenderVideoTicketParams {
|
||||
/// Connected texture output node (borrowed).
|
||||
pub output_node: OakNodeNode,
|
||||
/// Video params by value (oakcommon handle).
|
||||
pub video_params: OakVideoParams,
|
||||
/// Borrowed oakcore audio params, may be null ctx.
|
||||
pub audio_params: *const OakAudioParams,
|
||||
/// Frame timestamp numerator (seconds rational).
|
||||
pub time_num: i64,
|
||||
/// Frame timestamp denominator.
|
||||
pub time_den: i64,
|
||||
/// Borrowed color manager; empty ctx = NULL.
|
||||
pub color_manager: OakNodeColorManager,
|
||||
/// `olive::RenderMode::Mode` as int.
|
||||
pub mode: c_int,
|
||||
/// Forced output width (0 = off).
|
||||
pub force_width: c_int,
|
||||
/// Forced output height (0 = off).
|
||||
pub force_height: c_int,
|
||||
/// Forced color matrix (used when `has_force_matrix` != 0).
|
||||
pub force_matrix: [f64; 16],
|
||||
/// Whether `force_matrix` is in effect.
|
||||
pub has_force_matrix: c_int,
|
||||
/// Forced pixel format (`PixelFormat` as int, -1 = off).
|
||||
pub force_format: c_int,
|
||||
/// Forced channel count (0 = off).
|
||||
pub force_channel_count: c_int,
|
||||
/// Forced color output (borrowed; empty ctx = none).
|
||||
pub force_color_output: OakColorProcessor,
|
||||
/// Forced color transform by value (empty ctx = default).
|
||||
pub force_color_transform: OakColorTransform,
|
||||
/// Borrowed frame cache; empty ctx = none.
|
||||
pub cache: OakRenderCache,
|
||||
pub type OakRenderVideoTicketParams = oakrender::ffi::OakVideoTicketParams;
|
||||
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_cancelatom_init() -> OakCancelAtom {
|
||||
unsafe { oakrender::ffi::cancelatom::oakrender_cancelatom_init() }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// --- cancelatom.h ---
|
||||
/// `oakrender_cancelatom_init`.
|
||||
pub fn oakrender_cancelatom_init() -> OakCancelAtom;
|
||||
/// `oakrender_cancelatom_free`.
|
||||
pub fn oakrender_cancelatom_free(atom: *mut OakCancelAtom);
|
||||
/// `oakrender_cancelatom_cancel`.
|
||||
pub fn oakrender_cancelatom_cancel(atom: OakCancelAtom) -> c_int;
|
||||
/// `oakrender_cancelatom_is_cancelled`.
|
||||
pub fn oakrender_cancelatom_is_cancelled(atom: OakCancelAtom, cancelled: *mut c_int) -> c_int;
|
||||
/// `oakrender_cancelatom_heard_cancel`.
|
||||
pub fn oakrender_cancelatom_heard_cancel(atom: OakCancelAtom, heard: *mut c_int) -> c_int;
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_cancelatom_free(atom: *mut OakCancelAtom) {
|
||||
unsafe { oakrender::ffi::cancelatom::oakrender_cancelatom_free(atom) }
|
||||
}
|
||||
|
||||
// --- ticket.h ---
|
||||
/// `oakrender_ticket_render_frame`.
|
||||
pub fn oakrender_ticket_render_frame(
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_cancelatom_cancel(atom: OakCancelAtom) -> c_int {
|
||||
unsafe { oakrender::ffi::cancelatom::oakrender_cancelatom_cancel(atom) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_cancelatom_is_cancelled(atom: OakCancelAtom, cancelled: *mut c_int) -> c_int {
|
||||
unsafe { oakrender::ffi::cancelatom::oakrender_cancelatom_is_cancelled(atom, cancelled) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_cancelatom_heard_cancel(atom: OakCancelAtom, heard: *mut c_int) -> c_int {
|
||||
unsafe { oakrender::ffi::cancelatom::oakrender_cancelatom_heard_cancel(atom, heard) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_render_frame(
|
||||
params: *const OakRenderVideoTicketParams,
|
||||
cb: Option<OakRenderTicketFinishedFn>,
|
||||
userdata: *mut c_void,
|
||||
) -> OakRenderTicket;
|
||||
/// `oakrender_ticket_render_audio`.
|
||||
pub fn oakrender_ticket_render_audio(
|
||||
) -> OakRenderTicket {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_render_frame(params, cb, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_render_audio(
|
||||
output_node: OakNodeNode,
|
||||
in_num: i64,
|
||||
in_den: i64,
|
||||
@@ -275,80 +133,125 @@ extern "C" {
|
||||
mode: c_int,
|
||||
cb: Option<OakRenderTicketFinishedFn>,
|
||||
userdata: *mut c_void,
|
||||
) -> OakRenderTicket;
|
||||
/// `oakrender_ticket_is_finished`.
|
||||
pub fn oakrender_ticket_is_finished(ticket: OakRenderTicket) -> c_int;
|
||||
/// `oakrender_ticket_wait`.
|
||||
pub fn oakrender_ticket_wait(ticket: OakRenderTicket) -> c_int;
|
||||
/// `oakrender_ticket_cancel`.
|
||||
pub fn oakrender_ticket_cancel(ticket: OakRenderTicket) -> c_int;
|
||||
/// `oakrender_ticket_get_type`.
|
||||
pub fn oakrender_ticket_get_type(ticket: OakRenderTicket) -> c_int;
|
||||
/// `oakrender_ticket_get_frame`.
|
||||
pub fn oakrender_ticket_get_frame(ticket: OakRenderTicket, out: *mut OakFrame) -> c_int;
|
||||
/// `oakrender_ticket_get_time`.
|
||||
pub fn oakrender_ticket_get_time(ticket: OakRenderTicket, out_num: *mut i64, out_den: *mut i64) -> c_int;
|
||||
/// `oakrender_ticket_get_range`.
|
||||
pub fn oakrender_ticket_get_range(
|
||||
) -> OakRenderTicket {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_render_audio(output_node, in_num, in_den, out_num, out_den, params, mode, cb, userdata) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_is_finished(ticket: OakRenderTicket) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_is_finished(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_wait(ticket: OakRenderTicket) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_wait(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_cancel(ticket: OakRenderTicket) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_cancel(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_get_type(ticket: OakRenderTicket) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_type(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_get_frame(ticket: OakRenderTicket, out: *mut OakFrame) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_frame(ticket, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_get_time(ticket: OakRenderTicket, out_num: *mut i64, out_den: *mut i64) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_time(ticket, out_num, out_den) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_get_range(
|
||||
ticket: OakRenderTicket,
|
||||
in_num: *mut i64,
|
||||
in_den: *mut i64,
|
||||
out_num: *mut i64,
|
||||
out_den: *mut i64,
|
||||
) -> c_int;
|
||||
/// `oakrender_ticket_get_samples`.
|
||||
pub fn oakrender_ticket_get_samples(ticket: OakRenderTicket, out: *mut *mut std::ffi::c_void) -> c_int;
|
||||
/// `oakrender_ticket_free`.
|
||||
pub fn oakrender_ticket_free(ticket: *mut OakRenderTicket);
|
||||
) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_range(ticket, in_num, in_den, out_num, out_den) }
|
||||
}
|
||||
|
||||
// --- copier.h ---
|
||||
/// `oakrender_project_copier_create`.
|
||||
pub fn oakrender_project_copier_create() -> OakRenderProjectCopier;
|
||||
/// `oakrender_project_copier_free`.
|
||||
pub fn oakrender_project_copier_free(copier: *mut OakRenderProjectCopier);
|
||||
/// `oakrender_project_copier_set_project`.
|
||||
pub fn oakrender_project_copier_set_project(
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_get_samples(ticket: OakRenderTicket, out: *mut *mut std::ffi::c_void) -> c_int {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_samples(ticket, out) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_ticket_free(ticket: *mut OakRenderTicket) {
|
||||
unsafe { oakrender::ffi::ticket::oakrender_ticket_free(ticket) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_project_copier_create() -> OakRenderProjectCopier {
|
||||
unsafe { oakrender::ffi::copier::oakrender_project_copier_create() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_project_copier_free(copier: *mut OakRenderProjectCopier) {
|
||||
unsafe { oakrender::ffi::copier::oakrender_project_copier_free(copier) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_project_copier_set_project(
|
||||
copier: OakRenderProjectCopier,
|
||||
project: OakNodeProject,
|
||||
) -> c_int;
|
||||
/// `oakrender_project_copier_get_copy`.
|
||||
pub fn oakrender_project_copier_get_copy(
|
||||
) -> c_int {
|
||||
unsafe { oakrender::ffi::copier::oakrender_project_copier_set_project(copier, project) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_project_copier_get_copy(
|
||||
copier: OakRenderProjectCopier,
|
||||
original: OakNodeNode,
|
||||
) -> OakNodeNode;
|
||||
/// `oakrender_project_copier_get_copied_project`.
|
||||
pub fn oakrender_project_copier_get_copied_project(
|
||||
copier: OakRenderProjectCopier,
|
||||
) -> OakNodeProject;
|
||||
) -> OakNodeNode {
|
||||
unsafe { oakrender::ffi::copier::oakrender_project_copier_get_copy(copier, original) }
|
||||
}
|
||||
|
||||
// --- color.h ---
|
||||
/// `oakrender_color_processor_create` — builds a processor between two
|
||||
/// color spaces; `direction` is `OAKRENDER_COLOR_DIRECTION_*`
|
||||
/// (include/render/color.h).
|
||||
pub fn oakrender_color_processor_create(
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_project_copier_get_copied_project(
|
||||
copier: OakRenderProjectCopier,
|
||||
) -> OakNodeProject {
|
||||
unsafe { oakrender::ffi::copier::oakrender_project_copier_get_copied_project(copier) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_color_processor_create(
|
||||
src_space: *const c_char,
|
||||
dst_transform: *const c_char,
|
||||
direction: c_int,
|
||||
) -> OakColorProcessor;
|
||||
/// `oakrender_color_processor_free`.
|
||||
pub fn oakrender_color_processor_free(processor: *mut OakColorProcessor);
|
||||
/// `oakrender_color_processor_is_valid`.
|
||||
pub fn oakrender_color_processor_is_valid(processor: OakColorProcessor) -> c_int;
|
||||
) -> OakColorProcessor {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_create(src_space, dst_transform, direction) }
|
||||
}
|
||||
|
||||
// --- renderer.h ---
|
||||
/// `oakrender_codec_frame_free` — release a frame handed out by a
|
||||
/// render ticket.
|
||||
pub fn oakrender_codec_frame_free(frame: *mut crate::bridge::codec::OakFrame);
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_color_processor_free(processor: *mut OakColorProcessor) {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_free(processor) }
|
||||
}
|
||||
|
||||
// --- manager.h ---
|
||||
/// `oakrender_manager_set_aggressive_gc`.
|
||||
pub fn oakrender_manager_set_aggressive_gc(enabled: c_int) -> c_int;
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_color_processor_is_valid(processor: OakColorProcessor) -> c_int {
|
||||
unsafe { oakrender::ffi::color::oakrender_color_processor_is_valid(processor) }
|
||||
}
|
||||
|
||||
// --- cache.h ---
|
||||
/// `oakrender_cache_get_invalidated_ranges` — two-stage range query on
|
||||
/// a frame cache; returns the number of ranges (or the required flat
|
||||
/// array size).
|
||||
pub fn oakrender_cache_get_invalidated_ranges(
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_codec_frame_free(frame: *mut crate::bridge::codec::OakFrame) {
|
||||
unsafe { oakrender::ffi::renderer::oakrender_codec_frame_free(frame) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
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).
|
||||
pub fn oakrender_cache_get_invalidated_ranges(
|
||||
cache: OakRenderCache,
|
||||
in_num: i64,
|
||||
in_den: i64,
|
||||
@@ -356,7 +259,12 @@ extern "C" {
|
||||
out_den: i64,
|
||||
flat: *mut i64,
|
||||
flat_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakrender_cache_free`.
|
||||
pub fn oakrender_cache_free(cache: *mut OakRenderCache);
|
||||
) -> c_int {
|
||||
unsafe { oakrender::ffi::cache::oakrender_cache_get_invalidated_ranges(cache, in_num, in_den, out_num, out_den, flat, flat_size) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakrender` crate (single-lib unification).
|
||||
pub fn oakrender_cache_free(cache: *mut OakRenderCache) {
|
||||
unsafe { oakrender::ffi::cache::oakrender_cache_free(cache) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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. The OTIO load task builds tracks through the
|
||||
//! timeline edit factories (`include/timeline/edit.h`) instead of the raw
|
||||
//! track-list primitives, matching `src/task/src/project/loadotio/loadotio.cpp`.
|
||||
@@ -22,8 +38,8 @@
|
||||
use crate::bridge::node::OakNodeTrackList;
|
||||
use crate::bridge::undo::OakUndoCommand;
|
||||
|
||||
extern "C" {
|
||||
/// `oaktimeline_add_track_command` (`include/timeline/edit.h`) —
|
||||
/// olive::TimelineAddTrackCommand.
|
||||
pub fn oaktimeline_add_track_command(list: OakNodeTrackList) -> OakUndoCommand;
|
||||
/// Direct call into the `oaktimeline` crate (single-lib unification).
|
||||
pub fn oaktimeline_add_track_command(list: OakNodeTrackList) -> OakUndoCommand {
|
||||
unsafe { oaktimeline::ffi::edit::oaktimeline_add_track_command(list) }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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. Import/load tasks build undo commands through the
|
||||
//! C ABI vtable (`oakundo_command_init` with Rust closures as userdata) —
|
||||
//! no C++ UndoCommand subclassing exists on this side. Mirrors
|
||||
@@ -27,31 +43,46 @@ use crate::handle::CHandle;
|
||||
pub type OakUndoCommand = CHandle;
|
||||
|
||||
/// Mirror of `OakUndoCommandVtable` (`include/undo/undocommand.h`).
|
||||
#[repr(C)]
|
||||
pub struct OakUndoCommandVtable {
|
||||
/// Redo callback; may be NULL.
|
||||
pub redo: Option<unsafe extern "C" fn(userdata: *mut c_void)>,
|
||||
/// Undo callback; may be NULL.
|
||||
pub undo: Option<unsafe extern "C" fn(userdata: *mut c_void)>,
|
||||
/// Free callback; may be NULL.
|
||||
pub free_fn: Option<unsafe extern "C" fn(userdata: *mut c_void)>,
|
||||
pub type OakUndoCommandVtable = oakundo::undocommand::OakUndoCommandVtable;
|
||||
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> OakUndoCommand {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
/// `oakundo_command_init` (vtable command).
|
||||
pub fn oakundo_command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> OakUndoCommand;
|
||||
/// `oakundo_command_init_multi`.
|
||||
pub fn oakundo_command_init_multi() -> OakUndoCommand;
|
||||
/// `oakundo_command_multi_add_child`.
|
||||
pub fn oakundo_command_multi_add_child(multi: OakUndoCommand, child: OakUndoCommand) -> c_int;
|
||||
/// `oakundo_command_multi_child_count`.
|
||||
pub fn oakundo_command_multi_child_count(multi: OakUndoCommand, out_count: *mut c_int) -> c_int;
|
||||
/// `oakundo_command_multi_child`.
|
||||
pub fn oakundo_command_multi_child(multi: OakUndoCommand, index: c_int, out_child: *mut OakUndoCommand) -> c_int;
|
||||
/// `oakundo_command_redo_now`.
|
||||
pub fn oakundo_command_redo_now(command: OakUndoCommand) -> c_int;
|
||||
/// `oakundo_command_undo_now`.
|
||||
pub fn oakundo_command_undo_now(command: OakUndoCommand) -> c_int;
|
||||
/// `oakundo_command_free`.
|
||||
pub fn oakundo_command_free(command: *mut OakUndoCommand);
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_init_multi() -> OakUndoCommand {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init_multi() }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_multi_add_child(multi: OakUndoCommand, child: OakUndoCommand) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_multi_child_count(multi: OakUndoCommand, 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).
|
||||
pub fn oakundo_command_multi_child(multi: OakUndoCommand, index: c_int, out_child: *mut OakUndoCommand) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_child(multi, index, out_child) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_redo_now(command: OakUndoCommand) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_undo_now(command: OakUndoCommand) -> c_int {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_undo_now(command) }
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_free(command: *mut OakUndoCommand) {
|
||||
unsafe { oakundo::ffi::command::oakundo_command_free(command) }
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ fn proxy_params_from_codec(params: &bridge::codec::OakCodecProxyParams) -> Proxy
|
||||
}
|
||||
|
||||
/// Read a NUL-terminated char array into a String (lossy).
|
||||
unsafe fn cstr_buf_to_string(buf: &[c_char]) -> String {
|
||||
unsafe fn cstr_buf_to_string(buf: &[u8]) -> String {
|
||||
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
|
||||
let bytes = unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, len) };
|
||||
String::from_utf8_lossy(bytes).into_owned()
|
||||
|
||||
@@ -142,7 +142,7 @@ impl TaskBehavior for ConformTask {
|
||||
self.sample_rate,
|
||||
self.channel_layout,
|
||||
self.sample_format,
|
||||
bridge::render::OakCancelAtom::from_chandle(task.get_cancel_atom()),
|
||||
task.get_cancel_atom(),
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
|
||||
@@ -49,7 +49,7 @@ impl CustomCacheState {
|
||||
pub fn finish(&self) {
|
||||
*self.cancelled_through_finish.lock().unwrap() = true;
|
||||
if !self.atom.is_null() {
|
||||
let atom = crate::bridge::render::OakCancelAtom::from_chandle(self.atom);
|
||||
let atom = self.atom;
|
||||
unsafe {
|
||||
crate::bridge::render::oakrender_cancelatom_cancel(atom);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ impl CustomCacheState {
|
||||
/// hook. Used by the owning cache to abort a fill.
|
||||
pub fn cancel(&self) {
|
||||
if !self.atom.is_null() {
|
||||
let atom = crate::bridge::render::OakCancelAtom::from_chandle(self.atom);
|
||||
let atom = self.atom;
|
||||
unsafe {
|
||||
crate::bridge::render::oakrender_cancelatom_cancel(atom);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ impl ExportTask {
|
||||
};
|
||||
let bytes = self.encoding_params.filename.as_bytes();
|
||||
let n = bytes.len().min(1023);
|
||||
params.filename[..n].copy_from_slice(unsafe { std::slice::from_raw_parts(bytes.as_ptr() as *const i8, n) });
|
||||
params.filename[..n].copy_from_slice(&bytes[..n]);
|
||||
params.format = self.encoding_params.format;
|
||||
params.video_enabled = self.encoding_params.video_enabled as i32;
|
||||
params.video_codec = self.encoding_params.video_codec;
|
||||
|
||||
@@ -386,8 +386,7 @@ unsafe fn convert_encoding_params(p: &OakCodecEncodingParams) -> EncodingParams
|
||||
}
|
||||
|
||||
/// Read a NUL-terminated char array into a String (lossy).
|
||||
unsafe fn c_char_array_to_string(buf: &[c_char]) -> String {
|
||||
unsafe fn c_char_array_to_string(buf: &[u8]) -> String {
|
||||
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
|
||||
let bytes = unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, len) };
|
||||
String::from_utf8_lossy(bytes).into_owned()
|
||||
String::from_utf8_lossy(&buf[..len]).into_owned()
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ impl TaskBehavior for PreCacheTask {
|
||||
bridge::node::oaknode_node_get_video_frame_cache(self.sequence, &mut cache);
|
||||
}
|
||||
|
||||
self.render.set_render_inputs(color_manager, cache.to_chandle(), 0 /* k_online */, false, range);
|
||||
self.render.set_render_inputs(color_manager, cache, 0 /* k_online */, false, range);
|
||||
|
||||
// Drive the render with `self` as the subclass behavior (the C++
|
||||
// virtual dispatch receiver); the render is temporarily moved out to
|
||||
|
||||
@@ -197,7 +197,7 @@ impl ProjectImportTask {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
bridge::node::oaknode_footage_set_cancel_atom(footage, bridge::render::OakCancelAtom::from_chandle(task.get_cancel_atom()));
|
||||
bridge::node::oaknode_footage_set_cancel_atom(footage, task.get_cancel_atom());
|
||||
}
|
||||
let ok = unsafe { bridge::node::oaknode_footage_set_filename(footage, cstr(file_path)) } == 0;
|
||||
unsafe {
|
||||
|
||||
@@ -259,14 +259,14 @@ impl RenderTask {
|
||||
has_force_matrix: if force.has_force_matrix { 1 } else { 0 },
|
||||
force_format: force.force_format,
|
||||
force_channel_count: force.force_channel_count,
|
||||
force_color_output: bridge::render::OakColorProcessor::from_chandle(force.force_color_output),
|
||||
force_color_output: force.force_color_output,
|
||||
force_color_transform: OakColorTransform {
|
||||
ctx: std::ptr::null_mut(),
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 0,
|
||||
},
|
||||
cache: bridge::render::OakRenderCache::from_chandle(self.cache),
|
||||
cache: self.cache,
|
||||
};
|
||||
|
||||
let ticket = unsafe {
|
||||
|
||||
@@ -122,7 +122,7 @@ impl Drop for Task {
|
||||
// Free the cancellation atom only when we created it ourselves;
|
||||
// borrowed atoms are released by their owner.
|
||||
if self.owns_atom && !self.cancel_atom.is_null() {
|
||||
let mut atom = bridge::render::OakCancelAtom::from_chandle(self.cancel_atom);
|
||||
let mut atom = self.cancel_atom;
|
||||
unsafe {
|
||||
bridge::render::oakrender_cancelatom_free(&mut atom);
|
||||
}
|
||||
@@ -137,7 +137,7 @@ impl Task {
|
||||
pub fn new(title: &str, cancel_atom: CHandle) -> Task {
|
||||
let (cancel_atom, owns_atom) = if cancel_atom.is_null() {
|
||||
let atom = unsafe { bridge::render::oakrender_cancelatom_init() };
|
||||
(atom.to_chandle(), true)
|
||||
(atom, true)
|
||||
} else {
|
||||
(cancel_atom, false)
|
||||
};
|
||||
@@ -210,7 +210,7 @@ impl Task {
|
||||
/// invoke the cancel event callback if one is registered.
|
||||
pub fn cancel(&mut self) {
|
||||
if !self.cancel_atom.is_null() {
|
||||
let atom = bridge::render::OakCancelAtom::from_chandle(self.cancel_atom);
|
||||
let atom = self.cancel_atom;
|
||||
unsafe {
|
||||
bridge::render::oakrender_cancelatom_cancel(atom);
|
||||
}
|
||||
@@ -225,7 +225,7 @@ impl Task {
|
||||
if self.cancel_atom.is_null() {
|
||||
return false;
|
||||
}
|
||||
let atom = bridge::render::OakCancelAtom::from_chandle(self.cancel_atom);
|
||||
let atom = self.cancel_atom;
|
||||
let mut cancelled = 0;
|
||||
unsafe {
|
||||
bridge::render::oakrender_cancelatom_is_cancelled(atom, &mut cancelled);
|
||||
@@ -243,7 +243,7 @@ impl Task {
|
||||
/// between a task and its behavior's inner base task.
|
||||
pub fn set_cancel_atom(&mut self, atom: CHandle) {
|
||||
if self.owns_atom && !self.cancel_atom.is_null() {
|
||||
let mut old = bridge::render::OakCancelAtom::from_chandle(self.cancel_atom);
|
||||
let mut old = self.cancel_atom;
|
||||
unsafe {
|
||||
bridge::render::oakrender_cancelatom_free(&mut old);
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ pub fn fake_atom() -> oaktask::bridge::render::OakCancelAtom {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_cstr(s: &str, buf: *mut c_char, size: i32) -> i32 {
|
||||
pub fn write_cstr(s: &str, buf: *mut u8, size: i32) -> i32 {
|
||||
let bytes = s.as_bytes();
|
||||
let needed = bytes.len() as i32 + 1;
|
||||
if !buf.is_null() && size >= needed {
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(bytes.as_ptr() as *const c_char, buf, bytes.len());
|
||||
std::ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
|
||||
*buf.add(bytes.len()) = 0;
|
||||
}
|
||||
}
|
||||
@@ -346,7 +346,7 @@ pub unsafe extern "C" fn oakcodec_decoder_last_error(
|
||||
buf: *mut c_char,
|
||||
size: c_int,
|
||||
) -> c_int {
|
||||
write_cstr(&DECODER_LAST_ERROR.lock().unwrap().clone(), buf, size)
|
||||
write_cstr(&DECODER_LAST_ERROR.lock().unwrap().clone(), buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -390,7 +390,7 @@ pub unsafe extern "C" fn oakcodec_decoder_transform_image_sequence_file_name(
|
||||
let count = digits.len().max(1);
|
||||
let prefix = &stem[..stem.len() - digits.len()];
|
||||
let out = format!("{prefix}{:0count$}{ext}", number);
|
||||
write_cstr(&out, buf, size)
|
||||
write_cstr(&out, buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -460,7 +460,7 @@ pub unsafe extern "C" fn oakcodec_encoder_last_error(
|
||||
size: c_int,
|
||||
) -> c_int {
|
||||
if ENCODER_FLUSH_ERROR.load(Ordering::SeqCst) != 0 {
|
||||
write_cstr(&ENCODER_LAST_ERROR.lock().unwrap().clone(), buf, size)
|
||||
write_cstr(&ENCODER_LAST_ERROR.lock().unwrap().clone(), buf as *mut u8, size)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -485,7 +485,7 @@ pub unsafe extern "C" fn oakcodec_encoding_generate_matrix(
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oakcodec_export_format_get_extension(_format: c_int, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("srt", buf, size)
|
||||
write_cstr("srt", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -498,7 +498,7 @@ pub unsafe extern "C" fn oakcodec_proxy_find_ffmpeg(
|
||||
if path.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
write_cstr(&path, buf, size)
|
||||
write_cstr(&path, buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -729,7 +729,7 @@ pub unsafe extern "C" fn oakcommon_config_get(
|
||||
}
|
||||
let key = std::ffi::CStr::from_ptr(key).to_string_lossy().into_owned();
|
||||
if key == "DefaultSequenceFrameRate" && CONFIG_DEFAULT_SEQ_FRAME_RATE.load(Ordering::SeqCst) != 0 {
|
||||
write_cstr("25/1", buf, size)
|
||||
write_cstr("25/1", buf as *mut u8, size)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -774,17 +774,17 @@ pub unsafe extern "C" fn oaknode_project_root(_project: oaktask::bridge::node::O
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_project_name(_project: oaktask::bridge::node::OakNodeProject, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("proj", buf, size)
|
||||
write_cstr("proj", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_project_filename(_project: oaktask::bridge::node::OakNodeProject, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr(&PROJECT_FILENAME.lock().unwrap().clone(), buf, size)
|
||||
write_cstr(&PROJECT_FILENAME.lock().unwrap().clone(), buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_project_pretty_filename(_project: oaktask::bridge::node::OakNodeProject, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("pretty", buf, size)
|
||||
write_cstr("pretty", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -809,7 +809,7 @@ pub unsafe extern "C" fn oaknode_project_is_new(_project: oaktask::bridge::node:
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_project_cache_path(_project: oaktask::bridge::node::OakNodeProject, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("/tmp/oak-cache", buf, size)
|
||||
write_cstr("/tmp/oak-cache", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -829,7 +829,7 @@ pub unsafe extern "C" fn oaknode_project_set_cache_location_setting(_project: oa
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_project_get_custom_cache_path(_project: oaktask::bridge::node::OakNodeProject, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("", buf, size)
|
||||
write_cstr("", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -839,7 +839,7 @@ pub unsafe extern "C" fn oaknode_project_set_custom_cache_path(_project: oaktask
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_project_get_uuid(_project: oaktask::bridge::node::OakNodeProject, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("uuid", buf, size)
|
||||
write_cstr("uuid", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -941,7 +941,7 @@ pub unsafe extern "C" fn oaknode_footage_as_node(footage: oaktask::bridge::node:
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_footage_filename(_footage: oaktask::bridge::node::OakNodeFootage, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr(&FOOTAGE_FILENAME.lock().unwrap().clone(), buf, size)
|
||||
write_cstr(&FOOTAGE_FILENAME.lock().unwrap().clone(), buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -973,7 +973,7 @@ pub unsafe extern "C" fn oaknode_footage_set_timestamp(_footage: oaktask::bridge
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_footage_decoder(_footage: oaktask::bridge::node::OakNodeFootage, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("ffmpeg", buf, size)
|
||||
write_cstr("ffmpeg", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1023,7 +1023,7 @@ pub unsafe extern "C" fn oaknode_footage_set_proxy_enabled(_footage: oaktask::br
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_footage_proxy_path(_footage: oaktask::bridge::node::OakNodeFootage, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("", buf, size)
|
||||
write_cstr("", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1335,7 +1335,7 @@ pub unsafe extern "C" fn oaknode_tracklist_get_sequence(_list: oaktask::bridge::
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_tracklist_get_track_input_id(_list: oaktask::bridge::node::OakNodeTrackList, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("sub_in", buf, size)
|
||||
write_cstr("sub_in", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1648,7 +1648,7 @@ pub unsafe extern "C" fn oaknode_serializer_savedata_set_property(
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_serializer_save_to_xml(_save_data: oaktask::bridge::node::OakNodeSerializerSaveData, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr("<oakproj/>", buf, size)
|
||||
write_cstr("<oakproj/>", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1667,7 +1667,7 @@ pub unsafe extern "C" fn oaknode_serializer_load_from_xml(
|
||||
if !_out_load_data.is_null() {
|
||||
*_out_load_data = fake_handle();
|
||||
}
|
||||
write_cstr(&SERIALIZER_DETAILS.lock().unwrap().clone(), _details, _details_size);
|
||||
write_cstr(&SERIALIZER_DETAILS.lock().unwrap().clone(), _details as *mut u8, _details_size);
|
||||
SERIALIZER_LOAD_RET.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
@@ -1692,7 +1692,7 @@ pub unsafe extern "C" fn oaknode_serializer_loaddata_get_property(
|
||||
buf: *mut c_char,
|
||||
size: c_int,
|
||||
) -> c_int {
|
||||
write_cstr("", buf, size)
|
||||
write_cstr("", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1726,7 +1726,7 @@ pub unsafe extern "C" fn oaknode_serializer_save_to_file(
|
||||
if !out_code.is_null() {
|
||||
*out_code = code;
|
||||
}
|
||||
write_cstr(&SERIALIZER_DETAILS.lock().unwrap().clone(), _details, _details_size);
|
||||
write_cstr(&SERIALIZER_DETAILS.lock().unwrap().clone(), _details as *mut u8, _details_size);
|
||||
if code == 0 && !filename.is_null() {
|
||||
// Success path writes a real file so tests can assert existence.
|
||||
let name = std::ffi::CStr::from_ptr(filename).to_string_lossy().into_owned();
|
||||
@@ -1755,13 +1755,13 @@ pub unsafe extern "C" fn oaknode_serializer_load_from_file(
|
||||
if !out_code.is_null() {
|
||||
*out_code = code;
|
||||
}
|
||||
write_cstr(&SERIALIZER_DETAILS.lock().unwrap().clone(), _details, _details_size);
|
||||
write_cstr(&SERIALIZER_DETAILS.lock().unwrap().clone(), _details as *mut u8, _details_size);
|
||||
SERIALIZER_LOAD_RET.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_node_get_label(_node: oaktask::bridge::node::OakNodeNode, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr(&NODE_LABEL.lock().unwrap().clone(), buf, size)
|
||||
write_cstr(&NODE_LABEL.lock().unwrap().clone(), buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1771,7 +1771,7 @@ pub unsafe extern "C" fn oaknode_node_set_label(_node: oaktask::bridge::node::Oa
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn oaknode_node_get_id(_node: oaktask::bridge::node::OakNodeNode, buf: *mut c_char, size: c_int) -> c_int {
|
||||
write_cstr(&NODE_ID.lock().unwrap().clone(), buf, size)
|
||||
write_cstr(&NODE_ID.lock().unwrap().clone(), buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1831,7 +1831,7 @@ pub unsafe extern "C" fn oaknode_node_get_input_string(
|
||||
buf: *mut c_char,
|
||||
size: c_int,
|
||||
) -> c_int {
|
||||
write_cstr("subtitle text", buf, size)
|
||||
write_cstr("subtitle text", buf as *mut u8, size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -54,7 +54,7 @@ fn render_task(frames: i64, audio: bool) -> RenderTask {
|
||||
VIDEO_TIME_BASE_NUM.store(1, Ordering::SeqCst);
|
||||
VIDEO_TIME_BASE_DEN.store(1, Ordering::SeqCst);
|
||||
let range = TimeRange::new(Rational::new(0, 1), Rational::new(frames, 1));
|
||||
let base = Task::new("render-loop-test", fake_atom().to_chandle());
|
||||
let base = Task::new("render-loop-test", fake_atom());
|
||||
let mut rt = RenderTask::new(
|
||||
base,
|
||||
CHandle::null(),
|
||||
@@ -190,7 +190,7 @@ fn render_cancel_drains_inflight_and_fires_their_completions() {
|
||||
// the loop; the loop then sees the cancellation and drains.
|
||||
unsafe {
|
||||
oaktask::bridge::render::oakrender_cancelatom_cancel(
|
||||
oaktask::bridge::render::OakCancelAtom::from_chandle(atom),
|
||||
atom,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -476,7 +476,7 @@ fn task_base_api_and_events() {
|
||||
let _g = lock();
|
||||
reset_stubs();
|
||||
|
||||
let mut task = Task::new("Base API", common::fake_atom().to_chandle());
|
||||
let mut task = Task::new("Base API", common::fake_atom());
|
||||
task.set_title("Renamed");
|
||||
assert_eq!(task.title(), "Renamed");
|
||||
assert!(task.error().is_none());
|
||||
@@ -514,7 +514,7 @@ fn task_base_api_and_events() {
|
||||
task.cancel();
|
||||
assert!(task.is_cancelled());
|
||||
unsafe {
|
||||
oaktask::bridge::render::oakrender_cancelatom_cancel(oaktask::bridge::render::OakCancelAtom::from_chandle(atom));
|
||||
oaktask::bridge::render::oakrender_cancelatom_cancel(atom);
|
||||
}
|
||||
assert!(task.is_cancelled());
|
||||
|
||||
|
||||
Generated
+559
@@ -2,13 +2,572 @@
|
||||
# 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 = "aho-corasick"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[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 2.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[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 = "either"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6380599799e175191eb7ffe82c97f36a2a90a36cbc54c738a903e5287d7f516a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ffmpeg-sys-next",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-sys-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b939bf79dd5949412a4b81cfe21a07f48ea21b47fcbb5f57816c8c2de5ae30b"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
"num_cpus",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[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 = "glob"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
|
||||
|
||||
[[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 = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[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 = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[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 = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[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 = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcodec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ffmpeg-next",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "oaknode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oakundo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oaktimeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oaknode",
|
||||
"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 = "pkg-config"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
||||
|
||||
[[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 = "regex"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[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 = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[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",
|
||||
]
|
||||
|
||||
@@ -13,10 +13,15 @@ crate-type = ["staticlib", "rlib"]
|
||||
panic = "unwind"
|
||||
|
||||
[features]
|
||||
# Compile the in-crate C ABI mocks (src/bridge/teststubs.rs) so the unit and
|
||||
# integration tests can link without the oaknode/oakundo/oakcommon DLLs.
|
||||
# Every test run must pass this flag (see README.md "testing").
|
||||
# Compile the in-crate mock implementations (src/bridge/teststubs.rs) so the
|
||||
# integration tests can resolve `bridge::teststubs`; the bridge fns route to
|
||||
# them under this feature (see single-lib.md). Plain Rust mocks, no
|
||||
# `#[no_mangle]` — they coexist with the real oaknode/oakundo/oakcommon
|
||||
# path dependencies. Every test run must pass this flag (README "testing").
|
||||
test-stubs = []
|
||||
|
||||
[dependencies]
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakundo = { path = "../../undo/rust" }
|
||||
oaknode = { path = "../../node/rust" }
|
||||
oakcommon = { path = "../../common/rust" }
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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 (XML reader/writer + config), mirroring
|
||||
//! `include/common/xmlutils.h` and `include/common/config.h`.
|
||||
|
||||
@@ -21,49 +37,233 @@ use std::ffi::{c_char, c_int};
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
extern "C" {
|
||||
/// `oakcommon_xml_reader_init` — create a reader over a NUL-terminated
|
||||
/// document; the document must outlive the reader.
|
||||
pub fn oakcommon_xml_reader_init(data: *const c_char) -> CHandle;
|
||||
/// `oakcommon_xml_reader_free` — release the reader; NULL is a no-op.
|
||||
pub fn oakcommon_xml_reader_free(reader: *mut CHandle);
|
||||
/// `oakcommon_xml_reader_skip_current_element` — skip to the end of the
|
||||
/// current element subtree.
|
||||
pub fn oakcommon_xml_reader_skip_current_element(reader: CHandle) -> c_int;
|
||||
/// `oakcommon_xml_reader_read_next_start_element` — advance to the next
|
||||
/// start element, writing its (possibly empty) name into `name`.
|
||||
pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, name: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_name` — the current element's name.
|
||||
pub fn oakcommon_xml_reader_name(reader: CHandle, name: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_read_element_text` — read the current element's
|
||||
/// text content.
|
||||
pub fn oakcommon_xml_reader_read_element_text(reader: CHandle, text: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_attribute_count` — number of attributes on the
|
||||
/// current element.
|
||||
pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_attribute_name` — name of attribute `i`.
|
||||
pub fn oakcommon_xml_reader_attribute_name(reader: CHandle, index: c_int, name: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_attribute_value` — value of attribute `i`.
|
||||
pub fn oakcommon_xml_reader_attribute_value(reader: CHandle, index: c_int, value: *mut c_char, buf_size: c_int) -> c_int;
|
||||
/// `oakcommon_xml_reader_has_error` — whether the reader hit an error.
|
||||
pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int;
|
||||
/// `oakcommon_xml_writer_init` — create a writer.
|
||||
pub fn oakcommon_xml_writer_init() -> CHandle;
|
||||
/// `oakcommon_xml_writer_free` — release the writer; NULL is a no-op.
|
||||
pub fn oakcommon_xml_writer_free(writer: *mut CHandle);
|
||||
/// `oakcommon_xml_writer_write_start_element` — open `<name>`.
|
||||
pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_end_element` — close the current element.
|
||||
pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_end_document` — finish the document.
|
||||
pub fn oakcommon_xml_writer_write_end_document(writer: CHandle) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_attribute` — write `key="value"`.
|
||||
pub fn oakcommon_xml_writer_write_attribute(writer: CHandle, key: *const c_char, value: *const c_char) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_characters` — write raw text content.
|
||||
pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int;
|
||||
/// `oakcommon_xml_writer_write_text_element` — write `<name>text</name>`.
|
||||
pub fn oakcommon_xml_writer_write_text_element(writer: CHandle, name: *const c_char, text: *const c_char) -> c_int;
|
||||
/// `oakcommon_config_get_int` — read an integer config value (marker default
|
||||
/// colour).
|
||||
pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, default: c_int) -> c_int;
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_init(data: *const c_char) -> CHandle {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_init(data)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_init(data) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_free(reader: *mut CHandle) {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_free(reader)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_free(reader) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_skip_current_element(reader: CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_skip_current_element(reader)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_skip_current_element(reader) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification). The
|
||||
/// real ABI advances the reader and writes a 1/0 `found` flag (the name is
|
||||
/// read with [`oakcommon_xml_reader_name`]).
|
||||
pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, found: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_read_next_start_element(reader, found)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_read_next_start_element(reader, found) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_name(reader: CHandle, name: *mut c_char, buf_size: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_name(reader, name, buf_size)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_name(reader, name, buf_size) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_read_element_text(reader: CHandle, text: *mut c_char, buf_size: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_read_element_text(reader, text, buf_size)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_read_element_text(reader, text, buf_size) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_attribute_count(reader, count)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_count(reader, count) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_attribute_name(reader: CHandle, index: c_int, name: *mut c_char, buf_size: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_attribute_name(reader, index, name, buf_size)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_name(reader, index, name, buf_size) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_attribute_value(reader: CHandle, index: c_int, value: *mut c_char, buf_size: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_attribute_value(reader, index, value, buf_size)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_attribute_value(reader, index, value, buf_size) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_reader_has_error(reader, has_error)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_reader_has_error(reader, has_error) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_init() -> CHandle {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_init()
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_init() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_free(writer: *mut CHandle) {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_free(writer)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_free(writer) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_write_start_element(writer, name)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_start_element(writer, name) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_write_end_element(writer)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_end_element(writer) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_write_end_document(writer: CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_write_end_document(writer)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_end_document(writer) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_write_attribute(writer: CHandle, key: *const c_char, value: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_write_attribute(writer, key, value)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_attribute(writer, key, value) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_write_characters(writer, text)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_characters(writer, text) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_xml_writer_write_text_element(writer: CHandle, name: *const c_char, text: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_xml_writer_write_text_element(writer, name, text)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::xmlutils::oakcommon_xml_writer_write_text_element(writer, name, text) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakcommon` crate (single-lib unification).
|
||||
pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, default: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakcommon_config_get_int(group, key, default)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_int(group, key, default) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,10 @@ pub mod common;
|
||||
pub mod node;
|
||||
pub mod undo;
|
||||
|
||||
/// In-crate C ABI mocks, compiled only for tests (feature `test-stubs`).
|
||||
/// Each `#[no_mangle]` function here provides a definition for the `extern
|
||||
/// "C"` symbol declared in the submodules above, so `cargo test
|
||||
/// --features test-stubs` links without the real oak DLLs.
|
||||
#[cfg(feature = "test-stubs")]
|
||||
/// In-crate mock implementations of the bridge surface, compiled for tests
|
||||
/// (`cfg(test)` or the `test-stubs` feature); the bridge fns route to them
|
||||
/// via their `#[cfg(any(test, feature = "test-stubs"))]` variants. Plain
|
||||
/// Rust (no `#[no_mangle]`), so they coexist with the real
|
||||
/// oaknode/oakundo/oakcommon rlibs linked in the same test binary.
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
pub mod teststubs;
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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/>.
|
||||
|
||||
//! oaknode C ABI imports (`include/node/{block,node,sequence,track,project}.h`).
|
||||
//! Timeline reads and mutates the block/track/sequence graph exclusively
|
||||
//! through these frozen functions — it never reimplements node internals.
|
||||
@@ -39,129 +55,663 @@ pub type OakNodeProject = CHandle;
|
||||
/// A track list (`OakNodeTrackList`). Opaque handle.
|
||||
pub type OakNodeTrackList = CHandle;
|
||||
|
||||
extern "C" {
|
||||
/// `oaknode_block_clip_create` — a new clip block (count 1).
|
||||
pub fn oaknode_block_clip_create() -> OakNodeBlock;
|
||||
/// `oaknode_block_gap_create` — a new gap block (count 1).
|
||||
pub fn oaknode_block_gap_create() -> OakNodeBlock;
|
||||
/// `oaknode_block_as_node` — the block viewed as a generic node.
|
||||
pub fn oaknode_block_as_node(block: OakNodeBlock) -> OakNodeNode;
|
||||
/// `oaknode_block_get_in` — the block's in point as an int pair.
|
||||
pub fn oaknode_block_get_in(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int;
|
||||
/// `oaknode_block_get_out` — the block's out point as an int pair.
|
||||
pub fn oaknode_block_get_out(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int;
|
||||
/// `oaknode_block_get_length` — the block's length as an int pair.
|
||||
pub fn oaknode_block_get_length(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int;
|
||||
/// `oaknode_block_set_length_and_media_out` — resize keeping media-in fixed.
|
||||
pub fn oaknode_block_set_length_and_media_out(block: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int;
|
||||
/// `oaknode_block_set_length_and_media_in` — resize keeping the out point fixed.
|
||||
pub fn oaknode_block_set_length_and_media_in(block: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int;
|
||||
/// `oaknode_block_get_enabled` — the block's enabled flag.
|
||||
pub fn oaknode_block_get_enabled(block: OakNodeBlock, enabled: *mut c_int) -> c_int;
|
||||
/// `oaknode_block_set_enabled` — set the enabled flag.
|
||||
pub fn oaknode_block_set_enabled(block: OakNodeBlock, enabled: c_int) -> c_int;
|
||||
/// `oaknode_block_get_previous` — borrowed previous block (empty when none).
|
||||
pub fn oaknode_block_get_previous(block: OakNodeBlock, out: *mut OakNodeBlock) -> c_int;
|
||||
/// `oaknode_block_get_next` — borrowed next block (empty when none).
|
||||
pub fn oaknode_block_get_next(block: OakNodeBlock, out: *mut OakNodeBlock) -> c_int;
|
||||
/// `oaknode_block_get_track` — the owning track (empty when detached).
|
||||
pub fn oaknode_block_get_track(block: OakNodeBlock, out: *mut OakNodeTrack) -> c_int;
|
||||
/// `oaknode_block_link` — link two blocks so they move together.
|
||||
pub fn oaknode_block_link(a: OakNodeBlock, b: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_block_unlink` — unlink two blocks.
|
||||
pub fn oaknode_block_unlink(a: OakNodeBlock, b: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_get_length` — the track's length as an int pair.
|
||||
pub fn oaknode_track_get_length(track: OakNodeTrack, numerator: *mut c_int, denominator: *mut c_int) -> c_int;
|
||||
/// `oaknode_track_get_sequence` — the owning sequence (empty when detached).
|
||||
pub fn oaknode_track_get_sequence(track: OakNodeTrack, out: *mut OakNodeSequence) -> c_int;
|
||||
/// `oaknode_track_prepend_block` — prepend a block.
|
||||
pub fn oaknode_track_prepend_block(track: OakNodeTrack, block: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_insert_block_after` — insert after `before`.
|
||||
pub fn oaknode_track_insert_block_after(track: OakNodeTrack, block: OakNodeBlock, before: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_ripple_remove_block` — remove a block, shifting later ones
|
||||
/// earlier; ownership returns to the caller.
|
||||
pub fn oaknode_track_ripple_remove_block(track: OakNodeTrack, block: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_replace_block` — replace `old_block` with `new_block`
|
||||
/// (equal lengths required).
|
||||
pub fn oaknode_track_replace_block(track: OakNodeTrack, old_block: OakNodeBlock, new_block: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_sequence_as_node` — the sequence viewed as a generic node.
|
||||
pub fn oaknode_sequence_as_node(sequence: OakNodeSequence) -> OakNodeNode;
|
||||
/// `oaknode_sequence_from_node` — a generic node viewed as a sequence.
|
||||
pub fn oaknode_sequence_from_node(node: OakNodeNode) -> OakNodeSequence;
|
||||
/// `oaknode_node_get_project` — the owning project (empty when detached).
|
||||
pub fn oaknode_node_get_project(node: OakNodeNode, out: *mut OakNodeProject) -> c_int;
|
||||
/// `oaknode_node_output_connection_count` — number of output connections.
|
||||
pub fn oaknode_node_output_connection_count(node: OakNodeNode, out_count: *mut c_int) -> c_int;
|
||||
/// `oaknode_node_get_markers` — borrow the node's marker list.
|
||||
pub fn oaknode_node_get_markers(node: OakNodeNode, out: *mut crate::handle::CHandle) -> c_int;
|
||||
/// `oaknode_node_get_work_area` — borrow the node's work area.
|
||||
pub fn oaknode_node_get_work_area(node: OakNodeNode, out: *mut crate::handle::CHandle) -> c_int;
|
||||
/// `oaknode_project_add_node` — adopt a node into a project.
|
||||
pub fn oaknode_project_add_node(project: OakNodeProject, node: OakNodeNode) -> c_int;
|
||||
/// `oaknode_project_remove_node` — remove a node from a project.
|
||||
pub fn oaknode_project_remove_node(project: OakNodeProject, node: OakNodeNode) -> c_int;
|
||||
/// `oaknode_command_create_remove_node` — a command that removes a node.
|
||||
pub fn oaknode_command_create_remove_node(node: OakNodeNode) -> crate::handle::CHandle;
|
||||
|
||||
// --- block.h: querying / building blocks -------------------------------
|
||||
|
||||
/// `oaknode_block_get_kind` — the block's kind (`OAKNODE_BLOCK_*`).
|
||||
pub fn oaknode_block_get_kind(block: OakNodeBlock, out_kind: *mut c_int) -> c_int;
|
||||
/// `oaknode_block_from_node` — a generic node viewed as a block (empty when not a block).
|
||||
pub fn oaknode_block_from_node(node: OakNodeNode) -> OakNodeBlock;
|
||||
/// `oaknode_block_are_linked` — whether two blocks are linked (`linked` receives 1/0).
|
||||
pub fn oaknode_block_are_linked(a: OakNodeBlock, b: OakNodeBlock, linked: *mut c_int) -> c_int;
|
||||
/// `oaknode_clip_add_cache_passthrough_from` — copy render-cache passthroughs from `other`.
|
||||
pub fn oaknode_clip_add_cache_passthrough_from(clip: OakNodeBlock, other: OakNodeBlock) -> c_int;
|
||||
/// `oaknode_clip_get_media_in` — the clip's media-in as an int pair (clip blocks only).
|
||||
pub fn oaknode_clip_get_media_in(clip: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int;
|
||||
/// `oaknode_clip_set_media_in` — set the clip's media-in as an int pair (clip blocks only).
|
||||
pub fn oaknode_clip_set_media_in(clip: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int;
|
||||
|
||||
// --- track.h: tracks and track lists -----------------------------------
|
||||
|
||||
/// `oaknode_track_create` — a new detached track of the given type.
|
||||
pub fn oaknode_track_create(kind: c_int) -> OakNodeTrack;
|
||||
/// `oaknode_track_get_locked` — whether the track is locked (`locked` receives 1/0).
|
||||
pub fn oaknode_track_get_locked(track: OakNodeTrack, locked: *mut c_int) -> c_int;
|
||||
/// `oaknode_track_set_locked` — set the locked flag.
|
||||
pub fn oaknode_track_set_locked(track: OakNodeTrack, locked: c_int) -> c_int;
|
||||
/// `oaknode_track_get_block_count` — number of blocks on the track.
|
||||
pub fn oaknode_track_get_block_count(track: OakNodeTrack, count: *mut c_int) -> c_int;
|
||||
/// `oaknode_track_get_block_at` — borrowed block at `index`.
|
||||
pub fn oaknode_track_get_block_at(track: OakNodeTrack, index: c_int, out: *mut OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_get_block_containing_time` — block strictly containing `time` (in < t < out).
|
||||
pub fn oaknode_track_get_block_containing_time(track: OakNodeTrack, numerator: c_int, denominator: c_int, out: *mut OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_get_nearest_block_before_or_at` — block at or before `time`.
|
||||
pub fn oaknode_track_get_nearest_block_before_or_at(track: OakNodeTrack, numerator: c_int, denominator: c_int, out: *mut OakNodeBlock) -> c_int;
|
||||
/// `oaknode_track_get_nearest_block_after_or_at` — block at or after `time`.
|
||||
pub fn oaknode_track_get_nearest_block_after_or_at(track: OakNodeTrack, numerator: c_int, denominator: c_int, out: *mut OakNodeBlock) -> c_int;
|
||||
/// `oaknode_tracklist_get_type` — the track list's track type.
|
||||
pub fn oaknode_tracklist_get_type(list: OakNodeTrackList, kind: *mut c_int) -> c_int;
|
||||
/// `oaknode_tracklist_get_track_count` — number of tracks in the list.
|
||||
pub fn oaknode_tracklist_get_track_count(list: OakNodeTrackList, count: *mut c_int) -> c_int;
|
||||
/// `oaknode_tracklist_get_track_at` — borrowed track at `index`.
|
||||
pub fn oaknode_tracklist_get_track_at(list: OakNodeTrackList, index: c_int, out: *mut OakNodeTrack) -> c_int;
|
||||
/// `oaknode_tracklist_array_append` — append a track-array element on the parent sequence.
|
||||
pub fn oaknode_tracklist_array_append(list: OakNodeTrackList) -> c_int;
|
||||
/// `oaknode_tracklist_array_remove_last` — remove the last track-array element.
|
||||
pub fn oaknode_tracklist_array_remove_last(list: OakNodeTrackList) -> c_int;
|
||||
|
||||
// --- sequence.h ---------------------------------------------------------
|
||||
|
||||
/// `oaknode_sequence_get_track_list` — borrowed per-type track list.
|
||||
pub fn oaknode_sequence_get_track_list(sequence: OakNodeSequence, kind: c_int, out: *mut OakNodeTrackList) -> c_int;
|
||||
/// `oaknode_sequence_get_all_track_count` — total connected tracks across all types.
|
||||
pub fn oaknode_sequence_get_all_track_count(sequence: OakNodeSequence, count: *mut c_int) -> c_int;
|
||||
/// `oaknode_sequence_get_all_track_at` — borrowed track at `index` (flat cache).
|
||||
pub fn oaknode_sequence_get_all_track_at(sequence: OakNodeSequence, index: c_int, out: *mut OakNodeTrack) -> c_int;
|
||||
|
||||
// --- node.h: edges and cloning ------------------------------------------
|
||||
|
||||
/// `oaknode_node_connect` — connect `output_node` to `input_node`'s `input_id` (live).
|
||||
pub fn oaknode_node_connect(output_node: OakNodeNode, input_node: OakNodeNode, input_id: *const c_char) -> c_int;
|
||||
/// `oaknode_node_disconnect` — remove the edge feeding `input_node`'s `input_id` (live).
|
||||
pub fn oaknode_node_disconnect(input_node: OakNodeNode, input_id: *const c_char) -> c_int;
|
||||
/// `oaknode_node_copy_in_graph` — clone `node` in its graph; `*out_command` receives an owned undo handle.
|
||||
pub fn oaknode_node_copy_in_graph(node: OakNodeNode, out_command: *mut crate::handle::CHandle) -> OakNodeNode;
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_clip_create() -> OakNodeBlock {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_clip_create()
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_clip_create() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_gap_create() -> OakNodeBlock {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_gap_create()
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_gap_create() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_as_node(block: OakNodeBlock) -> OakNodeNode {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_as_node(block)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_as_node(block) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_in(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_in(block, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_in(block, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_out(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_out(block, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_out(block, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_length(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_length(block, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_length(block, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_set_length_and_media_out(block: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_set_length_and_media_out(block, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_set_length_and_media_out(block, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_set_length_and_media_in(block: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_set_length_and_media_in(block, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_set_length_and_media_in(block, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_enabled(block: OakNodeBlock, enabled: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_enabled(block, enabled)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_enabled(block, enabled) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_set_enabled(block: OakNodeBlock, enabled: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_set_enabled(block, enabled)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_set_enabled(block, enabled) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_previous(block: OakNodeBlock, out: *mut OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_previous(block, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_previous(block, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_next(block: OakNodeBlock, out: *mut OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_next(block, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_next(block, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_track(block: OakNodeBlock, out: *mut OakNodeTrack) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_track(block, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_track(block, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_link(a: OakNodeBlock, b: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_link(a, b)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_link(a, b) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_unlink(a: OakNodeBlock, b: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_unlink(a, b)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_unlink(a, b) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_length(track: OakNodeTrack, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_length(track, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_length(track, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_sequence(track: OakNodeTrack, out: *mut OakNodeSequence) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_sequence(track, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_sequence(track, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_prepend_block(track: OakNodeTrack, block: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_prepend_block(track, block)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_prepend_block(track, block) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_insert_block_after(track: OakNodeTrack, block: OakNodeBlock, before: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_insert_block_after(track, block, before)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_insert_block_after(track, block, before) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_ripple_remove_block(track: OakNodeTrack, block: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_ripple_remove_block(track, block)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_ripple_remove_block(track, block) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_replace_block(track: OakNodeTrack, old_block: OakNodeBlock, new_block: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_replace_block(track, old_block, new_block)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_replace_block(track, old_block, new_block) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_sequence_as_node(sequence: OakNodeSequence) -> OakNodeNode {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_sequence_as_node(sequence)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::sequence::oaknode_sequence_as_node(sequence) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_sequence_from_node(node: OakNodeNode) -> OakNodeSequence {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_sequence_from_node(node)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::sequence::oaknode_sequence_from_node(node) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_get_project(node: OakNodeNode, out: *mut OakNodeProject) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_get_project(node, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_get_project(node, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_output_connection_count(node: OakNodeNode, out_count: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_output_connection_count(node, out_count)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_output_connection_count(node, out_count) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_get_markers(node: OakNodeNode, out: *mut crate::handle::CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_get_markers(node, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_get_markers(node, out as *mut std::ffi::c_void) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_get_work_area(node: OakNodeNode, out: *mut crate::handle::CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_get_work_area(node, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_get_work_area(node, out as *mut std::ffi::c_void) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_project_add_node(project: OakNodeProject, node: OakNodeNode) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_project_add_node(project, node)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::project::oaknode_project_add_node(project, node) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_project_remove_node(project: OakNodeProject, node: OakNodeNode) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_project_remove_node(project, node)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::project::oaknode_project_remove_node(project, node) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_command_create_remove_node(node: OakNodeNode) -> crate::handle::CHandle {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_command_create_remove_node(node)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_command_create_remove_node(node) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_get_kind(block: OakNodeBlock, out_kind: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_get_kind(block, out_kind)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_get_kind(block, out_kind) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_from_node(node: OakNodeNode) -> OakNodeBlock {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_from_node(node)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_from_node(node) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_block_are_linked(a: OakNodeBlock, b: OakNodeBlock, linked: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_block_are_linked(a, b, linked)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_block_are_linked(a, b, linked) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_clip_add_cache_passthrough_from(clip: OakNodeBlock, other: OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_clip_add_cache_passthrough_from(clip, other)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_clip_add_cache_passthrough_from(clip, other) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_clip_get_media_in(clip: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_clip_get_media_in(clip, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_clip_get_media_in(clip, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_clip_set_media_in(clip: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_clip_set_media_in(clip, numerator, denominator)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::block::oaknode_clip_set_media_in(clip, numerator, denominator) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_create(kind: c_int) -> OakNodeTrack {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_create(kind)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_create(kind) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_locked(track: OakNodeTrack, locked: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_locked(track, locked)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_locked(track, locked) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_set_locked(track: OakNodeTrack, locked: c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_set_locked(track, locked)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_set_locked(track, locked) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_block_count(track: OakNodeTrack, count: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_block_count(track, count)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_block_count(track, count) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_block_at(track: OakNodeTrack, index: c_int, out: *mut OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_block_at(track, index, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_block_at(track, index, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_block_containing_time(track: OakNodeTrack, numerator: c_int, denominator: c_int, out: *mut OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_block_containing_time(track, numerator, denominator, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_block_containing_time(track, numerator, denominator, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_nearest_block_before_or_at(track: OakNodeTrack, numerator: c_int, denominator: c_int, out: *mut OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_nearest_block_before_or_at(track, numerator, denominator, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_nearest_block_before_or_at(track, numerator, denominator, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_track_get_nearest_block_after_or_at(track: OakNodeTrack, numerator: c_int, denominator: c_int, out: *mut OakNodeBlock) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_track_get_nearest_block_after_or_at(track, numerator, denominator, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_track_get_nearest_block_after_or_at(track, numerator, denominator, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_tracklist_get_type(list: OakNodeTrackList, kind: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_tracklist_get_type(list, kind)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_tracklist_get_type(list, kind) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_tracklist_get_track_count(list: OakNodeTrackList, count: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_tracklist_get_track_count(list, count)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_count(list, count) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_tracklist_get_track_at(list: OakNodeTrackList, index: c_int, out: *mut OakNodeTrack) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_tracklist_get_track_at(list, index, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_at(list, index, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_tracklist_array_append(list: OakNodeTrackList) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_tracklist_array_append(list)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_tracklist_array_append(list) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_tracklist_array_remove_last(list: OakNodeTrackList) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_tracklist_array_remove_last(list)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::track::oaknode_tracklist_array_remove_last(list) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_sequence_get_track_list(sequence: OakNodeSequence, kind: c_int, out: *mut OakNodeTrackList) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_sequence_get_track_list(sequence, kind, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_list(sequence, kind, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_sequence_get_all_track_count(sequence: OakNodeSequence, count: *mut c_int) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_sequence_get_all_track_count(sequence, count)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_all_track_count(sequence, count) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_sequence_get_all_track_at(sequence: OakNodeSequence, index: c_int, out: *mut OakNodeTrack) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_sequence_get_all_track_at(sequence, index, out)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_all_track_at(sequence, index, out) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_connect(output_node: OakNodeNode, input_node: OakNodeNode, input_id: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_connect(output_node, input_node, input_id)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_connect(output_node, input_node, input_id) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_disconnect(input_node: OakNodeNode, input_id: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_disconnect(input_node, input_id)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_disconnect(input_node, input_id) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oaknode` crate (single-lib unification).
|
||||
pub fn oaknode_node_copy_in_graph(node: OakNodeNode, out_command: *mut crate::handle::CHandle) -> OakNodeNode {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oaknode_node_copy_in_graph(node, out_command)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oaknode::ffi::node::oaknode_node_copy_in_graph(node, out_command) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
//! In-crate C ABI mocks, compiled only with `--features test-stubs`.
|
||||
//!
|
||||
//! Each `#[no_mangle]` function here supplies a definition for the `extern
|
||||
//! "C"` symbol declared in [`super::undo`] / [`super::common`] /
|
||||
//! [`super::node`], so unit and integration tests link without the real
|
||||
//! oaknode / oakundo / oakcommon DLLs.
|
||||
//! In-crate mock implementations of the oaknode/oakundo/oakcommon bridge
|
||||
//! surface, called directly by the bridge fns' `#[cfg(test)]` variants.
|
||||
//! The mocks are plain Rust (no `#[no_mangle]`/`extern "C"`), so they
|
||||
//! coexist with the real oaknode/oakundo/oakcommon rlibs linked in the
|
||||
//! same test binary. Timeline's tests build fixtures with these mocks; the
|
||||
//! production (non-test) bridge fns call the real crates.
|
||||
//!
|
||||
//! The mocks are intentionally simple and single-threaded. Handles box a
|
||||
//! [`MockNode`] (for every node-graph kind), a [`MockMarkerList`], a
|
||||
@@ -59,8 +61,7 @@ unsafe impl Send for MockUndoCommand {}
|
||||
|
||||
/// `oakundo_command_init`: box the vtable + userdata and hand back an owning
|
||||
/// handle.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_command_init(
|
||||
pub fn oakundo_command_init(
|
||||
vtable: *const super::undo::OakUndoCommandVtable,
|
||||
userdata: *mut c_void,
|
||||
) -> CHandle {
|
||||
@@ -78,8 +79,7 @@ pub extern "C" fn oakundo_command_init(
|
||||
}
|
||||
|
||||
/// `oakundo_command_init_multi`: an empty multi command (no-op here).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_command_init_multi() -> CHandle {
|
||||
pub fn oakundo_command_init_multi() -> CHandle {
|
||||
make_owned(MockUndoCommand {
|
||||
vtable: super::undo::OakUndoCommandVtable {
|
||||
redo: None,
|
||||
@@ -91,14 +91,12 @@ pub extern "C" fn oakundo_command_init_multi() -> CHandle {
|
||||
}
|
||||
|
||||
/// `oakundo_command_multi_add_child`: no-op in the mock (returns 0).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_command_multi_add_child(_multi: CHandle, _child: CHandle) -> c_int {
|
||||
pub fn oakundo_command_multi_add_child(_multi: CHandle, _child: CHandle) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oakundo_command_redo_now`: invoke the redo callback.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_command_redo_now(command: CHandle) -> c_int {
|
||||
pub fn oakundo_command_redo_now(command: CHandle) -> c_int {
|
||||
// SAFETY: the handle boxes a MockUndoCommand (created by init above).
|
||||
if let Some(m) = unsafe { get_mut::<MockUndoCommand>(&command) } {
|
||||
if let Some(f) = m.vtable.redo {
|
||||
@@ -111,8 +109,7 @@ pub extern "C" fn oakundo_command_redo_now(command: CHandle) -> c_int {
|
||||
}
|
||||
|
||||
/// `oakundo_command_undo_now`: invoke the undo callback.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_command_undo_now(command: CHandle) -> c_int {
|
||||
pub fn oakundo_command_undo_now(command: CHandle) -> c_int {
|
||||
// SAFETY: the handle boxes a MockUndoCommand.
|
||||
if let Some(m) = unsafe { get_mut::<MockUndoCommand>(&command) } {
|
||||
if let Some(f) = m.vtable.undo {
|
||||
@@ -125,8 +122,7 @@ pub extern "C" fn oakundo_command_undo_now(command: CHandle) -> c_int {
|
||||
|
||||
/// `oakundo_command_free`: run `free_fn`, drop the box and clear the handle.
|
||||
/// NULL / empty-handle is a no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_command_free(command: *mut CHandle) {
|
||||
pub fn oakundo_command_free(command: *mut CHandle) {
|
||||
if command.is_null() {
|
||||
return;
|
||||
}
|
||||
@@ -153,8 +149,7 @@ pub extern "C" fn oakundo_command_free(command: *mut CHandle) {
|
||||
}
|
||||
|
||||
/// `oakundo_stack_push`: record the push into the stack's mock (returns 0).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakundo_stack_push(
|
||||
pub fn oakundo_stack_push(
|
||||
stack: CHandle,
|
||||
_command: CHandle,
|
||||
_text: *const c_char,
|
||||
@@ -216,47 +211,41 @@ pub fn xml_reader_handle(nodes: Vec<MockXmlNode>) -> CHandle {
|
||||
/// `oakcommon_xml_reader_init`: build an empty reader over a NUL-terminated
|
||||
/// document. The mock only supports the `reader_handle` builder, so a
|
||||
/// document string yields an empty reader.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_init(_data: *const c_char) -> CHandle {
|
||||
pub fn oakcommon_xml_reader_init(_data: *const c_char) -> CHandle {
|
||||
make_owned(MockXmlReader::new(Vec::new()))
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_free`: release and clear; NULL / empty no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_free(reader: *mut CHandle) {
|
||||
pub fn oakcommon_xml_reader_free(reader: *mut CHandle) {
|
||||
free_box::<MockXmlReader>(reader);
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_skip_current_element`: no-op (flat model).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_skip_current_element(_reader: CHandle) -> c_int {
|
||||
pub fn oakcommon_xml_reader_skip_current_element(_reader: CHandle) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_read_next_start_element`: advance and write the
|
||||
/// element name. Returns 1 while elements remain, else 0.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_read_next_start_element(
|
||||
reader: CHandle,
|
||||
name: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
pub fn oakcommon_xml_reader_read_next_start_element(reader: CHandle, found: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockXmlReader.
|
||||
let Some(r) = (unsafe { get_mut::<MockXmlReader>(&reader) }) else {
|
||||
return 0;
|
||||
};
|
||||
if found.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if r.cur >= r.nodes.len() {
|
||||
// End of stream: no element yielded (0), found stays 0.
|
||||
return 0;
|
||||
}
|
||||
let n = r.nodes[r.cur].name.clone();
|
||||
r.cur += 1;
|
||||
write_cstr(name, buf_size, &n);
|
||||
unsafe { *found = 1 };
|
||||
1
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_name`: the current element's name.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_name(reader: CHandle, name: *mut c_char, buf_size: c_int) -> c_int {
|
||||
pub fn oakcommon_xml_reader_name(reader: CHandle, name: *mut c_char, buf_size: c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockXmlReader.
|
||||
let Some(r) = (unsafe { get::<MockXmlReader>(&reader) }) else {
|
||||
return 0;
|
||||
@@ -269,8 +258,7 @@ pub extern "C" fn oakcommon_xml_reader_name(reader: CHandle, name: *mut c_char,
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_read_element_text`: the current element's text.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_read_element_text(
|
||||
pub fn oakcommon_xml_reader_read_element_text(
|
||||
reader: CHandle,
|
||||
text: *mut c_char,
|
||||
buf_size: c_int,
|
||||
@@ -288,8 +276,7 @@ pub extern "C" fn oakcommon_xml_reader_read_element_text(
|
||||
|
||||
/// `oakcommon_xml_reader_attribute_count`: attribute count on the current
|
||||
/// element.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int {
|
||||
pub fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *mut c_int) -> c_int {
|
||||
// SAFETY: caller passes a valid count pointer.
|
||||
let c = match unsafe { get::<MockXmlReader>(&reader) } {
|
||||
Some(r) => r
|
||||
@@ -305,8 +292,7 @@ pub extern "C" fn oakcommon_xml_reader_attribute_count(reader: CHandle, count: *
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_attribute_name`: name of attribute `i`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_attribute_name(
|
||||
pub fn oakcommon_xml_reader_attribute_name(
|
||||
reader: CHandle,
|
||||
index: c_int,
|
||||
name: *mut c_char,
|
||||
@@ -327,8 +313,7 @@ pub extern "C" fn oakcommon_xml_reader_attribute_name(
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_attribute_value`: value of attribute `i`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_attribute_value(
|
||||
pub fn oakcommon_xml_reader_attribute_value(
|
||||
reader: CHandle,
|
||||
index: c_int,
|
||||
value: *mut c_char,
|
||||
@@ -349,8 +334,7 @@ pub extern "C" fn oakcommon_xml_reader_attribute_value(
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_reader_has_error`: whether the reader errored.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int {
|
||||
pub fn oakcommon_xml_reader_has_error(reader: CHandle, has_error: *mut c_int) -> c_int {
|
||||
let e = match unsafe { get::<MockXmlReader>(&reader) } {
|
||||
Some(r) => r.error as c_int,
|
||||
None => 0,
|
||||
@@ -367,20 +351,17 @@ pub struct MockXmlWriter {
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_init`: a new writer.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_init() -> CHandle {
|
||||
pub fn oakcommon_xml_writer_init() -> CHandle {
|
||||
make_owned(MockXmlWriter { buf: String::new() })
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_free`: release and clear; NULL / empty no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_free(writer: *mut CHandle) {
|
||||
pub fn oakcommon_xml_writer_free(writer: *mut CHandle) {
|
||||
free_box::<MockXmlWriter>(writer);
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_write_start_element`: append `<name>`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int {
|
||||
pub fn oakcommon_xml_writer_write_start_element(writer: CHandle, name: *const c_char) -> c_int {
|
||||
// SAFETY: caller passes a NUL-terminated string.
|
||||
let n = unsafe { cstr(name) };
|
||||
// SAFETY: handle boxes a MockXmlWriter.
|
||||
@@ -391,8 +372,7 @@ pub extern "C" fn oakcommon_xml_writer_write_start_element(writer: CHandle, name
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_write_end_element`: append `</>`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int {
|
||||
pub fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockXmlWriter.
|
||||
if let Some(w) = unsafe { get_mut::<MockXmlWriter>(&writer) } {
|
||||
w.buf.push_str("</>");
|
||||
@@ -401,14 +381,12 @@ pub extern "C" fn oakcommon_xml_writer_write_end_element(writer: CHandle) -> c_i
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_write_end_document`: no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_write_end_document(_writer: CHandle) -> c_int {
|
||||
pub fn oakcommon_xml_writer_write_end_document(_writer: CHandle) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_write_attribute`: append ` key="value"`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_write_attribute(
|
||||
pub fn oakcommon_xml_writer_write_attribute(
|
||||
writer: CHandle,
|
||||
key: *const c_char,
|
||||
value: *const c_char,
|
||||
@@ -423,8 +401,7 @@ pub extern "C" fn oakcommon_xml_writer_write_attribute(
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_write_characters`: append raw text.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int {
|
||||
pub fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *const c_char) -> c_int {
|
||||
// SAFETY: caller passes a NUL-terminated string.
|
||||
let t = unsafe { cstr(text) };
|
||||
// SAFETY: handle boxes a MockXmlWriter.
|
||||
@@ -435,8 +412,7 @@ pub extern "C" fn oakcommon_xml_writer_write_characters(writer: CHandle, text: *
|
||||
}
|
||||
|
||||
/// `oakcommon_xml_writer_write_text_element`: append `<name>text</name>`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_xml_writer_write_text_element(
|
||||
pub fn oakcommon_xml_writer_write_text_element(
|
||||
writer: CHandle,
|
||||
name: *const c_char,
|
||||
text: *const c_char,
|
||||
@@ -452,8 +428,7 @@ pub extern "C" fn oakcommon_xml_writer_write_text_element(
|
||||
|
||||
/// `oakcommon_config_get_int`: return the supplied default (the mock keeps no
|
||||
/// config store; the marker default colour path uses the default).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oakcommon_config_get_int(
|
||||
pub fn oakcommon_config_get_int(
|
||||
_group: *const c_char,
|
||||
_key: *const c_char,
|
||||
default: c_int,
|
||||
@@ -554,8 +529,7 @@ impl Default for MockNode {
|
||||
}
|
||||
|
||||
/// `oaknode_block_clip_create`: a new clip block.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_clip_create() -> CHandle {
|
||||
pub fn oaknode_block_clip_create() -> CHandle {
|
||||
make_owned(MockNode {
|
||||
kind: MockKind::Clip,
|
||||
..Default::default()
|
||||
@@ -563,8 +537,7 @@ pub extern "C" fn oaknode_block_clip_create() -> CHandle {
|
||||
}
|
||||
|
||||
/// `oaknode_block_gap_create`: a new gap block.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_gap_create() -> CHandle {
|
||||
pub fn oaknode_block_gap_create() -> CHandle {
|
||||
make_owned(MockNode {
|
||||
kind: MockKind::Gap,
|
||||
..Default::default()
|
||||
@@ -572,14 +545,12 @@ pub extern "C" fn oaknode_block_gap_create() -> CHandle {
|
||||
}
|
||||
|
||||
/// `oaknode_block_as_node`: a borrowed generic-node view of a block.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_as_node(block: CHandle) -> CHandle {
|
||||
pub fn oaknode_block_as_node(block: CHandle) -> CHandle {
|
||||
ref_clone(&block)
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_in`: read the in point as an int pair.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_in(
|
||||
pub fn oaknode_block_get_in(
|
||||
block: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
@@ -593,8 +564,7 @@ pub extern "C" fn oaknode_block_get_in(
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_out`: read the out point as an int pair.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_out(
|
||||
pub fn oaknode_block_get_out(
|
||||
block: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
@@ -608,8 +578,7 @@ pub extern "C" fn oaknode_block_get_out(
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_length`: read the length as an int pair.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_length(
|
||||
pub fn oaknode_block_get_length(
|
||||
block: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
@@ -624,8 +593,7 @@ pub extern "C" fn oaknode_block_get_length(
|
||||
|
||||
/// `oaknode_block_set_length_and_media_out`: set length, keeping the media-in
|
||||
/// fixed (the out point follows).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_set_length_and_media_out(
|
||||
pub fn oaknode_block_set_length_and_media_out(
|
||||
block: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
@@ -641,8 +609,7 @@ pub extern "C" fn oaknode_block_set_length_and_media_out(
|
||||
|
||||
/// `oaknode_block_set_length_and_media_in`: set length, keeping the out point
|
||||
/// fixed (the media-in follows).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_set_length_and_media_in(
|
||||
pub fn oaknode_block_set_length_and_media_in(
|
||||
block: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
@@ -657,8 +624,7 @@ pub extern "C" fn oaknode_block_set_length_and_media_in(
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_enabled`: read the enabled flag.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_enabled(block: CHandle, enabled: *mut c_int) -> c_int {
|
||||
pub fn oaknode_block_get_enabled(block: CHandle, enabled: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(b) = (unsafe { get::<MockNode>(&block) }) else {
|
||||
return -1;
|
||||
@@ -669,8 +635,7 @@ pub extern "C" fn oaknode_block_get_enabled(block: CHandle, enabled: *mut c_int)
|
||||
}
|
||||
|
||||
/// `oaknode_block_set_enabled`: set the enabled flag.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_set_enabled(block: CHandle, enabled: c_int) -> c_int {
|
||||
pub fn oaknode_block_set_enabled(block: CHandle, enabled: c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(b) = (unsafe { get_mut::<MockNode>(&block) }) else {
|
||||
return -1;
|
||||
@@ -680,8 +645,7 @@ pub extern "C" fn oaknode_block_set_enabled(block: CHandle, enabled: c_int) -> c
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_previous`: write a borrowed handle to the previous block.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_previous(block: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_block_get_previous(block: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(b) = (unsafe { get::<MockNode>(&block) }) else {
|
||||
return -1;
|
||||
@@ -691,8 +655,7 @@ pub extern "C" fn oaknode_block_get_previous(block: CHandle, out: *mut CHandle)
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_next`: write a borrowed handle to the next block.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_next(block: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_block_get_next(block: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(b) = (unsafe { get::<MockNode>(&block) }) else {
|
||||
return -1;
|
||||
@@ -702,8 +665,7 @@ pub extern "C" fn oaknode_block_get_next(block: CHandle, out: *mut CHandle) -> c
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_track`: write a borrowed handle to the owning track.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_track(block: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_block_get_track(block: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(b) = (unsafe { get::<MockNode>(&block) }) else {
|
||||
return -1;
|
||||
@@ -713,8 +675,7 @@ pub extern "C" fn oaknode_block_get_track(block: CHandle, out: *mut CHandle) ->
|
||||
}
|
||||
|
||||
/// `oaknode_block_link`: link two blocks so they move together.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_link(a: CHandle, b: CHandle) -> c_int {
|
||||
pub fn oaknode_block_link(a: CHandle, b: CHandle) -> c_int {
|
||||
// SAFETY: both handles box MockNodes.
|
||||
let (pa, pb) = unsafe {
|
||||
match (get_mut::<MockNode>(&a), get_mut::<MockNode>(&b)) {
|
||||
@@ -734,8 +695,7 @@ pub extern "C" fn oaknode_block_link(a: CHandle, b: CHandle) -> c_int {
|
||||
}
|
||||
|
||||
/// `oaknode_block_unlink`: unlink two blocks.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_unlink(a: CHandle, b: CHandle) -> c_int {
|
||||
pub fn oaknode_block_unlink(a: CHandle, b: CHandle) -> c_int {
|
||||
// SAFETY: both handles box MockNodes.
|
||||
let (pa, pb) = unsafe {
|
||||
match (get_mut::<MockNode>(&a), get_mut::<MockNode>(&b)) {
|
||||
@@ -753,8 +713,7 @@ pub extern "C" fn oaknode_block_unlink(a: CHandle, b: CHandle) -> c_int {
|
||||
}
|
||||
|
||||
/// `oaknode_track_get_length`: read the track length as an int pair.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_length(track: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
pub fn oaknode_track_get_length(track: CHandle, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(t) = (unsafe { get::<MockNode>(&track) }) else {
|
||||
return -1;
|
||||
@@ -770,8 +729,7 @@ pub extern "C" fn oaknode_track_get_length(track: CHandle, numerator: *mut c_int
|
||||
}
|
||||
|
||||
/// `oaknode_track_get_sequence`: write a borrowed handle to the owning sequence.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_sequence(track: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_track_get_sequence(track: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(t) = (unsafe { get::<MockNode>(&track) }) else {
|
||||
return -1;
|
||||
@@ -781,8 +739,7 @@ pub extern "C" fn oaknode_track_get_sequence(track: CHandle, out: *mut CHandle)
|
||||
}
|
||||
|
||||
/// `oaknode_track_prepend_block`: insert a block at the front of the track.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_prepend_block(track: CHandle, block: CHandle) -> c_int {
|
||||
pub fn oaknode_track_prepend_block(track: CHandle, block: CHandle) -> c_int {
|
||||
// SAFETY: both handles box MockNodes.
|
||||
let (pt, pb) = unsafe {
|
||||
match (get_mut::<MockNode>(&track), get_mut::<MockNode>(&block)) {
|
||||
@@ -808,8 +765,7 @@ pub extern "C" fn oaknode_track_prepend_block(track: CHandle, block: CHandle) ->
|
||||
}
|
||||
|
||||
/// `oaknode_track_insert_block_after`: insert `block` after `before` on `track`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_insert_block_after(
|
||||
pub fn oaknode_track_insert_block_after(
|
||||
track: CHandle,
|
||||
block: CHandle,
|
||||
before: CHandle,
|
||||
@@ -866,8 +822,7 @@ pub extern "C" fn oaknode_track_insert_block_after(
|
||||
|
||||
/// `oaknode_track_ripple_remove_block`: remove a block, shifting later ones
|
||||
/// earlier; ownership returns to the caller (the caller keeps its handle).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_ripple_remove_block(track: CHandle, block: CHandle) -> c_int {
|
||||
pub fn oaknode_track_ripple_remove_block(track: CHandle, block: CHandle) -> c_int {
|
||||
// SAFETY: handles box MockNodes.
|
||||
let (pt, pb) = unsafe {
|
||||
match (get_mut::<MockNode>(&track), get_mut::<MockNode>(&block)) {
|
||||
@@ -900,8 +855,7 @@ pub extern "C" fn oaknode_track_ripple_remove_block(track: CHandle, block: CHand
|
||||
}
|
||||
|
||||
/// `oaknode_track_replace_block`: replace `old_block` with `new_block`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_replace_block(
|
||||
pub fn oaknode_track_replace_block(
|
||||
track: CHandle,
|
||||
old_block: CHandle,
|
||||
new_block: CHandle,
|
||||
@@ -948,20 +902,17 @@ pub extern "C" fn oaknode_track_replace_block(
|
||||
}
|
||||
|
||||
/// `oaknode_sequence_as_node`: a borrowed generic-node view of a sequence.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_sequence_as_node(sequence: CHandle) -> CHandle {
|
||||
pub fn oaknode_sequence_as_node(sequence: CHandle) -> CHandle {
|
||||
ref_clone(&sequence)
|
||||
}
|
||||
|
||||
/// `oaknode_sequence_from_node`: a borrowed sequence view of a generic node.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_sequence_from_node(node: CHandle) -> CHandle {
|
||||
pub fn oaknode_sequence_from_node(node: CHandle) -> CHandle {
|
||||
ref_clone(&node)
|
||||
}
|
||||
|
||||
/// `oaknode_node_get_project`: write a borrowed handle to the owning project.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_get_project(node: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_node_get_project(node: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(n) = (unsafe { get::<MockNode>(&node) }) else {
|
||||
return -1;
|
||||
@@ -971,8 +922,7 @@ pub extern "C" fn oaknode_node_get_project(node: CHandle, out: *mut CHandle) ->
|
||||
}
|
||||
|
||||
/// `oaknode_node_output_connection_count`: read the output connection count.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_output_connection_count(node: CHandle, out_count: *mut c_int) -> c_int {
|
||||
pub fn oaknode_node_output_connection_count(node: CHandle, out_count: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(n) = (unsafe { get::<MockNode>(&node) }) else {
|
||||
return -1;
|
||||
@@ -983,8 +933,7 @@ pub extern "C" fn oaknode_node_output_connection_count(node: CHandle, out_count:
|
||||
}
|
||||
|
||||
/// `oaknode_node_get_markers`: write a borrowed handle to the node's markers.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_get_markers(node: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_node_get_markers(node: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(n) = (unsafe { get::<MockNode>(&node) }) else {
|
||||
return -1;
|
||||
@@ -995,8 +944,7 @@ pub extern "C" fn oaknode_node_get_markers(node: CHandle, out: *mut CHandle) ->
|
||||
}
|
||||
|
||||
/// `oaknode_node_get_work_area`: write a borrowed handle to the node's work area.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_get_work_area(node: CHandle, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_node_get_work_area(node: CHandle, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(n) = (unsafe { get::<MockNode>(&node) }) else {
|
||||
return -1;
|
||||
@@ -1007,8 +955,7 @@ pub extern "C" fn oaknode_node_get_work_area(node: CHandle, out: *mut CHandle) -
|
||||
}
|
||||
|
||||
/// `oaknode_project_add_node`: adopt a node into a project.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_project_add_node(project: CHandle, node: CHandle) -> c_int {
|
||||
pub fn oaknode_project_add_node(project: CHandle, node: CHandle) -> c_int {
|
||||
// SAFETY: handles box MockNodes.
|
||||
let (pp, pn) = unsafe {
|
||||
match (get_mut::<MockNode>(&project), get_mut::<MockNode>(&node)) {
|
||||
@@ -1022,8 +969,7 @@ pub extern "C" fn oaknode_project_add_node(project: CHandle, node: CHandle) -> c
|
||||
}
|
||||
|
||||
/// `oaknode_project_remove_node`: remove a node from a project.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_project_remove_node(project: CHandle, node: CHandle) -> c_int {
|
||||
pub fn oaknode_project_remove_node(project: CHandle, node: CHandle) -> c_int {
|
||||
// SAFETY: handles box MockNodes.
|
||||
let (pp, pn) = unsafe {
|
||||
match (get_mut::<MockNode>(&project), get_mut::<MockNode>(&node)) {
|
||||
@@ -1043,8 +989,7 @@ pub extern "C" fn oaknode_project_remove_node(project: CHandle, node: CHandle) -
|
||||
/// `oaknode_command_create_remove_node`: a command that removes a node. The
|
||||
/// mock returns a command handle whose redo/undo no-op, but whose free drops
|
||||
/// the wrapped node handle it borrows.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_command_create_remove_node(node: CHandle) -> CHandle {
|
||||
pub fn oaknode_command_create_remove_node(node: CHandle) -> CHandle {
|
||||
let node_owned = ref_clone(&node);
|
||||
make_owned(MockUndoCommand {
|
||||
vtable: super::undo::OakUndoCommandVtable {
|
||||
@@ -1064,8 +1009,7 @@ extern "C" fn free_owned_handle(userdata: *mut c_void) {
|
||||
}
|
||||
|
||||
/// `oaknode_block_get_kind`: map a block's kind to an `OAKNODE_BLOCK_*` int.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_get_kind(block: CHandle, out_kind: *mut c_int) -> c_int {
|
||||
pub fn oaknode_block_get_kind(block: CHandle, out_kind: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(b) = (unsafe { get::<MockNode>(&block) }) else {
|
||||
return -1;
|
||||
@@ -1082,8 +1026,7 @@ pub extern "C" fn oaknode_block_get_kind(block: CHandle, out_kind: *mut c_int) -
|
||||
|
||||
/// `oaknode_block_from_node`: a borrowed block view of a generic node (empty
|
||||
/// when the node is not a block).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_from_node(node: CHandle) -> CHandle {
|
||||
pub fn oaknode_block_from_node(node: CHandle) -> CHandle {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(n) = (unsafe { get::<MockNode>(&node) }) else {
|
||||
return CHandle::null();
|
||||
@@ -1096,8 +1039,7 @@ pub extern "C" fn oaknode_block_from_node(node: CHandle) -> CHandle {
|
||||
|
||||
/// `oaknode_block_are_linked`: whether `a` and `b` are linked (`linked` gets
|
||||
/// 1/0).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_block_are_linked(a: CHandle, b: CHandle, linked: *mut c_int) -> c_int {
|
||||
pub fn oaknode_block_are_linked(a: CHandle, b: CHandle, linked: *mut c_int) -> c_int {
|
||||
// SAFETY: both handles box MockNodes.
|
||||
let (pa, pb) = unsafe {
|
||||
match (get::<MockNode>(&a), get::<MockNode>(&b)) {
|
||||
@@ -1119,14 +1061,12 @@ pub extern "C" fn oaknode_block_are_linked(a: CHandle, b: CHandle, linked: *mut
|
||||
|
||||
/// `oaknode_clip_add_cache_passthrough_from`: copy render-cache passthroughs
|
||||
/// from `other`. The mock has no cache model, so this is a no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_clip_add_cache_passthrough_from(_clip: CHandle, _other: CHandle) -> c_int {
|
||||
pub fn oaknode_clip_add_cache_passthrough_from(_clip: CHandle, _other: CHandle) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oaknode_clip_get_media_in`: read a clip's media-in as an int pair.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_clip_get_media_in(
|
||||
pub fn oaknode_clip_get_media_in(
|
||||
clip: CHandle,
|
||||
numerator: *mut c_int,
|
||||
denominator: *mut c_int,
|
||||
@@ -1143,8 +1083,7 @@ pub extern "C" fn oaknode_clip_get_media_in(
|
||||
}
|
||||
|
||||
/// `oaknode_clip_set_media_in`: set a clip's media-in as an int pair.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_clip_set_media_in(
|
||||
pub fn oaknode_clip_set_media_in(
|
||||
clip: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
@@ -1161,8 +1100,7 @@ pub extern "C" fn oaknode_clip_set_media_in(
|
||||
}
|
||||
|
||||
/// `oaknode_track_create`: a new detached track of the given type.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_create(kind: c_int) -> CHandle {
|
||||
pub fn oaknode_track_create(kind: c_int) -> CHandle {
|
||||
make_owned(MockNode {
|
||||
kind: MockKind::Track,
|
||||
track_type: kind,
|
||||
@@ -1171,8 +1109,7 @@ pub extern "C" fn oaknode_track_create(kind: c_int) -> CHandle {
|
||||
}
|
||||
|
||||
/// `oaknode_track_get_locked`: read a track's locked flag (`locked` gets 1/0).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_locked(track: CHandle, locked: *mut c_int) -> c_int {
|
||||
pub fn oaknode_track_get_locked(track: CHandle, locked: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(t) = (unsafe { get::<MockNode>(&track) }) else {
|
||||
return -1;
|
||||
@@ -1186,8 +1123,7 @@ pub extern "C" fn oaknode_track_get_locked(track: CHandle, locked: *mut c_int) -
|
||||
}
|
||||
|
||||
/// `oaknode_track_set_locked`: set a track's locked flag.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_set_locked(track: CHandle, locked: c_int) -> c_int {
|
||||
pub fn oaknode_track_set_locked(track: CHandle, locked: c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(t) = (unsafe { get_mut::<MockNode>(&track) }) else {
|
||||
return -1;
|
||||
@@ -1200,8 +1136,7 @@ pub extern "C" fn oaknode_track_set_locked(track: CHandle, locked: c_int) -> c_i
|
||||
}
|
||||
|
||||
/// `oaknode_track_get_block_count`: number of blocks on a track.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_block_count(track: CHandle, count: *mut c_int) -> c_int {
|
||||
pub fn oaknode_track_get_block_count(track: CHandle, count: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(t) = (unsafe { get::<MockNode>(&track) }) else {
|
||||
return -1;
|
||||
@@ -1215,8 +1150,7 @@ pub extern "C" fn oaknode_track_get_block_count(track: CHandle, count: *mut c_in
|
||||
}
|
||||
|
||||
/// `oaknode_track_get_block_at`: borrowed block at `index` on a track.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_block_at(track: CHandle, index: c_int, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_track_get_block_at(track: CHandle, index: c_int, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(t) = (unsafe { get::<MockNode>(&track) }) else {
|
||||
return -1;
|
||||
@@ -1233,8 +1167,7 @@ pub extern "C" fn oaknode_track_get_block_at(track: CHandle, index: c_int, out:
|
||||
|
||||
/// `oaknode_track_get_block_containing_time`: the block strictly containing
|
||||
/// `time` (in < t < out); writes null and returns -1 when none.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_block_containing_time(
|
||||
pub fn oaknode_track_get_block_containing_time(
|
||||
track: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
@@ -1264,8 +1197,7 @@ pub extern "C" fn oaknode_track_get_block_containing_time(
|
||||
|
||||
/// `oaknode_track_get_nearest_block_before_or_at`: the block whose in point is
|
||||
/// at or before `time` (the latest such); null when none.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_nearest_block_before_or_at(
|
||||
pub fn oaknode_track_get_nearest_block_before_or_at(
|
||||
track: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
@@ -1295,8 +1227,7 @@ pub extern "C" fn oaknode_track_get_nearest_block_before_or_at(
|
||||
|
||||
/// `oaknode_track_get_nearest_block_after_or_at`: the block whose in point is
|
||||
/// at or after `time` (the earliest such); null when none.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_track_get_nearest_block_after_or_at(
|
||||
pub fn oaknode_track_get_nearest_block_after_or_at(
|
||||
track: CHandle,
|
||||
numerator: c_int,
|
||||
denominator: c_int,
|
||||
@@ -1325,8 +1256,7 @@ pub extern "C" fn oaknode_track_get_nearest_block_after_or_at(
|
||||
}
|
||||
|
||||
/// `oaknode_tracklist_get_type`: the track list's track type.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_tracklist_get_type(list: CHandle, kind: *mut c_int) -> c_int {
|
||||
pub fn oaknode_tracklist_get_type(list: CHandle, kind: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(l) = (unsafe { get::<MockNode>(&list) }) else {
|
||||
return -1;
|
||||
@@ -1340,8 +1270,7 @@ pub extern "C" fn oaknode_tracklist_get_type(list: CHandle, kind: *mut c_int) ->
|
||||
}
|
||||
|
||||
/// `oaknode_tracklist_get_track_count`: number of tracks in a track list.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_tracklist_get_track_count(list: CHandle, count: *mut c_int) -> c_int {
|
||||
pub fn oaknode_tracklist_get_track_count(list: CHandle, count: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(l) = (unsafe { get::<MockNode>(&list) }) else {
|
||||
return -1;
|
||||
@@ -1355,8 +1284,7 @@ pub extern "C" fn oaknode_tracklist_get_track_count(list: CHandle, count: *mut c
|
||||
}
|
||||
|
||||
/// `oaknode_tracklist_get_track_at`: borrowed track at `index` in a track list.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_tracklist_get_track_at(list: CHandle, index: c_int, out: *mut CHandle) -> c_int {
|
||||
pub fn oaknode_tracklist_get_track_at(list: CHandle, index: c_int, out: *mut CHandle) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(l) = (unsafe { get::<MockNode>(&list) }) else {
|
||||
return -1;
|
||||
@@ -1374,22 +1302,19 @@ pub extern "C" fn oaknode_tracklist_get_track_at(list: CHandle, index: c_int, ou
|
||||
/// `oaknode_tracklist_array_append`: append a track-array element on the
|
||||
/// parent sequence. The mock keeps track lists as plain vectors, so this is a
|
||||
/// no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_tracklist_array_append(_list: CHandle) -> c_int {
|
||||
pub fn oaknode_tracklist_array_append(_list: CHandle) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oaknode_tracklist_array_remove_last`: remove the last track-array element.
|
||||
/// No-op in the mock (see `oaknode_tracklist_array_append`).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_tracklist_array_remove_last(_list: CHandle) -> c_int {
|
||||
pub fn oaknode_tracklist_array_remove_last(_list: CHandle) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oaknode_sequence_get_track_list`: the borrowed per-type track list, or
|
||||
/// null when the sequence has no list of that type.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_sequence_get_track_list(
|
||||
pub fn oaknode_sequence_get_track_list(
|
||||
sequence: CHandle,
|
||||
kind: c_int,
|
||||
out: *mut CHandle,
|
||||
@@ -1416,8 +1341,7 @@ pub extern "C" fn oaknode_sequence_get_track_list(
|
||||
|
||||
/// `oaknode_sequence_get_all_track_count`: total connected tracks across all
|
||||
/// types.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_sequence_get_all_track_count(sequence: CHandle, count: *mut c_int) -> c_int {
|
||||
pub fn oaknode_sequence_get_all_track_count(sequence: CHandle, count: *mut c_int) -> c_int {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(s) = (unsafe { get::<MockNode>(&sequence) }) else {
|
||||
return -1;
|
||||
@@ -1440,8 +1364,7 @@ pub extern "C" fn oaknode_sequence_get_all_track_count(sequence: CHandle, count:
|
||||
|
||||
/// `oaknode_sequence_get_all_track_at`: borrowed track at `index` across the
|
||||
/// flat, all-types track list.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_sequence_get_all_track_at(
|
||||
pub fn oaknode_sequence_get_all_track_at(
|
||||
sequence: CHandle,
|
||||
index: c_int,
|
||||
out: *mut CHandle,
|
||||
@@ -1471,8 +1394,7 @@ pub extern "C" fn oaknode_sequence_get_all_track_at(
|
||||
/// `oaknode_node_connect`: connect `output_node` to `input_node`'s `input_id`.
|
||||
/// The mock tracks only the output connection count (input edge table is not
|
||||
/// modelled), so this bumps `output_conns`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_connect(
|
||||
pub fn oaknode_node_connect(
|
||||
output_node: CHandle,
|
||||
_input_node: CHandle,
|
||||
_input_id: *const c_char,
|
||||
@@ -1487,16 +1409,14 @@ pub extern "C" fn oaknode_node_connect(
|
||||
|
||||
/// `oaknode_node_disconnect`: remove the edge feeding `input_node`'s
|
||||
/// `input_id`. The mock has no input-edge table, so this is a no-op.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_disconnect(_input_node: CHandle, _input_id: *const c_char) -> c_int {
|
||||
pub fn oaknode_node_disconnect(_input_node: CHandle, _input_id: *const c_char) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
/// `oaknode_node_copy_in_graph`: clone `node` in its graph; `*out_command`
|
||||
/// receives an owned undo handle. The mock clones the node box and hands back
|
||||
/// a no-op command.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn oaknode_node_copy_in_graph(node: CHandle, out_command: *mut CHandle) -> CHandle {
|
||||
pub fn oaknode_node_copy_in_graph(node: CHandle, out_command: *mut CHandle) -> CHandle {
|
||||
// SAFETY: handle boxes a MockNode.
|
||||
let Some(n) = (unsafe { get::<MockNode>(&node) }) else {
|
||||
return CHandle::null();
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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 (`include/undo/undocommand.h`). Undo commands are
|
||||
//! created through the C ABI vtable (`oakundo_command_init` with Rust
|
||||
//! closures as `userdata`) — timeline does not subclass the C++
|
||||
@@ -27,30 +43,92 @@ use crate::handle::CHandle;
|
||||
/// `OakUndoCommandVtable` — callback table backing a caller-defined undo
|
||||
/// command (undocommand.h). Any callback may be NULL (a NULL redo/undo makes
|
||||
/// that direction a no-op); `free_fn` runs when the command is destroyed.
|
||||
#[repr(C)]
|
||||
pub struct OakUndoCommandVtable {
|
||||
/// `redo` callback (NULL = no-op).
|
||||
pub redo: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// `undo` callback (NULL = no-op).
|
||||
pub undo: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// `free_fn` — releases `userdata` on destruction.
|
||||
pub free_fn: Option<unsafe extern "C" fn(*mut c_void)>,
|
||||
/// 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).
|
||||
pub fn oakundo_command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> CHandle {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_command_init(vtable, userdata)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) }
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
/// `oakundo_command_init` — create a command backed by C callbacks; takes
|
||||
/// ownership of `userdata`, copies `vtable`.
|
||||
pub fn oakundo_command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> CHandle;
|
||||
/// `oakundo_command_init_multi` — an empty multi command.
|
||||
pub fn oakundo_command_init_multi() -> CHandle;
|
||||
/// `oakundo_command_multi_add_child` — add a child to a multi command.
|
||||
pub fn oakundo_command_multi_add_child(multi: CHandle, child: CHandle) -> c_int;
|
||||
/// `oakundo_command_redo_now` — run the command's redo outside a stack.
|
||||
pub fn oakundo_command_redo_now(command: CHandle) -> c_int;
|
||||
/// `oakundo_command_undo_now` — run the command's undo outside a stack.
|
||||
pub fn oakundo_command_undo_now(command: CHandle) -> c_int;
|
||||
/// `oakundo_command_free` — release one reference; NULL is a no-op.
|
||||
pub fn oakundo_command_free(command: *mut CHandle);
|
||||
/// `oakundo_stack_push` — push a command onto a facade-owned stack.
|
||||
pub fn oakundo_stack_push(stack: CHandle, command: CHandle, text: *const c_char) -> c_int;
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_init_multi() -> CHandle {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_command_init_multi()
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::command::oakundo_command_init_multi() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_multi_add_child(multi: CHandle, child: CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_command_multi_add_child(multi, child)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::command::oakundo_command_multi_add_child(multi, child) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_redo_now(command: CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_command_redo_now(command)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::command::oakundo_command_redo_now(command) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_undo_now(command: CHandle) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_command_undo_now(command)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::command::oakundo_command_undo_now(command) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification).
|
||||
pub fn oakundo_command_free(command: *mut CHandle) {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_command_free(command)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::command::oakundo_command_free(command) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Direct call into the `oakundo` crate (single-lib unification; the C ABI
|
||||
/// name is `oakundo_undostack_push` — kept as `oakundo_stack_push` here for
|
||||
/// source compatibility).
|
||||
pub fn oakundo_stack_push(stack: CHandle, command: CHandle, text: *const c_char) -> c_int {
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
{
|
||||
super::teststubs::oakundo_stack_push(stack, command, text)
|
||||
}
|
||||
#[cfg(not(any(test, feature = "test-stubs")))]
|
||||
{
|
||||
unsafe { oakundo::ffi::undostack::oakundo_undostack_push(stack, command, text) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -976,12 +976,18 @@ fn write_cstr(dst: *mut c_char, size: c_int, s: &str) {
|
||||
|
||||
/// Read the next start element's name from `reader`; empty at EOF/error.
|
||||
fn xml_read_next(reader: &H) -> String {
|
||||
// Advance to the next start element (the real ABI writes a 1/0 flag).
|
||||
let mut found = 0;
|
||||
// SAFETY: `found` is a valid out pointer; `reader` is a valid handle.
|
||||
let r = unsafe { xml::oakcommon_xml_reader_read_next_start_element(reader.clone(), &mut found) };
|
||||
if r <= 0 || found == 0 {
|
||||
return String::new();
|
||||
}
|
||||
// Read the current element's name (two-stage).
|
||||
let mut buf = [0 as c_char; 4096];
|
||||
// SAFETY: `buf` is a valid writable buffer; `reader` is a valid handle.
|
||||
let r = unsafe {
|
||||
xml::oakcommon_xml_reader_read_next_start_element(reader.clone(), buf.as_mut_ptr(), buf.len() as c_int)
|
||||
};
|
||||
if r <= 0 {
|
||||
let n = unsafe { xml::oakcommon_xml_reader_name(reader.clone(), buf.as_mut_ptr(), buf.len() as c_int) };
|
||||
if n <= 0 {
|
||||
return String::new();
|
||||
}
|
||||
// SAFETY: the reader wrote a NUL-terminated string into `buf`.
|
||||
|
||||
@@ -105,7 +105,7 @@ pub fn free_detached_handle(h: *mut CHandle) {
|
||||
}
|
||||
|
||||
/// Read a block time field as a `Rational`.
|
||||
fn block_pair(b: CHandle, f: unsafe extern "C" fn(CHandle, *mut i32, *mut i32) -> i32) -> Rational {
|
||||
fn block_pair(b: CHandle, f: fn(CHandle, *mut i32, *mut i32) -> i32) -> Rational {
|
||||
let mut n = 0;
|
||||
let mut d = 0;
|
||||
// SAFETY: `n`/`d` are valid out pointers.
|
||||
|
||||
@@ -208,8 +208,9 @@ fn xml_bridge_validate_handles() {
|
||||
|
||||
// A null reader is an invalid argument: read fails cleanly (0).
|
||||
let mut buf = [0i8; 64];
|
||||
let mut found = 0;
|
||||
assert_eq!(
|
||||
unsafe { oakcommon_xml_reader_read_next_start_element(CHandle::null(), buf.as_mut_ptr(), 64) },
|
||||
unsafe { oakcommon_xml_reader_read_next_start_element(CHandle::null(), &mut found) },
|
||||
0
|
||||
);
|
||||
|
||||
@@ -217,8 +218,9 @@ fn xml_bridge_validate_handles() {
|
||||
// elements it reports end-of-stream for every accessor.
|
||||
let mut reader = unsafe { oakcommon_xml_reader_init(b"<project/>\0".as_ptr() as *const std::ffi::c_char) };
|
||||
assert!(!reader.is_null());
|
||||
let mut found = 0;
|
||||
assert_eq!(
|
||||
unsafe { oakcommon_xml_reader_read_next_start_element(reader.clone(), buf.as_mut_ptr(), 64) },
|
||||
unsafe { oakcommon_xml_reader_read_next_start_element(reader.clone(), &mut found) },
|
||||
0
|
||||
);
|
||||
assert_eq!(unsafe { oakcommon_xml_reader_name(reader.clone(), buf.as_mut_ptr(), 64) }, 0);
|
||||
@@ -242,8 +244,14 @@ fn xml_bridge_validate_handles() {
|
||||
text: "hello".to_string(),
|
||||
attrs: vec![("color".to_string(), "red".to_string())],
|
||||
}]);
|
||||
let mut found = 0;
|
||||
assert_eq!(
|
||||
unsafe { oakcommon_xml_reader_read_next_start_element(r.clone(), buf.as_mut_ptr(), 64) },
|
||||
unsafe { oakcommon_xml_reader_read_next_start_element(r.clone(), &mut found) },
|
||||
1
|
||||
);
|
||||
assert_eq!(found, 1);
|
||||
assert_eq!(
|
||||
unsafe { oakcommon_xml_reader_name(r.clone(), buf.as_mut_ptr(), 64) },
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -107,8 +107,9 @@ fn xml_reader_accessors_missing() {
|
||||
let mut buf = [0 as c_char; 16];
|
||||
// No current element: every accessor returns 0.
|
||||
let mut r = xml_reader_handle(Vec::new());
|
||||
let mut found = 0;
|
||||
unsafe { oaktimeline::bridge::common::oakcommon_xml_reader_read_next_start_element(
|
||||
r.clone(), buf.as_mut_ptr(), 16,
|
||||
r.clone(), &mut found,
|
||||
) };
|
||||
assert_eq!(unsafe { oakcommon_xml_reader_name(r.clone(), buf.as_mut_ptr(), 16) }, 0);
|
||||
assert_eq!(unsafe { oakcommon_xml_reader_read_element_text(r.clone(), buf.as_mut_ptr(), 16) }, 0);
|
||||
@@ -126,8 +127,9 @@ fn xml_reader_accessors_missing() {
|
||||
text: String::new(),
|
||||
attrs: Vec::new(),
|
||||
}]);
|
||||
let mut found = 0;
|
||||
unsafe { oaktimeline::bridge::common::oakcommon_xml_reader_read_next_start_element(
|
||||
r2.clone(), buf.as_mut_ptr(), 16,
|
||||
r2.clone(), &mut found,
|
||||
) };
|
||||
unsafe { oakcommon_xml_reader_attribute_count(r2.clone(), &mut count) };
|
||||
assert_eq!(count, 0);
|
||||
|
||||
Reference in New Issue
Block a user