Files
oak-editor/crates/oaktask/tests/common/mod.rs
T
Mike-Solar 013a175707 refactor: workspace layout — crates/, app at root, legacy C++ removed
Single mechanical restructure commit:
- root Cargo.toml = oakapp bin + workspace; one cargo build produces
  oakapp, oak-cli, oak-worker, liboakengine.dylib
- app/rust/src -> src/ (app at repo root, no rust/ nesting)
- src/<mod>/rust -> crates/oak<mod>; src/oakcore-rs -> crates/oakcore;
  src/bindings/oakotio -> crates/oakotio; src/engine/rust ->
  crates/oakengine (keeps cdylib+staticlib+rlib)
- public C headers include/<mod>/ -> crates/oakengine/include/<mod>/
- OFX SDK headers vendored into crates/oakplugin/ofx/ (HostSupport gone)
- legacy deleted: old src/ C++ modules, engine/, core/, ffmpeg_bridge/,
  app/ (Qt), cli/worker C++, root CMakeLists, third_party/KDDockWidgets
  submodule, otio-install, all build-* output (~40GB)
- oakstorage kept but excluded from the workspace (skeleton w/ todos);
  gpui excluded (own workspace)
- verified: cargo build green, cargo test --workspace 1845/0
  (with the documented OCIO_RS_* env override for the homebrew OCIO)
2026-08-10 20:24:25 +08:00

2471 lines
74 KiB
Rust

// 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/>.
//! Test-only `#[no_mangle]` stubs for every extern C symbol the crate
//! imports. Integration test binaries link the crate's rlib, which
//! references the real module DLLs; these stubs satisfy the linker and let
//! the real task logic run against controllable behavior. Each stub family
//! exposes `set_*` helpers used by the tests to drive success/failure paths.
#![allow(non_snake_case, dead_code, unused_variables, clippy::missing_safety_doc)]
use std::ffi::{c_char, c_int, c_void};
use std::sync::atomic::{AtomicI32, AtomicI64, Ordering};
// AtomicUsize/Condvar are only used by the simulated oakrender ticket
// arena, which the `real-oakrender` feature compiles out.
#[cfg(not(feature = "real-oakrender"))]
use std::sync::atomic::AtomicUsize;
use std::sync::Mutex;
#[cfg(not(feature = "real-oakrender"))]
use std::sync::Condvar;
// ---------------------------------------------------------------------------
// Fake handle helpers
// ---------------------------------------------------------------------------
/// A fake refcounted handle: non-null ctx with no-op addref/release.
pub fn fake_handle() -> oaktask::handle::CHandle {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::handle::CHandle {
ctx: 1usize as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
pub fn empty_handle() -> oaktask::handle::CHandle {
oaktask::handle::CHandle::null()
}
/// A fake OakCancelAtom (ctx non-null so `is_null()` is false).
pub fn fake_atom() -> oaktask::bridge::render::OakCancelAtom {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::bridge::render::OakCancelAtom {
ctx: 2usize as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
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(), buf, bytes.len());
*buf.add(bytes.len()) = 0;
}
}
needed
}
pub fn cstr_of(s: &str) -> *const c_char {
let mut v = s.as_bytes().to_vec();
v.push(0);
v.leak().as_ptr() as *const c_char
}
// ---------------------------------------------------------------------------
// Control statics
// ---------------------------------------------------------------------------
pub static SERIALIZER_LOAD_CODE: AtomicI32 = AtomicI32::new(0); // OAKNODE_SERIALIZER_RESULT_*
pub static SERIALIZER_LOAD_RET: AtomicI32 = AtomicI32::new(0); // oaknode_serializer_load_from_file return
pub static SERIALIZER_SAVE_CODE: AtomicI32 = AtomicI32::new(0);
pub static SERIALIZER_DETAILS: Mutex<&'static str> = Mutex::new("");
pub static PROJECT_FILENAME: Mutex<String> = Mutex::new(String::new());
pub static NODE_LABEL: Mutex<String> = Mutex::new(String::new());
pub static FOOTAGE_FILENAME: Mutex<String> = Mutex::new(String::new());
pub static FOOTAGE_VALID: AtomicI32 = AtomicI32::new(1);
pub static FOOTAGE_STREAM_COUNT: AtomicI32 = AtomicI32::new(1);
pub static VIDEO_TYPE: AtomicI32 = AtomicI32::new(1); // OAKCOMMON_VIDEO_TYPE_STILL
pub static VIDEO_IS_VALID: AtomicI32 = AtomicI32::new(1);
pub static VIDEO_WIDTH: AtomicI32 = AtomicI32::new(640);
pub static VIDEO_HEIGHT: AtomicI32 = AtomicI32::new(360);
pub static VIDEO_TIME_BASE_NUM: AtomicI32 = AtomicI32::new(0); // 0 => render falls back to 1/1
pub static VIDEO_TIME_BASE_DEN: AtomicI32 = AtomicI32::new(1);
pub static VIDEO_LENGTH_NUM: AtomicI64 = AtomicI64::new(0);
pub static VIDEO_LENGTH_DEN: AtomicI64 = AtomicI64::new(1);
pub static SEQUENCE_LENGTH_NUM: AtomicI32 = AtomicI32::new(0);
pub static SEQUENCE_LENGTH_DEN: AtomicI32 = AtomicI32::new(1);
pub static CONNECTED_NODE: AtomicI64 = AtomicI64::new(1); // non-null => connected
pub static FOLDER_CHILD_COUNT: AtomicI32 = AtomicI32::new(0);
pub static REDO_DELTA: AtomicI32 = AtomicI32::new(0);
pub static MULTI_CHILDREN: AtomicI32 = AtomicI32::new(0);
pub static DECODER_OPEN_RESULT: AtomicI32 = AtomicI32::new(0);
pub static DECODER_CONFORM_RESULT: AtomicI32 = AtomicI32::new(0);
pub static DECODER_LAST_ERROR: Mutex<String> = Mutex::new(String::new());
pub static ENCODER_INIT_NULL: AtomicI32 = AtomicI32::new(0);
pub static ENCODER_OPEN_RESULT: AtomicI32 = AtomicI32::new(0);
pub static ENCODER_WRITE_VIDEO_RESULT: AtomicI32 = AtomicI32::new(0);
pub static ENCODER_WRITE_SUBTITLE_RESULT: AtomicI32 = AtomicI32::new(0);
pub static ENCODER_FLUSH_ERROR: AtomicI32 = AtomicI32::new(0); // non-zero => flush reports an error
pub static ENCODER_LAST_ERROR: Mutex<String> = Mutex::new(String::new());
pub static DESIRED_PIXEL_FORMAT: AtomicI32 = AtomicI32::new(0);
pub static IMAGE_SEQUENCE_DIGIT_COUNT: AtomicI32 = AtomicI32::new(0);
pub static CONFIG_DEFAULT_SEQ_FRAME_RATE: AtomicI32 = AtomicI32::new(0); // 0 => config_get returns nothing
pub static PROXY_FFMPEG_PATH: Mutex<String> = Mutex::new(String::new());
pub static SUBMIT_CB: Mutex<Option<unsafe extern "C" fn(*const oaktask::bridge::codec::OakCodecTaskRequest, *mut c_void) -> c_int>> =
Mutex::new(None);
// Simulated-oakrender-arena state below is only linked in stub mode: the
// `real-oakrender` feature replaces the render stubs with the real
// oakrender exports, so these statics and the `#[no_mangle]` render stubs
// are compiled out together.
#[cfg(not(feature = "real-oakrender"))]
pub static ATOM_CANCELLED: AtomicI32 = AtomicI32::new(0);
#[cfg(not(feature = "real-oakrender"))]
pub static TICKET_FRAME_VALID: AtomicI32 = AtomicI32::new(1); // 0 => get_frame returns empty frame
#[cfg(not(feature = "real-oakrender"))]
pub static TICKET_GET_FRAME_RESULT: AtomicI32 = AtomicI32::new(0);
// Simulated ticket arena (bridge::render ticket stubs below).
// 0 = tickets complete synchronously on submit (the deterministic
// single-thread path the export/task tests rely on); 1 = tickets stay in
// flight until the test fires them with `stub_complete` (scrambled
// completion-order tests).
#[cfg(not(feature = "real-oakrender"))]
pub static TICKET_DEFER: AtomicI32 = AtomicI32::new(0);
pub static NODE_ID: Mutex<String> = Mutex::new(String::new());
pub static AUDIO_TRACK_LIST_NULL: AtomicI32 = AtomicI32::new(1); // 1 => sequence audio track list is empty (null handle)
pub static FOOTAGE_FOUND: AtomicI32 = AtomicI32::new(1); // 0 => oaknode_node_find_input_footage finds nothing
pub static BLOCK_KIND: AtomicI32 = AtomicI32::new(1); // OAKNODE_BLOCK_CLIP
pub static BLOCK_IN_NUM: AtomicI32 = AtomicI32::new(0);
pub static BLOCK_IN_DEN: AtomicI32 = AtomicI32::new(1);
pub static BLOCK_LENGTH_NUM: AtomicI32 = AtomicI32::new(0);
pub static BLOCK_LENGTH_DEN: AtomicI32 = AtomicI32::new(1);
pub static TRACK_BLOCK_COUNT: AtomicI32 = AtomicI32::new(0);
pub static TRACK_TYPE: AtomicI32 = AtomicI32::new(0); // OAKNODE_TRACK_TYPE_VIDEO
pub static TRACK_LENGTH_NUM: AtomicI32 = AtomicI32::new(0);
pub static TRACK_LENGTH_DEN: AtomicI32 = AtomicI32::new(1);
pub static TRACK_LIST_TRACK_COUNT: AtomicI32 = AtomicI32::new(1);
pub static VIDEO_FRAME_RATE_NUM: AtomicI32 = AtomicI32::new(0);
pub static VIDEO_FRAME_RATE_DEN: AtomicI32 = AtomicI32::new(1);
pub static VIDEO_DURATION: AtomicI64 = AtomicI64::new(0);
pub static APPENDED_BLOCKS: AtomicI32 = AtomicI32::new(0);
pub static FOOTAGE_CREATE_COUNT: AtomicI32 = AtomicI32::new(0);
pub static MEDIA_IN_NUM: AtomicI32 = AtomicI32::new(0);
pub static MEDIA_IN_DEN: AtomicI32 = AtomicI32::new(1);
pub static SET_LENGTH_NUM: AtomicI32 = AtomicI32::new(0);
pub static SET_LENGTH_DEN: AtomicI32 = AtomicI32::new(1);
pub static TRANSITION_IN_NUM: AtomicI32 = AtomicI32::new(0);
pub static TRANSITION_IN_DEN: AtomicI32 = AtomicI32::new(1);
pub static TRANSITION_OUT_NUM: AtomicI32 = AtomicI32::new(0);
pub static TRANSITION_OUT_DEN: AtomicI32 = AtomicI32::new(1);
pub static CONNECT_INPUT_IDS: Mutex<Vec<String>> = Mutex::new(Vec::new());
/// Serialize manager-dependent tests in one binary (the singleton is
/// process-wide).
pub static MANAGER_LOCK: Mutex<()> = Mutex::new(());
pub fn reset_stubs() {
SERIALIZER_LOAD_CODE.store(0, Ordering::SeqCst);
SERIALIZER_LOAD_RET.store(0, Ordering::SeqCst);
SERIALIZER_SAVE_CODE.store(0, Ordering::SeqCst);
*SERIALIZER_DETAILS.lock().unwrap() = "";
PROJECT_FILENAME.lock().unwrap().clear();
NODE_LABEL.lock().unwrap().clear();
FOOTAGE_FILENAME.lock().unwrap().clear();
FOOTAGE_VALID.store(1, Ordering::SeqCst);
FOOTAGE_STREAM_COUNT.store(1, Ordering::SeqCst);
VIDEO_TYPE.store(1, Ordering::SeqCst);
VIDEO_IS_VALID.store(1, Ordering::SeqCst);
VIDEO_WIDTH.store(640, Ordering::SeqCst);
VIDEO_HEIGHT.store(360, Ordering::SeqCst);
VIDEO_TIME_BASE_NUM.store(0, Ordering::SeqCst);
VIDEO_TIME_BASE_DEN.store(1, Ordering::SeqCst);
VIDEO_LENGTH_NUM.store(0, Ordering::SeqCst);
VIDEO_LENGTH_DEN.store(1, Ordering::SeqCst);
SEQUENCE_LENGTH_NUM.store(0, Ordering::SeqCst);
SEQUENCE_LENGTH_DEN.store(1, Ordering::SeqCst);
CONNECTED_NODE.store(1, Ordering::SeqCst);
FOLDER_CHILD_COUNT.store(0, Ordering::SeqCst);
REDO_DELTA.store(0, Ordering::SeqCst);
MULTI_CHILDREN.store(0, Ordering::SeqCst);
DECODER_OPEN_RESULT.store(0, Ordering::SeqCst);
DECODER_CONFORM_RESULT.store(0, Ordering::SeqCst);
*DECODER_LAST_ERROR.lock().unwrap() = String::from("stub decoder error");
*ENCODER_LAST_ERROR.lock().unwrap() = String::from("stub encoder error");
ENCODER_INIT_NULL.store(0, Ordering::SeqCst);
ENCODER_OPEN_RESULT.store(0, Ordering::SeqCst);
ENCODER_WRITE_VIDEO_RESULT.store(0, Ordering::SeqCst);
ENCODER_WRITE_SUBTITLE_RESULT.store(0, Ordering::SeqCst);
ENCODER_FLUSH_ERROR.store(0, Ordering::SeqCst);
DESIRED_PIXEL_FORMAT.store(0, Ordering::SeqCst);
IMAGE_SEQUENCE_DIGIT_COUNT.store(0, Ordering::SeqCst);
CONFIG_DEFAULT_SEQ_FRAME_RATE.store(0, Ordering::SeqCst);
PROXY_FFMPEG_PATH.lock().unwrap().clear();
*SUBMIT_CB.lock().unwrap() = None;
#[cfg(not(feature = "real-oakrender"))]
ATOM_CANCELLED.store(0, Ordering::SeqCst);
#[cfg(not(feature = "real-oakrender"))]
TICKET_FRAME_VALID.store(1, Ordering::SeqCst);
#[cfg(not(feature = "real-oakrender"))]
TICKET_GET_FRAME_RESULT.store(0, Ordering::SeqCst);
// Ticket arena state: back to immediate-completion mode, no tickets.
#[cfg(not(feature = "real-oakrender"))]
TICKET_DEFER.store(0, Ordering::SeqCst);
#[cfg(not(feature = "real-oakrender"))]
TICKET_NEXT_ID.store(0, Ordering::SeqCst);
#[cfg(not(feature = "real-oakrender"))]
TICKET_SUBMITTED.store(0, Ordering::SeqCst);
#[cfg(not(feature = "real-oakrender"))]
TICKET_COMPLETED.store(0, Ordering::SeqCst);
#[cfg(not(feature = "real-oakrender"))]
TICKETS.lock().unwrap_or_else(|e| e.into_inner()).clear();
NODE_ID.lock().unwrap().clear();
AUDIO_TRACK_LIST_NULL.store(1, Ordering::SeqCst);
FOOTAGE_FOUND.store(1, Ordering::SeqCst);
BLOCK_KIND.store(1, Ordering::SeqCst);
BLOCK_IN_NUM.store(0, Ordering::SeqCst);
BLOCK_IN_DEN.store(1, Ordering::SeqCst);
BLOCK_LENGTH_NUM.store(0, Ordering::SeqCst);
BLOCK_LENGTH_DEN.store(1, Ordering::SeqCst);
TRACK_BLOCK_COUNT.store(0, Ordering::SeqCst);
TRACK_TYPE.store(0, Ordering::SeqCst);
TRACK_LENGTH_NUM.store(0, Ordering::SeqCst);
TRACK_LENGTH_DEN.store(1, Ordering::SeqCst);
TRACK_LIST_TRACK_COUNT.store(1, Ordering::SeqCst);
VIDEO_FRAME_RATE_NUM.store(0, Ordering::SeqCst);
VIDEO_FRAME_RATE_DEN.store(1, Ordering::SeqCst);
VIDEO_DURATION.store(0, Ordering::SeqCst);
APPENDED_BLOCKS.store(0, Ordering::SeqCst);
FOOTAGE_CREATE_COUNT.store(0, Ordering::SeqCst);
MEDIA_IN_NUM.store(0, Ordering::SeqCst);
MEDIA_IN_DEN.store(1, Ordering::SeqCst);
SET_LENGTH_NUM.store(0, Ordering::SeqCst);
SET_LENGTH_DEN.store(1, Ordering::SeqCst);
TRANSITION_IN_NUM.store(0, Ordering::SeqCst);
TRANSITION_IN_DEN.store(1, Ordering::SeqCst);
TRANSITION_OUT_NUM.store(0, Ordering::SeqCst);
TRANSITION_OUT_DEN.store(1, Ordering::SeqCst);
CONNECT_INPUT_IDS.lock().unwrap().clear();
}
// ---------------------------------------------------------------------------
// bridge::codec stubs
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oakcodec_set_task_submit_cb(
cb: Option<unsafe extern "C" fn(*const oaktask::bridge::codec::OakCodecTaskRequest, *mut c_void) -> c_int>,
_userdata: *mut c_void,
) {
*SUBMIT_CB.lock().unwrap() = cb;
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_task_submit_is_registered() -> c_int {
if SUBMIT_CB.lock().unwrap().is_some() {
1
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_init() -> oaktask::bridge::codec::OakDecoder {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_free(_decoder: *mut oaktask::bridge::codec::OakDecoder) {}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_open(
_decoder: oaktask::bridge::codec::OakDecoder,
_filename: *const c_char,
_stream_index: c_int,
) -> c_int {
DECODER_OPEN_RESULT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_close(_decoder: oaktask::bridge::codec::OakDecoder) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_is_open(_decoder: oaktask::bridge::codec::OakDecoder) -> c_int {
1
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_decode_video(
_decoder: oaktask::bridge::codec::OakDecoder,
_numerator: c_int,
_denominator: c_int,
) -> oaktask::bridge::codec::OakDecoder {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_decode_audio(
_decoder: oaktask::bridge::codec::OakDecoder,
_in_num: c_int,
_in_den: c_int,
_out_num: c_int,
_out_den: c_int,
_sample_rate: c_int,
_channel_layout: u64,
_buf: *mut f32,
_buf_frames: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_conform_audio(
_decoder: oaktask::bridge::codec::OakDecoder,
_output_filenames: *const *const c_char,
_filename_count: c_int,
_sample_rate: c_int,
_channel_layout: u64,
_sample_format: c_int,
_cancelled: oaktask::bridge::render::OakCancelAtom,
) -> c_int {
DECODER_CONFORM_RESULT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_last_error(
_decoder: oaktask::bridge::codec::OakDecoder,
buf: *mut c_char,
size: c_int,
) -> c_int {
write_cstr(&DECODER_LAST_ERROR.lock().unwrap().clone(), buf as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_get_image_sequence_digit_count(_filename: *const c_char) -> c_int {
IMAGE_SEQUENCE_DIGIT_COUNT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_get_image_sequence_index(filename: *const c_char) -> i64 {
// Trailing digits of the stem (before the extension).
let s = if filename.is_null() {
String::new()
} else {
std::ffi::CStr::from_ptr(filename).to_string_lossy().into_owned()
};
let stem = match s.rfind('.') {
Some(dot) => &s[..dot],
None => s.as_str(),
};
let digits: String = stem.chars().rev().take_while(|c| c.is_ascii_digit()).collect();
digits.chars().rev().collect::<String>().parse().unwrap_or(-1)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_decoder_transform_image_sequence_file_name(
filename: *const c_char,
number: i64,
buf: *mut c_char,
size: c_int,
) -> c_int {
let s = if filename.is_null() {
String::new()
} else {
std::ffi::CStr::from_ptr(filename).to_string_lossy().into_owned()
};
let (stem, ext) = match s.rfind('.') {
Some(dot) => (&s[..dot], &s[dot..]),
None => (s.as_str(), ""),
};
let digits: String = stem.chars().rev().take_while(|c| c.is_ascii_digit()).collect();
let count = digits.len().max(1);
let prefix = &stem[..stem.len() - digits.len()];
let out = format!("{prefix}{:0count$}{ext}", number);
write_cstr(&out, buf as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_init(
_params: *const oaktask::bridge::codec::OakCodecEncodingParams,
) -> oaktask::bridge::codec::OakEncoder {
if ENCODER_INIT_NULL.load(Ordering::SeqCst) != 0 {
empty_handle()
} else {
fake_handle()
}
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_free(_encoder: *mut oaktask::bridge::codec::OakEncoder) {}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_set_video_option(
_encoder: oaktask::bridge::codec::OakEncoder,
_key: *const c_char,
_value: *const c_char,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_open(_encoder: oaktask::bridge::codec::OakEncoder) -> c_int {
ENCODER_OPEN_RESULT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_write_video(
_encoder: oaktask::bridge::codec::OakEncoder,
_frame: oaktask::bridge::codec::OakFrame,
) -> c_int {
ENCODER_WRITE_VIDEO_RESULT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_write_audio(
_encoder: oaktask::bridge::codec::OakEncoder,
_samples: *const f32,
_frame_count: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_write_subtitle(
_encoder: oaktask::bridge::codec::OakEncoder,
_text: *const c_char,
_in_seconds: f64,
_out_seconds: f64,
) -> c_int {
ENCODER_WRITE_SUBTITLE_RESULT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_flush(_encoder: oaktask::bridge::codec::OakEncoder) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_last_error(
_encoder: oaktask::bridge::codec::OakEncoder,
buf: *mut c_char,
size: c_int,
) -> c_int {
if ENCODER_FLUSH_ERROR.load(Ordering::SeqCst) != 0 {
write_cstr(&ENCODER_LAST_ERROR.lock().unwrap().clone(), buf as *mut u8, size)
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_encoder_get_desired_pixel_format(_encoder: oaktask::bridge::codec::OakEncoder) -> c_int {
DESIRED_PIXEL_FORMAT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" 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 {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_proxy_find_ffmpeg(
_configured_path: *const c_char,
buf: *mut c_char,
size: c_int,
) -> c_int {
let path = PROXY_FFMPEG_PATH.lock().unwrap().clone();
if path.is_empty() {
return 0;
}
write_cstr(&path, buf as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oakcodec_proxy_params_default(
out: *mut oaktask::bridge::codec::OakCodecProxyParams,
) -> c_int {
if out.is_null() {
return -1;
}
(*out).width = 1280;
(*out).height = 720;
(*out).divider = 1;
(*out).version = 0;
(*out).crf = 23;
(*out).include_audio = 1;
write_cstr("mp4", (*out).extension.as_mut_ptr(), 32);
write_cstr("veryfast", (*out).preset.as_mut_ptr(), 32);
0
}
// ---------------------------------------------------------------------------
// bridge::common stubs
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_init() -> oaktask::bridge::common::OakVideoParams {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_init_basic(
_width: c_int,
_height: c_int,
_pixel_format: c_int,
_nb_channels: c_int,
_pixel_aspect_num: c_int,
_pixel_aspect_den: c_int,
_interlacing: c_int,
_divider: c_int,
) -> oaktask::bridge::common::OakVideoParams {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_free(_params: *mut oaktask::bridge::common::OakVideoParams) {}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_width(_params: oaktask::bridge::common::OakVideoParams, width: *mut c_int) -> c_int {
if !width.is_null() {
*width = VIDEO_WIDTH.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_height(_params: oaktask::bridge::common::OakVideoParams, height: *mut c_int) -> c_int {
if !height.is_null() {
*height = VIDEO_HEIGHT.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_format(_params: oaktask::bridge::common::OakVideoParams, format: *mut c_int) -> c_int {
if !format.is_null() {
*format = 0;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_set_format(_params: oaktask::bridge::common::OakVideoParams, _format: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_time_base(
_params: oaktask::bridge::common::OakVideoParams,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
if !numerator.is_null() {
*numerator = VIDEO_TIME_BASE_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = VIDEO_TIME_BASE_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_set_time_base(
_params: oaktask::bridge::common::OakVideoParams,
_numerator: c_int,
_denominator: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_frame_rate_as_time_base(
_params: oaktask::bridge::common::OakVideoParams,
out_num: *mut c_int,
out_den: *mut c_int,
) -> c_int {
if !out_num.is_null() {
*out_num = VIDEO_TIME_BASE_NUM.load(Ordering::SeqCst);
}
if !out_den.is_null() {
*out_den = VIDEO_TIME_BASE_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_set_frame_rate(
_params: oaktask::bridge::common::OakVideoParams,
_numerator: c_int,
_denominator: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_video_type(
_params: oaktask::bridge::common::OakVideoParams,
out_type: *mut c_int,
) -> c_int {
if !out_type.is_null() {
*out_type = VIDEO_TYPE.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_set_video_type(_params: oaktask::bridge::common::OakVideoParams, _video_type: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_set_start_time(_params: oaktask::bridge::common::OakVideoParams, _start: i64) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_set_duration(_params: oaktask::bridge::common::OakVideoParams, _duration: i64) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_is_valid(
_params: oaktask::bridge::common::OakVideoParams,
out_valid: *mut c_int,
) -> c_int {
if !out_valid.is_null() {
*out_valid = VIDEO_IS_VALID.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_frame_rate(
_params: oaktask::bridge::common::OakVideoParams,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
if !numerator.is_null() {
*numerator = VIDEO_FRAME_RATE_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = VIDEO_FRAME_RATE_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_videoparams_get_duration(
_params: oaktask::bridge::common::OakVideoParams,
duration: *mut i64,
) -> c_int {
if !duration.is_null() {
*duration = VIDEO_DURATION.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_colortransform_init_display(
_display: *const c_char,
_view: *const c_char,
_look: *const c_char,
) -> oaktask::bridge::common::OakColorTransform {
oaktask::bridge::common::OakColorTransform {
ctx: 3usize as *mut c_void,
addref: None,
release: None,
abi_version: 1,
}
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_colortransform_init_output(
_output: *const c_char,
_display: *const c_char,
_view: *const c_char,
_look: *const c_char,
) -> oaktask::bridge::common::OakColorTransform {
oaktask::bridge::common::OakColorTransform {
ctx: 3usize as *mut c_void,
addref: None,
release: None,
abi_version: 1,
}
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_colortransform_free(_transform: *mut oaktask::bridge::common::OakColorTransform) {}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_config_get(
_group: *const c_char,
key: *const c_char,
buf: *mut c_char,
size: c_int,
) -> c_int {
if key.is_null() {
return 0;
}
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 as *mut u8, size)
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_config_get_int(_group: *const c_char, _key: *const c_char, default: c_int) -> c_int {
default
}
#[no_mangle]
pub unsafe extern "C" fn oakcommon_config_get_bool(_group: *const c_char, _key: *const c_char, default: c_int) -> c_int {
default
}
// ---------------------------------------------------------------------------
// bridge::node stubs
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_init() -> oaktask::bridge::node::OakNodeProject {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_free(_project: *mut oaktask::bridge::node::OakNodeProject) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_initialize(_project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_clear(_project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_root(_project: oaktask::bridge::node::OakNodeProject) -> oaktask::bridge::node::OakNodeFolder {
fake_handle()
}
#[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 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 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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_set_filename(_project: oaktask::bridge::node::OakNodeProject, _filename: *const c_char) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_is_modified(_project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_set_modified(_project: oaktask::bridge::node::OakNodeProject, _modified: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_is_new(_project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_copy_settings(_dst: oaktask::bridge::node::OakNodeProject, _src: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_get_cache_location_setting(_project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_set_cache_location_setting(_project: oaktask::bridge::node::OakNodeProject, _setting: c_int) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_set_custom_cache_path(_project: oaktask::bridge::node::OakNodeProject, _path: *const c_char) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_add_node(_project: oaktask::bridge::node::OakNodeProject, _node: oaktask::bridge::node::OakNodeNode) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_remove_node(_project: oaktask::bridge::node::OakNodeProject, _node: oaktask::bridge::node::OakNodeNode) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_node_count(_project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_project_node_at(_project: oaktask::bridge::node::OakNodeProject, _index: c_int) -> oaktask::bridge::node::OakNodeNode {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_create(_project: oaktask::bridge::node::OakNodeProject) -> oaktask::bridge::node::OakNodeFolder {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_child_count(_folder: oaktask::bridge::node::OakNodeFolder) -> c_int {
FOLDER_CHILD_COUNT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_child_at(_folder: oaktask::bridge::node::OakNodeFolder, _index: c_int) -> oaktask::bridge::node::OakNodeNode {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_add_child(_folder: oaktask::bridge::node::OakNodeFolder, _child: oaktask::bridge::node::OakNodeNode) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_as_node(folder: oaktask::bridge::node::OakNodeFolder) -> oaktask::bridge::node::OakNodeNode {
folder
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_command_create_folder_add_child(
_folder: oaktask::bridge::node::OakNodeFolder,
_child: oaktask::bridge::node::OakNodeNode,
) -> oaktask::bridge::undo::OakUndoCommand {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_command_create_remove_node(_node: oaktask::bridge::node::OakNodeNode) -> oaktask::bridge::undo::OakUndoCommand {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_remove_child(_folder: oaktask::bridge::node::OakNodeFolder, _child: oaktask::bridge::node::OakNodeNode) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_move_children(_nodes: *const oaktask::bridge::node::OakNodeNode, _count: c_int, _dest: oaktask::bridge::node::OakNodeFolder) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_has_child_recursive(_folder: oaktask::bridge::node::OakNodeFolder, _child: oaktask::bridge::node::OakNodeNode) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_index_of_child(_folder: oaktask::bridge::node::OakNodeFolder, _child: oaktask::bridge::node::OakNodeNode) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_folder_parent_of(_node: oaktask::bridge::node::OakNodeNode) -> oaktask::bridge::node::OakNodeFolder {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_create(
_project: oaktask::bridge::node::OakNodeProject,
_filename: *const c_char,
) -> oaktask::bridge::node::OakNodeFootage {
FOOTAGE_CREATE_COUNT.fetch_add(1, Ordering::SeqCst);
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_as_node(footage: oaktask::bridge::node::OakNodeFootage) -> oaktask::bridge::node::OakNodeNode {
footage
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_set_filename(
_footage: oaktask::bridge::node::OakNodeFootage,
filename: *const c_char,
) -> c_int {
if !filename.is_null() {
*FOOTAGE_FILENAME.lock().unwrap() =
std::ffi::CStr::from_ptr(filename).to_string_lossy().into_owned();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_is_valid(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
FOOTAGE_VALID.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_timestamp(_footage: oaktask::bridge::node::OakNodeFootage, _out_timestamp: *mut i64) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_set_timestamp(_footage: oaktask::bridge::node::OakNodeFootage, _timestamp: i64) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_total_stream_count(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
FOOTAGE_STREAM_COUNT.load(Ordering::SeqCst)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_video_stream_count(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
1
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_audio_stream_count(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_subtitle_stream_count(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_duration(
_footage: oaktask::bridge::node::OakNodeFootage,
out_numerator: *mut c_int,
out_denominator: *mut c_int,
) -> c_int {
if !out_numerator.is_null() {
*out_numerator = 0;
}
if !out_denominator.is_null() {
*out_denominator = 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_proxy_enabled(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_set_proxy_enabled(_footage: oaktask::bridge::node::OakNodeFootage, _enabled: c_int) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_proxy_state(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_set_proxy(
_footage: oaktask::bridge::node::OakNodeFootage,
_path: *const c_char,
_state: c_int,
_video_stream_index: c_int,
_preset_version: c_int,
_enabled: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_clear_proxy(_footage: oaktask::bridge::node::OakNodeFootage) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_get_video_params(
_footage: oaktask::bridge::node::OakNodeFootage,
_index: c_int,
out: *mut oaktask::bridge::common::OakVideoParams,
) -> c_int {
if !out.is_null() {
*out = oakcommon_videoparams_init();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_set_video_params(
_footage: oaktask::bridge::node::OakNodeFootage,
_index: c_int,
_params: *const oaktask::bridge::common::OakVideoParams,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_get_video_length(
_footage: oaktask::bridge::node::OakNodeFootage,
out_num: *mut i64,
out_den: *mut i64,
) -> c_int {
if !out_num.is_null() {
*out_num = VIDEO_LENGTH_NUM.load(Ordering::SeqCst);
}
if !out_den.is_null() {
*out_den = VIDEO_LENGTH_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_footage_set_cancel_atom(
_footage: oaktask::bridge::node::OakNodeFootage,
_atom: oaktask::bridge::render::OakCancelAtom,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_create() -> oaktask::bridge::node::OakNodeSequence {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_free(_sequence: *mut oaktask::bridge::node::OakNodeSequence) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_set_default_parameters(_sequence: oaktask::bridge::node::OakNodeSequence) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_as_node(sequence: oaktask::bridge::node::OakNodeSequence) -> oaktask::bridge::node::OakNodeNode {
sequence
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_from_node(node: oaktask::bridge::node::OakNodeNode) -> oaktask::bridge::node::OakNodeSequence {
node
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_track_list(
_sequence: oaktask::bridge::node::OakNodeSequence,
r#type: c_int,
out: *mut oaktask::bridge::node::OakNodeTrackList,
) -> c_int {
if !out.is_null() {
if r#type == 1 && AUDIO_TRACK_LIST_NULL.load(Ordering::SeqCst) != 0 {
// Audio track list requested but the test marks it empty.
*out = empty_handle();
} else {
*out = fake_handle();
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_track_count(_sequence: oaktask::bridge::node::OakNodeSequence, _type: c_int, count: *mut c_int) -> c_int {
if !count.is_null() {
*count = 0;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_track_at(
_sequence: oaktask::bridge::node::OakNodeSequence,
_type: c_int,
_index: c_int,
out: *mut oaktask::bridge::node::OakNodeTrack,
) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_all_track_count(_sequence: oaktask::bridge::node::OakNodeSequence, count: *mut c_int) -> c_int {
if !count.is_null() {
*count = 0;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_all_track_at(
_sequence: oaktask::bridge::node::OakNodeSequence,
_index: c_int,
out: *mut oaktask::bridge::node::OakNodeTrack,
) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_playhead(_sequence: oaktask::bridge::node::OakNodeSequence, n: *mut c_int, d: *mut c_int) -> c_int {
if !n.is_null() {
*n = 0;
}
if !d.is_null() {
*d = 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_set_playhead(_sequence: oaktask::bridge::node::OakNodeSequence, _n: c_int, _d: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_length(_sequence: oaktask::bridge::node::OakNodeSequence, n: *mut c_int, d: *mut c_int) -> c_int {
if !n.is_null() {
*n = SEQUENCE_LENGTH_NUM.load(Ordering::SeqCst);
}
if !d.is_null() {
*d = SEQUENCE_LENGTH_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_video_length(_sequence: oaktask::bridge::node::OakNodeSequence, n: *mut c_int, d: *mut c_int) -> c_int {
if !n.is_null() {
*n = 0;
}
if !d.is_null() {
*d = 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_audio_length(_sequence: oaktask::bridge::node::OakNodeSequence, n: *mut c_int, d: *mut c_int) -> c_int {
if !n.is_null() {
*n = 0;
}
if !d.is_null() {
*d = 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_verify_length(_sequence: oaktask::bridge::node::OakNodeSequence) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_video_stream_count(_sequence: oaktask::bridge::node::OakNodeSequence, count: *mut c_int) -> c_int {
if !count.is_null() {
*count = 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_audio_stream_count(_sequence: oaktask::bridge::node::OakNodeSequence, count: *mut c_int) -> c_int {
if !count.is_null() {
*count = 0;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_video_params(
_sequence: oaktask::bridge::node::OakNodeSequence,
_index: c_int,
out: *mut oaktask::bridge::common::OakVideoParams,
) -> c_int {
if !out.is_null() {
*out = oakcommon_videoparams_init();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_set_video_params(
_sequence: oaktask::bridge::node::OakNodeSequence,
_index: c_int,
_params: oaktask::bridge::common::OakVideoParams,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_get_audio_params(
_sequence: oaktask::bridge::node::OakNodeSequence,
_index: c_int,
out: *mut *const c_void,
) -> c_int {
if !out.is_null() {
*out = std::ptr::null();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_sequence_set_audio_params(_sequence: oaktask::bridge::node::OakNodeSequence, _index: c_int, _params: *const c_void) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_as_node(track: oaktask::bridge::node::OakNodeTrack) -> oaktask::bridge::node::OakNodeNode {
track
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_create(_type: c_int) -> oaktask::bridge::node::OakNodeTrack {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_free(_track: *mut oaktask::bridge::node::OakNodeTrack) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_get_type(_track: oaktask::bridge::node::OakNodeTrack, r#type: *mut c_int) -> c_int {
if !r#type.is_null() {
*r#type = TRACK_TYPE.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_set_type(_track: oaktask::bridge::node::OakNodeTrack, _type: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_get_index(_track: oaktask::bridge::node::OakNodeTrack, _index: *mut c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_set_index(_track: oaktask::bridge::node::OakNodeTrack, _index: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_get_sequence(_track: oaktask::bridge::node::OakNodeTrack, out: *mut oaktask::bridge::node::OakNodeSequence) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_sequence(_list: oaktask::bridge::node::OakNodeTrackList, out: *mut oaktask::bridge::node::OakNodeSequence) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_array_append(_list: oaktask::bridge::node::OakNodeTrackList) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_array_remove_last(_list: oaktask::bridge::node::OakNodeTrackList) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_array_index_from_cache_index(_list: oaktask::bridge::node::OakNodeTrackList, _ci: c_int, out: *mut c_int) -> c_int {
if !out.is_null() {
*out = _ci;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_type(_list: oaktask::bridge::node::OakNodeTrackList, _type: *mut c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_track_count(_list: oaktask::bridge::node::OakNodeTrackList, count: *mut c_int) -> c_int {
if !count.is_null() {
if _list.ctx.is_null() {
*count = 0;
} else {
*count = TRACK_LIST_TRACK_COUNT.load(Ordering::SeqCst);
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_track_at(_list: oaktask::bridge::node::OakNodeTrackList, _index: c_int, out: *mut oaktask::bridge::node::OakNodeTrack) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
// ---------------------------------------------------------------------------
// bridge::node block stubs (node/block.h)
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_clip_create() -> oaktask::bridge::node::OakNodeBlock {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_gap_create() -> oaktask::bridge::node::OakNodeBlock {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_transition_create(_kind: c_int) -> oaktask::bridge::node::OakNodeBlock {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_as_node(block: oaktask::bridge::node::OakNodeBlock) -> oaktask::bridge::node::OakNodeNode {
block
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_get_kind(_block: oaktask::bridge::node::OakNodeBlock, out_kind: *mut c_int) -> c_int {
if !out_kind.is_null() {
*out_kind = BLOCK_KIND.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_get_in(
_block: oaktask::bridge::node::OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
if !numerator.is_null() {
*numerator = BLOCK_IN_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = BLOCK_IN_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_get_length(
_block: oaktask::bridge::node::OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
if !numerator.is_null() {
*numerator = BLOCK_LENGTH_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = BLOCK_LENGTH_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_block_set_length_and_media_out(
_block: oaktask::bridge::node::OakNodeBlock,
numerator: c_int,
denominator: c_int,
) -> c_int {
SET_LENGTH_NUM.store(numerator, Ordering::SeqCst);
SET_LENGTH_DEN.store(denominator, Ordering::SeqCst);
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_clip_set_media_in(
_clip: oaktask::bridge::node::OakNodeBlock,
numerator: c_int,
denominator: c_int,
) -> c_int {
MEDIA_IN_NUM.store(numerator, Ordering::SeqCst);
MEDIA_IN_DEN.store(denominator, Ordering::SeqCst);
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_transition_get_in_offset(
_transition: oaktask::bridge::node::OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
if !numerator.is_null() {
*numerator = TRANSITION_IN_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = TRANSITION_IN_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_transition_get_out_offset(
_transition: oaktask::bridge::node::OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
if !numerator.is_null() {
*numerator = TRANSITION_OUT_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = TRANSITION_OUT_DEN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_transition_set_offsets_and_length(
_transition: oaktask::bridge::node::OakNodeBlock,
in_num: c_int,
in_den: c_int,
out_num: c_int,
out_den: c_int,
) -> c_int {
TRANSITION_IN_NUM.store(in_num, Ordering::SeqCst);
TRANSITION_IN_DEN.store(in_den, Ordering::SeqCst);
TRANSITION_OUT_NUM.store(out_num, Ordering::SeqCst);
TRANSITION_OUT_DEN.store(out_den, Ordering::SeqCst);
0
}
// ---------------------------------------------------------------------------
// bridge::node track block stubs (node/track.h)
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_append_block(_track: oaktask::bridge::node::OakNodeTrack, _block: oaktask::bridge::node::OakNodeBlock) -> c_int {
APPENDED_BLOCKS.fetch_add(1, Ordering::SeqCst);
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_get_block_count(_track: oaktask::bridge::node::OakNodeTrack, count: *mut c_int) -> c_int {
if !count.is_null() {
*count = TRACK_BLOCK_COUNT.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_get_block_at(_track: oaktask::bridge::node::OakNodeTrack, _index: c_int, out: *mut oaktask::bridge::node::OakNodeBlock) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_track_get_length(_track: oaktask::bridge::node::OakNodeTrack, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
if !numerator.is_null() {
*numerator = TRACK_LENGTH_NUM.load(Ordering::SeqCst);
}
if !denominator.is_null() {
*denominator = TRACK_LENGTH_DEN.load(Ordering::SeqCst);
}
0
}
// ---------------------------------------------------------------------------
// bridge::timeline stubs (timeline/edit.h)
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oaktimeline_add_track_command(_list: oaktask::bridge::node::OakNodeTrackList) -> oaktask::bridge::undo::OakUndoCommand {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_total_length(_list: oaktask::bridge::node::OakNodeTrackList, n: *mut c_int, d: *mut c_int) -> c_int {
if !n.is_null() {
*n = 0;
}
if !d.is_null() {
*d = 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_get_array_size(_list: oaktask::bridge::node::OakNodeTrackList, size: *mut c_int) -> c_int {
if !size.is_null() {
*size = 0;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_add_track(_list: oaktask::bridge::node::OakNodeTrackList, _track: oaktask::bridge::node::OakNodeTrack) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_tracklist_remove_track(_list: oaktask::bridge::node::OakNodeTrackList, _track: oaktask::bridge::node::OakNodeTrack) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_colormanager_init(_project: oaktask::bridge::node::OakNodeProject) -> oaktask::bridge::node::OakNodeColorManager {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_colormanager_free(_manager: *mut oaktask::bridge::node::OakNodeColorManager) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_colormanager_wrap_borrowed(_native: *mut c_void) -> oaktask::bridge::node::OakNodeColorManager {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_colormanager_initialize(_manager: oaktask::bridge::node::OakNodeColorManager) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_colormanager_set_up_default_config() -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_initialize() -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_shutdown() {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_savedata_create(
_load_type: c_int,
_project: oaktask::bridge::node::OakNodeProject,
) -> oaktask::bridge::node::OakNodeSerializerSaveData {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_savedata_free(_save_data: *mut oaktask::bridge::node::OakNodeSerializerSaveData) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_savedata_set_nodes(
_save_data: oaktask::bridge::node::OakNodeSerializerSaveData,
_nodes: *const oaktask::bridge::node::OakNodeNode,
_count: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_savedata_set_property(
_save_data: oaktask::bridge::node::OakNodeSerializerSaveData,
_node: oaktask::bridge::node::OakNodeNode,
_key: *const c_char,
_value: *const c_char,
) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_load_from_xml(
_project: oaktask::bridge::node::OakNodeProject,
_xml: *const c_char,
_load_type: c_int,
out_result: *mut c_int,
_out_load_data: *mut oaktask::bridge::node::OakNodeSerializerLoadData,
_details: *mut c_char,
_details_size: c_int,
) -> c_int {
if !out_result.is_null() {
*out_result = SERIALIZER_LOAD_CODE.load(Ordering::SeqCst);
}
if !_out_load_data.is_null() {
*_out_load_data = fake_handle();
}
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_serializer_loaddata_free(_load_data: *mut oaktask::bridge::node::OakNodeSerializerLoadData) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_loaddata_node_count(_load_data: oaktask::bridge::node::OakNodeSerializerLoadData) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_loaddata_node_at(_load_data: oaktask::bridge::node::OakNodeSerializerLoadData, _index: c_int) -> oaktask::bridge::node::OakNodeNode {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_loaddata_get_property(
_load_data: oaktask::bridge::node::OakNodeSerializerLoadData,
_node: oaktask::bridge::node::OakNodeNode,
_key: *const c_char,
buf: *mut c_char,
size: c_int,
) -> c_int {
write_cstr("", buf as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_loaddata_connection_count(_load_data: oaktask::bridge::node::OakNodeSerializerLoadData) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_loaddata_connection_at(
_load_data: oaktask::bridge::node::OakNodeSerializerLoadData,
_index: c_int,
_out_output: *mut oaktask::bridge::node::OakNodeNode,
_out_input: *mut oaktask::bridge::node::OakNodeNode,
_input_id: *mut c_char,
_input_id_size: c_int,
_out_element: *mut c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_save_to_file(
_project: oaktask::bridge::node::OakNodeProject,
filename: *const c_char,
_use_compression: c_int,
out_code: *mut c_int,
_details: *mut c_char,
_details_size: c_int,
) -> c_int {
let code = SERIALIZER_SAVE_CODE.load(Ordering::SeqCst);
if !out_code.is_null() {
*out_code = code;
}
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();
let _ = std::fs::write(&name, b"oakproj-stub");
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_serializer_load_from_file(
_project: oaktask::bridge::node::OakNodeProject,
filename: *const c_char,
out_code: *mut c_int,
_details: *mut c_char,
_details_size: c_int,
) -> c_int {
// A missing file is a file error (mirrors the real serializer); the
// code is controllable otherwise.
let mut code = SERIALIZER_LOAD_CODE.load(Ordering::SeqCst);
if !filename.is_null() {
let name = std::ffi::CStr::from_ptr(filename).to_string_lossy().into_owned();
if !std::path::Path::new(&name).exists() {
code = 4; // OAKNODE_SERIALIZER_RESULT_FILE_ERROR
}
}
if !out_code.is_null() {
*out_code = code;
}
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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_set_label(_node: oaktask::bridge::node::OakNodeNode, _label: *const c_char) -> c_int {
0
}
#[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 as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_set_context_position(
_node: oaktask::bridge::node::OakNodeNode,
_context: oaktask::bridge::node::OakNodeNode,
_x: f64,
_y: f64,
_expanded: c_int,
) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_find_input_footage(
_node: oaktask::bridge::node::OakNodeNode,
out: *mut oaktask::bridge::node::OakNodeFootage,
) -> c_int {
if !out.is_null() {
if FOOTAGE_FOUND.load(Ordering::SeqCst) != 0 {
*out = fake_handle();
} else {
*out = empty_handle();
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_get_project(_node: oaktask::bridge::node::OakNodeNode, out: *mut oaktask::bridge::node::OakNodeProject) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_input_get_connected_node(
_node: oaktask::bridge::node::OakNodeNode,
_input_id: *const c_char,
out: *mut oaktask::bridge::node::OakNodeNode,
) -> c_int {
if !out.is_null() {
if CONNECTED_NODE.load(Ordering::SeqCst) != 0 {
*out = fake_handle();
} else {
*out = empty_handle();
}
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_get_input_string(
_node: oaktask::bridge::node::OakNodeNode,
_input_id: *const c_char,
buf: *mut c_char,
size: c_int,
) -> c_int {
write_cstr("subtitle text", buf as *mut u8, size)
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_create_copy(_node: oaktask::bridge::node::OakNodeNode) -> oaktask::bridge::node::OakNodeNode {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_copy_inputs(_dst: oaktask::bridge::node::OakNodeNode, _src: oaktask::bridge::node::OakNodeNode, _include_connections: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_connect(
_output: oaktask::bridge::node::OakNodeNode,
_input: oaktask::bridge::node::OakNodeNode,
input_id: *const c_char,
) -> c_int {
if !input_id.is_null() {
CONNECT_INPUT_IDS
.lock()
.unwrap()
.push(std::ffi::CStr::from_ptr(input_id).to_string_lossy().into_owned());
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_set_value_hint_track(_node: oaktask::bridge::node::OakNodeNode, _input_id: *const c_char, _track_type: c_int, _track_index: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_get_video_frame_cache(
_node: oaktask::bridge::node::OakNodeNode,
out: *mut oaktask::bridge::render::OakRenderCache,
) -> c_int {
if !out.is_null() {
*out = oakrender_cache_from_fake();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_node_free(_node: *mut oaktask::bridge::node::OakNodeNode) {}
#[no_mangle]
pub unsafe extern "C" fn oaknode_factory_create_from_id(_type_id: *const c_char) -> oaktask::bridge::node::OakNodeNode {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_viewer_set_video_params(_viewer: oaktask::bridge::node::OakNodeNode, _params: *const oaktask::bridge::common::OakVideoParams) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn oaknode_viewer_set_audio_params(_viewer: oaktask::bridge::node::OakNodeNode, _params: *const c_void) -> c_int {
0
}
// ---------------------------------------------------------------------------
// bridge::render stubs
// ---------------------------------------------------------------------------
fn oakrender_cache_from_fake() -> oaktask::bridge::render::OakRenderCache {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::bridge::render::OakRenderCache {
ctx: 5usize as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
// ---------------------------------------------------------------------------
// Simulated oakrender ticket arena (include/render/ticket.h contract)
//
// Every submitted ticket gets a unique id (assigned in submission order)
// and a distinct handle ctx. The finished callback (`cb`) is the ticket's
// return channel; by default it fires synchronously on submit (the
// deterministic single-thread path). With TICKET_DEFER = 1 the ticket
// stays in flight until the test fires it with stub_complete(), so tests
// can drive arbitrary (scrambled) completion orders. Cancelling a ticket —
// or the cancel atom — finishes it exactly like the real arena: the
// completion still fires exactly once.
// ---------------------------------------------------------------------------
/// OAKRENDER_TICKET_VIDEO (include/render/ticket.h).
#[cfg(not(feature = "real-oakrender"))]
const OAKRENDER_TICKET_VIDEO: c_int = 0;
/// OAKRENDER_TICKET_AUDIO (include/render/ticket.h).
#[cfg(not(feature = "real-oakrender"))]
const OAKRENDER_TICKET_AUDIO: c_int = 1;
/// Base of the ticket handle ctx (0x6000 + id).
#[cfg(not(feature = "real-oakrender"))]
const STUB_TICKET_CTX_BASE: usize = 0x6000;
/// Base of the frame handle ctx (0x10000 + ticket id), so tests can tell
/// which frame a delivered result came from.
#[cfg(not(feature = "real-oakrender"))]
const STUB_FRAME_CTX_BASE: usize = 0x10000;
/// Next ticket id (submission order).
#[cfg(not(feature = "real-oakrender"))]
static TICKET_NEXT_ID: AtomicUsize = AtomicUsize::new(0);
/// Tickets submitted so far (for [`stub_wait_submitted`]).
#[cfg(not(feature = "real-oakrender"))]
static TICKET_SUBMITTED: AtomicUsize = AtomicUsize::new(0);
/// Completions fired so far (callbacks invoked).
#[cfg(not(feature = "real-oakrender"))]
static TICKET_COMPLETED: AtomicUsize = AtomicUsize::new(0);
/// Submitted-count condvar (test sync point).
#[cfg(not(feature = "real-oakrender"))]
static TICKET_SUBMIT_CV: (Mutex<()>, Condvar) = (Mutex::new(()), Condvar::new());
/// A simulated in-flight ticket.
#[cfg(not(feature = "real-oakrender"))]
struct StubTicket {
id: usize,
kind: c_int,
time_num: i64,
time_den: i64,
range: (i64, i64, i64, i64),
cb: Option<oaktask::bridge::render::OakRenderTicketFinishedFn>,
userdata: *mut c_void,
finished: bool,
}
// The userdata is an opaque pointer handed through the ticket's finished
// callback (the same contract as the real C ABI, where tickets complete on
// worker threads); it is never dereferenced by the stub.
#[cfg(not(feature = "real-oakrender"))]
unsafe impl Send for StubTicket {}
#[cfg(not(feature = "real-oakrender"))]
unsafe impl Sync for StubTicket {}
/// The registry (guarded; ticket queries/cancel/wait race the render loop).
#[cfg(not(feature = "real-oakrender"))]
static TICKETS: Mutex<Vec<StubTicket>> = Mutex::new(Vec::new());
/// Wakes `oakrender_ticket_wait` callers when a ticket finishes.
#[cfg(not(feature = "real-oakrender"))]
static TICKET_CV: Condvar = Condvar::new();
#[cfg(not(feature = "real-oakrender"))]
fn stub_ticket_handle(id: usize) -> oaktask::bridge::render::OakRenderTicket {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::bridge::render::OakRenderTicket {
ctx: (STUB_TICKET_CTX_BASE + id) as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
#[cfg(not(feature = "real-oakrender"))]
fn stub_ticket_id(ticket: oaktask::bridge::render::OakRenderTicket) -> Option<usize> {
let v = ticket.ctx as usize;
if v >= STUB_TICKET_CTX_BASE && v < STUB_TICKET_CTX_BASE + 1_000_000 {
Some(v - STUB_TICKET_CTX_BASE)
} else {
None
}
}
#[cfg(not(feature = "real-oakrender"))]
fn stub_frame_handle(id: usize) -> oaktask::bridge::codec::OakFrame {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::bridge::codec::OakFrame {
ctx: (STUB_FRAME_CTX_BASE + id) as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
/// Register a submitted ticket; in immediate mode its completion fires
/// synchronously (before this returns).
#[cfg(not(feature = "real-oakrender"))]
fn stub_register_ticket(
kind: c_int,
time_num: i64,
time_den: i64,
range: (i64, i64, i64, i64),
cb: Option<oaktask::bridge::render::OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> oaktask::bridge::render::OakRenderTicket {
let id = TICKET_NEXT_ID.fetch_add(1, Ordering::SeqCst);
{
let mut tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
tickets.push(StubTicket {
id,
kind,
time_num,
time_den,
range,
cb,
userdata,
finished: false,
});
}
{
let _g = TICKET_SUBMIT_CV.0.lock().unwrap_or_else(|e| e.into_inner());
TICKET_SUBMITTED.fetch_add(1, Ordering::SeqCst);
TICKET_SUBMIT_CV.1.notify_all();
}
let handle = stub_ticket_handle(id);
if TICKET_DEFER.load(Ordering::SeqCst) == 0 {
stub_complete(id);
}
handle
}
/// Fire the finished callback of ticket `id` (exactly once). Tests call
/// this to drive completion in any order.
#[cfg(not(feature = "real-oakrender"))]
pub fn stub_complete(id: usize) {
let to_fire = {
let mut tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
match tickets.iter_mut().find(|t| t.id == id) {
Some(t) if !t.finished => {
t.finished = true;
TICKET_COMPLETED.fetch_add(1, Ordering::SeqCst);
TICKET_CV.notify_all();
Some((t.cb, t.userdata))
}
_ => None,
}
};
if let Some((cb, userdata)) = to_fire {
if let Some(cb) = cb {
unsafe { cb(stub_ticket_handle(id), userdata) };
}
}
}
/// Block until at least `count` tickets have been submitted.
#[cfg(not(feature = "real-oakrender"))]
pub fn stub_wait_submitted(count: usize) {
let mut guard = TICKET_SUBMIT_CV.0.lock().unwrap_or_else(|e| e.into_inner());
while TICKET_SUBMITTED.load(Ordering::SeqCst) < count {
guard = TICKET_SUBMIT_CV.1.wait(guard).unwrap_or_else(|e| e.into_inner());
}
}
/// Tickets submitted so far.
#[cfg(not(feature = "real-oakrender"))]
pub fn stub_submitted_count() -> usize {
TICKET_SUBMITTED.load(Ordering::SeqCst)
}
/// Completions fired so far (callbacks invoked).
#[cfg(not(feature = "real-oakrender"))]
pub fn stub_completed_count() -> usize {
TICKET_COMPLETED.load(Ordering::SeqCst)
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cancelatom_init() -> oaktask::bridge::render::OakCancelAtom {
fake_atom()
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cancelatom_free(_atom: *mut oaktask::bridge::render::OakCancelAtom) {}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cancelatom_cancel(_atom: oaktask::bridge::render::OakCancelAtom) -> c_int {
ATOM_CANCELLED.store(1, Ordering::SeqCst);
// Simulate cancellation propagating into in-flight renders: every
// pending ticket finishes (its completion fires exactly once), waking
// any render loop waiting on the completion channel. This is what the
// real oakrender does when a cancel atom is shared into the render.
let ids: Vec<usize> = {
let tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
tickets.iter().filter(|t| !t.finished).map(|t| t.id).collect()
};
for id in ids {
stub_complete(id);
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cancelatom_is_cancelled(_atom: oaktask::bridge::render::OakCancelAtom, cancelled: *mut c_int) -> c_int {
if !cancelled.is_null() {
*cancelled = ATOM_CANCELLED.load(Ordering::SeqCst);
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cancelatom_heard_cancel(_atom: oaktask::bridge::render::OakCancelAtom, heard: *mut c_int) -> c_int {
if !heard.is_null() {
*heard = 0;
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_render_frame(
params: *const oaktask::bridge::render::OakRenderVideoTicketParams,
cb: Option<oaktask::bridge::render::OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> oaktask::bridge::render::OakRenderTicket {
let (time_num, time_den) = if params.is_null() {
(0, 1)
} else {
((*params).time_num, (*params).time_den)
};
stub_register_ticket(OAKRENDER_TICKET_VIDEO, time_num, time_den, (0, 1, 0, 1), cb, userdata)
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_render_audio(
_output_node: oaktask::bridge::node::OakNodeNode,
in_num: i64,
in_den: i64,
out_num: i64,
out_den: i64,
_params: *const oaktask::bridge::common::OakAudioParams,
_mode: c_int,
cb: Option<oaktask::bridge::render::OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> oaktask::bridge::render::OakRenderTicket {
stub_register_ticket(
OAKRENDER_TICKET_AUDIO,
in_num,
in_den,
(in_num, in_den, out_num, out_den),
cb,
userdata,
)
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_is_finished(ticket: oaktask::bridge::render::OakRenderTicket) -> c_int {
match stub_ticket_id(ticket) {
Some(id) => {
let tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
if tickets.iter().any(|t| t.id == id && t.finished) {
1
} else {
0
}
}
None => 0,
}
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_wait(ticket: oaktask::bridge::render::OakRenderTicket) -> c_int {
if let Some(id) = stub_ticket_id(ticket) {
let mut tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
while !tickets.iter().any(|t| t.id == id && t.finished) {
tickets = TICKET_CV.wait(tickets).unwrap_or_else(|e| e.into_inner());
}
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_cancel(ticket: oaktask::bridge::render::OakRenderTicket) -> c_int {
if let Some(id) = stub_ticket_id(ticket) {
// The real cancel contract: the ticket finishes and its completion
// still fires exactly once (a NULL result via get_frame).
stub_complete(id);
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_get_type(ticket: oaktask::bridge::render::OakRenderTicket) -> c_int {
match stub_ticket_id(ticket) {
Some(id) => {
let tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
match tickets.iter().find(|t| t.id == id) {
Some(t) => t.kind,
None => OAKRENDER_TICKET_VIDEO,
}
}
None => OAKRENDER_TICKET_VIDEO,
}
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_get_frame(
ticket: oaktask::bridge::render::OakRenderTicket,
out: *mut oaktask::bridge::codec::OakFrame,
) -> c_int {
if !out.is_null() {
if TICKET_FRAME_VALID.load(Ordering::SeqCst) != 0 {
// The frame handle's ctx encodes the ticket id so tests can
// assert the delivery order of frames.
match stub_ticket_id(ticket) {
Some(id) => *out = stub_frame_handle(id),
None => *out = fake_handle(),
}
} else {
*out = empty_handle();
}
}
TICKET_GET_FRAME_RESULT.load(Ordering::SeqCst)
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_get_time(
ticket: oaktask::bridge::render::OakRenderTicket,
n: *mut i64,
d: *mut i64,
) -> c_int {
let info = match stub_ticket_id(ticket) {
Some(id) => {
let tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
tickets.iter().find(|t| t.id == id).map(|t| (t.time_num, t.time_den))
}
None => None,
};
if let Some((num, den)) = info {
if !n.is_null() {
*n = num;
}
if !d.is_null() {
*d = den;
}
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_get_range(
ticket: oaktask::bridge::render::OakRenderTicket,
a: *mut i64,
b: *mut i64,
c: *mut i64,
d: *mut i64,
) -> c_int {
let info = match stub_ticket_id(ticket) {
Some(id) => {
let tickets = TICKETS.lock().unwrap_or_else(|e| e.into_inner());
tickets.iter().find(|t| t.id == id).map(|t| t.range)
}
None => None,
};
if let Some((in_num, in_den, out_num, out_den)) = info {
if !a.is_null() {
*a = in_num;
}
if !b.is_null() {
*b = in_den;
}
if !c.is_null() {
*c = out_num;
}
if !d.is_null() {
*d = out_den;
}
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_get_samples(_ticket: oaktask::bridge::render::OakRenderTicket, out: *mut *mut c_void) -> c_int {
if !out.is_null() {
*out = std::ptr::null_mut();
}
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_ticket_free(_ticket: *mut oaktask::bridge::render::OakRenderTicket) {}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_project_copier_create() -> oaktask::bridge::render::OakRenderProjectCopier {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::bridge::render::OakRenderProjectCopier {
ctx: 7usize as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_project_copier_free(_copier: *mut oaktask::bridge::render::OakRenderProjectCopier) {}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_project_copier_set_project(_copier: oaktask::bridge::render::OakRenderProjectCopier, _project: oaktask::bridge::node::OakNodeProject) -> c_int {
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_project_copier_get_copy(_copier: oaktask::bridge::render::OakRenderProjectCopier, original: oaktask::bridge::node::OakNodeNode) -> oaktask::bridge::node::OakNodeNode {
original
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_project_copier_get_copied_project(_copier: oaktask::bridge::render::OakRenderProjectCopier) -> oaktask::bridge::node::OakNodeProject {
fake_handle()
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_color_processor_create(
_src_space: *const c_char,
_dst_transform: *const c_char,
_direction: c_int,
) -> oaktask::bridge::render::OakColorProcessor {
unsafe extern "C" fn noop(_ctx: *mut c_void) {}
oaktask::bridge::render::OakColorProcessor {
ctx: 8usize as *mut c_void,
addref: Some(noop),
release: Some(noop),
abi_version: 1,
}
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_color_processor_free(_processor: *mut oaktask::bridge::render::OakColorProcessor) {}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_color_processor_is_valid(_processor: oaktask::bridge::render::OakColorProcessor) -> c_int {
1
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_codec_frame_free(_frame: *mut oaktask::bridge::codec::OakFrame) {}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_manager_set_aggressive_gc(_enabled: c_int) -> c_int {
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cache_get_invalidated_ranges(
_cache: oaktask::bridge::render::OakRenderCache,
_in_num: i64,
_in_den: i64,
_out_num: i64,
_out_den: i64,
_flat: *mut i64,
_flat_size: c_int,
) -> c_int {
0
}
#[cfg(not(feature = "real-oakrender"))]
#[no_mangle]
pub unsafe extern "C" fn oakrender_cache_free(_cache: *mut oaktask::bridge::render::OakRenderCache) {}
// ---------------------------------------------------------------------------
// bridge::undo stubs
// ---------------------------------------------------------------------------
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_init(
_vtable: *const oaktask::bridge::undo::OakUndoCommandVtable,
_userdata: *mut c_void,
) -> oaktask::bridge::undo::OakUndoCommand {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_init_multi() -> oaktask::bridge::undo::OakUndoCommand {
fake_handle()
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_multi_add_child(_multi: oaktask::bridge::undo::OakUndoCommand, _child: oaktask::bridge::undo::OakUndoCommand) -> c_int {
MULTI_CHILDREN.fetch_add(1, Ordering::SeqCst);
0
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_multi_child_count(_multi: oaktask::bridge::undo::OakUndoCommand, out: *mut c_int) -> c_int {
if !out.is_null() {
*out = MULTI_CHILDREN.load(Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_multi_child(_multi: oaktask::bridge::undo::OakUndoCommand, _index: c_int, out: *mut oaktask::bridge::undo::OakUndoCommand) -> c_int {
if !out.is_null() {
*out = fake_handle();
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_redo_now(_command: oaktask::bridge::undo::OakUndoCommand) -> c_int {
// Approximate redo: the folder gains the accumulated children.
let delta = MULTI_CHILDREN.load(Ordering::SeqCst);
if delta > 0 {
FOLDER_CHILD_COUNT.fetch_add(delta, Ordering::SeqCst);
REDO_DELTA.store(delta, Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_undo_now(_command: oaktask::bridge::undo::OakUndoCommand) -> c_int {
let delta = REDO_DELTA.load(Ordering::SeqCst);
if delta > 0 {
FOLDER_CHILD_COUNT.fetch_sub(delta, Ordering::SeqCst);
REDO_DELTA.store(0, Ordering::SeqCst);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn oakundo_command_free(_command: *mut oaktask::bridge::undo::OakUndoCommand) {}