Files
oak-editor/crates/oaktask/tests/common/mod.rs
T
Mike-Solar 18ff60f147 feat(engine): clip move, clip effect_input, mandatory static FFmpeg
- oakengine_sequence_move_clip implemented for real (oaktimeline
  TrackMoveBlockCommand; fixes the graph-ownership/gap-anchor/ripple
  trim bugs the stub was hiding); same-track via the frozen C ABI,
  cross-track supported by the module command
- oaknode clip blocks now declare a tex_in texture input and set
  effect_input to it, so timeline clips can host effect chains; facade
  test covers effect insert/remove on a real clip
- oakffmpeg-link: FFMPEG_DIR is now mandatory with a clear panic (a
  Homebrew upgrade left the system ffmpeg .pc pointing at a deleted
  dav1d Cellar path, breaking links); reads a git-ignored workspace
  .env for IDEs that cannot inject env vars (RustRover); links the C++
  stdlib for C++ codec libs (svt-av1)
- oakengine re-exports oaknode so tests share one crate instance;
  it_node uses the direct instance's value type where it calls the
  module FFI (the --workspace dev-dependency feature split builds
  oaknode twice)
2026-08-11 23:04:48 +08:00

2989 lines
76 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;
#[cfg(not(feature = "real-oakrender"))]
use std::sync::Condvar;
use std::sync::Mutex;
// ---------------------------------------------------------------------------
// 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,
) {
}