#![allow(unsafe_code)]
#![deny(unsafe_op_in_unsafe_fn)]
use crate::include::common::validate::validate_input;
use crate::include::dav1d::common::Dav1dDataProps;
use crate::include::dav1d::common::Rav1dDataProps;
use crate::include::dav1d::data::Dav1dData;
use crate::include::dav1d::dav1d::Dav1dContext;
use crate::include::dav1d::dav1d::Dav1dEventFlags;
use crate::include::dav1d::dav1d::Dav1dSettings;
use crate::include::dav1d::headers::Dav1dSequenceHeader;
use crate::include::dav1d::picture::Dav1dPicture;
use crate::include::dav1d::picture::Rav1dPicture;
use crate::src::c_arc::RawArc;
use crate::src::c_box::FnFree;
use crate::src::error::Dav1dResult;
use crate::src::error::Rav1dError::EINVAL;
use crate::src::error::Rav1dResult;
use crate::src::lib::DAV1D_API_VERSION_MAJOR;
use crate::src::lib::DAV1D_API_VERSION_MINOR;
use crate::src::lib::DAV1D_API_VERSION_PATCH;
use crate::src::lib::DAV1D_VERSION;
use crate::src::lib::rav1d_apply_grain;
use crate::src::lib::rav1d_close;
use crate::src::lib::rav1d_flush;
use crate::src::lib::rav1d_get_frame_delay;
use crate::src::lib::rav1d_get_picture;
use crate::src::lib::rav1d_open;
use crate::src::lib::rav1d_send_data;
use crate::src::obu::rav1d_parse_sequence_header;
use crate::src::send_sync_non_null::SendSyncNonNull;
use std::ffi::c_char;
use std::ffi::c_uint;
use std::ffi::c_void;
use std::mem;
use std::ptr;
use std::ptr::NonNull;
use std::slice;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use to_method::To as _;
use crate::include::dav1d::data::Rav1dData;
use crate::include::dav1d::dav1d::Rav1dSettings;
use crate::src::internal::Rav1dContextTaskType;
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_version"))]
#[cfg_attr(not(feature = "dav1d-compat"), unsafe(export_name = "rav1d_version"))]
#[cold]
pub extern "C" fn dav1d_version() -> *const c_char {
DAV1D_VERSION.as_ptr()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_version_api"))]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_version_api")
)]
#[cold]
pub extern "C" fn dav1d_version_api() -> c_uint {
u32::from_be_bytes([
0,
DAV1D_API_VERSION_MAJOR,
DAV1D_API_VERSION_MINOR,
DAV1D_API_VERSION_PATCH,
])
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_default_settings")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_default_settings")
)]
#[cold]
pub unsafe extern "C" fn dav1d_default_settings(s: NonNull<Dav1dSettings>) {
let settings = Rav1dSettings::default().into();
unsafe { s.as_ptr().write(settings) };
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_get_frame_delay")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_get_frame_delay")
)]
#[cold]
pub unsafe extern "C" fn dav1d_get_frame_delay(s: Option<NonNull<Dav1dSettings>>) -> Dav1dResult {
(|| {
let s = validate_input!(s.ok_or(EINVAL))?;
let s = unsafe { s.as_ptr().read() };
let s = s.try_into()?;
rav1d_get_frame_delay(&s).map(|frame_delay| frame_delay as c_uint)
})()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_open"))]
#[cfg_attr(not(feature = "dav1d-compat"), unsafe(export_name = "rav1d_open"))]
#[cold]
pub unsafe extern "C" fn dav1d_open(
c_out: Option<NonNull<Option<Dav1dContext>>>,
s: Option<NonNull<Dav1dSettings>>,
) -> Dav1dResult {
(|| {
let mut c_out = validate_input!(c_out.ok_or(EINVAL))?;
let s = validate_input!(s.ok_or(EINVAL))?;
let c_out = unsafe { c_out.as_mut() };
let s = unsafe { s.as_ptr().read() };
let s = s.try_into()?;
let (c, handles) = rav1d_open(&s).inspect_err(|_| {
*c_out = None;
})?;
if !handles.is_empty() {
let ctx_clone = Arc::clone(&c);
thread::spawn(move || {
loop {
let all_died = ctx_clone.tc.iter().all(|tc| {
matches!(tc.task, Rav1dContextTaskType::Single(_))
|| tc.thread_data.die.get()
});
if all_died {
break;
}
thread::sleep(Duration::from_millis(10));
}
for handle in handles {
let _ = handle.join();
}
});
}
*c_out = Some(RawArc::from_arc(c));
Ok(())
})()
.into()
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_parse_sequence_header")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_parse_sequence_header")
)]
pub unsafe extern "C" fn dav1d_parse_sequence_header(
out: Option<NonNull<Dav1dSequenceHeader>>,
ptr: Option<NonNull<u8>>,
sz: usize,
) -> Dav1dResult {
(|| {
let out = validate_input!(out.ok_or(EINVAL))?;
let ptr = validate_input!(ptr.ok_or(EINVAL))?;
validate_input!((sz > 0 && sz <= usize::MAX / 2, EINVAL))?;
let data = unsafe { slice::from_raw_parts(ptr.as_ptr(), sz) };
let seq_hdr = rav1d_parse_sequence_header(data)?.dav1d;
unsafe { out.as_ptr().write(seq_hdr) };
Ok(())
})()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_send_data"))]
#[cfg_attr(not(feature = "dav1d-compat"), unsafe(export_name = "rav1d_send_data"))]
pub unsafe extern "C" fn dav1d_send_data(
c: Option<Dav1dContext>,
r#in: Option<NonNull<Dav1dData>>,
) -> Dav1dResult {
(|| {
let c = validate_input!(c.ok_or(EINVAL))?;
let r#in = validate_input!(r#in.ok_or(EINVAL))?;
let c = unsafe { c.as_ref() };
let in_c = unsafe { r#in.as_ptr().read() };
let mut in_rust = in_c.into();
let result = rav1d_send_data(c, &mut in_rust);
let in_c = in_rust.into();
unsafe { r#in.as_ptr().write(in_c) };
result
})()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_get_picture"))]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_get_picture")
)]
pub unsafe extern "C" fn dav1d_get_picture(
c: Option<Dav1dContext>,
out: Option<NonNull<Dav1dPicture>>,
) -> Dav1dResult {
(|| {
let c = validate_input!(c.ok_or(EINVAL))?;
let out = validate_input!(out.ok_or(EINVAL))?;
let c = unsafe { c.as_ref() };
let mut out_rust = Default::default(); let result = rav1d_get_picture(c, &mut out_rust);
let out_c = out_rust.into();
unsafe { out.as_ptr().write(out_c) };
result
})()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_apply_grain"))]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_apply_grain")
)]
pub unsafe extern "C" fn dav1d_apply_grain(
c: Option<Dav1dContext>,
out: Option<NonNull<Dav1dPicture>>,
r#in: Option<NonNull<Dav1dPicture>>,
) -> Dav1dResult {
(|| {
let c = validate_input!(c.ok_or(EINVAL))?;
let out = validate_input!(out.ok_or(EINVAL))?;
let r#in = validate_input!(r#in.ok_or(EINVAL))?;
let c = unsafe { c.as_ref() };
let in_c = unsafe { r#in.as_ptr().read() };
let mut out_rust = Default::default(); let in_rust = in_c.into();
let result = rav1d_apply_grain(c, &mut out_rust, &in_rust);
let out_c = out_rust.into();
unsafe { out.as_ptr().write(out_c) };
result
})()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_flush"))]
#[cfg_attr(not(feature = "dav1d-compat"), unsafe(export_name = "rav1d_flush"))]
pub unsafe extern "C" fn dav1d_flush(c: Dav1dContext) {
let c = unsafe { c.as_ref() };
rav1d_flush(c)
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_close"))]
#[cfg_attr(not(feature = "dav1d-compat"), unsafe(export_name = "rav1d_close"))]
#[cold]
pub unsafe extern "C" fn dav1d_close(c_out: Option<NonNull<Option<Dav1dContext>>>) {
let Ok(mut c_out) = validate_input!(c_out.ok_or(())) else {
return;
};
let c_out = unsafe { c_out.as_mut() };
mem::take(c_out).map(|c| {
let c = unsafe { c.into_arc() };
rav1d_close(c);
});
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_get_event_flags")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_get_event_flags")
)]
pub unsafe extern "C" fn dav1d_get_event_flags(
c: Option<Dav1dContext>,
flags: Option<NonNull<Dav1dEventFlags>>,
) -> Dav1dResult {
(|| {
let c = validate_input!(c.ok_or(EINVAL))?;
let flags = validate_input!(flags.ok_or(EINVAL))?;
let c = unsafe { c.as_ref() };
let state = &mut *c.state.try_lock().unwrap();
let flags_rust = mem::take(&mut state.event_flags);
let flags_c = flags_rust.into();
unsafe { flags.as_ptr().write(flags_c) };
Ok(())
})()
.into()
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_get_decode_error_data_props")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_get_decode_error_data_props")
)]
pub unsafe extern "C" fn dav1d_get_decode_error_data_props(
c: Option<Dav1dContext>,
out: Option<NonNull<Dav1dDataProps>>,
) -> Dav1dResult {
(|| {
let c = validate_input!(c.ok_or(EINVAL))?;
let out = validate_input!(out.ok_or(EINVAL))?;
let c = unsafe { c.as_ref() };
let state = &mut *c.state.try_lock().unwrap();
let props_rust = mem::take(&mut state.cached_error_props);
let props_c = props_rust.into();
unsafe { out.as_ptr().write(props_c) };
Ok(())
})()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_picture_unref"))]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_picture_unref")
)]
pub unsafe extern "C" fn dav1d_picture_unref(p: Option<NonNull<Dav1dPicture>>) {
let Ok(p) = validate_input!(p.ok_or(())) else {
return;
};
let p_c = unsafe { p.as_ptr().read() };
let mut p_rust = p_c.to::<Rav1dPicture>();
let _ = mem::take(&mut p_rust);
let p_c = p_rust.into();
unsafe { p.as_ptr().write(p_c) };
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_data_create"))]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_data_create")
)]
pub unsafe extern "C" fn dav1d_data_create(buf: Option<NonNull<Dav1dData>>, sz: usize) -> *mut u8 {
|| -> Rav1dResult<*mut u8> {
let buf = validate_input!(buf.ok_or(EINVAL))?;
validate_input!((sz <= usize::MAX / 2, EINVAL))?;
let data = Rav1dData::create(sz)?;
let data = data.to::<Dav1dData>();
let ptr = data
.data
.map(|ptr| ptr.as_ptr())
.unwrap_or_else(ptr::null_mut);
unsafe { buf.as_ptr().write(data) };
Ok(ptr)
}()
.unwrap_or_else(|_| ptr::null_mut())
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_data_wrap"))]
#[cfg_attr(not(feature = "dav1d-compat"), unsafe(export_name = "rav1d_data_wrap"))]
pub unsafe extern "C" fn dav1d_data_wrap(
buf: Option<NonNull<Dav1dData>>,
ptr: Option<NonNull<u8>>,
sz: usize,
free_callback: Option<FnFree>,
user_data: Option<SendSyncNonNull<c_void>>,
) -> Dav1dResult {
|| -> Rav1dResult {
let buf = validate_input!(buf.ok_or(EINVAL))?;
let ptr = validate_input!(ptr.ok_or(EINVAL))?;
validate_input!((sz <= usize::MAX / 2, EINVAL))?;
let data = unsafe { slice::from_raw_parts(ptr.as_ptr(), sz) };
let data = unsafe { Rav1dData::wrap(data.into(), free_callback, user_data) }?;
let data_c = data.into();
unsafe { buf.as_ptr().write(data_c) };
Ok(())
}()
.into()
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_data_wrap_user_data")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_data_wrap_user_data")
)]
pub unsafe extern "C" fn dav1d_data_wrap_user_data(
buf: Option<NonNull<Dav1dData>>,
user_data: Option<NonNull<u8>>,
free_callback: Option<FnFree>,
cookie: Option<SendSyncNonNull<c_void>>,
) -> Dav1dResult {
|| -> Rav1dResult {
let buf = validate_input!(buf.ok_or(EINVAL))?;
let user_data = validate_input!(user_data.ok_or(EINVAL))?;
let data_c = unsafe { buf.as_ptr().read() };
let mut data = data_c.to::<Rav1dData>();
unsafe { data.wrap_user_data(user_data, free_callback, cookie) }?;
let data_c = data.into();
unsafe { buf.as_ptr().write(data_c) };
Ok(())
}()
.into()
}
#[cfg_attr(feature = "dav1d-compat", unsafe(export_name = "dav1d_data_unref"))]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_data_unref")
)]
pub unsafe extern "C" fn dav1d_data_unref(buf: Option<NonNull<Dav1dData>>) {
let buf = validate_input!(buf.ok_or(()));
let Ok(mut buf) = buf else { return };
let buf = unsafe { buf.as_mut() };
let _ = mem::take(buf).to::<Rav1dData>();
}
#[cfg_attr(
feature = "dav1d-compat",
unsafe(export_name = "dav1d_data_props_unref")
)]
#[cfg_attr(
not(feature = "dav1d-compat"),
unsafe(export_name = "rav1d_data_props_unref")
)]
pub unsafe extern "C" fn dav1d_data_props_unref(props: Option<NonNull<Dav1dDataProps>>) {
let props = validate_input!(props.ok_or(()));
let Ok(mut props) = props else { return };
let props = unsafe { props.as_mut() };
let _ = mem::take(props).to::<Rav1dDataProps>();
}