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:
@@ -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) }
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}));
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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>),
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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() => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user