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)
This commit is contained in:
2026-08-11 23:04:48 +08:00
parent a209f63d52
commit 18ff60f147
351 changed files with 32880 additions and 15939 deletions
+101 -59
View File
@@ -54,7 +54,6 @@ pub const OAKCODEC_E_FAILED: c_int = -50003;
/// Mirror of `OakCodecTaskRequest` (`include/codec/task.h`).
pub type OakCodecTaskRequest = oakcodec::task::OakCodecTaskRequest;
/// `oakcodec_task_submit_fn` callback typedef.
pub type OakCodecTaskSubmitFn =
unsafe extern "C" fn(req: *const OakCodecTaskRequest, userdata: *mut c_void) -> c_int;
@@ -71,18 +70,13 @@ pub type OakDecoder = CHandle;
/// Mirror of `OakCodecProxyParams` (`include/codec/proxy.h`).
pub type OakCodecProxyParams = oakcodec::ffi::proxy::oakcodec_proxy_params;
/// Mirror of `oakcodec_encoding_params` (`include/codec/encoder.h`) — the
/// export task fills this to open the encoder. Layout mirrors the header
/// verbatim (a zeroed struct = all tracks disabled).
pub type OakCodecEncodingParams = oakcodec::ffi::encoder::oakcodec_encoding_params;
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_set_task_submit_cb(
cb: Option<OakCodecTaskSubmitFn>,
userdata: *mut c_void,
) {
pub fn oakcodec_set_task_submit_cb(cb: Option<OakCodecTaskSubmitFn>, userdata: *mut c_void) {
unsafe { oakcodec::ffi::task::oakcodec_set_task_submit_cb(cb, userdata) }
}
@@ -103,10 +97,10 @@ pub fn oakcodec_decoder_free(decoder: *mut OakDecoder) {
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_decoder_open(
decoder: OakDecoder,
filename: *const c_char,
stream_index: c_int,
) -> c_int {
decoder: OakDecoder,
filename: *const c_char,
stream_index: c_int,
) -> c_int {
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_open(decoder, filename, stream_index) }
}
@@ -122,34 +116,60 @@ pub fn oakcodec_decoder_is_open(decoder: OakDecoder) -> c_int {
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_decoder_decode_audio(
decoder: OakDecoder,
in_num: c_int,
in_den: c_int,
out_num: c_int,
out_den: c_int,
sample_rate: c_int,
channel_layout: u64,
buf: *mut f32,
buf_frames: c_int,
) -> c_int {
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_decode_audio(decoder, in_num, in_den, out_num, out_den, sample_rate, channel_layout, buf, buf_frames) }
decoder: 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 {
unsafe {
oakcodec::ffi::decoder::oakcodec_decoder_decode_audio(
decoder,
in_num,
in_den,
out_num,
out_den,
sample_rate,
channel_layout,
buf,
buf_frames,
)
}
}
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_decoder_conform_audio(
decoder: OakDecoder,
output_filenames: *const *const c_char,
filename_count: c_int,
sample_rate: c_int,
channel_layout: u64,
sample_format: c_int,
cancelled: OakCancelAtom,
) -> c_int {
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_conform_audio(decoder, output_filenames, filename_count, sample_rate, channel_layout, sample_format, cancelled) }
decoder: OakDecoder,
output_filenames: *const *const c_char,
filename_count: c_int,
sample_rate: c_int,
channel_layout: u64,
sample_format: c_int,
cancelled: OakCancelAtom,
) -> c_int {
unsafe {
oakcodec::ffi::decoder::oakcodec_decoder_conform_audio(
decoder,
output_filenames,
filename_count,
sample_rate,
channel_layout,
sample_format,
cancelled,
)
}
}
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_decoder_last_error(decoder: OakDecoder, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oakcodec_decoder_last_error(
decoder: OakDecoder,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_last_error(decoder, buf, buf_size) }
}
@@ -165,12 +185,16 @@ pub fn oakcodec_decoder_get_image_sequence_index(filename: *const c_char) -> i64
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_decoder_transform_image_sequence_file_name(
filename: *const c_char,
number: i64,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_transform_image_sequence_file_name(filename, number, buf, buf_size) }
filename: *const c_char,
number: i64,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe {
oakcodec::ffi::decoder::oakcodec_decoder_transform_image_sequence_file_name(
filename, number, buf, buf_size,
)
}
}
/// Direct call into the `oakcodec` crate (single-lib unification).
@@ -180,18 +204,26 @@ pub fn oakcodec_encoder_get_desired_pixel_format(encoder: OakEncoder) -> c_int {
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_encoding_generate_matrix(
method: c_int,
src_width: c_int,
src_height: c_int,
dst_width: c_int,
dst_height: c_int,
out_matrix: *mut f64,
) -> c_int {
unsafe { oakcodec::ffi::encoder::oakcodec_encoding_generate_matrix(method, src_width, src_height, dst_width, dst_height, out_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 {
unsafe {
oakcodec::ffi::encoder::oakcodec_encoding_generate_matrix(
method, src_width, src_height, dst_width, dst_height, out_matrix,
)
}
}
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_proxy_find_ffmpeg(configured_path: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oakcodec_proxy_find_ffmpeg(
configured_path: *const c_char,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oakcodec::ffi::proxy::oakcodec_proxy_find_ffmpeg(configured_path, buf, buf_size) }
}
@@ -222,21 +254,28 @@ pub fn oakcodec_encoder_write_video(encoder: OakEncoder, frame: OakFrame) -> c_i
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_encoder_write_audio(
encoder: OakEncoder,
samples: *const f32,
frame_count: c_int,
) -> c_int {
encoder: OakEncoder,
samples: *const f32,
frame_count: c_int,
) -> c_int {
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_write_audio(encoder, samples, frame_count) }
}
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_encoder_write_subtitle(
encoder: OakEncoder,
text: *const c_char,
in_seconds: f64,
out_seconds: f64,
) -> c_int {
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_write_subtitle(encoder, text, in_seconds, out_seconds) }
encoder: OakEncoder,
text: *const c_char,
in_seconds: f64,
out_seconds: f64,
) -> c_int {
unsafe {
oakcodec::ffi::encoder::oakcodec_encoder_write_subtitle(
encoder,
text,
in_seconds,
out_seconds,
)
}
}
/// Direct call into the `oakcodec` crate (single-lib unification).
@@ -245,7 +284,10 @@ pub fn oakcodec_encoder_flush(encoder: OakEncoder) -> c_int {
}
/// Direct call into the `oakcodec` crate (single-lib unification).
pub fn oakcodec_encoder_last_error(encoder: OakEncoder, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oakcodec_encoder_last_error(
encoder: OakEncoder,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_last_error(encoder, buf, buf_size) }
}
+91 -47
View File
@@ -68,16 +68,27 @@ pub fn oakcommon_videoparams_init() -> OakVideoParams {
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_videoparams_init_basic(
width: c_int,
height: c_int,
pixel_format: c_int,
nb_channels: c_int,
pixel_aspect_num: c_int,
pixel_aspect_den: c_int,
interlacing: c_int,
divider: c_int,
) -> OakVideoParams {
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_init_basic(width, height, pixel_format, nb_channels, pixel_aspect_num, pixel_aspect_den, interlacing, divider) }
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,
) -> OakVideoParams {
unsafe {
oakcommon::ffi::videoparams::oakcommon_videoparams_init_basic(
width,
height,
pixel_format,
nb_channels,
pixel_aspect_num,
pixel_aspect_den,
interlacing,
divider,
)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
@@ -107,38 +118,60 @@ pub fn oakcommon_videoparams_set_format(params: OakVideoParams, format: c_int) -
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_videoparams_get_time_base(
params: OakVideoParams,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_time_base(params, numerator, denominator) }
params: OakVideoParams,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oakcommon::ffi::videoparams::oakcommon_videoparams_get_time_base(
params,
numerator,
denominator,
)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_videoparams_set_time_base(
params: OakVideoParams,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_time_base(params, numerator, denominator) }
params: OakVideoParams,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe {
oakcommon::ffi::videoparams::oakcommon_videoparams_set_time_base(
params,
numerator,
denominator,
)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_videoparams_frame_rate_as_time_base(
params: OakVideoParams,
out_num: *mut c_int,
out_den: *mut c_int,
) -> c_int {
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_frame_rate_as_time_base(params, out_num, out_den) }
params: OakVideoParams,
out_num: *mut c_int,
out_den: *mut c_int,
) -> c_int {
unsafe {
oakcommon::ffi::videoparams::oakcommon_videoparams_frame_rate_as_time_base(
params, out_num, out_den,
)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_videoparams_set_frame_rate(
params: OakVideoParams,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_set_frame_rate(params, numerator, denominator) }
params: OakVideoParams,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe {
oakcommon::ffi::videoparams::oakcommon_videoparams_set_frame_rate(
params,
numerator,
denominator,
)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
@@ -168,11 +201,17 @@ pub fn oakcommon_videoparams_get_is_valid(params: OakVideoParams, out_valid: *mu
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_videoparams_get_frame_rate(
params: OakVideoParams,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oakcommon::ffi::videoparams::oakcommon_videoparams_get_frame_rate(params, numerator, denominator) }
params: OakVideoParams,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oakcommon::ffi::videoparams::oakcommon_videoparams_get_frame_rate(
params,
numerator,
denominator,
)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
@@ -182,11 +221,13 @@ pub fn oakcommon_videoparams_get_duration(params: OakVideoParams, duration: *mut
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_colortransform_init_display(
display: *const c_char,
view: *const c_char,
look: *const c_char,
) -> OakColorTransform {
unsafe { oakcommon::ffi::colortransform::oakcommon_colortransform_init_display(display, view, look) }
display: *const c_char,
view: *const c_char,
look: *const c_char,
) -> OakColorTransform {
unsafe {
oakcommon::ffi::colortransform::oakcommon_colortransform_init_display(display, view, look)
}
}
/// Direct call into the `oakcommon` crate (single-lib unification).
@@ -201,11 +242,11 @@ pub fn oakcommon_colortransform_free(transform: *mut OakColorTransform) {
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_config_get(
group: *const c_char,
key: *const c_char,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
group: *const c_char,
key: *const c_char,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oakcommon::ffi::config::oakcommon_config_get(group, key, buf, buf_size) }
}
@@ -215,7 +256,10 @@ pub fn oakcommon_config_get_int(group: *const c_char, key: *const c_char, defaul
}
/// Direct call into the `oakcommon` crate (single-lib unification).
pub fn oakcommon_config_get_bool(group: *const c_char, key: *const c_char, default: c_int) -> c_int {
pub fn oakcommon_config_get_bool(
group: *const c_char,
key: *const c_char,
default: c_int,
) -> c_int {
unsafe { oakcommon::ffi::config::oakcommon_config_get_bool(group, key, default) }
}
+471 -113
View File
@@ -131,21 +131,21 @@ pub fn oaknode_node_get_project(node: OakNodeNode, out: *mut OakNodeProject) ->
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_input_get_connected_node(
node: OakNodeNode,
input_id: *const c_char,
out_node: *mut OakNodeNode,
) -> c_int {
node: OakNodeNode,
input_id: *const c_char,
out_node: *mut OakNodeNode,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_input_get_connected_node(node, input_id, out_node) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_set_context_position(
node: OakNodeNode,
context: OakNodeNode,
x: f64,
y: f64,
expanded: c_int,
) -> c_int {
node: OakNodeNode,
context: OakNodeNode,
x: f64,
y: f64,
expanded: c_int,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_set_context_position(node, context, x, y, expanded) }
}
@@ -156,11 +156,11 @@ pub fn oaknode_node_find_input_footage(node: OakNodeNode, out: *mut OakNodeFoota
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_get_input_string(
node: OakNodeNode,
input_id: *const c_char,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
node: OakNodeNode,
input_id: *const c_char,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_get_input_string(node, input_id, buf, buf_size) }
}
@@ -170,31 +170,48 @@ pub fn oaknode_node_create_copy(node: OakNodeNode) -> OakNodeNode {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_copy_inputs(dst: OakNodeNode, src: OakNodeNode, include_connections: c_int) -> c_int {
pub fn oaknode_node_copy_inputs(
dst: OakNodeNode,
src: OakNodeNode,
include_connections: c_int,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_copy_inputs(dst, src, include_connections) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_connect(output_node: OakNodeNode, input_node: OakNodeNode, input_id: *const c_char) -> c_int {
pub fn oaknode_node_connect(
output_node: OakNodeNode,
input_node: OakNodeNode,
input_id: *const c_char,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_connect(output_node, input_node, input_id) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_set_value_hint_track(
node: OakNodeNode,
input_id: *const c_char,
track_type: c_int,
track_index: c_int,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_set_value_hint_track(node, input_id, track_type, track_index) }
node: OakNodeNode,
input_id: *const c_char,
track_type: c_int,
track_index: c_int,
) -> c_int {
unsafe {
oaknode::ffi::node::oaknode_node_set_value_hint_track(
node,
input_id,
track_type,
track_index,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_node_get_video_frame_cache(
node: OakNodeNode,
out: *mut crate::bridge::render::OakRenderCache,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_node_get_video_frame_cache(node, out as *mut std::ffi::c_void) }
node: OakNodeNode,
out: *mut crate::bridge::render::OakRenderCache,
) -> c_int {
unsafe {
oaknode::ffi::node::oaknode_node_get_video_frame_cache(node, out as *mut std::ffi::c_void)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -203,7 +220,9 @@ pub fn oaknode_node_free(node: *mut OakNodeNode) {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_command_create_remove_node(node: OakNodeNode) -> crate::bridge::undo::OakUndoCommand {
pub fn oaknode_command_create_remove_node(
node: OakNodeNode,
) -> crate::bridge::undo::OakUndoCommand {
unsafe { oaknode::ffi::node::oaknode_command_create_remove_node(node) }
}
@@ -213,12 +232,23 @@ pub fn oaknode_factory_create_from_id(type_id: *const c_char) -> OakNodeNode {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_viewer_set_video_params(viewer: OakNodeNode, params: *const OakVideoParams) -> c_int {
unsafe { oaknode::ffi::node::oaknode_viewer_set_video_params(viewer, params as *const std::ffi::c_void) }
pub fn oaknode_viewer_set_video_params(
viewer: OakNodeNode,
params: *const OakVideoParams,
) -> c_int {
unsafe {
oaknode::ffi::node::oaknode_viewer_set_video_params(
viewer,
params as *const std::ffi::c_void,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_viewer_set_audio_params(viewer: OakNodeNode, params: *const std::ffi::c_void) -> c_int {
pub fn oaknode_viewer_set_audio_params(
viewer: OakNodeNode,
params: *const std::ffi::c_void,
) -> c_int {
unsafe { oaknode::ffi::node::oaknode_viewer_set_audio_params(viewer, params) }
}
@@ -248,44 +278,78 @@ pub fn oaknode_block_get_kind(block: OakNodeBlock, out_kind: *mut c_int) -> c_in
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_block_get_in(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
pub fn oaknode_block_get_in(
block: OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::block::oaknode_block_get_in(block, numerator, denominator) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_block_get_length(block: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
pub fn oaknode_block_get_length(
block: OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::block::oaknode_block_get_length(block, numerator, denominator) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_block_set_length_and_media_out(block: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int {
unsafe { oaknode::ffi::block::oaknode_block_set_length_and_media_out(block, numerator, denominator) }
pub fn oaknode_block_set_length_and_media_out(
block: OakNodeBlock,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe {
oaknode::ffi::block::oaknode_block_set_length_and_media_out(block, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_clip_set_media_in(clip: OakNodeBlock, numerator: c_int, denominator: c_int) -> c_int {
pub fn oaknode_clip_set_media_in(
clip: OakNodeBlock,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe { oaknode::ffi::block::oaknode_clip_set_media_in(clip, numerator, denominator) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_transition_get_in_offset(transition: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
unsafe { oaknode::ffi::block::oaknode_transition_get_in_offset(transition, numerator, denominator) }
pub fn oaknode_transition_get_in_offset(
transition: OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::block::oaknode_transition_get_in_offset(transition, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_transition_get_out_offset(transition: OakNodeBlock, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
unsafe { oaknode::ffi::block::oaknode_transition_get_out_offset(transition, numerator, denominator) }
pub fn oaknode_transition_get_out_offset(
transition: OakNodeBlock,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::block::oaknode_transition_get_out_offset(transition, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_transition_set_offsets_and_length(
transition: OakNodeBlock,
in_num: c_int,
in_den: c_int,
out_num: c_int,
out_den: c_int,
) -> c_int {
unsafe { oaknode::ffi::block::oaknode_transition_set_offsets_and_length(transition, in_num, in_den, out_num, out_den) }
transition: OakNodeBlock,
in_num: c_int,
in_den: c_int,
out_num: c_int,
out_den: c_int,
) -> c_int {
unsafe {
oaknode::ffi::block::oaknode_transition_set_offsets_and_length(
transition, in_num, in_den, out_num, out_den,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -319,12 +383,20 @@ pub fn oaknode_project_name(project: OakNodeProject, buf: *mut c_char, buf_size:
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_filename(project: OakNodeProject, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_project_filename(
project: OakNodeProject,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_filename(project, buf, buf_size) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_pretty_filename(project: OakNodeProject, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_project_pretty_filename(
project: OakNodeProject,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_pretty_filename(project, buf, buf_size) }
}
@@ -349,7 +421,11 @@ pub fn oaknode_project_is_new(project: OakNodeProject) -> c_int {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_cache_path(project: OakNodeProject, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_project_cache_path(
project: OakNodeProject,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_cache_path(project, buf, buf_size) }
}
@@ -364,22 +440,36 @@ pub fn oaknode_project_get_cache_location_setting(project: OakNodeProject) -> c_
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_set_cache_location_setting(project: OakNodeProject, setting: c_int) -> c_int {
pub fn oaknode_project_set_cache_location_setting(
project: OakNodeProject,
setting: c_int,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_set_cache_location_setting(project, setting) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_get_custom_cache_path(project: OakNodeProject, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_project_get_custom_cache_path(
project: OakNodeProject,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_get_custom_cache_path(project, buf, buf_size) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_set_custom_cache_path(project: OakNodeProject, path: *const c_char) -> c_int {
pub fn oaknode_project_set_custom_cache_path(
project: OakNodeProject,
path: *const c_char,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_set_custom_cache_path(project, path) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_project_get_uuid(project: OakNodeProject, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_project_get_uuid(
project: OakNodeProject,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::project::oaknode_project_get_uuid(project, buf, buf_size) }
}
@@ -429,7 +519,10 @@ pub fn oaknode_folder_as_node(folder: OakNodeFolder) -> OakNodeNode {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_command_create_folder_add_child(folder: OakNodeFolder, child: OakNodeNode) -> crate::bridge::undo::OakUndoCommand {
pub fn oaknode_command_create_folder_add_child(
folder: OakNodeFolder,
child: OakNodeNode,
) -> crate::bridge::undo::OakUndoCommand {
unsafe { oaknode::ffi::folder::oaknode_command_create_folder_add_child(folder, child) }
}
@@ -439,7 +532,11 @@ pub fn oaknode_folder_remove_child(folder: OakNodeFolder, child: OakNodeNode) ->
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_folder_move_children(nodes: *const OakNodeNode, count: c_int, dest_folder: OakNodeFolder) -> c_int {
pub fn oaknode_folder_move_children(
nodes: *const OakNodeNode,
count: c_int,
dest_folder: OakNodeFolder,
) -> c_int {
unsafe { oaknode::ffi::folder::oaknode_folder_move_children(nodes, count, dest_folder) }
}
@@ -469,7 +566,11 @@ pub fn oaknode_footage_as_node(footage: OakNodeFootage) -> OakNodeNode {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_filename(footage: OakNodeFootage, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_footage_filename(
footage: OakNodeFootage,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_filename(footage, buf, buf_size) }
}
@@ -494,7 +595,11 @@ pub fn oaknode_footage_set_timestamp(footage: OakNodeFootage, timestamp: i64) ->
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_decoder(footage: OakNodeFootage, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_footage_decoder(
footage: OakNodeFootage,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_decoder(footage, buf, buf_size) }
}
@@ -519,8 +624,14 @@ pub fn oaknode_footage_subtitle_stream_count(footage: OakNodeFootage) -> c_int {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_duration(footage: OakNodeFootage, out_numerator: *mut c_int, out_denominator: *mut c_int) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_duration(footage, out_numerator, out_denominator) }
pub fn oaknode_footage_duration(
footage: OakNodeFootage,
out_numerator: *mut c_int,
out_denominator: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::footage::oaknode_footage_duration(footage, out_numerator, out_denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -534,7 +645,11 @@ pub fn oaknode_footage_set_proxy_enabled(footage: OakNodeFootage, enabled: c_int
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_proxy_path(footage: OakNodeFootage, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_footage_proxy_path(
footage: OakNodeFootage,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_proxy_path(footage, buf, buf_size) }
}
@@ -544,8 +659,24 @@ pub fn oaknode_footage_proxy_state(footage: OakNodeFootage) -> c_int {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_set_proxy(footage: OakNodeFootage, path: *const c_char, state: c_int, video_stream_index: c_int, preset_version: c_int, enabled: c_int) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_set_proxy(footage, path, state, video_stream_index, preset_version, enabled) }
pub fn oaknode_footage_set_proxy(
footage: OakNodeFootage,
path: *const c_char,
state: c_int,
video_stream_index: c_int,
preset_version: c_int,
enabled: c_int,
) -> c_int {
unsafe {
oaknode::ffi::footage::oaknode_footage_set_proxy(
footage,
path,
state,
video_stream_index,
preset_version,
enabled,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -554,17 +685,41 @@ pub fn oaknode_footage_clear_proxy(footage: OakNodeFootage) -> c_int {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_get_video_params(footage: OakNodeFootage, index: c_int, out: *mut OakVideoParams) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_get_video_params(footage, index, out as *mut std::ffi::c_void) }
pub fn oaknode_footage_get_video_params(
footage: OakNodeFootage,
index: c_int,
out: *mut OakVideoParams,
) -> c_int {
unsafe {
oaknode::ffi::footage::oaknode_footage_get_video_params(
footage,
index,
out as *mut std::ffi::c_void,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_set_video_params(footage: OakNodeFootage, index: c_int, params: *const OakVideoParams) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_set_video_params(footage, index, params as *const std::ffi::c_void) }
pub fn oaknode_footage_set_video_params(
footage: OakNodeFootage,
index: c_int,
params: *const OakVideoParams,
) -> c_int {
unsafe {
oaknode::ffi::footage::oaknode_footage_set_video_params(
footage,
index,
params as *const std::ffi::c_void,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_footage_get_video_length(footage: OakNodeFootage, out_num: *mut i64, out_den: *mut i64) -> c_int {
pub fn oaknode_footage_get_video_length(
footage: OakNodeFootage,
out_num: *mut i64,
out_den: *mut i64,
) -> c_int {
unsafe { oaknode::ffi::footage::oaknode_footage_get_video_length(footage, out_num, out_den) }
}
@@ -599,17 +754,30 @@ pub fn oaknode_sequence_from_node(node: OakNodeNode) -> OakNodeSequence {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_track_list(sequence: OakNodeSequence, r#type: c_int, out: *mut OakNodeTrackList) -> c_int {
pub fn oaknode_sequence_get_track_list(
sequence: OakNodeSequence,
r#type: c_int,
out: *mut OakNodeTrackList,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_list(sequence, r#type, out) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_track_count(sequence: OakNodeSequence, r#type: c_int, count: *mut c_int) -> c_int {
pub fn oaknode_sequence_get_track_count(
sequence: OakNodeSequence,
r#type: c_int,
count: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_count(sequence, r#type, count) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_track_at(sequence: OakNodeSequence, r#type: c_int, index: c_int, out: *mut OakNodeTrack) -> c_int {
pub fn oaknode_sequence_get_track_at(
sequence: OakNodeSequence,
r#type: c_int,
index: c_int,
out: *mut OakNodeTrack,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_track_at(sequence, r#type, index, out) }
}
@@ -619,33 +787,65 @@ pub fn oaknode_sequence_get_all_track_count(sequence: OakNodeSequence, count: *m
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_all_track_at(sequence: OakNodeSequence, index: c_int, out: *mut OakNodeTrack) -> c_int {
pub fn oaknode_sequence_get_all_track_at(
sequence: OakNodeSequence,
index: c_int,
out: *mut OakNodeTrack,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_all_track_at(sequence, index, out) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_playhead(sequence: OakNodeSequence, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_playhead(sequence, numerator, denominator) }
pub fn oaknode_sequence_get_playhead(
sequence: OakNodeSequence,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::sequence::oaknode_sequence_get_playhead(sequence, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_set_playhead(sequence: OakNodeSequence, numerator: c_int, denominator: c_int) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_set_playhead(sequence, numerator, denominator) }
pub fn oaknode_sequence_set_playhead(
sequence: OakNodeSequence,
numerator: c_int,
denominator: c_int,
) -> c_int {
unsafe {
oaknode::ffi::sequence::oaknode_sequence_set_playhead(sequence, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_length(sequence: OakNodeSequence, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
pub fn oaknode_sequence_get_length(
sequence: OakNodeSequence,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_length(sequence, numerator, denominator) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_video_length(sequence: OakNodeSequence, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_video_length(sequence, numerator, denominator) }
pub fn oaknode_sequence_get_video_length(
sequence: OakNodeSequence,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::sequence::oaknode_sequence_get_video_length(sequence, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_audio_length(sequence: OakNodeSequence, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_audio_length(sequence, numerator, denominator) }
pub fn oaknode_sequence_get_audio_length(
sequence: OakNodeSequence,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::sequence::oaknode_sequence_get_audio_length(sequence, numerator, denominator)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -654,32 +854,60 @@ pub fn oaknode_sequence_verify_length(sequence: OakNodeSequence) -> c_int {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_video_stream_count(sequence: OakNodeSequence, count: *mut c_int) -> c_int {
pub fn oaknode_sequence_get_video_stream_count(
sequence: OakNodeSequence,
count: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_video_stream_count(sequence, count) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_audio_stream_count(sequence: OakNodeSequence, count: *mut c_int) -> c_int {
pub fn oaknode_sequence_get_audio_stream_count(
sequence: OakNodeSequence,
count: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_audio_stream_count(sequence, count) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_video_params(sequence: OakNodeSequence, index: c_int, out: *mut OakVideoParams) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_video_params(sequence, index, out as *mut std::ffi::c_void) }
pub fn oaknode_sequence_get_video_params(
sequence: OakNodeSequence,
index: c_int,
out: *mut OakVideoParams,
) -> c_int {
unsafe {
oaknode::ffi::sequence::oaknode_sequence_get_video_params(
sequence,
index,
out as *mut std::ffi::c_void,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_set_video_params(sequence: OakNodeSequence, index: c_int, params: OakVideoParams) -> c_int {
pub fn oaknode_sequence_set_video_params(
sequence: OakNodeSequence,
index: c_int,
params: OakVideoParams,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_set_video_params(sequence, index, params) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_get_audio_params(sequence: OakNodeSequence, index: c_int, out: *mut *mut std::ffi::c_void) -> c_int {
pub fn oaknode_sequence_get_audio_params(
sequence: OakNodeSequence,
index: c_int,
out: *mut *mut std::ffi::c_void,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_get_audio_params(sequence, index, out) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_sequence_set_audio_params(sequence: OakNodeSequence, index: c_int, params: *const c_void) -> c_int {
pub fn oaknode_sequence_set_audio_params(
sequence: OakNodeSequence,
index: c_int,
params: *const c_void,
) -> c_int {
unsafe { oaknode::ffi::sequence::oaknode_sequence_set_audio_params(sequence, index, params) }
}
@@ -704,7 +932,11 @@ pub fn oaknode_track_get_type(track: OakNodeTrack, r#type: *mut c_int) -> c_int
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_track_get_length(track: OakNodeTrack, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
pub fn oaknode_track_get_length(
track: OakNodeTrack,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::track::oaknode_track_get_length(track, numerator, denominator) }
}
@@ -714,7 +946,11 @@ pub fn oaknode_track_get_block_count(track: OakNodeTrack, count: *mut c_int) ->
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_track_get_block_at(track: OakNodeTrack, index: c_int, out: *mut OakNodeBlock) -> c_int {
pub fn oaknode_track_get_block_at(
track: OakNodeTrack,
index: c_int,
out: *mut OakNodeBlock,
) -> c_int {
unsafe { oaknode::ffi::track::oaknode_track_get_block_at(track, index, out) }
}
@@ -749,7 +985,11 @@ pub fn oaknode_tracklist_get_sequence(list: OakNodeTrackList, out: *mut OakNodeS
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_tracklist_get_track_input_id(list: OakNodeTrackList, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_tracklist_get_track_input_id(
list: OakNodeTrackList,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_input_id(list, buf, buf_size) }
}
@@ -764,8 +1004,18 @@ pub fn oaknode_tracklist_array_remove_last(list: OakNodeTrackList) -> c_int {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_tracklist_get_array_index_from_cache_index(list: OakNodeTrackList, cache_index: c_int, out_index: *mut c_int) -> c_int {
unsafe { oaknode::ffi::track::oaknode_tracklist_get_array_index_from_cache_index(list, cache_index, out_index) }
pub fn oaknode_tracklist_get_array_index_from_cache_index(
list: OakNodeTrackList,
cache_index: c_int,
out_index: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::track::oaknode_tracklist_get_array_index_from_cache_index(
list,
cache_index,
out_index,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -779,12 +1029,20 @@ pub fn oaknode_tracklist_get_track_count(list: OakNodeTrackList, count: *mut c_i
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_tracklist_get_track_at(list: OakNodeTrackList, index: c_int, out: *mut OakNodeTrack) -> c_int {
pub fn oaknode_tracklist_get_track_at(
list: OakNodeTrackList,
index: c_int,
out: *mut OakNodeTrack,
) -> c_int {
unsafe { oaknode::ffi::track::oaknode_tracklist_get_track_at(list, index, out) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_tracklist_get_total_length(list: OakNodeTrackList, numerator: *mut c_int, denominator: *mut c_int) -> c_int {
pub fn oaknode_tracklist_get_total_length(
list: OakNodeTrackList,
numerator: *mut c_int,
denominator: *mut c_int,
) -> c_int {
unsafe { oaknode::ffi::track::oaknode_tracklist_get_total_length(list, numerator, denominator) }
}
@@ -839,7 +1097,10 @@ pub fn oaknode_serializer_shutdown() {
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_savedata_create(load_type: c_int, project: OakNodeProject) -> OakNodeSerializerSaveData {
pub fn oaknode_serializer_savedata_create(
load_type: c_int,
project: OakNodeProject,
) -> OakNodeSerializerSaveData {
unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_create(load_type, project) }
}
@@ -849,23 +1110,60 @@ pub fn oaknode_serializer_savedata_free(save_data: *mut OakNodeSerializerSaveDat
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_savedata_set_nodes(save_data: OakNodeSerializerSaveData, nodes: *const OakNodeNode, count: c_int) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_set_nodes(save_data, nodes, count) }
pub fn oaknode_serializer_savedata_set_nodes(
save_data: OakNodeSerializerSaveData,
nodes: *const OakNodeNode,
count: c_int,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_savedata_set_nodes(save_data, nodes, count)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_savedata_set_property(save_data: OakNodeSerializerSaveData, node: OakNodeNode, key: *const c_char, value: *const c_char) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_savedata_set_property(save_data, node, key, value) }
pub fn oaknode_serializer_savedata_set_property(
save_data: OakNodeSerializerSaveData,
node: OakNodeNode,
key: *const c_char,
value: *const c_char,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_savedata_set_property(
save_data, node, key, value,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_save_to_xml(save_data: OakNodeSerializerSaveData, buf: *mut c_char, buf_size: c_int) -> c_int {
pub fn oaknode_serializer_save_to_xml(
save_data: OakNodeSerializerSaveData,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_save_to_xml(save_data, buf, buf_size) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_load_from_xml(project: OakNodeProject, xml: *const c_char, load_type: c_int, out_result: *mut c_int, out_load_data: *mut OakNodeSerializerLoadData, details_buf: *mut c_char, details_buf_size: c_int) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_load_from_xml(project, xml, load_type, out_result, out_load_data, details_buf, details_buf_size) }
pub fn oaknode_serializer_load_from_xml(
project: OakNodeProject,
xml: *const c_char,
load_type: c_int,
out_result: *mut c_int,
out_load_data: *mut OakNodeSerializerLoadData,
details_buf: *mut c_char,
details_buf_size: c_int,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_load_from_xml(
project,
xml,
load_type,
out_result,
out_load_data,
details_buf,
details_buf_size,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -879,13 +1177,26 @@ pub fn oaknode_serializer_loaddata_node_count(load_data: OakNodeSerializerLoadDa
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_loaddata_node_at(load_data: OakNodeSerializerLoadData, index: c_int) -> OakNodeNode {
pub fn oaknode_serializer_loaddata_node_at(
load_data: OakNodeSerializerLoadData,
index: c_int,
) -> OakNodeNode {
unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_node_at(load_data, index) }
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_loaddata_get_property(load_data: OakNodeSerializerLoadData, node: OakNodeNode, key: *const c_char, buf: *mut c_char, buf_size: c_int) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_get_property(load_data, node, key, buf, buf_size) }
pub fn oaknode_serializer_loaddata_get_property(
load_data: OakNodeSerializerLoadData,
node: OakNodeNode,
key: *const c_char,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_loaddata_get_property(
load_data, node, key, buf, buf_size,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
@@ -894,17 +1205,64 @@ pub fn oaknode_serializer_loaddata_connection_count(load_data: OakNodeSerializer
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_loaddata_connection_at(load_data: OakNodeSerializerLoadData, index: c_int, out_output_node: *mut OakNodeNode, out_input_node: *mut OakNodeNode, input_id_buf: *mut c_char, input_id_buf_size: c_int, out_element: *mut c_int) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_loaddata_connection_at(load_data, index, out_output_node, out_input_node, input_id_buf, input_id_buf_size, out_element) }
pub fn oaknode_serializer_loaddata_connection_at(
load_data: OakNodeSerializerLoadData,
index: c_int,
out_output_node: *mut OakNodeNode,
out_input_node: *mut OakNodeNode,
input_id_buf: *mut c_char,
input_id_buf_size: c_int,
out_element: *mut c_int,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_loaddata_connection_at(
load_data,
index,
out_output_node,
out_input_node,
input_id_buf,
input_id_buf_size,
out_element,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_save_to_file(project: OakNodeProject, filename: *const c_char, use_compression: c_int, out_code: *mut c_int, details: *mut c_char, details_size: c_int) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_save_to_file(project, filename, use_compression, out_code, details, details_size) }
pub fn oaknode_serializer_save_to_file(
project: OakNodeProject,
filename: *const c_char,
use_compression: c_int,
out_code: *mut c_int,
details: *mut c_char,
details_size: c_int,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_save_to_file(
project,
filename,
use_compression,
out_code,
details,
details_size,
)
}
}
/// Direct call into the `oaknode` crate (single-lib unification).
pub fn oaknode_serializer_load_from_file(project: OakNodeProject, filename: *const c_char, out_code: *mut c_int, details: *mut c_char, details_size: c_int) -> c_int {
unsafe { oaknode::ffi::serializer::oaknode_serializer_load_from_file(project, filename, out_code, details, details_size) }
pub fn oaknode_serializer_load_from_file(
project: OakNodeProject,
filename: *const c_char,
out_code: *mut c_int,
details: *mut c_char,
details_size: c_int,
) -> c_int {
unsafe {
oaknode::ffi::serializer::oaknode_serializer_load_from_file(
project,
filename,
out_code,
details,
details_size,
)
}
}
+75 -57
View File
@@ -55,26 +55,18 @@ use crate::handle::CHandle;
/// Mirror of `OakCancelAtom` (`include/render/cancelatom.h`).
pub type OakCancelAtom = oakrender::ffi::OakCancelAtom;
/// Mirror of `OakRenderTicket` (`include/render/ticket.h`).
pub type OakRenderTicket = oakrender::ffi::OakRenderTicket;
/// Mirror of `OakRenderCache` (`include/render/cache.h`).
pub type OakRenderCache = oakrender::ffi::OakRenderCache;
/// Mirror of `OakRenderProjectCopier` (`include/render/copier.h`).
pub type OakRenderProjectCopier = oakrender::ffi::OakRenderProjectCopier;
/// Mirror of `OakColorProcessor` (`include/render/color.h`).
pub type OakColorProcessor = oakrender::ffi::OakColorProcessor;
/// Mirror of `oakrender_ticket_finished_fn` (`include/render/ticket.h`).
///
/// Two arguments — `(ticket, userdata)` — mirroring the header verbatim and
@@ -82,12 +74,12 @@ pub type OakColorProcessor = oakrender::ffi::OakColorProcessor;
/// The ticket is a borrowed copy of the submitter's handle (the submitter
/// keeps ownership and releases it); cancelled tickets fire with a NULL
/// result observed through `oakrender_ticket_get_frame`.
pub type OakRenderTicketFinishedFn = unsafe extern "C" fn(ticket: OakRenderTicket, userdata: *mut c_void);
pub type OakRenderTicketFinishedFn =
unsafe extern "C" fn(ticket: OakRenderTicket, userdata: *mut c_void);
/// Mirror of `oakrender_video_ticket_params` (`include/render/ticket.h`).
pub type OakRenderVideoTicketParams = oakrender::ffi::OakVideoTicketParams;
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_cancelatom_init() -> OakCancelAtom {
unsafe { oakrender::ffi::cancelatom::oakrender_cancelatom_init() }
@@ -115,26 +107,38 @@ pub fn oakrender_cancelatom_heard_cancel(atom: OakCancelAtom, heard: *mut c_int)
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_ticket_render_frame(
params: *const OakRenderVideoTicketParams,
cb: Option<OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> OakRenderTicket {
params: *const OakRenderVideoTicketParams,
cb: Option<OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> OakRenderTicket {
unsafe { oakrender::ffi::ticket::oakrender_ticket_render_frame(params, cb, userdata) }
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_ticket_render_audio(
output_node: OakNodeNode,
in_num: i64,
in_den: i64,
out_num: i64,
out_den: i64,
params: *const OakAudioParams,
mode: c_int,
cb: Option<OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> OakRenderTicket {
unsafe { oakrender::ffi::ticket::oakrender_ticket_render_audio(output_node, in_num, in_den, out_num, out_den, params, mode, cb, userdata) }
output_node: OakNodeNode,
in_num: i64,
in_den: i64,
out_num: i64,
out_den: i64,
params: *const OakAudioParams,
mode: c_int,
cb: Option<OakRenderTicketFinishedFn>,
userdata: *mut c_void,
) -> OakRenderTicket {
unsafe {
oakrender::ffi::ticket::oakrender_ticket_render_audio(
output_node,
in_num,
in_den,
out_num,
out_den,
params,
mode,
cb,
userdata,
)
}
}
/// Direct call into the `oakrender` crate (single-lib unification).
@@ -163,23 +167,32 @@ pub fn oakrender_ticket_get_frame(ticket: OakRenderTicket, out: *mut OakFrame) -
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_ticket_get_time(ticket: OakRenderTicket, out_num: *mut i64, out_den: *mut i64) -> c_int {
pub fn oakrender_ticket_get_time(
ticket: OakRenderTicket,
out_num: *mut i64,
out_den: *mut i64,
) -> c_int {
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_time(ticket, out_num, out_den) }
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_ticket_get_range(
ticket: OakRenderTicket,
in_num: *mut i64,
in_den: *mut i64,
out_num: *mut i64,
out_den: *mut i64,
) -> c_int {
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_range(ticket, in_num, in_den, out_num, out_den) }
ticket: OakRenderTicket,
in_num: *mut i64,
in_den: *mut i64,
out_num: *mut i64,
out_den: *mut i64,
) -> c_int {
unsafe {
oakrender::ffi::ticket::oakrender_ticket_get_range(ticket, in_num, in_den, out_num, out_den)
}
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_ticket_get_samples(ticket: OakRenderTicket, out: *mut *mut std::ffi::c_void) -> c_int {
pub fn oakrender_ticket_get_samples(
ticket: OakRenderTicket,
out: *mut *mut std::ffi::c_void,
) -> c_int {
unsafe { oakrender::ffi::ticket::oakrender_ticket_get_samples(ticket, out) }
}
@@ -200,34 +213,36 @@ pub fn oakrender_project_copier_free(copier: *mut OakRenderProjectCopier) {
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_project_copier_set_project(
copier: OakRenderProjectCopier,
project: OakNodeProject,
) -> c_int {
copier: OakRenderProjectCopier,
project: OakNodeProject,
) -> c_int {
unsafe { oakrender::ffi::copier::oakrender_project_copier_set_project(copier, project) }
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_project_copier_get_copy(
copier: OakRenderProjectCopier,
original: OakNodeNode,
) -> OakNodeNode {
copier: OakRenderProjectCopier,
original: OakNodeNode,
) -> OakNodeNode {
unsafe { oakrender::ffi::copier::oakrender_project_copier_get_copy(copier, original) }
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_project_copier_get_copied_project(
copier: OakRenderProjectCopier,
) -> OakNodeProject {
copier: OakRenderProjectCopier,
) -> OakNodeProject {
unsafe { oakrender::ffi::copier::oakrender_project_copier_get_copied_project(copier) }
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_color_processor_create(
src_space: *const c_char,
dst_transform: *const c_char,
direction: c_int,
) -> OakColorProcessor {
unsafe { oakrender::ffi::color::oakrender_color_processor_create(src_space, dst_transform, direction) }
src_space: *const c_char,
dst_transform: *const c_char,
direction: c_int,
) -> OakColorProcessor {
unsafe {
oakrender::ffi::color::oakrender_color_processor_create(src_space, dst_transform, direction)
}
}
/// Direct call into the `oakrender` crate (single-lib unification).
@@ -252,19 +267,22 @@ pub fn oakrender_manager_set_aggressive_gc(enabled: c_int) -> c_int {
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_cache_get_invalidated_ranges(
cache: OakRenderCache,
in_num: i64,
in_den: i64,
out_num: i64,
out_den: i64,
flat: *mut i64,
flat_size: c_int,
) -> c_int {
unsafe { oakrender::ffi::cache::oakrender_cache_get_invalidated_ranges(cache, in_num, in_den, out_num, out_den, flat, flat_size) }
cache: OakRenderCache,
in_num: i64,
in_den: i64,
out_num: i64,
out_den: i64,
flat: *mut i64,
flat_size: c_int,
) -> c_int {
unsafe {
oakrender::ffi::cache::oakrender_cache_get_invalidated_ranges(
cache, in_num, in_den, out_num, out_den, flat, flat_size,
)
}
}
/// Direct call into the `oakrender` crate (single-lib unification).
pub fn oakrender_cache_free(cache: *mut OakRenderCache) {
unsafe { oakrender::ffi::cache::oakrender_cache_free(cache) }
}
-1
View File
@@ -42,4 +42,3 @@ use crate::bridge::undo::OakUndoCommand;
pub fn oaktimeline_add_track_command(list: OakNodeTrackList) -> OakUndoCommand {
unsafe { oaktimeline::ffi::edit::oaktimeline_add_track_command(list) }
}
+9 -4
View File
@@ -45,9 +45,11 @@ pub type OakUndoCommand = CHandle;
/// Mirror of `OakUndoCommandVtable` (`include/undo/undocommand.h`).
pub type OakUndoCommandVtable = oakundo::undocommand::OakUndoCommandVtable;
/// Direct call into the `oakundo` crate (single-lib unification).
pub fn oakundo_command_init(vtable: *const OakUndoCommandVtable, userdata: *mut c_void) -> OakUndoCommand {
pub fn oakundo_command_init(
vtable: *const OakUndoCommandVtable,
userdata: *mut c_void,
) -> OakUndoCommand {
unsafe { oakundo::ffi::command::oakundo_command_init(vtable, userdata) }
}
@@ -67,7 +69,11 @@ pub fn oakundo_command_multi_child_count(multi: OakUndoCommand, out_count: *mut
}
/// Direct call into the `oakundo` crate (single-lib unification).
pub fn oakundo_command_multi_child(multi: OakUndoCommand, index: c_int, out_child: *mut OakUndoCommand) -> c_int {
pub fn oakundo_command_multi_child(
multi: OakUndoCommand,
index: c_int,
out_child: *mut OakUndoCommand,
) -> c_int {
unsafe { oakundo::ffi::command::oakundo_command_multi_child(multi, index, out_child) }
}
@@ -85,4 +91,3 @@ pub fn oakundo_command_undo_now(command: OakUndoCommand) -> c_int {
pub fn oakundo_command_free(command: *mut OakUndoCommand) {
unsafe { oakundo::ffi::command::oakundo_command_free(command) }
}
+4 -1
View File
@@ -58,7 +58,10 @@ unsafe fn cstr_buf_to_string(buf: &[u8]) -> String {
///
/// # Safety
/// `req` must be a valid `OakCodecTaskRequest` or null.
unsafe extern "C" fn submit_codec_task(req: *const bridge::codec::OakCodecTaskRequest, _userdata: *mut c_void) -> c_int {
unsafe extern "C" fn submit_codec_task(
req: *const bridge::codec::OakCodecTaskRequest,
_userdata: *mut c_void,
) -> c_int {
if req.is_null() {
return bridge::codec::OAKCODEC_E_INVALID;
}
+18 -5
View File
@@ -80,10 +80,14 @@ impl ConformTask {
/// tests/parity_test.rs).
///
/// CPP-PARITY: src/task/src/conform/conform.cpp (derive_filenames)
pub fn derive_filenames(first_channel_final: &str, channel_count: usize) -> Result<(Vec<String>, Vec<String>)> {
pub fn derive_filenames(
first_channel_final: &str,
channel_count: usize,
) -> Result<(Vec<String>, Vec<String>)> {
const SUFFIX: &str = ".0.pcm";
if channel_count < 1 || first_channel_final.len() <= SUFFIX.len()
if channel_count < 1
|| first_channel_final.len() <= SUFFIX.len()
|| !first_channel_final.ends_with(SUFFIX)
{
return Err(Error::Failed("Invalid conform output filename".to_string()));
@@ -124,7 +128,11 @@ impl TaskBehavior for ConformTask {
let result = (|| {
let open_result = unsafe {
bridge::codec::oakcodec_decoder_open(decoder, cstr(&self.input_filename), self.stream_index)
bridge::codec::oakcodec_decoder_open(
decoder,
cstr(&self.input_filename),
self.stream_index,
)
};
if open_result != 0 {
let err = decoder_error(decoder);
@@ -188,10 +196,15 @@ impl TaskBehavior for ConformTask {
/// Two-stage read of the decoder's last error string.
fn decoder_error(decoder: CHandle) -> String {
let mut buf = [0i8; 256];
let needed = unsafe { bridge::codec::oakcodec_decoder_last_error(decoder, buf.as_mut_ptr(), buf.len() as i32) };
let needed = unsafe {
bridge::codec::oakcodec_decoder_last_error(decoder, buf.as_mut_ptr(), buf.len() as i32)
};
if needed <= 0 {
return String::new();
}
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
unsafe { String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len)).into_owned() }
unsafe {
String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len))
.into_owned()
}
}
+6 -2
View File
@@ -102,7 +102,10 @@ impl CustomCacheTask {
/// Create a cache-fill task with the given sequence name. The cancel
/// hook that wakes the parked thread is installed on the base task.
pub fn new(sequence_name: &str) -> CustomCacheTask {
let base = Task::new(&format!("Caching custom range for \"{sequence_name}\""), CHandle::null());
let base = Task::new(
&format!("Caching custom range for \"{sequence_name}\""),
CHandle::null(),
);
let state = Arc::new(CustomCacheState {
cancelled_through_finish: Mutex::new(false),
wait: Condvar::new(),
@@ -115,7 +118,8 @@ impl CustomCacheTask {
state,
};
let hook_state = task.state.clone();
task.base.set_cancel_event(Box::new(move || hook_state.cancel_event()));
task.base
.set_cancel_event(Box::new(move || hook_state.cancel_event()));
task
}
+32 -7
View File
@@ -106,7 +106,14 @@ impl ExportTask {
let label = node_label(viewer);
let title = format!("Exporting \"{label}\"");
let base = Task::new(&title, CHandle::null());
let render = RenderTask::new(base, CHandle::null(), CHandle::null(), viewer, ForceParams::default(), None);
let render = RenderTask::new(
base,
CHandle::null(),
CHandle::null(),
viewer,
ForceParams::default(),
None,
);
ExportTask {
render,
viewer_node: viewer,
@@ -190,7 +197,10 @@ impl ExportTask {
unsafe {
bridge::node::oaknode_sequence_get_length(self.viewer_node, &mut len_num, &mut len_den);
}
TimeRange::new(Rational::new(0, 1), Rational::new(len_num as i64, len_den as i64))
TimeRange::new(
Rational::new(0, 1),
Rational::new(len_num as i64, len_den as i64),
)
}
}
@@ -222,7 +232,8 @@ impl TaskBehavior for ExportTask {
if self.encoding_params.video_enabled {
force.force_width = self.encoding_params.video_width;
force.force_height = self.encoding_params.video_height;
force.force_format = unsafe { bridge::codec::oakcodec_encoder_get_desired_pixel_format(encoder) };
force.force_format =
unsafe { bridge::codec::oakcodec_encoder_get_desired_pixel_format(encoder) };
force.force_channel_count = 4; // RGBA
}
self.render.force_params = force;
@@ -238,7 +249,8 @@ impl TaskBehavior for ExportTask {
// virtual dispatch receiver). The render is temporarily moved out of
// `self` to avoid a self-referential borrow; it is put back right
// after, before the encoder flush below.
let mut render = std::mem::replace(&mut self.render, crate::render::RenderTask::placeholder());
let mut render =
std::mem::replace(&mut self.render, crate::render::RenderTask::placeholder());
let result = render.render(task, self);
self.render = render;
result?;
@@ -299,7 +311,15 @@ impl RenderTaskBehavior for ExportTask {
}
// The simplified path does not carry the subtitle block's in/out
// times; write with 0.0/0.0 (the encoder default interval).
if unsafe { bridge::codec::oakcodec_encoder_write_subtitle(self.subtitle_encoder, cstr(text), 0.0, 0.0) } != 0 {
if unsafe {
bridge::codec::oakcodec_encoder_write_subtitle(
self.subtitle_encoder,
cstr(text),
0.0,
0.0,
)
} != 0
{
let err = encoder_error(self.subtitle_encoder);
task.set_error(&err);
return Err(Error::Failed("Failed to write subtitle".to_string()));
@@ -324,13 +344,18 @@ fn node_label(node: CHandle) -> String {
/// Read a NUL-terminated char buffer into a String (lossy).
fn buf_to_string(buf: &[i8]) -> String {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
unsafe { String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len)).into_owned() }
unsafe {
String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len))
.into_owned()
}
}
/// Two-stage read of the encoder's last error string.
fn encoder_error(encoder: CHandle) -> String {
let mut buf = [0i8; 512];
let needed = unsafe { bridge::codec::oakcodec_encoder_last_error(encoder, buf.as_mut_ptr(), buf.len() as i32) };
let needed = unsafe {
bridge::codec::oakcodec_encoder_last_error(encoder, buf.as_mut_ptr(), buf.len() as i32)
};
if needed <= 0 {
return String::new();
}
+21 -6
View File
@@ -45,7 +45,9 @@ use crate::ffi::taskhandle::{
};
use crate::handle::CHandle;
use crate::precache::PreCacheTask;
use crate::project::import::{import_file_count, import_title, ImageSequenceConfirmFn, ProjectImportTask};
use crate::project::import::{
import_file_count, import_title, ImageSequenceConfirmFn, ProjectImportTask,
};
use crate::project::load::{ProjectLoadBaseTask, ProjectLoadTask};
use crate::project::loadotio::{set_import_confirm_callback, LoadOTIOTask};
use crate::project::save::{project_filename, ProjectSaveTask};
@@ -53,8 +55,11 @@ use crate::project::saveotio::SaveOTIOTask;
use crate::task::Task;
/// `oaktask_otio_import_confirm_fn` (`include/task/project.h`).
pub type OakTaskOtioImportConfirmFn =
unsafe extern "C" fn(sequence_names: *const *const c_char, count: c_int, userdata: *mut c_void) -> c_int;
pub type OakTaskOtioImportConfirmFn = unsafe extern "C" fn(
sequence_names: *const *const c_char,
count: c_int,
userdata: *mut c_void,
) -> c_int;
/// `oaktask_image_sequence_confirm_fn` (`include/task/project.h`).
pub type OakTaskImageSequenceConfirmFn =
@@ -280,7 +285,10 @@ pub unsafe extern "C" fn oaktask_load_otio_take_project(t: CHandle) -> CHandle {
/// `.fcpxml`, case-insensitive; see `crate::project::format`), so the C
/// ABI needs no format parameter.
#[no_mangle]
pub unsafe extern "C" fn oaktask_create_project_save_otio(project: CHandle, filename: *const c_char) -> CHandle {
pub unsafe extern "C" fn oaktask_create_project_save_otio(
project: CHandle,
filename: *const c_char,
) -> CHandle {
if project.ctx.is_null() || filename.is_null() {
return CHandle::null();
}
@@ -300,7 +308,10 @@ pub unsafe extern "C" fn oaktask_create_project_save_otio(project: CHandle, file
/// `oaktask_load_otio_set_confirm_cb` (`include/task/project.h`).
#[no_mangle]
pub unsafe extern "C" fn oaktask_load_otio_set_confirm_cb(cb: Option<OakTaskOtioImportConfirmFn>, userdata: *mut c_void) {
pub unsafe extern "C" fn oaktask_load_otio_set_confirm_cb(
cb: Option<OakTaskOtioImportConfirmFn>,
userdata: *mut c_void,
) {
let Some(cb) = cb else {
set_import_confirm_callback(None);
return;
@@ -314,7 +325,11 @@ pub unsafe extern "C" fn oaktask_load_otio_set_confirm_cb(cb: Option<OakTaskOtio
/// `oaktask_create_precache` (`include/task/project.h`).
#[no_mangle]
pub unsafe extern "C" fn oaktask_create_precache(footage: CHandle, index: c_int, sequence: CHandle) -> CHandle {
pub unsafe extern "C" fn oaktask_create_precache(
footage: CHandle,
index: c_int,
sequence: CHandle,
) -> CHandle {
if footage.ctx.is_null() || sequence.ctx.is_null() {
return CHandle::null();
}
+25 -5
View File
@@ -178,7 +178,11 @@ pub unsafe extern "C" fn oaktask_task_succeeded(t: CHandle) -> c_int {
/// `oaktask_task_title` (`include/task/task.h`, two-stage string getter).
#[no_mangle]
pub unsafe extern "C" fn oaktask_task_title(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int {
pub unsafe extern "C" fn oaktask_task_title(
t: CHandle,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
let h = match get_task(&t) {
Some(h) => h,
None => return OAKTASK_E_INVALID,
@@ -188,7 +192,11 @@ pub unsafe extern "C" fn oaktask_task_title(t: CHandle, buf: *mut c_char, buf_si
/// `oaktask_task_error` (`include/task/task.h`, two-stage string getter).
#[no_mangle]
pub unsafe extern "C" fn oaktask_task_error(t: CHandle, buf: *mut c_char, buf_size: c_int) -> c_int {
pub unsafe extern "C" fn oaktask_task_error(
t: CHandle,
buf: *mut c_char,
buf_size: c_int,
) -> c_int {
let h = match get_task(&t) {
Some(h) => h,
None => return OAKTASK_E_INVALID,
@@ -199,7 +207,11 @@ pub unsafe extern "C" fn oaktask_task_error(t: CHandle, buf: *mut c_char, buf_si
/// `oaktask_task_subscribe` (`include/task/task.h`).
#[no_mangle]
pub unsafe extern "C" fn oaktask_task_subscribe(t: CHandle, cb: Option<OakTaskEventFn>, userdata: *mut c_void) -> i64 {
pub unsafe extern "C" fn oaktask_task_subscribe(
t: CHandle,
cb: Option<OakTaskEventFn>,
userdata: *mut c_void,
) -> i64 {
let h = match get_task(&t) {
Some(h) => h,
None => return OAKTASK_E_INVALID as i64,
@@ -218,9 +230,17 @@ pub unsafe extern "C" fn oaktask_task_subscribe(t: CHandle, cb: Option<OakTaskEv
(*h.task).set_subscriber(state.clone());
(*h.task).set_event_listener(Box::new(move |ev: TaskEvent| {
let (event_id, value) = match ev {
TaskEvent::Started => (OAKTASK_EVENT_STARTED, state.start_ms.load(std::sync::atomic::Ordering::SeqCst) as f64),
TaskEvent::Started => (
OAKTASK_EVENT_STARTED,
state.start_ms.load(std::sync::atomic::Ordering::SeqCst) as f64,
),
TaskEvent::Progress(p) => (OAKTASK_EVENT_PROGRESS, p),
TaskEvent::Finished => (OAKTASK_EVENT_FINISHED, state.finished_value.load(std::sync::atomic::Ordering::SeqCst) as f64),
TaskEvent::Finished => (
OAKTASK_EVENT_FINISHED,
state
.finished_value
.load(std::sync::atomic::Ordering::SeqCst) as f64,
),
};
cb(event_id, value, ud as *mut c_void);
}));
+8 -2
View File
@@ -153,7 +153,11 @@ pub fn copy_string(value: &str, buf: *mut std::ffi::c_char, buf_size: i32) -> i3
let needed = value.len() as i32 + 1;
if !buf.is_null() && buf_size >= needed {
unsafe {
std::ptr::copy_nonoverlapping(value.as_ptr() as *const std::ffi::c_char, buf, value.len());
std::ptr::copy_nonoverlapping(
value.as_ptr() as *const std::ffi::c_char,
buf,
value.len(),
);
*buf.add(value.len()) = 0;
}
}
@@ -169,7 +173,9 @@ pub unsafe fn cstr_to_string(ptr: *const std::ffi::c_char) -> String {
if ptr.is_null() {
return String::new();
}
unsafe { std::ffi::CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
unsafe { std::ffi::CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned()
}
/// Build a NUL-terminated C string for the duration of the call (leaked).
+11 -3
View File
@@ -48,7 +48,9 @@ unsafe extern "C" fn owned_addref<T: 'static>(ctx: *mut std::ffi::c_void) {
if !ctx.is_null() {
// CPP-PARITY: src/task/c_api/taskhandle.h (task_addref)
unsafe {
(*(ctx as *const RefBox<T>)).refs.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
(*(ctx as *const RefBox<T>))
.refs
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
}
@@ -86,7 +88,10 @@ unsafe extern "C" fn borrowed_release<T: 'static>(ctx: *mut std::ffi::c_void) {
/// Owned handle with count 1; empty on allocation failure.
pub fn make_owned<T: Send + 'static>(value: T) -> CHandle {
let b = Box::new(RefBox { refs: AtomicU32::new(1), value });
let b = Box::new(RefBox {
refs: AtomicU32::new(1),
value,
});
CHandle {
ctx: Box::into_raw(b) as *mut std::ffi::c_void,
addref: Some(owned_addref::<T>),
@@ -104,7 +109,10 @@ pub unsafe fn make_borrowed<T: Send + 'static>(ptr: *mut T) -> CHandle {
if ptr.is_null() {
return CHandle::null();
}
let b = Box::new(RefBox { refs: AtomicU32::new(1), value: ptr });
let b = Box::new(RefBox {
refs: AtomicU32::new(1),
value: ptr,
});
CHandle {
ctx: Box::into_raw(b) as *mut std::ffi::c_void,
addref: Some(owned_addref::<*mut T>),
+23 -6
View File
@@ -62,7 +62,14 @@ impl PreCacheTask {
let filename = footage_filename(footage);
let title = format!("Pre-caching {filename}:{index}");
let base = Task::new(&title, CHandle::null());
let render = RenderTask::new(base, video_params, CHandle::null(), sequence, Default::default(), None);
let render = RenderTask::new(
base,
video_params,
CHandle::null(),
sequence,
Default::default(),
None,
);
// A scratch project for the render color manager (simplified).
let project = unsafe { bridge::node::oaknode_project_init() };
@@ -87,7 +94,11 @@ impl TaskBehavior for PreCacheTask {
let mut len_num = 0i64;
let mut len_den = 1i64;
unsafe {
bridge::node::oaknode_footage_get_video_length(self.footage, &mut len_num, &mut len_den);
bridge::node::oaknode_footage_get_video_length(
self.footage,
&mut len_num,
&mut len_den,
);
}
let range = TimeRange::new(Rational::new(0, 1), Rational::new(len_num, len_den));
@@ -97,13 +108,15 @@ impl TaskBehavior for PreCacheTask {
bridge::node::oaknode_node_get_video_frame_cache(self.sequence, &mut cache);
}
self.render.set_render_inputs(color_manager, cache, 0 /* k_online */, false, range);
self.render
.set_render_inputs(color_manager, cache, 0 /* k_online */, false, range);
// Drive the render with `self` as the subclass behavior (the C++
// virtual dispatch receiver); the render is temporarily moved out to
// avoid a self-referential borrow and put back before the handles are
// released below.
let mut render = std::mem::replace(&mut self.render, crate::render::RenderTask::placeholder());
let mut render =
std::mem::replace(&mut self.render, crate::render::RenderTask::placeholder());
let result = render.render(task, self);
self.render = render;
@@ -143,7 +156,8 @@ impl RenderTaskBehavior for PreCacheTask {
/// Two-stage read of the footage filename.
fn footage_filename(footage: CHandle) -> String {
let needed = unsafe { bridge::node::oaknode_footage_filename(footage, std::ptr::null_mut(), 0) };
let needed =
unsafe { bridge::node::oaknode_footage_filename(footage, std::ptr::null_mut(), 0) };
if needed <= 0 {
return String::new();
}
@@ -152,5 +166,8 @@ fn footage_filename(footage: CHandle) -> String {
bridge::node::oaknode_footage_filename(footage, buf.as_mut_ptr(), needed);
}
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
unsafe { String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len)).into_owned() }
unsafe {
String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len))
.into_owned()
}
}
+106 -25
View File
@@ -156,7 +156,14 @@ impl ProjectImportTask {
&self.invalid_files[index]
}
fn import(&mut self, task: &mut Task, folder: CHandle, entries: &mut Vec<String>, counter: &mut usize, parent_command: CHandle) {
fn import(
&mut self,
task: &mut Task,
folder: CHandle,
entries: &mut Vec<String>,
counter: &mut usize,
parent_command: CHandle,
) {
let mut i = 0;
while i < entries.len() {
if task.is_cancelled() {
@@ -176,7 +183,8 @@ impl ProjectImportTask {
};
if !entry_list.is_empty() {
let folder_handle = unsafe { bridge::node::oaknode_folder_create(self.project) };
let folder_handle =
unsafe { bridge::node::oaknode_folder_create(self.project) };
if !folder_handle.ctx.is_null() {
unsafe {
bridge::node::oaknode_node_set_label(
@@ -184,13 +192,24 @@ impl ProjectImportTask {
cstr(&basename_of(file_path)),
);
}
self.add_item_to_folder(folder, unsafe { bridge::node::oaknode_folder_as_node(folder_handle) }, parent_command);
self.add_item_to_folder(
folder,
unsafe { bridge::node::oaknode_folder_as_node(folder_handle) },
parent_command,
);
let mut sub_entries = entry_list;
self.import(task, folder_handle, &mut sub_entries, counter, parent_command);
self.import(
task,
folder_handle,
&mut sub_entries,
counter,
parent_command,
);
}
}
} else {
let footage = unsafe { bridge::node::oaknode_footage_create(self.project, std::ptr::null()) };
let footage =
unsafe { bridge::node::oaknode_footage_create(self.project, std::ptr::null()) };
if footage.ctx.is_null() {
i += 1;
continue;
@@ -199,21 +218,33 @@ impl ProjectImportTask {
unsafe {
bridge::node::oaknode_footage_set_cancel_atom(footage, task.get_cancel_atom());
}
let ok = unsafe { bridge::node::oaknode_footage_set_filename(footage, cstr(file_path)) } == 0;
let ok =
unsafe { bridge::node::oaknode_footage_set_filename(footage, cstr(file_path)) }
== 0;
unsafe {
bridge::node::oaknode_footage_set_cancel_atom(footage, bridge::render::OakCancelAtom::null());
bridge::node::oaknode_footage_set_cancel_atom(
footage,
bridge::render::OakCancelAtom::null(),
);
}
if ok && unsafe { bridge::node::oaknode_footage_is_valid(footage) } != 0 {
unsafe {
bridge::node::oaknode_node_set_label(bridge::node::oaknode_footage_as_node(footage), cstr(&basename_of(file_path)));
bridge::node::oaknode_node_set_label(
bridge::node::oaknode_footage_as_node(footage),
cstr(&basename_of(file_path)),
);
}
// See if this footage is an image sequence.
self.validate_image_sequence(task, footage, entries, i);
// Create the undoable command that adds the item.
self.add_item_to_folder(folder, unsafe { bridge::node::oaknode_footage_as_node(footage) }, parent_command);
self.add_item_to_folder(
folder,
unsafe { bridge::node::oaknode_footage_as_node(footage) },
parent_command,
);
self.imported_footage.push(footage);
} else {
@@ -222,7 +253,11 @@ impl ProjectImportTask {
// Remove the invalid footage from the graph; the remove
// command takes ownership on redo and deletes the node
// when the command is destroyed.
let mut remove = unsafe { bridge::node::oaknode_command_create_remove_node(bridge::node::oaknode_footage_as_node(footage)) };
let mut remove = unsafe {
bridge::node::oaknode_command_create_remove_node(
bridge::node::oaknode_footage_as_node(footage),
)
};
if !remove.ctx.is_null() {
unsafe {
bridge::undo::oakundo_command_redo_now(remove);
@@ -247,18 +282,30 @@ impl ProjectImportTask {
}
}
fn validate_image_sequence(&mut self, task: &mut Task, footage: CHandle, info_list: &mut Vec<String>, index: usize) {
fn validate_image_sequence(
&mut self,
task: &mut Task,
footage: CHandle,
info_list: &mut Vec<String>,
index: usize,
) {
let filename = footage_filename(footage);
if filename.is_empty() {
return;
}
let digit_count = unsafe { bridge::codec::oakcodec_decoder_get_image_sequence_digit_count(cstr(&filename)) };
let digit_count = unsafe {
bridge::codec::oakcodec_decoder_get_image_sequence_digit_count(cstr(&filename))
};
if digit_count <= 0 {
return;
}
if self.image_sequence_ignore_files.iter().any(|f| f == &filename) {
if self
.image_sequence_ignore_files
.iter()
.any(|f| f == &filename)
{
return;
}
@@ -267,7 +314,9 @@ impl ProjectImportTask {
}
let mut video_stream = CHandle::null();
if unsafe { bridge::node::oaknode_footage_get_video_params(footage, 0, &mut video_stream) } != 0 {
if unsafe { bridge::node::oaknode_footage_get_video_params(footage, 0, &mut video_stream) }
!= 0
{
return;
}
@@ -278,13 +327,16 @@ impl ProjectImportTask {
bridge::common::oakcommon_videoparams_get_height(video_stream, &mut height);
}
let seq_index = unsafe { bridge::codec::oakcodec_decoder_get_image_sequence_index(cstr(&filename)) };
let seq_index =
unsafe { bridge::codec::oakcodec_decoder_get_image_sequence_index(cstr(&filename)) };
let prev_fn = transform_sequence_filename(&filename, seq_index - 1, digit_count);
let next_fn = transform_sequence_filename(&filename, seq_index + 1, digit_count);
let previous_file = unsafe { bridge::node::oaknode_footage_create(self.project, cstr(&prev_fn)) };
let next_file = unsafe { bridge::node::oaknode_footage_create(self.project, cstr(&next_fn)) };
let previous_file =
unsafe { bridge::node::oaknode_footage_create(self.project, cstr(&prev_fn)) };
let next_file =
unsafe { bridge::node::oaknode_footage_create(self.project, cstr(&next_fn)) };
let prev_matches = !previous_file.ctx.is_null()
&& unsafe { bridge::node::oaknode_footage_is_valid(previous_file) } != 0
@@ -325,22 +377,41 @@ impl ProjectImportTask {
if is_sequence {
unsafe {
bridge::common::oakcommon_videoparams_set_video_type(video_stream, bridge::common::OAKCOMMON_VIDEO_TYPE_IMAGE_SEQUENCE);
bridge::common::oakcommon_videoparams_set_video_type(
video_stream,
bridge::common::OAKCOMMON_VIDEO_TYPE_IMAGE_SEQUENCE,
);
let mut rate_buf = [0i8; 64];
let needed = bridge::common::oakcommon_config_get(std::ptr::null(), cstr("DefaultSequenceFrameRate"), rate_buf.as_mut_ptr(), rate_buf.len() as i32);
let needed = bridge::common::oakcommon_config_get(
std::ptr::null(),
cstr("DefaultSequenceFrameRate"),
rate_buf.as_mut_ptr(),
rate_buf.len() as i32,
);
if needed > 0 {
let rate = crate::project::load::buf_to_string(&rate_buf);
if let Some((num, den)) = parse_rational(&rate) {
if den != 0 {
bridge::common::oakcommon_videoparams_set_time_base(video_stream, num, den);
bridge::common::oakcommon_videoparams_set_frame_rate(video_stream, den, num);
bridge::common::oakcommon_videoparams_set_time_base(
video_stream,
num,
den,
);
bridge::common::oakcommon_videoparams_set_frame_rate(
video_stream,
den,
num,
);
}
}
}
bridge::common::oakcommon_videoparams_set_start_time(video_stream, start_index);
bridge::common::oakcommon_videoparams_set_duration(video_stream, end_index - start_index + 1);
bridge::common::oakcommon_videoparams_set_duration(
video_stream,
end_index - start_index + 1,
);
bridge::node::oaknode_footage_set_video_params(footage, 0, &video_stream);
}
}
@@ -355,7 +426,11 @@ impl ProjectImportTask {
// The probe footage was only created for comparison; remove it.
for probe in [previous_file, next_file] {
if !probe.ctx.is_null() {
let mut remove = unsafe { bridge::node::oaknode_command_create_remove_node(bridge::node::oaknode_footage_as_node(probe)) };
let mut remove = unsafe {
bridge::node::oaknode_command_create_remove_node(
bridge::node::oaknode_footage_as_node(probe),
)
};
if !remove.ctx.is_null() {
unsafe {
bridge::undo::oakundo_command_redo_now(remove);
@@ -483,7 +558,8 @@ fn basename_of(path: &str) -> String {
/// Two-stage read of the footage filename.
fn footage_filename(footage: CHandle) -> String {
let needed = unsafe { bridge::node::oaknode_footage_filename(footage, std::ptr::null_mut(), 0) };
let needed =
unsafe { bridge::node::oaknode_footage_filename(footage, std::ptr::null_mut(), 0) };
if needed <= 0 {
return String::new();
}
@@ -504,7 +580,12 @@ fn transform_sequence_filename(filename: &str, number: i64, digit_count: i32) ->
// extension; they are replaced by `number`.
let digits_start = dot.saturating_sub(width);
let prefix = &filename[..digits_start];
format!("{prefix}{:0width$}{}", number, &filename[dot..], width = width)
format!(
"{prefix}{:0width$}{}",
number,
&filename[dot..],
width = width
)
}
None => format!("{filename}{:0width$}", number, width = width),
}
+8 -2
View File
@@ -123,7 +123,10 @@ impl TaskBehavior for ProjectLoadBaseTask {
task.set_error("Failed to determine project version.");
}
OAKNODE_SERIALIZER_RESULT_FILE_ERROR => {
task.set_error(&format!("Failed to read file \"{}\" for reading.", self.filename));
task.set_error(&format!(
"Failed to read file \"{}\" for reading.",
self.filename
));
}
OAKNODE_SERIALIZER_RESULT_XML_ERROR => {
task.set_error(&format!(
@@ -166,5 +169,8 @@ impl TaskBehavior for ProjectLoadTask {
/// Read a NUL-terminated char buffer into a String (lossy).
pub(crate) fn buf_to_string(buf: &[i8]) -> String {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
unsafe { String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len)).into_owned() }
unsafe {
String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len))
.into_owned()
}
}
+69 -19
View File
@@ -128,7 +128,10 @@ impl TaskBehavior for LoadOTIOTask {
format!("Sequence {unnamed_sequence_count}")
};
unsafe {
bridge::node::oaknode_node_set_label(bridge::node::oaknode_sequence_as_node(sequence), cstr(&label));
bridge::node::oaknode_node_set_label(
bridge::node::oaknode_sequence_as_node(sequence),
cstr(&label),
);
}
// Set default params incase they aren't edited.
@@ -189,7 +192,9 @@ impl TaskBehavior for LoadOTIOTask {
unsafe {
bridge::node::oaknode_project_add_node(project, sequence_node);
}
let mut add_seq = unsafe { bridge::node::oaknode_command_create_folder_add_child(root_folder, sequence_node) };
let mut add_seq = unsafe {
bridge::node::oaknode_command_create_folder_add_child(root_folder, sequence_node)
};
if !add_seq.ctx.is_null() {
unsafe {
bridge::undo::oakundo_command_redo_now(add_seq);
@@ -239,9 +244,14 @@ impl TaskBehavior for LoadOTIOTask {
// Create a new track
let mut track_list = CHandle::null();
unsafe {
bridge::node::oaknode_sequence_get_track_list(*sequence, track_type, &mut track_list);
bridge::node::oaknode_sequence_get_track_list(
*sequence,
track_type,
&mut track_list,
);
}
let mut add_track = unsafe { bridge::timeline::oaktimeline_add_track_command(track_list) };
let mut add_track =
unsafe { bridge::timeline::oaktimeline_add_track_command(track_list) };
if !add_track.ctx.is_null() {
unsafe {
bridge::undo::oakundo_command_redo_now(add_track);
@@ -256,7 +266,11 @@ impl TaskBehavior for LoadOTIOTask {
}
if count > 0 {
unsafe {
bridge::node::oaknode_tracklist_get_track_at(track_list, count - 1, &mut track);
bridge::node::oaknode_tracklist_get_track_at(
track_list,
count - 1,
&mut track,
);
}
}
if track.ctx.is_null() {
@@ -279,7 +293,9 @@ impl TaskBehavior for LoadOTIOTask {
// Todo: Look into OTIO supported transitions and add
// them to Oak.
unsafe {
bridge::node::oaknode_block_transition_create(bridge::node::OAKNODE_TRANSITION_CROSS_DISSOLVE)
bridge::node::oaknode_block_transition_create(
bridge::node::OAKNODE_TRANSITION_CROSS_DISSOLVE,
)
}
}
other => {
@@ -394,10 +410,17 @@ impl TaskBehavior for LoadOTIOTask {
// Link footage
let footage_url = external.target_url().to_string();
let probed_item = if let Some(existing) = imported_footage.get(&footage_url) {
let probed_item = if let Some(existing) =
imported_footage.get(&footage_url)
{
*existing
} else {
let created = unsafe { bridge::node::oaknode_footage_create(project, cstr(&footage_url)) };
let created = unsafe {
bridge::node::oaknode_footage_create(
project,
cstr(&footage_url),
)
};
if !created.ctx.is_null() {
imported_footage.insert(footage_url.clone(), created);
@@ -422,7 +445,9 @@ impl TaskBehavior for LoadOTIOTask {
if !add_footage.ctx.is_null() {
unsafe {
bridge::undo::oakundo_command_redo_now(add_footage);
bridge::undo::oakundo_command_free(&mut add_footage);
bridge::undo::oakundo_command_free(
&mut add_footage,
);
}
}
}
@@ -447,23 +472,36 @@ impl TaskBehavior for LoadOTIOTask {
if track_type == bridge::node::OAKNODE_TRACK_TYPE_VIDEO {
let transform = unsafe {
bridge::node::oaknode_factory_create_from_id(cstr(bridge::node::OAKNODE_TYPE_TRANSFORM))
bridge::node::oaknode_factory_create_from_id(cstr(
bridge::node::OAKNODE_TYPE_TRANSFORM,
))
};
if !transform.ctx.is_null() {
unsafe {
bridge::node::oaknode_project_add_node(project, transform);
bridge::node::oaknode_project_add_node(
project, transform,
);
bridge::node::oaknode_node_connect(
bridge::node::oaknode_footage_as_node(probed_item),
transform,
cstr("tex_in"),
);
bridge::node::oaknode_node_connect(transform, block_node, cstr("buffer_in"));
bridge::node::oaknode_node_set_context_position(block_node, transform, -1.0, 0.0, 0);
bridge::node::oaknode_node_connect(
transform,
block_node,
cstr("buffer_in"),
);
bridge::node::oaknode_node_set_context_position(
block_node, transform, -1.0, 0.0, 0,
);
}
}
} else {
let volume =
unsafe { bridge::node::oaknode_factory_create_from_id(cstr(bridge::node::OAKNODE_TYPE_VOLUME)) };
let volume = unsafe {
bridge::node::oaknode_factory_create_from_id(cstr(
bridge::node::OAKNODE_TYPE_VOLUME,
))
};
if !volume.ctx.is_null() {
unsafe {
bridge::node::oaknode_project_add_node(project, volume);
@@ -472,8 +510,14 @@ impl TaskBehavior for LoadOTIOTask {
volume,
cstr("samples_in"),
);
bridge::node::oaknode_node_connect(volume, block_node, cstr("buffer_in"));
bridge::node::oaknode_node_set_context_position(block_node, volume, -1.0, 0.0, 0);
bridge::node::oaknode_node_connect(
volume,
block_node,
cstr("buffer_in"),
);
bridge::node::oaknode_node_set_context_position(
block_node, volume, -1.0, 0.0, 0,
);
}
}
}
@@ -511,7 +555,11 @@ unsafe fn set_own_context_position(node: CHandle) {
/// Format handling ends here — the caller builds the project from the
/// returned timelines regardless of the source format (C++ parity), so the
/// track/clip/footage code never forks.
fn parse_timelines(task: &mut Task, filename: &str, format: InterchangeFormat) -> Result<Vec<oakotio::Timeline>> {
fn parse_timelines(
task: &mut Task,
filename: &str,
format: InterchangeFormat,
) -> Result<Vec<oakotio::Timeline>> {
match format {
InterchangeFormat::OtioJson => {
let root = oakotio::from_json_file(filename).map_err(|e| {
@@ -530,7 +578,9 @@ fn parse_timelines(task: &mut Task, filename: &str, format: InterchangeFormat) -
Serializable::Timeline(timeline) => Ok(vec![timeline.clone()]),
_ => {
task.set_error("Unknown OpenTimelineIO root element");
Err(Error::Failed("Unknown OpenTimelineIO root element".to_string()))
Err(Error::Failed(
"Unknown OpenTimelineIO root element".to_string(),
))
}
}
}
+9 -3
View File
@@ -66,7 +66,9 @@ impl TaskBehavior for ProjectSaveTask {
if using_filename.is_empty() {
task.set_error("Project has no filename to save to.");
return Err(Error::Failed("Project has no filename to save to.".to_string()));
return Err(Error::Failed(
"Project has no filename to save to.".to_string(),
));
}
let mut code = OAKNODE_SERIALIZER_RESULT_FILE_ERROR;
@@ -89,7 +91,10 @@ impl TaskBehavior for ProjectSaveTask {
task.set_error("Failed to write XML data.");
}
OAKNODE_SERIALIZER_RESULT_FILE_ERROR => {
task.set_error(&format!("Failed to open file for writing: {}", buf_to_string(&details)));
task.set_error(&format!(
"Failed to open file for writing: {}",
buf_to_string(&details)
));
}
OAKNODE_SERIALIZER_RESULT_OVERWRITE_ERROR => {
task.set_error(&format!(
@@ -112,7 +117,8 @@ impl TaskBehavior for ProjectSaveTask {
/// Two-stage read of the project's own filename (empty when unset).
pub(crate) fn project_filename(project: CHandle) -> String {
let needed = unsafe { bridge::node::oaknode_project_filename(project, std::ptr::null_mut(), 0) };
let needed =
unsafe { bridge::node::oaknode_project_filename(project, std::ptr::null_mut(), 0) };
if needed <= 0 {
return String::new();
}
+105 -35
View File
@@ -29,8 +29,8 @@
use oakcore_rs::Rational;
use oakotio::{
Clip, Composable, ExternalReference, Gap, MediaReference, RationalTime, Serializable, SerializableCollection, TimeRange,
Timeline, Track, Transition,
Clip, Composable, ExternalReference, Gap, MediaReference, RationalTime, Serializable,
SerializableCollection, TimeRange, Timeline, Track, Transition,
};
use crate::bridge;
@@ -62,14 +62,17 @@ impl SaveOTIOTask {
///
/// CPP-PARITY: saveotio.cpp (SaveOTIOTask::serialize_timeline)
fn serialize_timeline(sequence: CHandle) -> Option<Timeline> {
let mut otio_timeline = Timeline::new(node_label_of(unsafe { bridge::node::oaknode_sequence_as_node(sequence) }));
let mut otio_timeline = Timeline::new(node_label_of(unsafe {
bridge::node::oaknode_sequence_as_node(sequence)
}));
let mut rate = 0.0f64;
{
let mut num = 0;
let mut den = 1;
let mut vp = CHandle::null();
if unsafe { bridge::node::oaknode_sequence_get_video_params(sequence, 0, &mut vp) } == 0 {
if unsafe { bridge::node::oaknode_sequence_get_video_params(sequence, 0, &mut vp) } == 0
{
unsafe {
bridge::common::oakcommon_videoparams_get_frame_rate(vp, &mut num, &mut den);
}
@@ -90,8 +93,16 @@ impl SaveOTIOTask {
let mut video_list = CHandle::null();
let mut audio_list = CHandle::null();
unsafe {
bridge::node::oaknode_sequence_get_track_list(sequence, bridge::node::OAKNODE_TRACK_TYPE_VIDEO, &mut video_list);
bridge::node::oaknode_sequence_get_track_list(sequence, bridge::node::OAKNODE_TRACK_TYPE_AUDIO, &mut audio_list);
bridge::node::oaknode_sequence_get_track_list(
sequence,
bridge::node::OAKNODE_TRACK_TYPE_VIDEO,
&mut video_list,
);
bridge::node::oaknode_sequence_get_track_list(
sequence,
bridge::node::OAKNODE_TRACK_TYPE_AUDIO,
&mut audio_list,
);
}
if !Self::serialize_track_list(video_list, &mut otio_timeline, rate)
@@ -107,7 +118,11 @@ impl SaveOTIOTask {
/// timeline. Each track is padded to the list's maximum track length.
///
/// CPP-PARITY: saveotio.cpp (SaveOTIOTask::serialize_track_list)
fn serialize_track_list(list: CHandle, otio_timeline: &mut Timeline, sequence_rate: f64) -> bool {
fn serialize_track_list(
list: CHandle,
otio_timeline: &mut Timeline,
sequence_rate: f64,
) -> bool {
if list.ctx.is_null() {
return true;
}
@@ -141,11 +156,14 @@ impl SaveOTIOTask {
continue;
}
let Some(otio_track) = Self::serialize_track(track, sequence_rate, max_track_length) else {
let Some(otio_track) = Self::serialize_track(track, sequence_rate, max_track_length)
else {
return false;
};
otio_timeline.tracks_mut().append_child(Composable::Track(otio_track));
otio_timeline
.tracks_mut()
.append_child(Composable::Track(otio_track));
}
true
@@ -156,7 +174,11 @@ impl SaveOTIOTask {
/// track is shorter than `max_track_length`.
///
/// CPP-PARITY: saveotio.cpp (SaveOTIOTask::serialize_track)
fn serialize_track(track: CHandle, sequence_rate: f64, max_track_length: Rational) -> Option<Track> {
fn serialize_track(
track: CHandle,
sequence_rate: f64,
max_track_length: Rational,
) -> Option<Track> {
let mut track_type = bridge::node::OAKNODE_TRACK_TYPE_NONE;
unsafe {
bridge::node::oaknode_track_get_type(track, &mut track_type);
@@ -193,7 +215,9 @@ impl SaveOTIOTask {
let otio_block: Option<Composable> = match kind {
bridge::node::OAKNODE_BLOCK_CLIP => {
let mut otio_clip = Clip::new(node_label_of(unsafe { bridge::node::oaknode_block_as_node(block) }));
let mut otio_clip = Clip::new(node_label_of(unsafe {
bridge::node::oaknode_block_as_node(block)
}));
otio_clip.set_source_range(TimeRange::new(
RationalTime::from_rational(block_in_of(block), sequence_rate),
@@ -202,10 +226,15 @@ impl SaveOTIOTask {
let mut media = CHandle::null();
unsafe {
bridge::node::oaknode_node_find_input_footage(bridge::node::oaknode_block_as_node(block), &mut media);
bridge::node::oaknode_node_find_input_footage(
bridge::node::oaknode_block_as_node(block),
&mut media,
);
}
if !media.ctx.is_null() {
let available_range = if track_type == bridge::node::OAKNODE_TRACK_TYPE_VIDEO {
let available_range = if track_type
== bridge::node::OAKNODE_TRACK_TYPE_VIDEO
{
// OTIO ExternalReference uses the source clips
// frame rate (or sample rate) as opposed to the
// sequences rate.
@@ -214,16 +243,23 @@ impl SaveOTIOTask {
let mut num = 0;
let mut den = 1;
let mut vp = CHandle::null();
if unsafe { bridge::node::oaknode_footage_get_video_params(media, 0, &mut vp) } == 0 {
if unsafe {
bridge::node::oaknode_footage_get_video_params(media, 0, &mut vp)
} == 0
{
unsafe {
bridge::common::oakcommon_videoparams_get_frame_rate(vp, &mut num, &mut den);
bridge::common::oakcommon_videoparams_get_frame_rate(
vp, &mut num, &mut den,
);
}
if den != 0 {
source_frame_rate = num as f64 / den as f64;
}
let mut dur = 0i64;
unsafe {
bridge::common::oakcommon_videoparams_get_duration(vp, &mut dur);
bridge::common::oakcommon_videoparams_get_duration(
vp, &mut dur,
);
}
duration = dur as f64;
if !vp.ctx.is_null() {
@@ -237,15 +273,17 @@ impl SaveOTIOTask {
RationalTime::new(duration, source_frame_rate),
)
} else {
TimeRange::new(RationalTime::new(0.0, 48000.0), RationalTime::new(0.0, 48000.0))
TimeRange::new(
RationalTime::new(0.0, 48000.0),
RationalTime::new(0.0, 48000.0),
)
};
let media_url = footage_filename(media);
if !media_url.is_empty() {
otio_clip.set_media_reference(MediaReference::ExternalReference(ExternalReference::new(
media_url,
Some(available_range),
)));
otio_clip.set_media_reference(MediaReference::ExternalReference(
ExternalReference::new(media_url, Some(available_range)),
));
}
}
@@ -259,12 +297,20 @@ impl SaveOTIOTask {
node_label_of(unsafe { bridge::node::oaknode_block_as_node(block) }),
))),
bridge::node::OAKNODE_BLOCK_TRANSITION => {
let mut otio_transition = Transition::new(node_label_of(unsafe { bridge::node::oaknode_block_as_node(block) }));
let mut otio_transition = Transition::new(node_label_of(unsafe {
bridge::node::oaknode_block_as_node(block)
}));
let (n, d) = transition_offset_of(block, true);
otio_transition.set_in_offset(RationalTime::from_rational(Rational::new(n as i64, d as i64), 24.0));
otio_transition.set_in_offset(RationalTime::from_rational(
Rational::new(n as i64, d as i64),
24.0,
));
let (n, d) = transition_offset_of(block, false);
otio_transition.set_out_offset(RationalTime::from_rational(Rational::new(n as i64, d as i64), 24.0));
otio_transition.set_out_offset(RationalTime::from_rational(
Rational::new(n as i64, d as i64),
24.0,
));
Some(Composable::Transition(otio_transition))
}
@@ -287,7 +333,10 @@ impl SaveOTIOTask {
if duration_seconds < max_track_length.to_f64() {
let time_left = max_track_length.to_f64() - duration_seconds;
let gap = Gap::new(TimeRange::new(duration, RationalTime::new(time_left, 1.0)), "");
let gap = Gap::new(
TimeRange::new(duration, RationalTime::new(time_left, 1.0)),
"",
);
otio_track.append_child(Composable::Gap(gap));
}
@@ -318,7 +367,9 @@ impl TaskBehavior for SaveOTIOTask {
let root = unsafe { bridge::node::oaknode_project_root(self.project) };
if root.ctx.is_null() {
task.set_error("Project contains no sequences to export.");
return Err(Error::Failed("Project contains no sequences to export.".to_string()));
return Err(Error::Failed(
"Project contains no sequences to export.".to_string(),
));
}
let mut sequences: Vec<CHandle> = Vec::new();
@@ -337,7 +388,9 @@ impl TaskBehavior for SaveOTIOTask {
if sequences.is_empty() {
task.set_error("Project contains no sequences to export.");
return Err(Error::Failed("Project contains no sequences to export.".to_string()));
return Err(Error::Failed(
"Project contains no sequences to export.".to_string(),
));
}
let mut serialized: Vec<Timeline> = Vec::with_capacity(sequences.len());
@@ -361,7 +414,9 @@ impl TaskBehavior for SaveOTIOTask {
let result: std::result::Result<(), String> = match format {
InterchangeFormat::OtioJson => {
if serialized.len() == 1 {
serialized[0].to_json_file(&self.filename).map_err(|e| e.to_string())
serialized[0]
.to_json_file(&self.filename)
.map_err(|e| e.to_string())
} else {
// Serialize all into a SerializableCollection.
let collection = SerializableCollection::new(
@@ -373,13 +428,20 @@ impl TaskBehavior for SaveOTIOTask {
.map_err(|e| e.to_string())
}
}
InterchangeFormat::Fcpxml => oakotio::to_fcpxml_file(&serialized, &self.filename).map_err(|e| e.to_string()),
InterchangeFormat::Fcpxml => {
oakotio::to_fcpxml_file(&serialized, &self.filename).map_err(|e| e.to_string())
}
};
result.map_err(|e| {
let (label, what) = match format {
InterchangeFormat::OtioJson => ("Failed to save OpenTimelineIO to file", "Failed to save OpenTimelineIO"),
InterchangeFormat::Fcpxml => ("Failed to save FCPXML to file", "Failed to save FCPXML"),
InterchangeFormat::OtioJson => (
"Failed to save OpenTimelineIO to file",
"Failed to save OpenTimelineIO",
),
InterchangeFormat::Fcpxml => {
("Failed to save FCPXML to file", "Failed to save FCPXML")
}
};
task.set_error(&format!("{label} \"{}\": {e}", self.filename));
Error::Failed(what.to_string())
@@ -461,7 +523,8 @@ fn transition_offset_of(block: CHandle, in_offset: bool) -> (i32, i32) {
/// Two-stage read of a footage's filename (empty when unset).
fn footage_filename(footage: CHandle) -> String {
let needed = unsafe { bridge::node::oaknode_footage_filename(footage, std::ptr::null_mut(), 0) };
let needed =
unsafe { bridge::node::oaknode_footage_filename(footage, std::ptr::null_mut(), 0) };
if needed <= 0 {
return String::new();
}
@@ -478,9 +541,16 @@ fn footage_filename(footage: CHandle) -> String {
fn track_duration(track: &Track) -> RationalTime {
let mut acc: Option<RationalTime> = None;
for child in track.children() {
let duration = match child.as_clip().and_then(|c| c.source_range()).map(|r| r.duration())
.or_else(|| child.as_gap().and_then(|g| g.source_range()).map(|r| r.duration()))
{
let duration = match child
.as_clip()
.and_then(|c| c.source_range())
.map(|r| r.duration())
.or_else(|| {
child
.as_gap()
.and_then(|g| g.source_range())
.map(|r| r.duration())
}) {
Some(d) => d,
// Transitions occupy no time.
None => RationalTime::new(0.0, 1.0),
+34 -7
View File
@@ -209,7 +209,11 @@ impl TaskBehavior for ProxyTask {
fn run(&mut self, task: &mut Task) -> Result<()> {
let mut ffmpeg_buf = [0i8; 1024];
let found = unsafe {
bridge::codec::oakcodec_proxy_find_ffmpeg(std::ptr::null(), ffmpeg_buf.as_mut_ptr(), ffmpeg_buf.len() as i32)
bridge::codec::oakcodec_proxy_find_ffmpeg(
std::ptr::null(),
ffmpeg_buf.as_mut_ptr(),
ffmpeg_buf.len() as i32,
)
};
if found <= 0 {
task.set_error(
@@ -224,7 +228,9 @@ impl TaskBehavior for ProxyTask {
if !parent.as_os_str().is_empty() && !parent.exists() {
if std::fs::create_dir_all(parent).is_err() {
task.set_error("Failed to create proxy output directory");
return Err(Error::Failed("Failed to create proxy output directory".to_string()));
return Err(Error::Failed(
"Failed to create proxy output directory".to_string(),
));
}
}
}
@@ -233,13 +239,21 @@ impl TaskBehavior for ProxyTask {
let working_filename = format!("{}.working.mp4", self.output_filename);
let _ = std::fs::remove_file(&working_filename);
let args = Self::build_arguments(&self.source_filename, self.stream_index, &self.params, &working_filename);
let args = Self::build_arguments(
&self.source_filename,
self.stream_index,
&self.params,
&working_filename,
);
// Probe the source duration for progress scaling (0 when unknown).
self.duration_seconds = probe_source_duration_seconds(&ffmpeg_path, &self.source_filename);
let mut command = Command::new(&ffmpeg_path);
command.args(&args).stdout(Stdio::piped()).stderr(Stdio::piped());
command
.args(&args)
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = match command.spawn() {
Ok(child) => child,
Err(_) => {
@@ -291,7 +305,9 @@ impl TaskBehavior for ProxyTask {
if !std::path::Path::new(&working_filename).exists() {
task.set_error("ffmpeg finished but proxy file was not created");
return Err(Error::Failed("ffmpeg finished but proxy file was not created".to_string()));
return Err(Error::Failed(
"ffmpeg finished but proxy file was not created".to_string(),
));
}
if std::fs::rename(&working_filename, &self.output_filename).is_err() {
@@ -307,7 +323,10 @@ impl TaskBehavior for ProxyTask {
/// Read a NUL-terminated C char buffer into a String.
fn buf_to_string(buf: &[i8]) -> String {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
unsafe { String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len)).into_owned() }
unsafe {
String::from_utf8_lossy(std::slice::from_raw_parts(buf.as_ptr() as *const u8, len))
.into_owned()
}
}
/// Probe the source duration via `ffprobe` next to ffmpeg; 0.0 when
@@ -318,7 +337,15 @@ fn probe_source_duration_seconds(ffmpeg_path: &str, source_filename: &str) -> f6
return 0.0;
}
let output = Command::new(&ffprobe)
.args(["-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", source_filename])
.args([
"-v",
"error",
"-show_entries",
"format=duration",
"-of",
"default=noprint_wrappers=1:nokey=1",
source_filename,
])
.output();
match output {
Ok(out) if out.status.success() => {
+38 -11
View File
@@ -159,7 +159,10 @@ impl RenderTask {
export_range: TimeRange::new(Rational::new(0, 1), Rational::new(0, 1)),
native_progress_signalling: true,
total_frames: 0,
max_inflight: std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1).max(1),
max_inflight: std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1)
.max(1),
}
}
@@ -236,7 +239,9 @@ impl RenderTask {
);
}
if output_node.ctx.is_null() {
return Err(Error::Failed("No node connected to the viewer output".to_string()));
return Err(Error::Failed(
"No node connected to the viewer output".to_string(),
));
}
let audio_params_ptr = if self.audio_params.ctx.is_null() {
@@ -282,7 +287,9 @@ impl RenderTask {
bridge::node::oaknode_node_free(&mut output_node);
}
if ticket.ctx.is_null() {
return Err(Error::Failed("Failed to start frame render ticket".to_string()));
return Err(Error::Failed(
"Failed to start frame render ticket".to_string(),
));
}
Ok(ticket)
}
@@ -303,7 +310,9 @@ impl RenderTask {
);
}
if output_node.ctx.is_null() {
return Err(Error::Failed("No node connected to the viewer samples input".to_string()));
return Err(Error::Failed(
"No node connected to the viewer samples input".to_string(),
));
}
let audio_params_ptr = if self.audio_params.ctx.is_null() {
@@ -328,7 +337,9 @@ impl RenderTask {
bridge::node::oaknode_node_free(&mut output_node);
}
if ticket.ctx.is_null() {
return Err(Error::Failed("Failed to start audio render ticket".to_string()));
return Err(Error::Failed(
"Failed to start audio render ticket".to_string(),
));
}
Ok(ticket)
}
@@ -439,7 +450,11 @@ impl RenderTask {
t = t + timebase;
}
self.total_frames = frame_times.len() as i64;
let total_length = if frame_times.is_empty() { 1.0 } else { frame_times.len() as f64 };
let total_length = if frame_times.is_empty() {
1.0
} else {
frame_times.len() as f64
};
// Delivery order: the audio range first (mirrors the C++ queue
// order), then every frame in ascending timestamp order. The reorder
@@ -460,7 +475,10 @@ impl RenderTask {
}
let mut slot_by_key: HashMap<(i32, i64, i64), usize> = HashMap::with_capacity(slots.len());
for (i, slot) in slots.iter().enumerate() {
slot_by_key.insert((slot.kind, slot.time.numerator(), slot.time.denominator()), i);
slot_by_key.insert(
(slot.kind, slot.time.numerator(), slot.time.denominator()),
i,
);
}
let total_slots = slots.len();
@@ -584,16 +602,25 @@ impl RenderTask {
// Wait for the next completion (a cancellation or a hook error
// aborts the wait; in-flight tickets then finish, waking us).
let mut guard = dispatch_ref.finished.lock().unwrap_or_else(|e| e.into_inner());
let mut guard = dispatch_ref
.finished
.lock()
.unwrap_or_else(|e| e.into_inner());
while guard.is_empty()
&& dispatch_ref.running.load(Ordering::SeqCst) > 0
&& !task.is_cancelled()
{
guard = dispatch_ref.cv.wait(guard).unwrap_or_else(|e| e.into_inner());
guard = dispatch_ref
.cv
.wait(guard)
.unwrap_or_else(|e| e.into_inner());
}
drop(guard);
if dispatch_ref.finished.lock().unwrap_or_else(|e| e.into_inner()).is_empty()
&& dispatch_ref.running.load(Ordering::SeqCst) == 0
if dispatch_ref
.finished
.lock()
.unwrap_or_else(|e| e.into_inner())
.is_empty() && dispatch_ref.running.load(Ordering::SeqCst) == 0
{
// Every ticket finished and its queue copy was consumed.
break;
+2 -1
View File
@@ -196,7 +196,8 @@ impl Task {
self.done.1.notify_all();
}
if let Some(s) = &self.subscriber {
s.finished_value.store(if succeeded { 1 } else { 0 }, Ordering::SeqCst);
s.finished_value
.store(if succeeded { 1 } else { 0 }, Ordering::SeqCst);
}
self.emit_event(TaskEvent::Finished);