From 3d6a8285709eef35415dd3eee90e5ac7a6d95807 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 6 Jul 2025 16:00:11 +0100 Subject: [PATCH 01/72] Implement Rust API --- Cargo.lock | 83 ++++ Cargo.toml | 2 + src/include/dav1d/common.rs | 2 +- src/include/dav1d/dav1d.rs | 4 +- src/include/dav1d/headers.rs | 2 +- src/include/dav1d/picture.rs | 8 +- src/lib.rs | 2 + src/rust_api.rs | 762 +++++++++++++++++++++++++++++++++++ 8 files changed, 857 insertions(+), 8 deletions(-) create mode 100644 src/rust_api.rs diff --git a/Cargo.lock b/Cargo.lock index 8a42a1322..5c04519e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,18 +34,43 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "av-data" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca67ba5d317924c02180c576157afd54babe48a76ebc66ce6d34bb8ba08308e" +dependencies = [ + "byte-slice-cast", + "bytes", + "num-derive", + "num-rational", + "num-traits", +] + [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + [[package]] name = "cc" version = "1.2.23" @@ -114,6 +139,56 @@ dependencies = [ "jobserver", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -173,6 +248,7 @@ version = "1.1.0" dependencies = [ "assert_matches", "atomig", + "av-data", "bitflags", "cc", "cfg-if", @@ -181,6 +257,7 @@ dependencies = [ "parking_lot", "paste", "raw-cpuid", + "static_assertions", "strum", "to_method", "zerocopy", @@ -239,6 +316,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strum" version = "0.27.1" diff --git a/Cargo.toml b/Cargo.toml index 443f2b67f..abb3b887d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ crate-type = ["staticlib", "rlib"] [dependencies] assert_matches = "1.5.0" atomig = { version = "0.4.0", features = ["derive"] } +av-data = "0.4.2" bitflags = "2.4.0" cfg-if = "1.0.0" libc = "0.2" @@ -26,6 +27,7 @@ parking_lot = "0.12.2" paste = "1.0.14" raw-cpuid = "11.0.1" strum = { version = "0.27", features = ["derive"] } +static_assertions = "1.0.0" to_method = "1.1.0" zerocopy = { version = "0.7.32", features = ["derive"] } diff --git a/src/include/dav1d/common.rs b/src/include/dav1d/common.rs index 314733100..10490c3b1 100644 --- a/src/include/dav1d/common.rs +++ b/src/include/dav1d/common.rs @@ -42,7 +42,7 @@ pub struct Dav1dDataProps { #[derive(Clone)] #[repr(C)] -pub(crate) struct Rav1dDataProps { +pub struct Rav1dDataProps { pub timestamp: i64, pub duration: i64, pub offset: libc::off_t, diff --git a/src/include/dav1d/dav1d.rs b/src/include/dav1d/dav1d.rs index 74505a786..14a20432b 100644 --- a/src/include/dav1d/dav1d.rs +++ b/src/include/dav1d/dav1d.rs @@ -30,7 +30,7 @@ pub const DAV1D_INLOOPFILTER_RESTORATION: Dav1dInloopFilterType = bitflags! { #[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] - pub(crate) struct Rav1dInloopFilterType: u8 { + pub struct Rav1dInloopFilterType: u8 { const DEBLOCK = 1 << 1; const CDEF = 1 << 2; const RESTORATION = 1 << 3; @@ -60,7 +60,7 @@ pub const DAV1D_DECODEFRAMETYPE_KEY: Dav1dDecodeFrameType = Rav1dDecodeFrameType::Key as Dav1dDecodeFrameType; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromRepr, Default)] -pub(crate) enum Rav1dDecodeFrameType { +pub enum Rav1dDecodeFrameType { /// decode and return all frames #[default] All = 0, diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 889c164a9..745ebbe72 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -379,7 +379,7 @@ impl From for Dav1dWarpedMotionParams { // TODO(kkysen) Eventually the [`impl Default`] might not be needed. /// Pixel layout of a frame. -#[derive(Clone, Copy, PartialEq, Eq, EnumCount, FromRepr, Default)] +#[derive(Clone, Copy, PartialEq, Eq, EnumCount, FromRepr, Default, Debug)] pub enum Rav1dPixelLayout { /// Monochrome. #[default] diff --git a/src/include/dav1d/picture.rs b/src/include/dav1d/picture.rs index 09c110c7a..3d794bef9 100644 --- a/src/include/dav1d/picture.rs +++ b/src/include/dav1d/picture.rs @@ -32,7 +32,7 @@ use crate::with_offset::WithOffset; // Number of bytes to align AND pad picture memory buffers by, so that SIMD // implementations can over-read by a few bytes, and use aligned read/write // instructions. -pub(crate) const RAV1D_PICTURE_ALIGNMENT: usize = 64; +pub const RAV1D_PICTURE_ALIGNMENT: usize = 64; pub const DAV1D_PICTURE_ALIGNMENT: usize = RAV1D_PICTURE_ALIGNMENT; #[derive(Default)] @@ -47,7 +47,7 @@ pub struct Dav1dPictureParameters { // TODO(kkysen) Eventually the [`impl Default`] might not be needed. #[derive(Clone, Default)] #[repr(C)] -pub(crate) struct Rav1dPictureParameters { +pub struct Rav1dPictureParameters { pub w: c_int, pub h: c_int, pub layout: Rav1dPixelLayout, @@ -404,7 +404,7 @@ impl Drop for Rav1dPictureData { // on [`Rav1dPictureParameters`] and [`Rav1dPixelLayout`]. #[derive(Clone, Default)] #[repr(C)] -pub(crate) struct Rav1dPicture { +pub struct Rav1dPicture { pub seq_hdr: Option>>, pub frame_hdr: Option>>, pub data: Option>, @@ -657,7 +657,7 @@ pub struct Dav1dPicAllocator { #[derive(Clone)] #[repr(C)] -pub(crate) struct Rav1dPicAllocator { +pub struct Rav1dPicAllocator { /// See [`Dav1dPicAllocator::cookie`]. /// /// # Safety diff --git a/src/lib.rs b/src/lib.rs index f7b4083a5..98d750c29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,6 +139,7 @@ mod pool; mod qm; mod recon; mod refmvs; +pub mod rust_api; mod scan; mod tables; mod thread_task; @@ -152,6 +153,7 @@ use std::sync::{Arc, Once}; use std::{cmp, mem, ptr, slice, thread}; use parking_lot::Mutex; +pub use rust_api::*; use to_method::To as _; use crate::c_arc::RawArc; diff --git a/src/rust_api.rs b/src/rust_api.rs new file mode 100644 index 000000000..ee44dde8d --- /dev/null +++ b/src/rust_api.rs @@ -0,0 +1,762 @@ +#![allow(non_upper_case_globals)] +#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))] +#![cfg_attr( + any(target_arch = "riscv32", target_arch = "riscv64"), + feature(stdarch_riscv_feature_detection) +)] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(clippy::all)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::missing_safety_doc)] + +#[cfg(not(any(feature = "bitdepth_8", feature = "bitdepth_16")))] +compile_error!("No bitdepths enabled. Enable one or more of the following features: `bitdepth_8`, `bitdepth_16`"); + +// --------------------------------------------------------------------------------------- + +/// Public Rust API. +/// +/// This is more or less the same API as , +/// and is indeed a fork of that work. +pub mod dav1d { + // This whole module was originally copied from https://github.com/rust-av/dav1d-rs/ + // (specifically https://github.com/rust-av/dav1d-rs/blob/94b1deaa1e25bf29c77bb5cc8a08ddaf7663eede/src/lib.rs) + // with some modifications. + // `dav1d-rs` is under the MIT license, replicated here: + + // MIT License + // + // Copyright (c) 2018 Luca Barbato + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + + // The code below provides a safe API around the rav1d C FFI layer. + + use std::convert::Infallible; + use std::ffi::c_void; + use std::fmt::{Debug, Display, Formatter}; + use std::ops::Deref; + use std::ptr::NonNull; + use std::sync::Arc; + use std::{fmt, mem}; + + pub use av_data::pixel; + use rav1d::error::Rav1dError; + use rav1d::include::dav1d::data::*; + use rav1d::include::dav1d::dav1d::*; + use rav1d::include::dav1d::headers::*; + use rav1d::include::dav1d::picture::*; + + pub use crate::include::dav1d::dav1d::Rav1dInloopFilterType as InloopFilterType; + pub use crate::include::dav1d::headers::{ + Rav1dContentLightLevel as ContentLightLevel, Rav1dMasteringDisplay as MasteringDisplay, + Rav1dPixelLayout as PixelLayout, + }; + pub use crate::include::dav1d::picture::RAV1D_PICTURE_ALIGNMENT as PICTURE_ALIGNMENT; + use crate::internal::Rav1dContext; + use crate::pixels::Pixels; + use crate::{ + self as rav1d, c_arc, c_box, dav1d_get_frame_delay, rav1d_close, rav1d_flush, + rav1d_get_picture, rav1d_open, rav1d_send_data, + }; + + fn option_nonnull(ptr: *mut T) -> Option> { + if ptr.is_null() { + None + } else { + Some(NonNull::new(ptr).unwrap()) + } + } + + /// Error enum return by various `dav1d` operations. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[non_exhaustive] + pub enum Error { + /// Try again. + /// + /// If this is returned by [`Decoder::send_data`] or [`Decoder::send_pending_data`] then there + /// are decoded frames pending that first have to be retrieved via [`Decoder::get_picture`] + /// before processing any further pending data. + /// + /// If this is returned by [`Decoder::get_picture`] then no decoded frames are pending + /// currently and more data needs to be sent to the decoder. + Again, + /// Invalid argument. + /// + /// One of the arguments passed to the function was invalid. + InvalidArgument, + /// Not enough memory. + /// + /// Not enough memory is currently available for performing this operation. + NotEnoughMemory, + /// Unsupported bitstream. + /// + /// The provided bitstream is not supported by `dav1d`. + UnsupportedBitstream, + /// Unknown error. + UnknownError(Rav1dError), + } + + impl From for Error { + fn from(err: Rav1dError) -> Self { + match err { + Rav1dError::EAGAIN => Error::Again, + Rav1dError::ENOMEM => Error::NotEnoughMemory, + Rav1dError::EINVAL => Error::InvalidArgument, + Rav1dError::ENOPROTOOPT => Error::UnsupportedBitstream, + _ => Error::UnknownError(err), + } + } + } + + impl Error { + pub const fn is_again(&self) -> bool { + matches!(self, Error::Again) + } + } + + impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Again => write!(fmt, "Try again"), + Error::InvalidArgument => write!(fmt, "Invalid argument"), + Error::NotEnoughMemory => write!(fmt, "Not enough memory available"), + Error::UnsupportedBitstream => write!(fmt, "Unsupported bitstream"), + Error::UnknownError(err) => write!(fmt, "Unknown error {err:?}"), + } + } + } + + impl std::error::Error for Error {} + + /// Settings for creating a new [`Decoder`] instance. + /// See documentation for native `Dav1dSettings` struct. + pub struct Settings { + pub(crate) dav1d_settings: Rav1dSettings, + } + + static_assertions::assert_impl_all!(Settings: Send, Sync); + + impl Default for Settings { + fn default() -> Self { + Self::new() + } + } + + impl Settings { + /// Creates a new [`Settings`] instance with default settings. + pub fn new() -> Self { + Self { + dav1d_settings: Rav1dSettings::default(), + } + } + + pub fn set_n_threads(&mut self, n_threads: u32) { + self.dav1d_settings.n_threads = n_threads as i32; + } + + pub fn get_n_threads(&self) -> u32 { + self.dav1d_settings.n_threads as u32 + } + + pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { + self.dav1d_settings.max_frame_delay = max_frame_delay as i32; + } + + pub fn get_max_frame_delay(&self) -> u32 { + self.dav1d_settings.max_frame_delay as u32 + } + + pub fn set_apply_grain(&mut self, apply_grain: bool) { + self.dav1d_settings.apply_grain = apply_grain; + } + + pub fn get_apply_grain(&self) -> bool { + self.dav1d_settings.apply_grain + } + + pub fn set_operating_point(&mut self, operating_point: u8) { + self.dav1d_settings.operating_point = operating_point; + } + + pub fn get_operating_point(&self) -> u32 { + self.dav1d_settings.operating_point as u32 + } + + pub fn set_all_layers(&mut self, all_layers: bool) { + self.dav1d_settings.all_layers = all_layers; + } + + pub fn get_all_layers(&self) -> bool { + self.dav1d_settings.all_layers + } + + pub fn set_frame_size_limit(&mut self, frame_size_limit: u32) { + self.dav1d_settings.frame_size_limit = frame_size_limit; + } + + pub fn get_frame_size_limit(&self) -> u32 { + self.dav1d_settings.frame_size_limit + } + + pub fn set_strict_std_compliance(&mut self, strict_std_compliance: bool) { + self.dav1d_settings.strict_std_compliance = strict_std_compliance; + } + + pub fn get_strict_std_compliance(&self) -> bool { + self.dav1d_settings.strict_std_compliance + } + + pub fn set_output_invisible_frames(&mut self, output_invisible_frames: bool) { + self.dav1d_settings.output_invisible_frames = output_invisible_frames; + } + + pub fn get_output_invisible_frames(&self) -> bool { + self.dav1d_settings.output_invisible_frames + } + + pub fn set_inloop_filters(&mut self, inloop_filters: Rav1dInloopFilterType) { + self.dav1d_settings.inloop_filters = inloop_filters; + } + + pub fn get_inloop_filters(&self) -> Rav1dInloopFilterType { + self.dav1d_settings.inloop_filters + } + + pub fn set_decode_frame_type(&mut self, decode_frame_type: Rav1dDecodeFrameType) { + self.dav1d_settings.decode_frame_type = decode_frame_type; + } + + pub fn get_decode_frame_type(&self) -> Rav1dDecodeFrameType { + self.dav1d_settings.decode_frame_type + } + } + + /// The error type returned when a conversion from a C enum fails. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub struct TryFromEnumError(()); + + impl Display for TryFromEnumError { + fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result { + fmt.write_str("Invalid enum value") + } + } + + impl From for TryFromEnumError { + fn from(x: Infallible) -> TryFromEnumError { + match x {} + } + } + + impl std::error::Error for TryFromEnumError {} + + /// A `dav1d` decoder instance. + pub struct Decoder { + dec: Arc, + pending_data: Option, + } + + impl Decoder { + /// Creates a new [`Decoder`] instance with given [`Settings`]. + pub fn with_settings(settings: &Settings) -> Result { + match rav1d_open(&settings.dav1d_settings) { + Ok(dec) => Ok(Decoder { + dec, + pending_data: None, + }), + Err(err) => Err(Error::from(err)), + } + } + + /// Creates a new [`Decoder`] instance with the default settings. + pub fn new() -> Result { + Self::with_settings(&Settings::default()) + } + + /// Flush the decoder. + /// + /// This flushes all delayed frames in the decoder and clears the internal decoder state. + /// + /// All currently pending frames are available afterwards via [`Decoder::get_picture`]. + pub fn flush(&mut self) { + rav1d_flush(&self.dec); + if let Some(mut pending_data) = self.pending_data.take() { + let _ = mem::take(&mut pending_data); + } + } + + /// Send new AV1 data to the decoder. + /// + /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// available via [`Decoder::get_picture`]. + /// + /// # Panics + /// + /// If a previous call returned [`Error::Again`] then this must not be called again until + /// [`Decoder::send_pending_data`] has returned `Ok(())`. + pub fn send_data + Send + Sync + 'static>( + &mut self, + buf: T, + offset: Option, + timestamp: Option, + duration: Option, + ) -> Result<(), Error> { + assert!( + self.pending_data.is_none(), + "Have pending data that needs to be handled first" + ); + + let buf: std::boxed::Box<[u8]> = buf.as_ref().to_vec().into_boxed_slice(); + let slice = (*buf).as_ref(); + let len = slice.len(); + + let mut data: Rav1dData = Rav1dData::create(len).unwrap(); + data.data = Some(c_arc::CArc::wrap(c_box::CBox::Rust(buf)).unwrap()); + if let Some(offset) = offset { + data.m.offset = offset as libc::off_t; + } + if let Some(timestamp) = timestamp { + data.m.timestamp = timestamp; + } + if let Some(duration) = duration { + data.m.duration = duration; + } + + let ret = rav1d_send_data(&self.dec, &mut data); + if let Err(err) = ret { + let ret = Error::from(err); + + if ret.is_again() { + self.pending_data = Some(data); + } else { + let _ = mem::take(&mut data); + } + + return Err(ret); + } + + if data.data.as_ref().is_some_and(|d| d.len() > 0) { + self.pending_data = Some(data); + return Err(Error::Again); + } + + Ok(()) + } + + /// Sends any pending data to the decoder. + /// + /// This has to be called after [`Decoder::send_data`] has returned `Err([Error::Again])` to + /// consume any futher pending data. + /// + /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// available via [`Decoder::get_picture`]. + pub fn send_pending_data(&mut self) -> Result<(), Error> { + let mut data = match self.pending_data.take() { + None => { + return Ok(()); + } + Some(data) => data, + }; + + let ret = rav1d_send_data(&self.dec, &mut data); + if let Err(err) = ret { + let ret = Error::from(err); + + if ret.is_again() { + self.pending_data = Some(data); + } else { + let _ = mem::take(&mut data); + } + + return Err(ret); + } + + if data.data.as_ref().is_some_and(|d| d.len() > 0) { + self.pending_data = Some(data); + return Err(Error::Again); + } + + Ok(()) + } + + /// Get the next decoded frame from the decoder. + /// + /// If this returns `Err([Error::Again])` then further data has to be sent to the decoder + /// before further decoded frames become available. + /// + /// To make most use of frame threading this function should only be called once per submitted + /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should + /// only be done to drain all pending frames at the end. + pub fn get_picture(&mut self) -> Result { + let mut pic: Rav1dPicture = Rav1dPicture::default(); + let ret = rav1d_get_picture(&self.dec, &mut pic); + + if let Err(err) = ret { + Err(Error::from(err)) + } else { + let inner = InnerPicture { pic }; + Ok(Picture { + inner: Arc::new(inner), + }) + } + } + + /// Get the decoder delay. + pub fn get_frame_delay(&self) -> u32 { + unsafe { + dav1d_get_frame_delay(option_nonnull(&self.dec as *const _ as *mut _)).0 as u32 + } + } + } + + impl Drop for Decoder { + fn drop(&mut self) { + if let Some(mut pending_data) = self.pending_data.take() { + let _ = mem::take(&mut pending_data); + } + rav1d_close(self.dec.clone()); + } + } + + static_assertions::assert_impl_all!(Decoder: Send, Sync); + + struct InnerPicture { + pub pic: Rav1dPicture, + } + + /// A decoded frame. + #[derive(Clone)] + pub struct Picture { + inner: Arc, + } + + /// Frame component. + #[derive(Eq, PartialEq, Copy, Clone, Debug)] + pub enum PlanarImageComponent { + /// Y component. + Y, + /// U component. + U, + /// V component. + V, + } + + impl From for PlanarImageComponent { + fn from(index: usize) -> Self { + match index { + 0 => PlanarImageComponent::Y, + 1 => PlanarImageComponent::U, + 2 => PlanarImageComponent::V, + _ => panic!("Invalid YUV index: {}", index), + } + } + } + + impl From for usize { + fn from(component: PlanarImageComponent) -> Self { + match component { + PlanarImageComponent::Y => 0, + PlanarImageComponent::U => 1, + PlanarImageComponent::V => 2, + } + } + } + + /// A single plane of a decoded frame. + /// + /// This can be used like a `&[u8]`. + #[derive(Clone)] + pub struct Plane(Picture, PlanarImageComponent); + + impl AsRef<[u8]> for Plane { + fn as_ref(&self) -> &[u8] { + let (stride, height) = self.0.plane_data_geometry(self.1); + unsafe { + std::slice::from_raw_parts( + self.0.plane_data_ptr(self.1) as *const u8, + (stride * height) as usize, + ) + } + } + } + + impl Deref for Plane { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } + } + + /// Number of bits per component. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub struct BitsPerComponent(pub usize); + + impl Picture { + /// Stride in pixels of the `component` for the decoded frame. + pub fn stride(&self, component: PlanarImageComponent) -> u32 { + let s = match component { + PlanarImageComponent::Y => 0, + _ => 1, + }; + self.inner.pic.stride[s] as u32 + } + + /// Raw pointer to the data of the `component` for the decoded frame. + pub fn plane_data_ptr(&self, component: PlanarImageComponent) -> *mut c_void { + let index: usize = component.into(); + self.inner.pic.data.as_ref().unwrap().data[index] + .as_byte_mut_ptr() + .cast() + } + + /// Plane geometry of the `component` for the decoded frame. + /// + /// This returns the stride and height. + pub fn plane_data_geometry(&self, component: PlanarImageComponent) -> (u32, u32) { + let height = match component { + PlanarImageComponent::Y => self.height(), + _ => match self.pixel_layout() { + Rav1dPixelLayout::I420 => (self.height() + 1) / 2, + Rav1dPixelLayout::I400 | Rav1dPixelLayout::I422 | Rav1dPixelLayout::I444 => { + self.height() + } + }, + }; + (self.stride(component), height) + } + + /// Plane data of the `component` for the decoded frame. + pub fn plane(&self, component: PlanarImageComponent) -> Plane { + Plane(self.clone(), component) + } + + /// Bit depth of the plane data. + /// + /// This returns 8 or 16 for the underlying integer type used for the plane data. + /// + /// Check [`Picture::bits_per_component`] for the number of bits that are used. + pub fn bit_depth(&self) -> usize { + self.inner.pic.p.bpc as usize + } + + /// Bits used per component of the plane data. + /// + /// Check [`Picture::bit_depth`] for the number of storage bits. + pub fn bits_per_component(&self) -> Option { + match self.inner.pic.seq_hdr.as_ref().unwrap().hbd { + 0 => Some(BitsPerComponent(8)), + 1 => Some(BitsPerComponent(10)), + 2 => Some(BitsPerComponent(12)), + _ => None, + } + } + + /// Width of the frame. + pub fn width(&self) -> u32 { + self.inner.pic.p.w as u32 + } + + /// Height of the frame. + pub fn height(&self) -> u32 { + self.inner.pic.p.h as u32 + } + + /// Pixel layout of the frame. + pub fn pixel_layout(&self) -> Rav1dPixelLayout { + self.inner.pic.p.layout + } + + /// Timestamp of the frame. + /// + /// This is the same timestamp as the one provided to [`Decoder::send_data`]. + pub fn timestamp(&self) -> Option { + let ts = self.inner.pic.m.timestamp; + if ts == i64::MIN { + None + } else { + Some(ts) + } + } + + /// Duration of the frame. + /// + /// This is the same duration as the one provided to [`Decoder::send_data`] or `0` if none was + /// provided. + pub fn duration(&self) -> i64 { + self.inner.pic.m.duration + } + + /// Offset of the frame. + /// + /// This is the same offset as the one provided to [`Decoder::send_data`] or `-1` if none was + /// provided. + pub fn offset(&self) -> i64 { + self.inner.pic.m.offset as i64 + } + + /// Chromaticity coordinates of the source colour primaries. + pub fn color_primaries(&self) -> pixel::ColorPrimaries { + match self.inner.pic.seq_hdr.as_ref().unwrap().pri { + Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, + Rav1dColorPrimaries::UNKNOWN => pixel::ColorPrimaries::Unspecified, + Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, + Rav1dColorPrimaries::BT470BG => pixel::ColorPrimaries::BT470BG, + Rav1dColorPrimaries::BT601 => pixel::ColorPrimaries::BT470BG, + Rav1dColorPrimaries::SMPTE240 => pixel::ColorPrimaries::ST240M, + Rav1dColorPrimaries::FILM => pixel::ColorPrimaries::Film, + Rav1dColorPrimaries::BT2020 => pixel::ColorPrimaries::BT2020, + Rav1dColorPrimaries::XYZ => pixel::ColorPrimaries::ST428, + Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, + Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, + Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, + Rav1dColorPrimaries(x) => { + if (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(x as u32)) { + pixel::ColorPrimaries::Unspecified + } else { + unreachable!() + } + } + } + } + + /// Transfer characteristics function. + pub fn transfer_characteristic(&self) -> pixel::TransferCharacteristic { + match self.inner.pic.seq_hdr.as_ref().unwrap().trc { + Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, + Rav1dTransferCharacteristics::UNKNOWN => pixel::TransferCharacteristic::Unspecified, + Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, + Rav1dTransferCharacteristics::BT470BG => pixel::TransferCharacteristic::BT470BG, + Rav1dTransferCharacteristics::BT601 => pixel::TransferCharacteristic::ST170M, + Rav1dTransferCharacteristics::SMPTE240 => pixel::TransferCharacteristic::ST240M, + Rav1dTransferCharacteristics::LINEAR => pixel::TransferCharacteristic::Linear, + Rav1dTransferCharacteristics::LOG100 => { + pixel::TransferCharacteristic::Logarithmic100 + } + Rav1dTransferCharacteristics::LOG100_SQRT10 => { + pixel::TransferCharacteristic::Logarithmic316 + } + Rav1dTransferCharacteristics::IEC61966 => pixel::TransferCharacteristic::SRGB, + Rav1dTransferCharacteristics::BT1361 => pixel::TransferCharacteristic::BT1886, + Rav1dTransferCharacteristics::SRGB => pixel::TransferCharacteristic::SRGB, + Rav1dTransferCharacteristics::BT2020_10BIT => { + pixel::TransferCharacteristic::BT2020Ten + } + Rav1dTransferCharacteristics::BT2020_12BIT => { + pixel::TransferCharacteristic::BT2020Twelve + } + Rav1dTransferCharacteristics::SMPTE2084 => { + pixel::TransferCharacteristic::PerceptualQuantizer + } + Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, + Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, + Rav1dTransferCharacteristics(x) => { + if (19..=DAV1D_TRC_RESERVED).contains(&(x as u32)) { + pixel::TransferCharacteristic::Unspecified + } else { + unreachable!() + } + } + } + } + + /// Matrix coefficients used in deriving luma and chroma signals from the + /// green, blue and red or X, Y and Z primaries. + pub fn matrix_coefficients(&self) -> pixel::MatrixCoefficients { + match self.inner.pic.seq_hdr.as_ref().unwrap().mtrx { + Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, + Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, + Rav1dMatrixCoefficients::UNKNOWN => pixel::MatrixCoefficients::Unspecified, + Rav1dMatrixCoefficients::FCC => pixel::MatrixCoefficients::BT470M, + Rav1dMatrixCoefficients::BT470BG => pixel::MatrixCoefficients::BT470BG, + Rav1dMatrixCoefficients::BT601 => pixel::MatrixCoefficients::BT470BG, + Rav1dMatrixCoefficients::SMPTE240 => pixel::MatrixCoefficients::ST240M, + Rav1dMatrixCoefficients::SMPTE_YCGCO => pixel::MatrixCoefficients::YCgCo, + Rav1dMatrixCoefficients::BT2020_NCL => { + pixel::MatrixCoefficients::BT2020NonConstantLuminance + } + Rav1dMatrixCoefficients::BT2020_CL => { + pixel::MatrixCoefficients::BT2020ConstantLuminance + } + Rav1dMatrixCoefficients::SMPTE2085 => pixel::MatrixCoefficients::ST2085, + Rav1dMatrixCoefficients::CHROMAT_NCL => { + pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance + } + Rav1dMatrixCoefficients::CHROMAT_CL => { + pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance + } + Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, + Rav1dMatrixCoefficients(x) => { + if (15..=DAV1D_MC_RESERVED).contains(&(x as u32)) { + pixel::MatrixCoefficients::Unspecified + } else { + unreachable!() + } + } + } + } + + /// YUV color range. + pub fn color_range(&self) -> pixel::YUVRange { + match self.inner.pic.seq_hdr.as_ref().unwrap().color_range { + 0 => pixel::YUVRange::Limited, + _ => pixel::YUVRange::Full, + } + } + + /// Sample position for subsampled chroma. + pub fn chroma_location(&self) -> pixel::ChromaLocation { + // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c + match self.inner.pic.seq_hdr.as_ref().unwrap().chr { + Rav1dChromaSamplePosition::Unknown | Rav1dChromaSamplePosition::Colocated => { + pixel::ChromaLocation::Center + } + Rav1dChromaSamplePosition::Vertical => pixel::ChromaLocation::Left, + Rav1dChromaSamplePosition::_Reserved => unreachable!(), + } + } + } + + impl Drop for InnerPicture { + fn drop(&mut self) { + let _ = mem::take(&mut self.pic); + } + } + + impl Debug for Picture { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Picture") + .field("width", &self.width()) + .field("height", &self.height()) + .field("bit_depth", &self.bit_depth()) + .field("pixel_layout", &self.pixel_layout()) + .field("timestamp", &self.timestamp()) + .field("duration", &self.duration()) + .field("offset", &self.offset()) + .field("color_primaries", &self.color_primaries()) + .field("transfer_characteristic", &self.transfer_characteristic()) + .field("matrix_coefficients", &self.matrix_coefficients()) + .field("color_range", &self.color_range()) + .field("chroma_location", &self.chroma_location()) + .finish() + } + } +} + +pub use dav1d::*; From f616c50ceab68ceda6167447e496844a6411f0ea Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Mon, 7 Jul 2025 18:34:28 +0100 Subject: [PATCH 02/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rust_api.rs b/src/rust_api.rs index ee44dde8d..b087c7e49 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -147,6 +147,7 @@ pub mod dav1d { /// Settings for creating a new [`Decoder`] instance. /// See documentation for native `Dav1dSettings` struct. + #[derive(Default)] pub struct Settings { pub(crate) dav1d_settings: Rav1dSettings, } From 14c32b61aaebfcaa5c59b035202cb65afac1beaf Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Mon, 7 Jul 2025 18:34:45 +0100 Subject: [PATCH 03/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index b087c7e49..2c73a733a 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -154,18 +154,10 @@ pub mod dav1d { static_assertions::assert_impl_all!(Settings: Send, Sync); - impl Default for Settings { - fn default() -> Self { - Self::new() - } - } - impl Settings { /// Creates a new [`Settings`] instance with default settings. pub fn new() -> Self { - Self { - dav1d_settings: Rav1dSettings::default(), - } + Self::default() } pub fn set_n_threads(&mut self, n_threads: u32) { From f5ae0e8836aadfdd9a630c097da495a4b1d2954b Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Mon, 7 Jul 2025 18:34:59 +0100 Subject: [PATCH 04/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 2c73a733a..7c65e4819 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -149,7 +149,7 @@ pub mod dav1d { /// See documentation for native `Dav1dSettings` struct. #[derive(Default)] pub struct Settings { - pub(crate) dav1d_settings: Rav1dSettings, + pub(crate) rav1d_settings: Rav1dSettings, } static_assertions::assert_impl_all!(Settings: Send, Sync); From 1aae7a8f16d62542c232076bc3a060981808fcd5 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Mon, 7 Jul 2025 18:33:49 +0100 Subject: [PATCH 05/72] Replaced Error type with Rav1dError and added better enum names and docs --- src/rust_api.rs | 102 ++++++------------------------------------------ 1 file changed, 13 insertions(+), 89 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 7c65e4819..3c3620f9d 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -1,17 +1,3 @@ -#![allow(non_upper_case_globals)] -#![cfg_attr(target_arch = "arm", feature(stdarch_arm_feature_detection))] -#![cfg_attr( - any(target_arch = "riscv32", target_arch = "riscv64"), - feature(stdarch_riscv_feature_detection) -)] -#![deny(unsafe_op_in_unsafe_fn)] -#![allow(clippy::all)] -#![deny(clippy::undocumented_unsafe_blocks)] -#![deny(clippy::missing_safety_doc)] - -#[cfg(not(any(feature = "bitdepth_8", feature = "bitdepth_16")))] -compile_error!("No bitdepths enabled. Enable one or more of the following features: `bitdepth_8`, `bitdepth_16`"); - // --------------------------------------------------------------------------------------- /// Public Rust API. @@ -84,67 +70,6 @@ pub mod dav1d { } } - /// Error enum return by various `dav1d` operations. - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - #[non_exhaustive] - pub enum Error { - /// Try again. - /// - /// If this is returned by [`Decoder::send_data`] or [`Decoder::send_pending_data`] then there - /// are decoded frames pending that first have to be retrieved via [`Decoder::get_picture`] - /// before processing any further pending data. - /// - /// If this is returned by [`Decoder::get_picture`] then no decoded frames are pending - /// currently and more data needs to be sent to the decoder. - Again, - /// Invalid argument. - /// - /// One of the arguments passed to the function was invalid. - InvalidArgument, - /// Not enough memory. - /// - /// Not enough memory is currently available for performing this operation. - NotEnoughMemory, - /// Unsupported bitstream. - /// - /// The provided bitstream is not supported by `dav1d`. - UnsupportedBitstream, - /// Unknown error. - UnknownError(Rav1dError), - } - - impl From for Error { - fn from(err: Rav1dError) -> Self { - match err { - Rav1dError::EAGAIN => Error::Again, - Rav1dError::ENOMEM => Error::NotEnoughMemory, - Rav1dError::EINVAL => Error::InvalidArgument, - Rav1dError::ENOPROTOOPT => Error::UnsupportedBitstream, - _ => Error::UnknownError(err), - } - } - } - - impl Error { - pub const fn is_again(&self) -> bool { - matches!(self, Error::Again) - } - } - - impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Again => write!(fmt, "Try again"), - Error::InvalidArgument => write!(fmt, "Invalid argument"), - Error::NotEnoughMemory => write!(fmt, "Not enough memory available"), - Error::UnsupportedBitstream => write!(fmt, "Unsupported bitstream"), - Error::UnknownError(err) => write!(fmt, "Unknown error {err:?}"), - } - } - } - - impl std::error::Error for Error {} - /// Settings for creating a new [`Decoder`] instance. /// See documentation for native `Dav1dSettings` struct. #[derive(Default)] @@ -267,18 +192,18 @@ pub mod dav1d { impl Decoder { /// Creates a new [`Decoder`] instance with given [`Settings`]. - pub fn with_settings(settings: &Settings) -> Result { + pub fn with_settings(settings: &Settings) -> Result { match rav1d_open(&settings.dav1d_settings) { Ok(dec) => Ok(Decoder { dec, pending_data: None, }), - Err(err) => Err(Error::from(err)), + Err(err) => Err(err), } } /// Creates a new [`Decoder`] instance with the default settings. - pub fn new() -> Result { + pub fn new() -> Result { Self::with_settings(&Settings::default()) } @@ -309,7 +234,7 @@ pub mod dav1d { offset: Option, timestamp: Option, duration: Option, - ) -> Result<(), Error> { + ) -> Result<(), Rav1dError> { assert!( self.pending_data.is_none(), "Have pending data that needs to be handled first" @@ -333,9 +258,8 @@ pub mod dav1d { let ret = rav1d_send_data(&self.dec, &mut data); if let Err(err) = ret { - let ret = Error::from(err); - - if ret.is_again() { + let ret = err; + if matches!(ret, Rav1dError::Again) { self.pending_data = Some(data); } else { let _ = mem::take(&mut data); @@ -346,7 +270,7 @@ pub mod dav1d { if data.data.as_ref().is_some_and(|d| d.len() > 0) { self.pending_data = Some(data); - return Err(Error::Again); + return Err(Rav1dError::Again); } Ok(()) @@ -359,7 +283,7 @@ pub mod dav1d { /// /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames /// available via [`Decoder::get_picture`]. - pub fn send_pending_data(&mut self) -> Result<(), Error> { + pub fn send_pending_data(&mut self) -> Result<(), Rav1dError> { let mut data = match self.pending_data.take() { None => { return Ok(()); @@ -369,9 +293,9 @@ pub mod dav1d { let ret = rav1d_send_data(&self.dec, &mut data); if let Err(err) = ret { - let ret = Error::from(err); + let ret = err; - if ret.is_again() { + if matches!(ret, Rav1dError::Again) { self.pending_data = Some(data); } else { let _ = mem::take(&mut data); @@ -382,7 +306,7 @@ pub mod dav1d { if data.data.as_ref().is_some_and(|d| d.len() > 0) { self.pending_data = Some(data); - return Err(Error::Again); + return Err(Rav1dError::Again); } Ok(()) @@ -396,12 +320,12 @@ pub mod dav1d { /// To make most use of frame threading this function should only be called once per submitted /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should /// only be done to drain all pending frames at the end. - pub fn get_picture(&mut self) -> Result { + pub fn get_picture(&mut self) -> Result { let mut pic: Rav1dPicture = Rav1dPicture::default(); let ret = rav1d_get_picture(&self.dec, &mut pic); if let Err(err) = ret { - Err(Error::from(err)) + Err(err) } else { let inner = InnerPicture { pic }; Ok(Picture { From 7c107755f6743cd2f9154bb2960b45dd1e84bd3a Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Mon, 7 Jul 2025 18:49:41 +0100 Subject: [PATCH 06/72] Changed types to more reasonable ones --- src/rust_api.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 3c3620f9d..88bcc97bf 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -86,83 +86,83 @@ pub mod dav1d { } pub fn set_n_threads(&mut self, n_threads: u32) { - self.dav1d_settings.n_threads = n_threads as i32; + self.rav1d_settings.n_threads = n_threads; } pub fn get_n_threads(&self) -> u32 { - self.dav1d_settings.n_threads as u32 + self.rav1d_settings.n_threads } pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { - self.dav1d_settings.max_frame_delay = max_frame_delay as i32; + self.rav1d_settings.max_frame_delay = max_frame_delay; } pub fn get_max_frame_delay(&self) -> u32 { - self.dav1d_settings.max_frame_delay as u32 + self.rav1d_settings.max_frame_delay } pub fn set_apply_grain(&mut self, apply_grain: bool) { - self.dav1d_settings.apply_grain = apply_grain; + self.rav1d_settings.apply_grain = apply_grain; } pub fn get_apply_grain(&self) -> bool { - self.dav1d_settings.apply_grain + self.rav1d_settings.apply_grain } pub fn set_operating_point(&mut self, operating_point: u8) { - self.dav1d_settings.operating_point = operating_point; + self.rav1d_settings.operating_point = operating_point; } - pub fn get_operating_point(&self) -> u32 { - self.dav1d_settings.operating_point as u32 + pub fn get_operating_point(&self) -> u8 { + self.rav1d_settings.operating_point } pub fn set_all_layers(&mut self, all_layers: bool) { - self.dav1d_settings.all_layers = all_layers; + self.rav1d_settings.all_layers = all_layers; } pub fn get_all_layers(&self) -> bool { - self.dav1d_settings.all_layers + self.rav1d_settings.all_layers } pub fn set_frame_size_limit(&mut self, frame_size_limit: u32) { - self.dav1d_settings.frame_size_limit = frame_size_limit; + self.rav1d_settings.frame_size_limit = frame_size_limit; } pub fn get_frame_size_limit(&self) -> u32 { - self.dav1d_settings.frame_size_limit + self.rav1d_settings.frame_size_limit } pub fn set_strict_std_compliance(&mut self, strict_std_compliance: bool) { - self.dav1d_settings.strict_std_compliance = strict_std_compliance; + self.rav1d_settings.strict_std_compliance = strict_std_compliance; } pub fn get_strict_std_compliance(&self) -> bool { - self.dav1d_settings.strict_std_compliance + self.rav1d_settings.strict_std_compliance } pub fn set_output_invisible_frames(&mut self, output_invisible_frames: bool) { - self.dav1d_settings.output_invisible_frames = output_invisible_frames; + self.rav1d_settings.output_invisible_frames = output_invisible_frames; } pub fn get_output_invisible_frames(&self) -> bool { - self.dav1d_settings.output_invisible_frames + self.rav1d_settings.output_invisible_frames } pub fn set_inloop_filters(&mut self, inloop_filters: Rav1dInloopFilterType) { - self.dav1d_settings.inloop_filters = inloop_filters; + self.rav1d_settings.inloop_filters = inloop_filters; } pub fn get_inloop_filters(&self) -> Rav1dInloopFilterType { - self.dav1d_settings.inloop_filters + self.rav1d_settings.inloop_filters } pub fn set_decode_frame_type(&mut self, decode_frame_type: Rav1dDecodeFrameType) { - self.dav1d_settings.decode_frame_type = decode_frame_type; + self.rav1d_settings.decode_frame_type = decode_frame_type; } pub fn get_decode_frame_type(&self) -> Rav1dDecodeFrameType { - self.dav1d_settings.decode_frame_type + self.rav1d_settings.decode_frame_type } } @@ -193,7 +193,7 @@ pub mod dav1d { impl Decoder { /// Creates a new [`Decoder`] instance with given [`Settings`]. pub fn with_settings(settings: &Settings) -> Result { - match rav1d_open(&settings.dav1d_settings) { + match rav1d_open(&settings.rav1d_settings) { Ok(dec) => Ok(Decoder { dec, pending_data: None, From a654fc445a0379efbfceaac1a7694e30d832a0ee Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:46:53 +0100 Subject: [PATCH 07/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 88bcc97bf..d1ef6f958 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -1,5 +1,3 @@ -// --------------------------------------------------------------------------------------- - /// Public Rust API. /// /// This is more or less the same API as , From 282b6d8ccc3af4a54959ebb3f596ec9f051373e8 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 16:53:58 +0100 Subject: [PATCH 08/72] Cleaned up imports, expose DecodeFrameType publicly --- src/rust_api.rs | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index d1ef6f958..1be6bcfe5 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -41,23 +41,27 @@ pub mod dav1d { use std::{fmt, mem}; pub use av_data::pixel; - use rav1d::error::Rav1dError; - use rav1d::include::dav1d::data::*; - use rav1d::include::dav1d::dav1d::*; - use rav1d::include::dav1d::headers::*; - use rav1d::include::dav1d::picture::*; - pub use crate::include::dav1d::dav1d::Rav1dInloopFilterType as InloopFilterType; + use crate::error::Rav1dError; + pub use crate::include::dav1d::dav1d::{ + Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, + }; + use crate::include::dav1d::headers::{ + Rav1dChromaSamplePosition, Rav1dColorPrimaries, Rav1dMatrixCoefficients, + Rav1dTransferCharacteristics, DAV1D_COLOR_PRI_RESERVED, DAV1D_MC_RESERVED, + DAV1D_TRC_RESERVED, + }; pub use crate::include::dav1d::headers::{ Rav1dContentLightLevel as ContentLightLevel, Rav1dMasteringDisplay as MasteringDisplay, Rav1dPixelLayout as PixelLayout, }; + use crate::include::dav1d::picture::Rav1dPicture; pub use crate::include::dav1d::picture::RAV1D_PICTURE_ALIGNMENT as PICTURE_ALIGNMENT; use crate::internal::Rav1dContext; use crate::pixels::Pixels; use crate::{ - self as rav1d, c_arc, c_box, dav1d_get_frame_delay, rav1d_close, rav1d_flush, - rav1d_get_picture, rav1d_open, rav1d_send_data, + c_arc, c_box, dav1d_get_frame_delay, rav1d_close, rav1d_flush, rav1d_get_picture, + rav1d_open, rav1d_send_data, Rav1dData, Rav1dSettings, }; fn option_nonnull(ptr: *mut T) -> Option> { @@ -147,19 +151,19 @@ pub mod dav1d { self.rav1d_settings.output_invisible_frames } - pub fn set_inloop_filters(&mut self, inloop_filters: Rav1dInloopFilterType) { + pub fn set_inloop_filters(&mut self, inloop_filters: InloopFilterType) { self.rav1d_settings.inloop_filters = inloop_filters; } - pub fn get_inloop_filters(&self) -> Rav1dInloopFilterType { + pub fn get_inloop_filters(&self) -> InloopFilterType { self.rav1d_settings.inloop_filters } - pub fn set_decode_frame_type(&mut self, decode_frame_type: Rav1dDecodeFrameType) { + pub fn set_decode_frame_type(&mut self, decode_frame_type: DecodeFrameType) { self.rav1d_settings.decode_frame_type = decode_frame_type; } - pub fn get_decode_frame_type(&self) -> Rav1dDecodeFrameType { + pub fn get_decode_frame_type(&self) -> DecodeFrameType { self.rav1d_settings.decode_frame_type } } @@ -448,10 +452,8 @@ pub mod dav1d { let height = match component { PlanarImageComponent::Y => self.height(), _ => match self.pixel_layout() { - Rav1dPixelLayout::I420 => (self.height() + 1) / 2, - Rav1dPixelLayout::I400 | Rav1dPixelLayout::I422 | Rav1dPixelLayout::I444 => { - self.height() - } + PixelLayout::I420 => (self.height() + 1) / 2, + PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), }, }; (self.stride(component), height) @@ -494,7 +496,7 @@ pub mod dav1d { } /// Pixel layout of the frame. - pub fn pixel_layout(&self) -> Rav1dPixelLayout { + pub fn pixel_layout(&self) -> PixelLayout { self.inner.pic.p.layout } From 0b85bd860ed0f6f9ed6b4c47a3ed239cb1bec032 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:00:34 +0100 Subject: [PATCH 09/72] Removed option_nonnull --- src/rust_api.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 1be6bcfe5..f86b6db61 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -64,14 +64,6 @@ pub mod dav1d { rav1d_open, rav1d_send_data, Rav1dData, Rav1dSettings, }; - fn option_nonnull(ptr: *mut T) -> Option> { - if ptr.is_null() { - None - } else { - Some(NonNull::new(ptr).unwrap()) - } - } - /// Settings for creating a new [`Decoder`] instance. /// See documentation for native `Dav1dSettings` struct. #[derive(Default)] @@ -338,9 +330,7 @@ pub mod dav1d { /// Get the decoder delay. pub fn get_frame_delay(&self) -> u32 { - unsafe { - dav1d_get_frame_delay(option_nonnull(&self.dec as *const _ as *mut _)).0 as u32 - } + unsafe { dav1d_get_frame_delay(NonNull::new(&self.dec as *const _ as *mut _)).0 as u32 } } } From 391c55739975ff987710d36eff40800b4b303425 Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:01:39 +0100 Subject: [PATCH 10/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index f86b6db61..c38f12777 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -165,7 +165,7 @@ pub mod dav1d { pub struct TryFromEnumError(()); impl Display for TryFromEnumError { - fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { fmt.write_str("Invalid enum value") } } From fa961b21358b9d1641963a834ab530892bc35dec Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:04:47 +0100 Subject: [PATCH 11/72] Remove TryFromEnumError as its no longer used --- src/rust_api.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index c38f12777..ba8d12b18 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -32,9 +32,8 @@ pub mod dav1d { // The code below provides a safe API around the rav1d C FFI layer. - use std::convert::Infallible; use std::ffi::c_void; - use std::fmt::{Debug, Display, Formatter}; + use std::fmt::Debug; use std::ops::Deref; use std::ptr::NonNull; use std::sync::Arc; @@ -160,24 +159,6 @@ pub mod dav1d { } } - /// The error type returned when a conversion from a C enum fails. - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct TryFromEnumError(()); - - impl Display for TryFromEnumError { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - fmt.write_str("Invalid enum value") - } - } - - impl From for TryFromEnumError { - fn from(x: Infallible) -> TryFromEnumError { - match x {} - } - } - - impl std::error::Error for TryFromEnumError {} - /// A `dav1d` decoder instance. pub struct Decoder { dec: Arc, From 7895fdaccd891e209cea9e767c4e2a2883b9b53d Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:07:19 +0100 Subject: [PATCH 12/72] Rename Decoder.dec to Decoder.ctx --- src/rust_api.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index ba8d12b18..e1694eae2 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -161,7 +161,7 @@ pub mod dav1d { /// A `dav1d` decoder instance. pub struct Decoder { - dec: Arc, + ctx: Arc, pending_data: Option, } @@ -170,7 +170,7 @@ pub mod dav1d { pub fn with_settings(settings: &Settings) -> Result { match rav1d_open(&settings.rav1d_settings) { Ok(dec) => Ok(Decoder { - dec, + ctx: dec, pending_data: None, }), Err(err) => Err(err), @@ -188,7 +188,7 @@ pub mod dav1d { /// /// All currently pending frames are available afterwards via [`Decoder::get_picture`]. pub fn flush(&mut self) { - rav1d_flush(&self.dec); + rav1d_flush(&self.ctx); if let Some(mut pending_data) = self.pending_data.take() { let _ = mem::take(&mut pending_data); } @@ -231,7 +231,7 @@ pub mod dav1d { data.m.duration = duration; } - let ret = rav1d_send_data(&self.dec, &mut data); + let ret = rav1d_send_data(&self.ctx, &mut data); if let Err(err) = ret { let ret = err; if matches!(ret, Rav1dError::Again) { @@ -266,7 +266,7 @@ pub mod dav1d { Some(data) => data, }; - let ret = rav1d_send_data(&self.dec, &mut data); + let ret = rav1d_send_data(&self.ctx, &mut data); if let Err(err) = ret { let ret = err; @@ -297,7 +297,7 @@ pub mod dav1d { /// only be done to drain all pending frames at the end. pub fn get_picture(&mut self) -> Result { let mut pic: Rav1dPicture = Rav1dPicture::default(); - let ret = rav1d_get_picture(&self.dec, &mut pic); + let ret = rav1d_get_picture(&self.ctx, &mut pic); if let Err(err) = ret { Err(err) @@ -311,7 +311,7 @@ pub mod dav1d { /// Get the decoder delay. pub fn get_frame_delay(&self) -> u32 { - unsafe { dav1d_get_frame_delay(NonNull::new(&self.dec as *const _ as *mut _)).0 as u32 } + unsafe { dav1d_get_frame_delay(NonNull::new(&self.ctx as *const _ as *mut _)).0 as u32 } } } @@ -320,7 +320,7 @@ pub mod dav1d { if let Some(mut pending_data) = self.pending_data.take() { let _ = mem::take(&mut pending_data); } - rav1d_close(self.dec.clone()); + rav1d_close(self.ctx.clone()); } } From 86c41fbd0729eab28497617e1412d7b985dc28f8 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:09:00 +0100 Subject: [PATCH 13/72] Cleanup --- src/rust_api.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index e1694eae2..540f090b3 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -168,13 +168,10 @@ pub mod dav1d { impl Decoder { /// Creates a new [`Decoder`] instance with given [`Settings`]. pub fn with_settings(settings: &Settings) -> Result { - match rav1d_open(&settings.rav1d_settings) { - Ok(dec) => Ok(Decoder { - ctx: dec, - pending_data: None, - }), - Err(err) => Err(err), - } + rav1d_open(&settings.rav1d_settings).map(|ctx| Decoder { + ctx, + pending_data: None, + }) } /// Creates a new [`Decoder`] instance with the default settings. From f2fc3874ded55ef5e56259bb4943aa483117cb02 Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:21:34 +0100 Subject: [PATCH 14/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 540f090b3..f0c7675d9 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -212,7 +212,7 @@ pub mod dav1d { "Have pending data that needs to be handled first" ); - let buf: std::boxed::Box<[u8]> = buf.as_ref().to_vec().into_boxed_slice(); + let buf = buf.as_ref().to_vec().into_boxed_slice(); let slice = (*buf).as_ref(); let len = slice.len(); From fab1bb1e767522460d07b8ec0b15aa88193c2c53 Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:21:50 +0100 Subject: [PATCH 15/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index f0c7675d9..36c60b9c8 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -213,7 +213,7 @@ pub mod dav1d { ); let buf = buf.as_ref().to_vec().into_boxed_slice(); - let slice = (*buf).as_ref(); + let slice = &*buf; let len = slice.len(); let mut data: Rav1dData = Rav1dData::create(len).unwrap(); From 3a41838d6973a69529163f3a8d46e501ed0cd45e Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:22:08 +0100 Subject: [PATCH 16/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 36c60b9c8..3ee71d4e9 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -216,7 +216,7 @@ pub mod dav1d { let slice = &*buf; let len = slice.len(); - let mut data: Rav1dData = Rav1dData::create(len).unwrap(); + let mut data = Rav1dData::create(len).unwrap(); data.data = Some(c_arc::CArc::wrap(c_box::CBox::Rust(buf)).unwrap()); if let Some(offset) = offset { data.m.offset = offset as libc::off_t; From 7c698944a50a15f7346e806cdb2cde7dc09d5d0d Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:26:34 +0100 Subject: [PATCH 17/72] Cleanup --- src/rust_api.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 3ee71d4e9..7e5ade292 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -41,6 +41,8 @@ pub mod dav1d { pub use av_data::pixel; + use crate::c_arc::CArc; + use crate::c_box::CBox; use crate::error::Rav1dError; pub use crate::include::dav1d::dav1d::{ Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, @@ -217,7 +219,7 @@ pub mod dav1d { let len = slice.len(); let mut data = Rav1dData::create(len).unwrap(); - data.data = Some(c_arc::CArc::wrap(c_box::CBox::Rust(buf)).unwrap()); + data.data = Some(CArc::wrap(CBox::from_box(buf)).unwrap()); if let Some(offset) = offset { data.m.offset = offset as libc::off_t; } From 99535603073b3546d09f61389c1e35d1edfe34d8 Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:26:59 +0100 Subject: [PATCH 18/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 7e5ade292..4a958100c 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -295,7 +295,7 @@ pub mod dav1d { /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should /// only be done to drain all pending frames at the end. pub fn get_picture(&mut self) -> Result { - let mut pic: Rav1dPicture = Rav1dPicture::default(); + let mut pic = Rav1dPicture::default(); let ret = rav1d_get_picture(&self.ctx, &mut pic); if let Err(err) = ret { From f0540e8bc59eaa1b48a1c39f9c18423ae9263426 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:48:45 +0100 Subject: [PATCH 19/72] Removed an unsafe block --- src/rust_api.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 4a958100c..f76efed89 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -33,9 +33,8 @@ pub mod dav1d { // The code below provides a safe API around the rav1d C FFI layer. use std::ffi::c_void; - use std::fmt::Debug; + use std::fmt::{Debug, Formatter}; use std::ops::Deref; - use std::ptr::NonNull; use std::sync::Arc; use std::{fmt, mem}; @@ -61,8 +60,8 @@ pub mod dav1d { use crate::internal::Rav1dContext; use crate::pixels::Pixels; use crate::{ - c_arc, c_box, dav1d_get_frame_delay, rav1d_close, rav1d_flush, rav1d_get_picture, - rav1d_open, rav1d_send_data, Rav1dData, Rav1dSettings, + rav1d_close, rav1d_flush, rav1d_get_frame_delay, rav1d_get_picture, rav1d_open, + rav1d_send_data, Rav1dData, Rav1dSettings, }; /// Settings for creating a new [`Decoder`] instance. @@ -165,6 +164,8 @@ pub mod dav1d { pub struct Decoder { ctx: Arc, pending_data: Option, + n_threads: u32, + max_frame_delay: u32, } impl Decoder { @@ -173,6 +174,8 @@ pub mod dav1d { rav1d_open(&settings.rav1d_settings).map(|ctx| Decoder { ctx, pending_data: None, + n_threads: settings.rav1d_settings.n_threads, + max_frame_delay: settings.rav1d_settings.max_frame_delay, }) } @@ -310,7 +313,14 @@ pub mod dav1d { /// Get the decoder delay. pub fn get_frame_delay(&self) -> u32 { - unsafe { dav1d_get_frame_delay(NonNull::new(&self.ctx as *const _ as *mut _)).0 as u32 } + // The only fields this actually needs from Rav1dSettings are n_threads and max_frame_delay so we just pass these in directly + + rav1d_get_frame_delay(&Rav1dSettings { + n_threads: self.n_threads, + max_frame_delay: self.max_frame_delay, + ..Default::default() + }) + .unwrap() as u32 } } @@ -627,7 +637,7 @@ pub mod dav1d { } impl Debug for Picture { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("Picture") .field("width", &self.width()) .field("height", &self.height()) From 93b2e6880c3c9ce47b24cf9dd2adcf0349b340f5 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:53:17 +0100 Subject: [PATCH 20/72] Removed Drop impl for InnerPicture --- src/rust_api.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index f76efed89..4a046b0f8 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -630,12 +630,6 @@ pub mod dav1d { } } - impl Drop for InnerPicture { - fn drop(&mut self) { - let _ = mem::take(&mut self.pic); - } - } - impl Debug for Picture { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("Picture") From cc813439cb9d367f1ae87f8d0396b6df31021f54 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 17:55:39 +0100 Subject: [PATCH 21/72] Made offset in Rav1dDataProps an i64 --- src/include/dav1d/common.rs | 2 +- src/rust_api.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/dav1d/common.rs b/src/include/dav1d/common.rs index 10490c3b1..9e9f46b72 100644 --- a/src/include/dav1d/common.rs +++ b/src/include/dav1d/common.rs @@ -45,7 +45,7 @@ pub struct Dav1dDataProps { pub struct Rav1dDataProps { pub timestamp: i64, pub duration: i64, - pub offset: libc::off_t, + pub offset: i64, pub size: usize, pub user_data: Rav1dUserData, } diff --git a/src/rust_api.rs b/src/rust_api.rs index 4a046b0f8..106fb14cd 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -224,7 +224,7 @@ pub mod dav1d { let mut data = Rav1dData::create(len).unwrap(); data.data = Some(CArc::wrap(CBox::from_box(buf)).unwrap()); if let Some(offset) = offset { - data.m.offset = offset as libc::off_t; + data.m.offset = offset; } if let Some(timestamp) = timestamp { data.m.timestamp = timestamp; From b5ae20f36dd262b6ae56b2c516d5572b8e9ed552 Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 22:23:57 +0100 Subject: [PATCH 22/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 106fb14cd..7c18948f4 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -405,7 +405,7 @@ pub mod dav1d { /// Number of bits per component. #[derive(Copy, Clone, Debug, PartialEq, Eq)] - pub struct BitsPerComponent(pub usize); + pub struct BitsPerComponent(pub u8); impl Picture { /// Stride in pixels of the `component` for the decoded frame. From 72cb0fa7769a707bfc6c6250430e5b97cb6276e8 Mon Sep 17 00:00:00 2001 From: leo030303 <59373587+leo030303@users.noreply.github.com> Date: Tue, 8 Jul 2025 22:24:10 +0100 Subject: [PATCH 23/72] Update src/rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 7c18948f4..9907be5dd 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -387,7 +387,7 @@ pub mod dav1d { fn as_ref(&self) -> &[u8] { let (stride, height) = self.0.plane_data_geometry(self.1); unsafe { - std::slice::from_raw_parts( + slice::from_raw_parts( self.0.plane_data_ptr(self.1) as *const u8, (stride * height) as usize, ) From 06d02694302df078996f9adc6783e96af2791331 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 22:37:46 +0100 Subject: [PATCH 24/72] Move some conversions into TryInto's --- src/include/dav1d/headers.rs | 126 ++++++++++++++++++++++++++++ src/rust_api.rs | 155 +++++++++++------------------------ 2 files changed, 173 insertions(+), 108 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 745ebbe72..788a880a0 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -4,10 +4,12 @@ use std::fmt::{Debug, Display, Formatter}; use std::ops::{BitAnd, Deref, Sub}; use std::sync::Arc; +use av_data::pixel; use strum::{EnumCount, FromRepr}; use crate::align::ArrayDefault; use crate::enum_map::EnumKey; +use crate::error::Rav1dError; use crate::levels::SegmentId; use crate::relaxed_atomic::RelaxedAtomic; @@ -565,6 +567,34 @@ impl Rav1dColorPrimaries { } } +impl TryInto for Rav1dColorPrimaries { + type Error = Rav1dError; + + fn try_into(self) -> Result { + match self { + Rav1dColorPrimaries::BT709 => Ok(pixel::ColorPrimaries::BT709), + Rav1dColorPrimaries::UNKNOWN => Ok(pixel::ColorPrimaries::Unspecified), + Rav1dColorPrimaries::BT470M => Ok(pixel::ColorPrimaries::BT470M), + Rav1dColorPrimaries::BT470BG => Ok(pixel::ColorPrimaries::BT470BG), + Rav1dColorPrimaries::BT601 => Ok(pixel::ColorPrimaries::BT470BG), + Rav1dColorPrimaries::SMPTE240 => Ok(pixel::ColorPrimaries::ST240M), + Rav1dColorPrimaries::FILM => Ok(pixel::ColorPrimaries::Film), + Rav1dColorPrimaries::BT2020 => Ok(pixel::ColorPrimaries::BT2020), + Rav1dColorPrimaries::XYZ => Ok(pixel::ColorPrimaries::ST428), + Rav1dColorPrimaries::SMPTE431 => Ok(pixel::ColorPrimaries::P3DCI), + Rav1dColorPrimaries::SMPTE432 => Ok(pixel::ColorPrimaries::P3Display), + Rav1dColorPrimaries::EBU3213 => Ok(pixel::ColorPrimaries::Tech3213), + Rav1dColorPrimaries(x) => { + if (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(x as u32)) { + Ok(pixel::ColorPrimaries::Unspecified) + } else { + Err(Rav1dError::InvalidArgument) + } + } + } + } +} + impl From for Dav1dColorPrimaries { fn from(value: Rav1dColorPrimaries) -> Self { value.to_dav1d() @@ -646,6 +676,49 @@ impl Rav1dTransferCharacteristics { } } +impl TryInto for Rav1dTransferCharacteristics { + type Error = Rav1dError; + + fn try_into(self) -> Result { + match self { + Rav1dTransferCharacteristics::BT709 => Ok(pixel::TransferCharacteristic::BT1886), + Rav1dTransferCharacteristics::UNKNOWN => Ok(pixel::TransferCharacteristic::Unspecified), + Rav1dTransferCharacteristics::BT470M => Ok(pixel::TransferCharacteristic::BT470M), + Rav1dTransferCharacteristics::BT470BG => Ok(pixel::TransferCharacteristic::BT470BG), + Rav1dTransferCharacteristics::BT601 => Ok(pixel::TransferCharacteristic::ST170M), + Rav1dTransferCharacteristics::SMPTE240 => Ok(pixel::TransferCharacteristic::ST240M), + Rav1dTransferCharacteristics::LINEAR => Ok(pixel::TransferCharacteristic::Linear), + Rav1dTransferCharacteristics::LOG100 => { + Ok(pixel::TransferCharacteristic::Logarithmic100) + } + Rav1dTransferCharacteristics::LOG100_SQRT10 => { + Ok(pixel::TransferCharacteristic::Logarithmic316) + } + Rav1dTransferCharacteristics::IEC61966 => Ok(pixel::TransferCharacteristic::SRGB), + Rav1dTransferCharacteristics::BT1361 => Ok(pixel::TransferCharacteristic::BT1886), + Rav1dTransferCharacteristics::SRGB => Ok(pixel::TransferCharacteristic::SRGB), + Rav1dTransferCharacteristics::BT2020_10BIT => { + Ok(pixel::TransferCharacteristic::BT2020Ten) + } + Rav1dTransferCharacteristics::BT2020_12BIT => { + Ok(pixel::TransferCharacteristic::BT2020Twelve) + } + Rav1dTransferCharacteristics::SMPTE2084 => { + Ok(pixel::TransferCharacteristic::PerceptualQuantizer) + } + Rav1dTransferCharacteristics::SMPTE428 => Ok(pixel::TransferCharacteristic::ST428), + Rav1dTransferCharacteristics::HLG => Ok(pixel::TransferCharacteristic::HybridLogGamma), + Rav1dTransferCharacteristics(x) => { + if (19..=DAV1D_TRC_RESERVED).contains(&(x as u32)) { + Ok(pixel::TransferCharacteristic::Unspecified) + } else { + Err(Rav1dError::InvalidArgument) + } + } + } + } +} + impl From for Dav1dTransferCharacteristics { fn from(value: Rav1dTransferCharacteristics) -> Self { value.to_dav1d() @@ -709,6 +782,44 @@ impl Rav1dMatrixCoefficients { } } +impl TryInto for Rav1dMatrixCoefficients { + type Error = Rav1dError; + + fn try_into(self) -> Result { + match self { + Rav1dMatrixCoefficients::IDENTITY => Ok(pixel::MatrixCoefficients::Identity), + Rav1dMatrixCoefficients::BT709 => Ok(pixel::MatrixCoefficients::BT709), + Rav1dMatrixCoefficients::UNKNOWN => Ok(pixel::MatrixCoefficients::Unspecified), + Rav1dMatrixCoefficients::FCC => Ok(pixel::MatrixCoefficients::BT470M), + Rav1dMatrixCoefficients::BT470BG => Ok(pixel::MatrixCoefficients::BT470BG), + Rav1dMatrixCoefficients::BT601 => Ok(pixel::MatrixCoefficients::BT470BG), + Rav1dMatrixCoefficients::SMPTE240 => Ok(pixel::MatrixCoefficients::ST240M), + Rav1dMatrixCoefficients::SMPTE_YCGCO => Ok(pixel::MatrixCoefficients::YCgCo), + Rav1dMatrixCoefficients::BT2020_NCL => { + Ok(pixel::MatrixCoefficients::BT2020NonConstantLuminance) + } + Rav1dMatrixCoefficients::BT2020_CL => { + Ok(pixel::MatrixCoefficients::BT2020ConstantLuminance) + } + Rav1dMatrixCoefficients::SMPTE2085 => Ok(pixel::MatrixCoefficients::ST2085), + Rav1dMatrixCoefficients::CHROMAT_NCL => { + Ok(pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance) + } + Rav1dMatrixCoefficients::CHROMAT_CL => { + Ok(pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance) + } + Rav1dMatrixCoefficients::ICTCP => Ok(pixel::MatrixCoefficients::ICtCp), + Rav1dMatrixCoefficients(x) => { + if (15..=DAV1D_MC_RESERVED).contains(&(x as u32)) { + Ok(pixel::MatrixCoefficients::Unspecified) + } else { + Err(Rav1dError::InvalidArgument) + } + } + } + } +} + impl From for Dav1dMatrixCoefficients { fn from(value: Rav1dMatrixCoefficients) -> Self { value.to_dav1d() @@ -748,6 +859,21 @@ impl From for Dav1dChromaSamplePosition { } } +impl TryInto for Rav1dChromaSamplePosition { + type Error = Rav1dError; + + fn try_into(self) -> Result { + // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c + match self { + Rav1dChromaSamplePosition::Unknown | Rav1dChromaSamplePosition::Colocated => { + Ok(pixel::ChromaLocation::Center) + } + Rav1dChromaSamplePosition::Vertical => Ok(pixel::ChromaLocation::Left), + Rav1dChromaSamplePosition::_Reserved => Err(Rav1dError::InvalidArgument), + } + } +} + impl TryFrom for Rav1dChromaSamplePosition { type Error = (); diff --git a/src/rust_api.rs b/src/rust_api.rs index 9907be5dd..a8471e64a 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -36,7 +36,7 @@ pub mod dav1d { use std::fmt::{Debug, Formatter}; use std::ops::Deref; use std::sync::Arc; - use std::{fmt, mem}; + use std::{fmt, mem, slice}; pub use av_data::pixel; @@ -46,11 +46,6 @@ pub mod dav1d { pub use crate::include::dav1d::dav1d::{ Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, }; - use crate::include::dav1d::headers::{ - Rav1dChromaSamplePosition, Rav1dColorPrimaries, Rav1dMatrixCoefficients, - Rav1dTransferCharacteristics, DAV1D_COLOR_PRI_RESERVED, DAV1D_MC_RESERVED, - DAV1D_TRC_RESERVED, - }; pub use crate::include::dav1d::headers::{ Rav1dContentLightLevel as ContentLightLevel, Rav1dMasteringDisplay as MasteringDisplay, Rav1dPixelLayout as PixelLayout, @@ -407,6 +402,19 @@ pub mod dav1d { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct BitsPerComponent(pub u8); + impl TryFrom for BitsPerComponent { + type Error = Rav1dError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(BitsPerComponent(8)), + 1 => Ok(BitsPerComponent(10)), + 2 => Ok(BitsPerComponent(12)), + _ => Err(Rav1dError::InvalidArgument), + } + } + } + impl Picture { /// Stride in pixels of the `component` for the decoded frame. pub fn stride(&self, component: PlanarImageComponent) -> u32 { @@ -457,12 +465,7 @@ pub mod dav1d { /// /// Check [`Picture::bit_depth`] for the number of storage bits. pub fn bits_per_component(&self) -> Option { - match self.inner.pic.seq_hdr.as_ref().unwrap().hbd { - 0 => Some(BitsPerComponent(8)), - 1 => Some(BitsPerComponent(10)), - 2 => Some(BitsPerComponent(12)), - _ => None, - } + BitsPerComponent::try_from(self.inner.pic.seq_hdr.as_ref().unwrap().hbd).ok() } /// Width of the frame. @@ -510,103 +513,39 @@ pub mod dav1d { /// Chromaticity coordinates of the source colour primaries. pub fn color_primaries(&self) -> pixel::ColorPrimaries { - match self.inner.pic.seq_hdr.as_ref().unwrap().pri { - Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, - Rav1dColorPrimaries::UNKNOWN => pixel::ColorPrimaries::Unspecified, - Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, - Rav1dColorPrimaries::BT470BG => pixel::ColorPrimaries::BT470BG, - Rav1dColorPrimaries::BT601 => pixel::ColorPrimaries::BT470BG, - Rav1dColorPrimaries::SMPTE240 => pixel::ColorPrimaries::ST240M, - Rav1dColorPrimaries::FILM => pixel::ColorPrimaries::Film, - Rav1dColorPrimaries::BT2020 => pixel::ColorPrimaries::BT2020, - Rav1dColorPrimaries::XYZ => pixel::ColorPrimaries::ST428, - Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, - Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, - Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, - Rav1dColorPrimaries(x) => { - if (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(x as u32)) { - pixel::ColorPrimaries::Unspecified - } else { - unreachable!() - } - } - } + self.inner + .pic + .seq_hdr + .as_ref() + .unwrap() + .pri + .try_into() + .unwrap() } /// Transfer characteristics function. pub fn transfer_characteristic(&self) -> pixel::TransferCharacteristic { - match self.inner.pic.seq_hdr.as_ref().unwrap().trc { - Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, - Rav1dTransferCharacteristics::UNKNOWN => pixel::TransferCharacteristic::Unspecified, - Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, - Rav1dTransferCharacteristics::BT470BG => pixel::TransferCharacteristic::BT470BG, - Rav1dTransferCharacteristics::BT601 => pixel::TransferCharacteristic::ST170M, - Rav1dTransferCharacteristics::SMPTE240 => pixel::TransferCharacteristic::ST240M, - Rav1dTransferCharacteristics::LINEAR => pixel::TransferCharacteristic::Linear, - Rav1dTransferCharacteristics::LOG100 => { - pixel::TransferCharacteristic::Logarithmic100 - } - Rav1dTransferCharacteristics::LOG100_SQRT10 => { - pixel::TransferCharacteristic::Logarithmic316 - } - Rav1dTransferCharacteristics::IEC61966 => pixel::TransferCharacteristic::SRGB, - Rav1dTransferCharacteristics::BT1361 => pixel::TransferCharacteristic::BT1886, - Rav1dTransferCharacteristics::SRGB => pixel::TransferCharacteristic::SRGB, - Rav1dTransferCharacteristics::BT2020_10BIT => { - pixel::TransferCharacteristic::BT2020Ten - } - Rav1dTransferCharacteristics::BT2020_12BIT => { - pixel::TransferCharacteristic::BT2020Twelve - } - Rav1dTransferCharacteristics::SMPTE2084 => { - pixel::TransferCharacteristic::PerceptualQuantizer - } - Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, - Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, - Rav1dTransferCharacteristics(x) => { - if (19..=DAV1D_TRC_RESERVED).contains(&(x as u32)) { - pixel::TransferCharacteristic::Unspecified - } else { - unreachable!() - } - } - } + self.inner + .pic + .seq_hdr + .as_ref() + .unwrap() + .trc + .try_into() + .unwrap() } /// Matrix coefficients used in deriving luma and chroma signals from the /// green, blue and red or X, Y and Z primaries. pub fn matrix_coefficients(&self) -> pixel::MatrixCoefficients { - match self.inner.pic.seq_hdr.as_ref().unwrap().mtrx { - Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, - Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, - Rav1dMatrixCoefficients::UNKNOWN => pixel::MatrixCoefficients::Unspecified, - Rav1dMatrixCoefficients::FCC => pixel::MatrixCoefficients::BT470M, - Rav1dMatrixCoefficients::BT470BG => pixel::MatrixCoefficients::BT470BG, - Rav1dMatrixCoefficients::BT601 => pixel::MatrixCoefficients::BT470BG, - Rav1dMatrixCoefficients::SMPTE240 => pixel::MatrixCoefficients::ST240M, - Rav1dMatrixCoefficients::SMPTE_YCGCO => pixel::MatrixCoefficients::YCgCo, - Rav1dMatrixCoefficients::BT2020_NCL => { - pixel::MatrixCoefficients::BT2020NonConstantLuminance - } - Rav1dMatrixCoefficients::BT2020_CL => { - pixel::MatrixCoefficients::BT2020ConstantLuminance - } - Rav1dMatrixCoefficients::SMPTE2085 => pixel::MatrixCoefficients::ST2085, - Rav1dMatrixCoefficients::CHROMAT_NCL => { - pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance - } - Rav1dMatrixCoefficients::CHROMAT_CL => { - pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance - } - Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, - Rav1dMatrixCoefficients(x) => { - if (15..=DAV1D_MC_RESERVED).contains(&(x as u32)) { - pixel::MatrixCoefficients::Unspecified - } else { - unreachable!() - } - } - } + self.inner + .pic + .seq_hdr + .as_ref() + .unwrap() + .mtrx + .try_into() + .unwrap() } /// YUV color range. @@ -619,14 +558,14 @@ pub mod dav1d { /// Sample position for subsampled chroma. pub fn chroma_location(&self) -> pixel::ChromaLocation { - // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c - match self.inner.pic.seq_hdr.as_ref().unwrap().chr { - Rav1dChromaSamplePosition::Unknown | Rav1dChromaSamplePosition::Colocated => { - pixel::ChromaLocation::Center - } - Rav1dChromaSamplePosition::Vertical => pixel::ChromaLocation::Left, - Rav1dChromaSamplePosition::_Reserved => unreachable!(), - } + self.inner + .pic + .seq_hdr + .as_ref() + .unwrap() + .chr + .try_into() + .unwrap() } } From ab3e04bee46f1106c6ed852fbe4bd237f638eaa4 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 22:42:47 +0100 Subject: [PATCH 25/72] Removed panic in From impl for PlanarImageComponent --- src/rust_api.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index a8471e64a..2e9f945d9 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -351,13 +351,14 @@ pub mod dav1d { V, } - impl From for PlanarImageComponent { - fn from(index: usize) -> Self { + impl TryFrom for PlanarImageComponent { + type Error = Rav1dError; + fn try_from(index: usize) -> Result { match index { - 0 => PlanarImageComponent::Y, - 1 => PlanarImageComponent::U, - 2 => PlanarImageComponent::V, - _ => panic!("Invalid YUV index: {}", index), + 0 => Ok(PlanarImageComponent::Y), + 1 => Ok(PlanarImageComponent::U), + 2 => Ok(PlanarImageComponent::V), + _ => Err(Rav1dError::InvalidArgument), } } } From 8b43733d3d9e54dc5b01d86e344628b9bc09ac80 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 22:46:16 +0100 Subject: [PATCH 26/72] Added chrominance and luminance comments --- src/rust_api.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 2e9f945d9..55022e0e8 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -343,11 +343,11 @@ pub mod dav1d { /// Frame component. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum PlanarImageComponent { - /// Y component. + /// Y component (Luminance). Y, - /// U component. + /// U component (Chrominance). U, - /// V component. + /// V component (Chrominance). V, } From ff67750ba351dc758a1430e4462fa7cf5c40e184 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 8 Jul 2025 23:23:19 +0100 Subject: [PATCH 27/72] Added check if stride is negative --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 55022e0e8..5cdfe6bd4 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -423,7 +423,7 @@ pub mod dav1d { PlanarImageComponent::Y => 0, _ => 1, }; - self.inner.pic.stride[s] as u32 + self.inner.pic.stride[s].try_into().unwrap() } /// Raw pointer to the data of the `component` for the decoded frame. From f07d83b224ec100532e7faf8f484f45f31fe6d3c Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Wed, 9 Jul 2025 10:28:58 +0100 Subject: [PATCH 28/72] Make height and width casting more robust on Picture --- src/rust_api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 5cdfe6bd4..d10910c64 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -471,12 +471,12 @@ pub mod dav1d { /// Width of the frame. pub fn width(&self) -> u32 { - self.inner.pic.p.w as u32 + self.inner.pic.p.w.try_into().unwrap() } /// Height of the frame. pub fn height(&self) -> u32 { - self.inner.pic.p.h as u32 + self.inner.pic.p.h.try_into().unwrap() } /// Pixel layout of the frame. From 4255b38b6c1b3a0b331152908d4df584ad7a4620 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 6 Jul 2025 16:00:11 +0100 Subject: [PATCH 29/72] Implement Rust API --- src/rust_api.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index d10910c64..fe2a71f6a 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -43,6 +43,7 @@ pub mod dav1d { use crate::c_arc::CArc; use crate::c_box::CBox; use crate::error::Rav1dError; + use crate::in_range::InRange; pub use crate::include::dav1d::dav1d::{ Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, }; @@ -75,19 +76,20 @@ pub mod dav1d { } pub fn set_n_threads(&mut self, n_threads: u32) { - self.rav1d_settings.n_threads = n_threads; + self.rav1d_settings.n_threads = InRange::new(n_threads.try_into().unwrap()).unwrap(); } pub fn get_n_threads(&self) -> u32 { - self.rav1d_settings.n_threads + self.rav1d_settings.n_threads.get() as u32 } pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { - self.rav1d_settings.max_frame_delay = max_frame_delay; + self.rav1d_settings.max_frame_delay = + InRange::new(max_frame_delay.try_into().unwrap()).unwrap(); } pub fn get_max_frame_delay(&self) -> u32 { - self.rav1d_settings.max_frame_delay + self.rav1d_settings.max_frame_delay.get() as u32 } pub fn set_apply_grain(&mut self, apply_grain: bool) { @@ -99,11 +101,12 @@ pub mod dav1d { } pub fn set_operating_point(&mut self, operating_point: u8) { - self.rav1d_settings.operating_point = operating_point; + self.rav1d_settings.operating_point = + InRange::new(operating_point.try_into().unwrap()).unwrap(); } pub fn get_operating_point(&self) -> u8 { - self.rav1d_settings.operating_point + self.rav1d_settings.operating_point.get() } pub fn set_all_layers(&mut self, all_layers: bool) { @@ -169,8 +172,8 @@ pub mod dav1d { rav1d_open(&settings.rav1d_settings).map(|ctx| Decoder { ctx, pending_data: None, - n_threads: settings.rav1d_settings.n_threads, - max_frame_delay: settings.rav1d_settings.max_frame_delay, + n_threads: settings.rav1d_settings.n_threads.get() as u32, + max_frame_delay: settings.rav1d_settings.max_frame_delay.get() as u32, }) } @@ -231,7 +234,7 @@ pub mod dav1d { let ret = rav1d_send_data(&self.ctx, &mut data); if let Err(err) = ret { let ret = err; - if matches!(ret, Rav1dError::Again) { + if matches!(ret, Rav1dError::TryAgain) { self.pending_data = Some(data); } else { let _ = mem::take(&mut data); @@ -242,7 +245,7 @@ pub mod dav1d { if data.data.as_ref().is_some_and(|d| d.len() > 0) { self.pending_data = Some(data); - return Err(Rav1dError::Again); + return Err(Rav1dError::TryAgain); } Ok(()) @@ -267,7 +270,7 @@ pub mod dav1d { if let Err(err) = ret { let ret = err; - if matches!(ret, Rav1dError::Again) { + if matches!(ret, Rav1dError::TryAgain) { self.pending_data = Some(data); } else { let _ = mem::take(&mut data); @@ -278,7 +281,7 @@ pub mod dav1d { if data.data.as_ref().is_some_and(|d| d.len() > 0) { self.pending_data = Some(data); - return Err(Rav1dError::Again); + return Err(Rav1dError::TryAgain); } Ok(()) @@ -311,8 +314,8 @@ pub mod dav1d { // The only fields this actually needs from Rav1dSettings are n_threads and max_frame_delay so we just pass these in directly rav1d_get_frame_delay(&Rav1dSettings { - n_threads: self.n_threads, - max_frame_delay: self.max_frame_delay, + n_threads: InRange::new(self.n_threads.try_into().unwrap()).unwrap(), + max_frame_delay: InRange::new(self.max_frame_delay.try_into().unwrap()).unwrap(), ..Default::default() }) .unwrap() as u32 From 3b20ca1ed6b6840f3b9b09b619028f9f09c57622 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 15 Jul 2025 10:43:03 +0100 Subject: [PATCH 30/72] Fixed CI error --- src/include/dav1d/common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/dav1d/common.rs b/src/include/dav1d/common.rs index 9e9f46b72..ddfab652f 100644 --- a/src/include/dav1d/common.rs +++ b/src/include/dav1d/common.rs @@ -74,7 +74,7 @@ impl From for Rav1dDataProps { Self { timestamp, duration, - offset, + offset: offset.into(), size, user_data: user_data.into(), } @@ -93,7 +93,7 @@ impl From for Dav1dDataProps { Self { timestamp, duration, - offset, + offset: offset.try_into().unwrap(), size, user_data: user_data.into(), } From 1101ea7fc1a8d196bb18712cd103364708fa00ce Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 15 Jul 2025 10:46:43 +0100 Subject: [PATCH 31/72] Added safety comment for raw slice --- src/rust_api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rust_api.rs b/src/rust_api.rs index fe2a71f6a..8686e3c09 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -385,6 +385,7 @@ pub mod dav1d { impl AsRef<[u8]> for Plane { fn as_ref(&self) -> &[u8] { let (stride, height) = self.0.plane_data_geometry(self.1); + // SAFETY: both stride and height can't be negative, the `stride` and `height` methods panic if they are so there's no undefined behaviour unsafe { slice::from_raw_parts( self.0.plane_data_ptr(self.1) as *const u8, From 89aa570c848c72afa417eab49f6e5227370b18d2 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:12:42 +0100 Subject: [PATCH 32/72] Remove Ok's on conversion functions --- src/include/dav1d/headers.rs | 114 +++++++++++++++++------------------ 1 file changed, 55 insertions(+), 59 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 788a880a0..6fecf1a28 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -571,27 +571,27 @@ impl TryInto for Rav1dColorPrimaries { type Error = Rav1dError; fn try_into(self) -> Result { - match self { - Rav1dColorPrimaries::BT709 => Ok(pixel::ColorPrimaries::BT709), - Rav1dColorPrimaries::UNKNOWN => Ok(pixel::ColorPrimaries::Unspecified), - Rav1dColorPrimaries::BT470M => Ok(pixel::ColorPrimaries::BT470M), - Rav1dColorPrimaries::BT470BG => Ok(pixel::ColorPrimaries::BT470BG), - Rav1dColorPrimaries::BT601 => Ok(pixel::ColorPrimaries::BT470BG), - Rav1dColorPrimaries::SMPTE240 => Ok(pixel::ColorPrimaries::ST240M), - Rav1dColorPrimaries::FILM => Ok(pixel::ColorPrimaries::Film), - Rav1dColorPrimaries::BT2020 => Ok(pixel::ColorPrimaries::BT2020), - Rav1dColorPrimaries::XYZ => Ok(pixel::ColorPrimaries::ST428), - Rav1dColorPrimaries::SMPTE431 => Ok(pixel::ColorPrimaries::P3DCI), - Rav1dColorPrimaries::SMPTE432 => Ok(pixel::ColorPrimaries::P3Display), - Rav1dColorPrimaries::EBU3213 => Ok(pixel::ColorPrimaries::Tech3213), + Ok(match self { + Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, + Rav1dColorPrimaries::UNKNOWN => pixel::ColorPrimaries::Unspecified, + Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, + Rav1dColorPrimaries::BT470BG => pixel::ColorPrimaries::BT470BG, + Rav1dColorPrimaries::BT601 => pixel::ColorPrimaries::BT470BG, + Rav1dColorPrimaries::SMPTE240 => pixel::ColorPrimaries::ST240M, + Rav1dColorPrimaries::FILM => pixel::ColorPrimaries::Film, + Rav1dColorPrimaries::BT2020 => pixel::ColorPrimaries::BT2020, + Rav1dColorPrimaries::XYZ => pixel::ColorPrimaries::ST428, + Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, + Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, + Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, Rav1dColorPrimaries(x) => { if (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(x as u32)) { - Ok(pixel::ColorPrimaries::Unspecified) + pixel::ColorPrimaries::Unspecified } else { - Err(Rav1dError::InvalidArgument) + return Err(Rav1dError::InvalidArgument); } } - } + }) } } @@ -680,42 +680,38 @@ impl TryInto for Rav1dTransferCharacteristics { type Error = Rav1dError; fn try_into(self) -> Result { - match self { - Rav1dTransferCharacteristics::BT709 => Ok(pixel::TransferCharacteristic::BT1886), - Rav1dTransferCharacteristics::UNKNOWN => Ok(pixel::TransferCharacteristic::Unspecified), - Rav1dTransferCharacteristics::BT470M => Ok(pixel::TransferCharacteristic::BT470M), - Rav1dTransferCharacteristics::BT470BG => Ok(pixel::TransferCharacteristic::BT470BG), - Rav1dTransferCharacteristics::BT601 => Ok(pixel::TransferCharacteristic::ST170M), - Rav1dTransferCharacteristics::SMPTE240 => Ok(pixel::TransferCharacteristic::ST240M), - Rav1dTransferCharacteristics::LINEAR => Ok(pixel::TransferCharacteristic::Linear), - Rav1dTransferCharacteristics::LOG100 => { - Ok(pixel::TransferCharacteristic::Logarithmic100) - } + Ok(match self { + Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, + Rav1dTransferCharacteristics::UNKNOWN => pixel::TransferCharacteristic::Unspecified, + Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, + Rav1dTransferCharacteristics::BT470BG => pixel::TransferCharacteristic::BT470BG, + Rav1dTransferCharacteristics::BT601 => pixel::TransferCharacteristic::ST170M, + Rav1dTransferCharacteristics::SMPTE240 => pixel::TransferCharacteristic::ST240M, + Rav1dTransferCharacteristics::LINEAR => pixel::TransferCharacteristic::Linear, + Rav1dTransferCharacteristics::LOG100 => pixel::TransferCharacteristic::Logarithmic100, Rav1dTransferCharacteristics::LOG100_SQRT10 => { - Ok(pixel::TransferCharacteristic::Logarithmic316) - } - Rav1dTransferCharacteristics::IEC61966 => Ok(pixel::TransferCharacteristic::SRGB), - Rav1dTransferCharacteristics::BT1361 => Ok(pixel::TransferCharacteristic::BT1886), - Rav1dTransferCharacteristics::SRGB => Ok(pixel::TransferCharacteristic::SRGB), - Rav1dTransferCharacteristics::BT2020_10BIT => { - Ok(pixel::TransferCharacteristic::BT2020Ten) + pixel::TransferCharacteristic::Logarithmic316 } + Rav1dTransferCharacteristics::IEC61966 => pixel::TransferCharacteristic::SRGB, + Rav1dTransferCharacteristics::BT1361 => pixel::TransferCharacteristic::BT1886, + Rav1dTransferCharacteristics::SRGB => pixel::TransferCharacteristic::SRGB, + Rav1dTransferCharacteristics::BT2020_10BIT => pixel::TransferCharacteristic::BT2020Ten, Rav1dTransferCharacteristics::BT2020_12BIT => { - Ok(pixel::TransferCharacteristic::BT2020Twelve) + pixel::TransferCharacteristic::BT2020Twelve } Rav1dTransferCharacteristics::SMPTE2084 => { - Ok(pixel::TransferCharacteristic::PerceptualQuantizer) + pixel::TransferCharacteristic::PerceptualQuantizer } - Rav1dTransferCharacteristics::SMPTE428 => Ok(pixel::TransferCharacteristic::ST428), - Rav1dTransferCharacteristics::HLG => Ok(pixel::TransferCharacteristic::HybridLogGamma), + Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, + Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, Rav1dTransferCharacteristics(x) => { if (19..=DAV1D_TRC_RESERVED).contains(&(x as u32)) { - Ok(pixel::TransferCharacteristic::Unspecified) + pixel::TransferCharacteristic::Unspecified } else { - Err(Rav1dError::InvalidArgument) + return Err(Rav1dError::InvalidArgument); } } - } + }) } } @@ -786,37 +782,37 @@ impl TryInto for Rav1dMatrixCoefficients { type Error = Rav1dError; fn try_into(self) -> Result { - match self { - Rav1dMatrixCoefficients::IDENTITY => Ok(pixel::MatrixCoefficients::Identity), - Rav1dMatrixCoefficients::BT709 => Ok(pixel::MatrixCoefficients::BT709), - Rav1dMatrixCoefficients::UNKNOWN => Ok(pixel::MatrixCoefficients::Unspecified), - Rav1dMatrixCoefficients::FCC => Ok(pixel::MatrixCoefficients::BT470M), - Rav1dMatrixCoefficients::BT470BG => Ok(pixel::MatrixCoefficients::BT470BG), - Rav1dMatrixCoefficients::BT601 => Ok(pixel::MatrixCoefficients::BT470BG), - Rav1dMatrixCoefficients::SMPTE240 => Ok(pixel::MatrixCoefficients::ST240M), - Rav1dMatrixCoefficients::SMPTE_YCGCO => Ok(pixel::MatrixCoefficients::YCgCo), + Ok(match self { + Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, + Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, + Rav1dMatrixCoefficients::UNKNOWN => pixel::MatrixCoefficients::Unspecified, + Rav1dMatrixCoefficients::FCC => pixel::MatrixCoefficients::BT470M, + Rav1dMatrixCoefficients::BT470BG => pixel::MatrixCoefficients::BT470BG, + Rav1dMatrixCoefficients::BT601 => pixel::MatrixCoefficients::BT470BG, + Rav1dMatrixCoefficients::SMPTE240 => pixel::MatrixCoefficients::ST240M, + Rav1dMatrixCoefficients::SMPTE_YCGCO => pixel::MatrixCoefficients::YCgCo, Rav1dMatrixCoefficients::BT2020_NCL => { - Ok(pixel::MatrixCoefficients::BT2020NonConstantLuminance) + pixel::MatrixCoefficients::BT2020NonConstantLuminance } Rav1dMatrixCoefficients::BT2020_CL => { - Ok(pixel::MatrixCoefficients::BT2020ConstantLuminance) + pixel::MatrixCoefficients::BT2020ConstantLuminance } - Rav1dMatrixCoefficients::SMPTE2085 => Ok(pixel::MatrixCoefficients::ST2085), + Rav1dMatrixCoefficients::SMPTE2085 => pixel::MatrixCoefficients::ST2085, Rav1dMatrixCoefficients::CHROMAT_NCL => { - Ok(pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance) + pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance } Rav1dMatrixCoefficients::CHROMAT_CL => { - Ok(pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance) + pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance } - Rav1dMatrixCoefficients::ICTCP => Ok(pixel::MatrixCoefficients::ICtCp), + Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, Rav1dMatrixCoefficients(x) => { if (15..=DAV1D_MC_RESERVED).contains(&(x as u32)) { - Ok(pixel::MatrixCoefficients::Unspecified) + pixel::MatrixCoefficients::Unspecified } else { - Err(Rav1dError::InvalidArgument) + return Err(Rav1dError::InvalidArgument); } } - } + }) } } From a4d03092ae2ed5dfd7f14172983f47807f42fcc8 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:29:58 +0100 Subject: [PATCH 33/72] Export Rav1dError correctly for the rust api --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 98d750c29..46bcab877 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,8 +160,7 @@ use crate::c_arc::RawArc; use crate::c_box::FnFree; use crate::cpu::{rav1d_init_cpu, rav1d_num_logical_processors}; use crate::decode::rav1d_decode_frame_exit; -pub use crate::error::Dav1dResult; -use crate::error::{Rav1dError, Rav1dResult}; +pub use crate::error::{Dav1dResult, Rav1dError, Rav1dResult}; use crate::extensions::OptionError as _; use crate::in_range::InRange; #[cfg(feature = "bitdepth_16")] From 12f5743e1cc9cca337bb5bce7ac80d9d1e53e897 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:38:08 +0100 Subject: [PATCH 34/72] Clean up casts --- src/rust_api.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 8686e3c09..b42228f6d 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -101,8 +101,7 @@ pub mod dav1d { } pub fn set_operating_point(&mut self, operating_point: u8) { - self.rav1d_settings.operating_point = - InRange::new(operating_point.try_into().unwrap()).unwrap(); + self.rav1d_settings.operating_point = InRange::new(operating_point).unwrap(); } pub fn get_operating_point(&self) -> u8 { @@ -463,14 +462,14 @@ pub mod dav1d { /// /// Check [`Picture::bits_per_component`] for the number of bits that are used. pub fn bit_depth(&self) -> usize { - self.inner.pic.p.bpc as usize + self.inner.pic.p.bpc.into() } /// Bits used per component of the plane data. /// /// Check [`Picture::bit_depth`] for the number of storage bits. pub fn bits_per_component(&self) -> Option { - BitsPerComponent::try_from(self.inner.pic.seq_hdr.as_ref().unwrap().hbd).ok() + self.inner.pic.seq_hdr.as_ref().unwrap().hbd.try_into().ok() } /// Width of the frame. From a9dd1dbeef4fd985714b0b1336f7c71b2ae1a0b8 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:40:13 +0100 Subject: [PATCH 35/72] Remove unnecessary declarations of 'ret' --- src/rust_api.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index b42228f6d..bb9c68c3b 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -230,16 +230,14 @@ pub mod dav1d { data.m.duration = duration; } - let ret = rav1d_send_data(&self.ctx, &mut data); - if let Err(err) = ret { - let ret = err; - if matches!(ret, Rav1dError::TryAgain) { + if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { + if matches!(err, Rav1dError::TryAgain) { self.pending_data = Some(data); } else { let _ = mem::take(&mut data); } - return Err(ret); + return Err(err); } if data.data.as_ref().is_some_and(|d| d.len() > 0) { @@ -265,17 +263,14 @@ pub mod dav1d { Some(data) => data, }; - let ret = rav1d_send_data(&self.ctx, &mut data); - if let Err(err) = ret { - let ret = err; - - if matches!(ret, Rav1dError::TryAgain) { + if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { + if matches!(err, Rav1dError::TryAgain) { self.pending_data = Some(data); } else { let _ = mem::take(&mut data); } - return Err(ret); + return Err(err); } if data.data.as_ref().is_some_and(|d| d.len() > 0) { From d6239de94698fa6c03d545b0b47d60bc0eca2526 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:43:17 +0100 Subject: [PATCH 36/72] Remove unnecessary InnerPicture struct --- src/rust_api.rs | 59 ++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index bb9c68c3b..4ad58778a 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -296,9 +296,8 @@ pub mod dav1d { if let Err(err) = ret { Err(err) } else { - let inner = InnerPicture { pic }; Ok(Picture { - inner: Arc::new(inner), + inner: Arc::new(pic), }) } } @@ -327,14 +326,10 @@ pub mod dav1d { static_assertions::assert_impl_all!(Decoder: Send, Sync); - struct InnerPicture { - pub pic: Rav1dPicture, - } - /// A decoded frame. #[derive(Clone)] pub struct Picture { - inner: Arc, + inner: Arc, } /// Frame component. @@ -421,13 +416,13 @@ pub mod dav1d { PlanarImageComponent::Y => 0, _ => 1, }; - self.inner.pic.stride[s].try_into().unwrap() + self.inner.stride[s].try_into().unwrap() } /// Raw pointer to the data of the `component` for the decoded frame. pub fn plane_data_ptr(&self, component: PlanarImageComponent) -> *mut c_void { let index: usize = component.into(); - self.inner.pic.data.as_ref().unwrap().data[index] + self.inner.data.as_ref().unwrap().data[index] .as_byte_mut_ptr() .cast() } @@ -457,36 +452,36 @@ pub mod dav1d { /// /// Check [`Picture::bits_per_component`] for the number of bits that are used. pub fn bit_depth(&self) -> usize { - self.inner.pic.p.bpc.into() + self.inner.p.bpc.into() } /// Bits used per component of the plane data. /// /// Check [`Picture::bit_depth`] for the number of storage bits. pub fn bits_per_component(&self) -> Option { - self.inner.pic.seq_hdr.as_ref().unwrap().hbd.try_into().ok() + self.inner.seq_hdr.as_ref().unwrap().hbd.try_into().ok() } /// Width of the frame. pub fn width(&self) -> u32 { - self.inner.pic.p.w.try_into().unwrap() + self.inner.p.w.try_into().unwrap() } /// Height of the frame. pub fn height(&self) -> u32 { - self.inner.pic.p.h.try_into().unwrap() + self.inner.p.h.try_into().unwrap() } /// Pixel layout of the frame. pub fn pixel_layout(&self) -> PixelLayout { - self.inner.pic.p.layout + self.inner.p.layout } /// Timestamp of the frame. /// /// This is the same timestamp as the one provided to [`Decoder::send_data`]. pub fn timestamp(&self) -> Option { - let ts = self.inner.pic.m.timestamp; + let ts = self.inner.m.timestamp; if ts == i64::MIN { None } else { @@ -499,7 +494,7 @@ pub mod dav1d { /// This is the same duration as the one provided to [`Decoder::send_data`] or `0` if none was /// provided. pub fn duration(&self) -> i64 { - self.inner.pic.m.duration + self.inner.m.duration } /// Offset of the frame. @@ -507,38 +502,23 @@ pub mod dav1d { /// This is the same offset as the one provided to [`Decoder::send_data`] or `-1` if none was /// provided. pub fn offset(&self) -> i64 { - self.inner.pic.m.offset as i64 + self.inner.m.offset as i64 } /// Chromaticity coordinates of the source colour primaries. pub fn color_primaries(&self) -> pixel::ColorPrimaries { - self.inner - .pic - .seq_hdr - .as_ref() - .unwrap() - .pri - .try_into() - .unwrap() + self.inner.seq_hdr.as_ref().unwrap().pri.try_into().unwrap() } /// Transfer characteristics function. pub fn transfer_characteristic(&self) -> pixel::TransferCharacteristic { - self.inner - .pic - .seq_hdr - .as_ref() - .unwrap() - .trc - .try_into() - .unwrap() + self.inner.seq_hdr.as_ref().unwrap().trc.try_into().unwrap() } /// Matrix coefficients used in deriving luma and chroma signals from the /// green, blue and red or X, Y and Z primaries. pub fn matrix_coefficients(&self) -> pixel::MatrixCoefficients { self.inner - .pic .seq_hdr .as_ref() .unwrap() @@ -549,7 +529,7 @@ pub mod dav1d { /// YUV color range. pub fn color_range(&self) -> pixel::YUVRange { - match self.inner.pic.seq_hdr.as_ref().unwrap().color_range { + match self.inner.seq_hdr.as_ref().unwrap().color_range { 0 => pixel::YUVRange::Limited, _ => pixel::YUVRange::Full, } @@ -557,14 +537,7 @@ pub mod dav1d { /// Sample position for subsampled chroma. pub fn chroma_location(&self) -> pixel::ChromaLocation { - self.inner - .pic - .seq_hdr - .as_ref() - .unwrap() - .chr - .try_into() - .unwrap() + self.inner.seq_hdr.as_ref().unwrap().chr.try_into().unwrap() } } From ff711cf47fd31c09427d847a8fa13574b5cd77f4 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:46:00 +0100 Subject: [PATCH 37/72] Rename Settings.rav1_settings to Settings.inner --- src/rust_api.rs | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 4ad58778a..a4aef412d 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -64,7 +64,7 @@ pub mod dav1d { /// See documentation for native `Dav1dSettings` struct. #[derive(Default)] pub struct Settings { - pub(crate) rav1d_settings: Rav1dSettings, + pub(crate) inner: Rav1dSettings, } static_assertions::assert_impl_all!(Settings: Send, Sync); @@ -76,84 +76,83 @@ pub mod dav1d { } pub fn set_n_threads(&mut self, n_threads: u32) { - self.rav1d_settings.n_threads = InRange::new(n_threads.try_into().unwrap()).unwrap(); + self.inner.n_threads = InRange::new(n_threads.try_into().unwrap()).unwrap(); } pub fn get_n_threads(&self) -> u32 { - self.rav1d_settings.n_threads.get() as u32 + self.inner.n_threads.get() as u32 } pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { - self.rav1d_settings.max_frame_delay = - InRange::new(max_frame_delay.try_into().unwrap()).unwrap(); + self.inner.max_frame_delay = InRange::new(max_frame_delay.try_into().unwrap()).unwrap(); } pub fn get_max_frame_delay(&self) -> u32 { - self.rav1d_settings.max_frame_delay.get() as u32 + self.inner.max_frame_delay.get() as u32 } pub fn set_apply_grain(&mut self, apply_grain: bool) { - self.rav1d_settings.apply_grain = apply_grain; + self.inner.apply_grain = apply_grain; } pub fn get_apply_grain(&self) -> bool { - self.rav1d_settings.apply_grain + self.inner.apply_grain } pub fn set_operating_point(&mut self, operating_point: u8) { - self.rav1d_settings.operating_point = InRange::new(operating_point).unwrap(); + self.inner.operating_point = InRange::new(operating_point).unwrap(); } pub fn get_operating_point(&self) -> u8 { - self.rav1d_settings.operating_point.get() + self.inner.operating_point.get() } pub fn set_all_layers(&mut self, all_layers: bool) { - self.rav1d_settings.all_layers = all_layers; + self.inner.all_layers = all_layers; } pub fn get_all_layers(&self) -> bool { - self.rav1d_settings.all_layers + self.inner.all_layers } pub fn set_frame_size_limit(&mut self, frame_size_limit: u32) { - self.rav1d_settings.frame_size_limit = frame_size_limit; + self.inner.frame_size_limit = frame_size_limit; } pub fn get_frame_size_limit(&self) -> u32 { - self.rav1d_settings.frame_size_limit + self.inner.frame_size_limit } pub fn set_strict_std_compliance(&mut self, strict_std_compliance: bool) { - self.rav1d_settings.strict_std_compliance = strict_std_compliance; + self.inner.strict_std_compliance = strict_std_compliance; } pub fn get_strict_std_compliance(&self) -> bool { - self.rav1d_settings.strict_std_compliance + self.inner.strict_std_compliance } pub fn set_output_invisible_frames(&mut self, output_invisible_frames: bool) { - self.rav1d_settings.output_invisible_frames = output_invisible_frames; + self.inner.output_invisible_frames = output_invisible_frames; } pub fn get_output_invisible_frames(&self) -> bool { - self.rav1d_settings.output_invisible_frames + self.inner.output_invisible_frames } pub fn set_inloop_filters(&mut self, inloop_filters: InloopFilterType) { - self.rav1d_settings.inloop_filters = inloop_filters; + self.inner.inloop_filters = inloop_filters; } pub fn get_inloop_filters(&self) -> InloopFilterType { - self.rav1d_settings.inloop_filters + self.inner.inloop_filters } pub fn set_decode_frame_type(&mut self, decode_frame_type: DecodeFrameType) { - self.rav1d_settings.decode_frame_type = decode_frame_type; + self.inner.decode_frame_type = decode_frame_type; } pub fn get_decode_frame_type(&self) -> DecodeFrameType { - self.rav1d_settings.decode_frame_type + self.inner.decode_frame_type } } @@ -168,11 +167,11 @@ pub mod dav1d { impl Decoder { /// Creates a new [`Decoder`] instance with given [`Settings`]. pub fn with_settings(settings: &Settings) -> Result { - rav1d_open(&settings.rav1d_settings).map(|ctx| Decoder { + rav1d_open(&settings.inner).map(|ctx| Decoder { ctx, pending_data: None, - n_threads: settings.rav1d_settings.n_threads.get() as u32, - max_frame_delay: settings.rav1d_settings.max_frame_delay.get() as u32, + n_threads: settings.inner.n_threads.get() as u32, + max_frame_delay: settings.inner.max_frame_delay.get() as u32, }) } From a2da46e4f73c2f9c68289f62ad4bab0530116fd7 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 20 Jul 2025 14:49:09 +0100 Subject: [PATCH 38/72] Make n_threads and max_frame_delay on Decoder into InRange types --- src/rust_api.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index a4aef412d..ad8be8b84 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -160,8 +160,8 @@ pub mod dav1d { pub struct Decoder { ctx: Arc, pending_data: Option, - n_threads: u32, - max_frame_delay: u32, + n_threads: InRange, + max_frame_delay: InRange, } impl Decoder { @@ -170,8 +170,8 @@ pub mod dav1d { rav1d_open(&settings.inner).map(|ctx| Decoder { ctx, pending_data: None, - n_threads: settings.inner.n_threads.get() as u32, - max_frame_delay: settings.inner.max_frame_delay.get() as u32, + n_threads: settings.inner.n_threads, + max_frame_delay: settings.inner.max_frame_delay, }) } @@ -306,8 +306,8 @@ pub mod dav1d { // The only fields this actually needs from Rav1dSettings are n_threads and max_frame_delay so we just pass these in directly rav1d_get_frame_delay(&Rav1dSettings { - n_threads: InRange::new(self.n_threads.try_into().unwrap()).unwrap(), - max_frame_delay: InRange::new(self.max_frame_delay.try_into().unwrap()).unwrap(), + n_threads: self.n_threads, + max_frame_delay: self.max_frame_delay, ..Default::default() }) .unwrap() as u32 From e13f288ca71c097d238d692db1855b84162dded3 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Thu, 24 Jul 2025 19:42:11 +0100 Subject: [PATCH 39/72] Remove unneccesary 'david' module in rust_api --- src/rust_api.rs | 930 ++++++++++++++++++++++++------------------------ 1 file changed, 460 insertions(+), 470 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index ad8be8b84..ecc0b47d2 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -1,563 +1,553 @@ -/// Public Rust API. -/// -/// This is more or less the same API as , -/// and is indeed a fork of that work. -pub mod dav1d { - // This whole module was originally copied from https://github.com/rust-av/dav1d-rs/ - // (specifically https://github.com/rust-av/dav1d-rs/blob/94b1deaa1e25bf29c77bb5cc8a08ddaf7663eede/src/lib.rs) - // with some modifications. - // `dav1d-rs` is under the MIT license, replicated here: - - // MIT License - // - // Copyright (c) 2018 Luca Barbato - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal - // in the Software without restriction, including without limitation the rights - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - // copies of the Software, and to permit persons to whom the Software is - // furnished to do so, subject to the following conditions: - // - // The above copyright notice and this permission notice shall be included in all - // copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - // SOFTWARE. - - // The code below provides a safe API around the rav1d C FFI layer. - - use std::ffi::c_void; - use std::fmt::{Debug, Formatter}; - use std::ops::Deref; - use std::sync::Arc; - use std::{fmt, mem, slice}; - - pub use av_data::pixel; - - use crate::c_arc::CArc; - use crate::c_box::CBox; - use crate::error::Rav1dError; - use crate::in_range::InRange; - pub use crate::include::dav1d::dav1d::{ - Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, - }; - pub use crate::include::dav1d::headers::{ - Rav1dContentLightLevel as ContentLightLevel, Rav1dMasteringDisplay as MasteringDisplay, - Rav1dPixelLayout as PixelLayout, - }; - use crate::include::dav1d::picture::Rav1dPicture; - pub use crate::include::dav1d::picture::RAV1D_PICTURE_ALIGNMENT as PICTURE_ALIGNMENT; - use crate::internal::Rav1dContext; - use crate::pixels::Pixels; - use crate::{ - rav1d_close, rav1d_flush, rav1d_get_frame_delay, rav1d_get_picture, rav1d_open, - rav1d_send_data, Rav1dData, Rav1dSettings, - }; - - /// Settings for creating a new [`Decoder`] instance. - /// See documentation for native `Dav1dSettings` struct. - #[derive(Default)] - pub struct Settings { - pub(crate) inner: Rav1dSettings, - } - - static_assertions::assert_impl_all!(Settings: Send, Sync); - - impl Settings { - /// Creates a new [`Settings`] instance with default settings. - pub fn new() -> Self { - Self::default() - } +// This whole module was originally copied from https://github.com/rust-av/dav1d-rs/ +// (specifically https://github.com/rust-av/dav1d-rs/blob/94b1deaa1e25bf29c77bb5cc8a08ddaf7663eede/src/lib.rs) +// with some modifications. +// `dav1d-rs` is under the MIT license, replicated here: + +// MIT License +// +// Copyright (c) 2018 Luca Barbato +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +use std::ffi::c_void; +use std::fmt::{Debug, Formatter}; +use std::ops::Deref; +use std::sync::Arc; +use std::{fmt, mem, slice}; + +pub use av_data::pixel; + +use crate::c_arc::CArc; +use crate::c_box::CBox; +use crate::error::Rav1dError; +use crate::in_range::InRange; +pub use crate::include::dav1d::dav1d::{ + Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, +}; +pub use crate::include::dav1d::headers::{ + Rav1dContentLightLevel as ContentLightLevel, Rav1dMasteringDisplay as MasteringDisplay, + Rav1dPixelLayout as PixelLayout, +}; +use crate::include::dav1d::picture::Rav1dPicture; +pub use crate::include::dav1d::picture::RAV1D_PICTURE_ALIGNMENT as PICTURE_ALIGNMENT; +use crate::internal::Rav1dContext; +use crate::pixels::Pixels; +use crate::{ + rav1d_close, rav1d_flush, rav1d_get_frame_delay, rav1d_get_picture, rav1d_open, + rav1d_send_data, Rav1dData, Rav1dSettings, +}; + +/// Settings for creating a new [`Decoder`] instance. +/// See documentation for native `Dav1dSettings` struct. +#[derive(Default)] +pub struct Settings { + pub(crate) inner: Rav1dSettings, +} - pub fn set_n_threads(&mut self, n_threads: u32) { - self.inner.n_threads = InRange::new(n_threads.try_into().unwrap()).unwrap(); - } +static_assertions::assert_impl_all!(Settings: Send, Sync); - pub fn get_n_threads(&self) -> u32 { - self.inner.n_threads.get() as u32 - } - - pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { - self.inner.max_frame_delay = InRange::new(max_frame_delay.try_into().unwrap()).unwrap(); - } +impl Settings { + /// Creates a new [`Settings`] instance with default settings. + pub fn new() -> Self { + Self::default() + } - pub fn get_max_frame_delay(&self) -> u32 { - self.inner.max_frame_delay.get() as u32 - } + pub fn set_n_threads(&mut self, n_threads: u32) { + self.inner.n_threads = InRange::new(n_threads.try_into().unwrap()).unwrap(); + } - pub fn set_apply_grain(&mut self, apply_grain: bool) { - self.inner.apply_grain = apply_grain; - } + pub fn get_n_threads(&self) -> u32 { + self.inner.n_threads.get() as u32 + } - pub fn get_apply_grain(&self) -> bool { - self.inner.apply_grain - } + pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { + self.inner.max_frame_delay = InRange::new(max_frame_delay.try_into().unwrap()).unwrap(); + } - pub fn set_operating_point(&mut self, operating_point: u8) { - self.inner.operating_point = InRange::new(operating_point).unwrap(); - } + pub fn get_max_frame_delay(&self) -> u32 { + self.inner.max_frame_delay.get() as u32 + } - pub fn get_operating_point(&self) -> u8 { - self.inner.operating_point.get() - } + pub fn set_apply_grain(&mut self, apply_grain: bool) { + self.inner.apply_grain = apply_grain; + } - pub fn set_all_layers(&mut self, all_layers: bool) { - self.inner.all_layers = all_layers; - } + pub fn get_apply_grain(&self) -> bool { + self.inner.apply_grain + } - pub fn get_all_layers(&self) -> bool { - self.inner.all_layers - } + pub fn set_operating_point(&mut self, operating_point: u8) { + self.inner.operating_point = InRange::new(operating_point).unwrap(); + } - pub fn set_frame_size_limit(&mut self, frame_size_limit: u32) { - self.inner.frame_size_limit = frame_size_limit; - } + pub fn get_operating_point(&self) -> u8 { + self.inner.operating_point.get() + } - pub fn get_frame_size_limit(&self) -> u32 { - self.inner.frame_size_limit - } + pub fn set_all_layers(&mut self, all_layers: bool) { + self.inner.all_layers = all_layers; + } - pub fn set_strict_std_compliance(&mut self, strict_std_compliance: bool) { - self.inner.strict_std_compliance = strict_std_compliance; - } + pub fn get_all_layers(&self) -> bool { + self.inner.all_layers + } - pub fn get_strict_std_compliance(&self) -> bool { - self.inner.strict_std_compliance - } + pub fn set_frame_size_limit(&mut self, frame_size_limit: u32) { + self.inner.frame_size_limit = frame_size_limit; + } - pub fn set_output_invisible_frames(&mut self, output_invisible_frames: bool) { - self.inner.output_invisible_frames = output_invisible_frames; - } + pub fn get_frame_size_limit(&self) -> u32 { + self.inner.frame_size_limit + } - pub fn get_output_invisible_frames(&self) -> bool { - self.inner.output_invisible_frames - } + pub fn set_strict_std_compliance(&mut self, strict_std_compliance: bool) { + self.inner.strict_std_compliance = strict_std_compliance; + } - pub fn set_inloop_filters(&mut self, inloop_filters: InloopFilterType) { - self.inner.inloop_filters = inloop_filters; - } + pub fn get_strict_std_compliance(&self) -> bool { + self.inner.strict_std_compliance + } - pub fn get_inloop_filters(&self) -> InloopFilterType { - self.inner.inloop_filters - } + pub fn set_output_invisible_frames(&mut self, output_invisible_frames: bool) { + self.inner.output_invisible_frames = output_invisible_frames; + } - pub fn set_decode_frame_type(&mut self, decode_frame_type: DecodeFrameType) { - self.inner.decode_frame_type = decode_frame_type; - } + pub fn get_output_invisible_frames(&self) -> bool { + self.inner.output_invisible_frames + } - pub fn get_decode_frame_type(&self) -> DecodeFrameType { - self.inner.decode_frame_type - } + pub fn set_inloop_filters(&mut self, inloop_filters: InloopFilterType) { + self.inner.inloop_filters = inloop_filters; } - /// A `dav1d` decoder instance. - pub struct Decoder { - ctx: Arc, - pending_data: Option, - n_threads: InRange, - max_frame_delay: InRange, + pub fn get_inloop_filters(&self) -> InloopFilterType { + self.inner.inloop_filters } - impl Decoder { - /// Creates a new [`Decoder`] instance with given [`Settings`]. - pub fn with_settings(settings: &Settings) -> Result { - rav1d_open(&settings.inner).map(|ctx| Decoder { - ctx, - pending_data: None, - n_threads: settings.inner.n_threads, - max_frame_delay: settings.inner.max_frame_delay, - }) - } + pub fn set_decode_frame_type(&mut self, decode_frame_type: DecodeFrameType) { + self.inner.decode_frame_type = decode_frame_type; + } - /// Creates a new [`Decoder`] instance with the default settings. - pub fn new() -> Result { - Self::with_settings(&Settings::default()) - } + pub fn get_decode_frame_type(&self) -> DecodeFrameType { + self.inner.decode_frame_type + } +} - /// Flush the decoder. - /// - /// This flushes all delayed frames in the decoder and clears the internal decoder state. - /// - /// All currently pending frames are available afterwards via [`Decoder::get_picture`]. - pub fn flush(&mut self) { - rav1d_flush(&self.ctx); - if let Some(mut pending_data) = self.pending_data.take() { - let _ = mem::take(&mut pending_data); - } - } +/// A `dav1d` decoder instance. +pub struct Decoder { + ctx: Arc, + pending_data: Option, + n_threads: InRange, + max_frame_delay: InRange, +} - /// Send new AV1 data to the decoder. - /// - /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames - /// available via [`Decoder::get_picture`]. - /// - /// # Panics - /// - /// If a previous call returned [`Error::Again`] then this must not be called again until - /// [`Decoder::send_pending_data`] has returned `Ok(())`. - pub fn send_data + Send + Sync + 'static>( - &mut self, - buf: T, - offset: Option, - timestamp: Option, - duration: Option, - ) -> Result<(), Rav1dError> { - assert!( - self.pending_data.is_none(), - "Have pending data that needs to be handled first" - ); - - let buf = buf.as_ref().to_vec().into_boxed_slice(); - let slice = &*buf; - let len = slice.len(); - - let mut data = Rav1dData::create(len).unwrap(); - data.data = Some(CArc::wrap(CBox::from_box(buf)).unwrap()); - if let Some(offset) = offset { - data.m.offset = offset; - } - if let Some(timestamp) = timestamp { - data.m.timestamp = timestamp; - } - if let Some(duration) = duration { - data.m.duration = duration; - } +impl Decoder { + /// Creates a new [`Decoder`] instance with given [`Settings`]. + pub fn with_settings(settings: &Settings) -> Result { + rav1d_open(&settings.inner).map(|ctx| Decoder { + ctx, + pending_data: None, + n_threads: settings.inner.n_threads, + max_frame_delay: settings.inner.max_frame_delay, + }) + } - if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { - if matches!(err, Rav1dError::TryAgain) { - self.pending_data = Some(data); - } else { - let _ = mem::take(&mut data); - } + /// Creates a new [`Decoder`] instance with the default settings. + pub fn new() -> Result { + Self::with_settings(&Settings::default()) + } - return Err(err); - } + /// Flush the decoder. + /// + /// This flushes all delayed frames in the decoder and clears the internal decoder state. + /// + /// All currently pending frames are available afterwards via [`Decoder::get_picture`]. + pub fn flush(&mut self) { + rav1d_flush(&self.ctx); + if let Some(mut pending_data) = self.pending_data.take() { + let _ = mem::take(&mut pending_data); + } + } - if data.data.as_ref().is_some_and(|d| d.len() > 0) { + /// Send new AV1 data to the decoder. + /// + /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// available via [`Decoder::get_picture`]. + /// + /// # Panics + /// + /// If a previous call returned [`Error::Again`] then this must not be called again until + /// [`Decoder::send_pending_data`] has returned `Ok(())`. + pub fn send_data + Send + Sync + 'static>( + &mut self, + buf: T, + offset: Option, + timestamp: Option, + duration: Option, + ) -> Result<(), Rav1dError> { + assert!( + self.pending_data.is_none(), + "Have pending data that needs to be handled first" + ); + + let buf = buf.as_ref().to_vec().into_boxed_slice(); + let slice = &*buf; + let len = slice.len(); + + let mut data = Rav1dData::create(len).unwrap(); + data.data = Some(CArc::wrap(CBox::from_box(buf)).unwrap()); + if let Some(offset) = offset { + data.m.offset = offset; + } + if let Some(timestamp) = timestamp { + data.m.timestamp = timestamp; + } + if let Some(duration) = duration { + data.m.duration = duration; + } + + if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { + if matches!(err, Rav1dError::TryAgain) { self.pending_data = Some(data); - return Err(Rav1dError::TryAgain); + } else { + let _ = mem::take(&mut data); } - Ok(()) + return Err(err); + } + + if data.data.as_ref().is_some_and(|d| d.len() > 0) { + self.pending_data = Some(data); + return Err(Rav1dError::TryAgain); } - /// Sends any pending data to the decoder. - /// - /// This has to be called after [`Decoder::send_data`] has returned `Err([Error::Again])` to - /// consume any futher pending data. - /// - /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames - /// available via [`Decoder::get_picture`]. - pub fn send_pending_data(&mut self) -> Result<(), Rav1dError> { - let mut data = match self.pending_data.take() { - None => { - return Ok(()); - } - Some(data) => data, - }; - - if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { - if matches!(err, Rav1dError::TryAgain) { - self.pending_data = Some(data); - } else { - let _ = mem::take(&mut data); - } - - return Err(err); + Ok(()) + } + + /// Sends any pending data to the decoder. + /// + /// This has to be called after [`Decoder::send_data`] has returned `Err([Error::Again])` to + /// consume any futher pending data. + /// + /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// available via [`Decoder::get_picture`]. + pub fn send_pending_data(&mut self) -> Result<(), Rav1dError> { + let mut data = match self.pending_data.take() { + None => { + return Ok(()); } + Some(data) => data, + }; - if data.data.as_ref().is_some_and(|d| d.len() > 0) { + if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { + if matches!(err, Rav1dError::TryAgain) { self.pending_data = Some(data); - return Err(Rav1dError::TryAgain); + } else { + let _ = mem::take(&mut data); } - Ok(()) + return Err(err); } - /// Get the next decoded frame from the decoder. - /// - /// If this returns `Err([Error::Again])` then further data has to be sent to the decoder - /// before further decoded frames become available. - /// - /// To make most use of frame threading this function should only be called once per submitted - /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should - /// only be done to drain all pending frames at the end. - pub fn get_picture(&mut self) -> Result { - let mut pic = Rav1dPicture::default(); - let ret = rav1d_get_picture(&self.ctx, &mut pic); - - if let Err(err) = ret { - Err(err) - } else { - Ok(Picture { - inner: Arc::new(pic), - }) - } + if data.data.as_ref().is_some_and(|d| d.len() > 0) { + self.pending_data = Some(data); + return Err(Rav1dError::TryAgain); } - /// Get the decoder delay. - pub fn get_frame_delay(&self) -> u32 { - // The only fields this actually needs from Rav1dSettings are n_threads and max_frame_delay so we just pass these in directly + Ok(()) + } - rav1d_get_frame_delay(&Rav1dSettings { - n_threads: self.n_threads, - max_frame_delay: self.max_frame_delay, - ..Default::default() + /// Get the next decoded frame from the decoder. + /// + /// If this returns `Err([Error::Again])` then further data has to be sent to the decoder + /// before further decoded frames become available. + /// + /// To make most use of frame threading this function should only be called once per submitted + /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should + /// only be done to drain all pending frames at the end. + pub fn get_picture(&mut self) -> Result { + let mut pic = Rav1dPicture::default(); + let ret = rav1d_get_picture(&self.ctx, &mut pic); + + if let Err(err) = ret { + Err(err) + } else { + Ok(Picture { + inner: Arc::new(pic), }) - .unwrap() as u32 } } - impl Drop for Decoder { - fn drop(&mut self) { - if let Some(mut pending_data) = self.pending_data.take() { - let _ = mem::take(&mut pending_data); - } - rav1d_close(self.ctx.clone()); + /// Get the decoder delay. + pub fn get_frame_delay(&self) -> u32 { + // The only fields this actually needs from Rav1dSettings are n_threads and max_frame_delay so we just pass these in directly + + rav1d_get_frame_delay(&Rav1dSettings { + n_threads: self.n_threads, + max_frame_delay: self.max_frame_delay, + ..Default::default() + }) + .unwrap() as u32 + } +} + +impl Drop for Decoder { + fn drop(&mut self) { + if let Some(mut pending_data) = self.pending_data.take() { + let _ = mem::take(&mut pending_data); } + rav1d_close(self.ctx.clone()); } +} - static_assertions::assert_impl_all!(Decoder: Send, Sync); +static_assertions::assert_impl_all!(Decoder: Send, Sync); - /// A decoded frame. - #[derive(Clone)] - pub struct Picture { - inner: Arc, - } +/// A decoded frame. +#[derive(Clone)] +pub struct Picture { + inner: Arc, +} - /// Frame component. - #[derive(Eq, PartialEq, Copy, Clone, Debug)] - pub enum PlanarImageComponent { - /// Y component (Luminance). - Y, - /// U component (Chrominance). - U, - /// V component (Chrominance). - V, - } +/// Frame component. +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub enum PlanarImageComponent { + /// Y component (Luminance). + Y, + /// U component (Chrominance). + U, + /// V component (Chrominance). + V, +} - impl TryFrom for PlanarImageComponent { - type Error = Rav1dError; - fn try_from(index: usize) -> Result { - match index { - 0 => Ok(PlanarImageComponent::Y), - 1 => Ok(PlanarImageComponent::U), - 2 => Ok(PlanarImageComponent::V), - _ => Err(Rav1dError::InvalidArgument), - } +impl TryFrom for PlanarImageComponent { + type Error = Rav1dError; + fn try_from(index: usize) -> Result { + match index { + 0 => Ok(PlanarImageComponent::Y), + 1 => Ok(PlanarImageComponent::U), + 2 => Ok(PlanarImageComponent::V), + _ => Err(Rav1dError::InvalidArgument), } } +} - impl From for usize { - fn from(component: PlanarImageComponent) -> Self { - match component { - PlanarImageComponent::Y => 0, - PlanarImageComponent::U => 1, - PlanarImageComponent::V => 2, - } +impl From for usize { + fn from(component: PlanarImageComponent) -> Self { + match component { + PlanarImageComponent::Y => 0, + PlanarImageComponent::U => 1, + PlanarImageComponent::V => 2, } } +} - /// A single plane of a decoded frame. - /// - /// This can be used like a `&[u8]`. - #[derive(Clone)] - pub struct Plane(Picture, PlanarImageComponent); - - impl AsRef<[u8]> for Plane { - fn as_ref(&self) -> &[u8] { - let (stride, height) = self.0.plane_data_geometry(self.1); - // SAFETY: both stride and height can't be negative, the `stride` and `height` methods panic if they are so there's no undefined behaviour - unsafe { - slice::from_raw_parts( - self.0.plane_data_ptr(self.1) as *const u8, - (stride * height) as usize, - ) - } +/// A single plane of a decoded frame. +/// +/// This can be used like a `&[u8]`. +#[derive(Clone)] +pub struct Plane(Picture, PlanarImageComponent); + +impl AsRef<[u8]> for Plane { + fn as_ref(&self) -> &[u8] { + let (stride, height) = self.0.plane_data_geometry(self.1); + // SAFETY: both stride and height can't be negative, the `stride` and `height` methods panic if they are so there's no undefined behaviour + unsafe { + slice::from_raw_parts( + self.0.plane_data_ptr(self.1) as *const u8, + (stride * height) as usize, + ) } } +} - impl Deref for Plane { - type Target = [u8]; +impl Deref for Plane { + type Target = [u8]; - fn deref(&self) -> &Self::Target { - self.as_ref() - } + fn deref(&self) -> &Self::Target { + self.as_ref() } +} - /// Number of bits per component. - #[derive(Copy, Clone, Debug, PartialEq, Eq)] - pub struct BitsPerComponent(pub u8); +/// Number of bits per component. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct BitsPerComponent(pub u8); - impl TryFrom for BitsPerComponent { - type Error = Rav1dError; +impl TryFrom for BitsPerComponent { + type Error = Rav1dError; - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(BitsPerComponent(8)), - 1 => Ok(BitsPerComponent(10)), - 2 => Ok(BitsPerComponent(12)), - _ => Err(Rav1dError::InvalidArgument), - } + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(BitsPerComponent(8)), + 1 => Ok(BitsPerComponent(10)), + 2 => Ok(BitsPerComponent(12)), + _ => Err(Rav1dError::InvalidArgument), } } +} - impl Picture { - /// Stride in pixels of the `component` for the decoded frame. - pub fn stride(&self, component: PlanarImageComponent) -> u32 { - let s = match component { - PlanarImageComponent::Y => 0, - _ => 1, - }; - self.inner.stride[s].try_into().unwrap() - } - - /// Raw pointer to the data of the `component` for the decoded frame. - pub fn plane_data_ptr(&self, component: PlanarImageComponent) -> *mut c_void { - let index: usize = component.into(); - self.inner.data.as_ref().unwrap().data[index] - .as_byte_mut_ptr() - .cast() - } +impl Picture { + /// Stride in pixels of the `component` for the decoded frame. + pub fn stride(&self, component: PlanarImageComponent) -> u32 { + let s = match component { + PlanarImageComponent::Y => 0, + _ => 1, + }; + self.inner.stride[s].try_into().unwrap() + } - /// Plane geometry of the `component` for the decoded frame. - /// - /// This returns the stride and height. - pub fn plane_data_geometry(&self, component: PlanarImageComponent) -> (u32, u32) { - let height = match component { - PlanarImageComponent::Y => self.height(), - _ => match self.pixel_layout() { - PixelLayout::I420 => (self.height() + 1) / 2, - PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), - }, - }; - (self.stride(component), height) - } + /// Raw pointer to the data of the `component` for the decoded frame. + pub fn plane_data_ptr(&self, component: PlanarImageComponent) -> *mut c_void { + let index: usize = component.into(); + self.inner.data.as_ref().unwrap().data[index] + .as_byte_mut_ptr() + .cast() + } - /// Plane data of the `component` for the decoded frame. - pub fn plane(&self, component: PlanarImageComponent) -> Plane { - Plane(self.clone(), component) - } + /// Plane geometry of the `component` for the decoded frame. + /// + /// This returns the stride and height. + pub fn plane_data_geometry(&self, component: PlanarImageComponent) -> (u32, u32) { + let height = match component { + PlanarImageComponent::Y => self.height(), + _ => match self.pixel_layout() { + PixelLayout::I420 => (self.height() + 1) / 2, + PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), + }, + }; + (self.stride(component), height) + } - /// Bit depth of the plane data. - /// - /// This returns 8 or 16 for the underlying integer type used for the plane data. - /// - /// Check [`Picture::bits_per_component`] for the number of bits that are used. - pub fn bit_depth(&self) -> usize { - self.inner.p.bpc.into() - } + /// Plane data of the `component` for the decoded frame. + pub fn plane(&self, component: PlanarImageComponent) -> Plane { + Plane(self.clone(), component) + } - /// Bits used per component of the plane data. - /// - /// Check [`Picture::bit_depth`] for the number of storage bits. - pub fn bits_per_component(&self) -> Option { - self.inner.seq_hdr.as_ref().unwrap().hbd.try_into().ok() - } + /// Bit depth of the plane data. + /// + /// This returns 8 or 16 for the underlying integer type used for the plane data. + /// + /// Check [`Picture::bits_per_component`] for the number of bits that are used. + pub fn bit_depth(&self) -> usize { + self.inner.p.bpc.into() + } - /// Width of the frame. - pub fn width(&self) -> u32 { - self.inner.p.w.try_into().unwrap() - } + /// Bits used per component of the plane data. + /// + /// Check [`Picture::bit_depth`] for the number of storage bits. + pub fn bits_per_component(&self) -> Option { + self.inner.seq_hdr.as_ref().unwrap().hbd.try_into().ok() + } - /// Height of the frame. - pub fn height(&self) -> u32 { - self.inner.p.h.try_into().unwrap() - } + /// Width of the frame. + pub fn width(&self) -> u32 { + self.inner.p.w.try_into().unwrap() + } - /// Pixel layout of the frame. - pub fn pixel_layout(&self) -> PixelLayout { - self.inner.p.layout - } + /// Height of the frame. + pub fn height(&self) -> u32 { + self.inner.p.h.try_into().unwrap() + } - /// Timestamp of the frame. - /// - /// This is the same timestamp as the one provided to [`Decoder::send_data`]. - pub fn timestamp(&self) -> Option { - let ts = self.inner.m.timestamp; - if ts == i64::MIN { - None - } else { - Some(ts) - } - } + /// Pixel layout of the frame. + pub fn pixel_layout(&self) -> PixelLayout { + self.inner.p.layout + } - /// Duration of the frame. - /// - /// This is the same duration as the one provided to [`Decoder::send_data`] or `0` if none was - /// provided. - pub fn duration(&self) -> i64 { - self.inner.m.duration + /// Timestamp of the frame. + /// + /// This is the same timestamp as the one provided to [`Decoder::send_data`]. + pub fn timestamp(&self) -> Option { + let ts = self.inner.m.timestamp; + if ts == i64::MIN { + None + } else { + Some(ts) } + } - /// Offset of the frame. - /// - /// This is the same offset as the one provided to [`Decoder::send_data`] or `-1` if none was - /// provided. - pub fn offset(&self) -> i64 { - self.inner.m.offset as i64 - } + /// Duration of the frame. + /// + /// This is the same duration as the one provided to [`Decoder::send_data`] or `0` if none was + /// provided. + pub fn duration(&self) -> i64 { + self.inner.m.duration + } - /// Chromaticity coordinates of the source colour primaries. - pub fn color_primaries(&self) -> pixel::ColorPrimaries { - self.inner.seq_hdr.as_ref().unwrap().pri.try_into().unwrap() - } + /// Offset of the frame. + /// + /// This is the same offset as the one provided to [`Decoder::send_data`] or `-1` if none was + /// provided. + pub fn offset(&self) -> i64 { + self.inner.m.offset as i64 + } - /// Transfer characteristics function. - pub fn transfer_characteristic(&self) -> pixel::TransferCharacteristic { - self.inner.seq_hdr.as_ref().unwrap().trc.try_into().unwrap() - } + /// Chromaticity coordinates of the source colour primaries. + pub fn color_primaries(&self) -> pixel::ColorPrimaries { + self.inner.seq_hdr.as_ref().unwrap().pri.try_into().unwrap() + } - /// Matrix coefficients used in deriving luma and chroma signals from the - /// green, blue and red or X, Y and Z primaries. - pub fn matrix_coefficients(&self) -> pixel::MatrixCoefficients { - self.inner - .seq_hdr - .as_ref() - .unwrap() - .mtrx - .try_into() - .unwrap() - } + /// Transfer characteristics function. + pub fn transfer_characteristic(&self) -> pixel::TransferCharacteristic { + self.inner.seq_hdr.as_ref().unwrap().trc.try_into().unwrap() + } - /// YUV color range. - pub fn color_range(&self) -> pixel::YUVRange { - match self.inner.seq_hdr.as_ref().unwrap().color_range { - 0 => pixel::YUVRange::Limited, - _ => pixel::YUVRange::Full, - } - } + /// Matrix coefficients used in deriving luma and chroma signals from the + /// green, blue and red or X, Y and Z primaries. + pub fn matrix_coefficients(&self) -> pixel::MatrixCoefficients { + self.inner + .seq_hdr + .as_ref() + .unwrap() + .mtrx + .try_into() + .unwrap() + } - /// Sample position for subsampled chroma. - pub fn chroma_location(&self) -> pixel::ChromaLocation { - self.inner.seq_hdr.as_ref().unwrap().chr.try_into().unwrap() + /// YUV color range. + pub fn color_range(&self) -> pixel::YUVRange { + match self.inner.seq_hdr.as_ref().unwrap().color_range { + 0 => pixel::YUVRange::Limited, + _ => pixel::YUVRange::Full, } } - impl Debug for Picture { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("Picture") - .field("width", &self.width()) - .field("height", &self.height()) - .field("bit_depth", &self.bit_depth()) - .field("pixel_layout", &self.pixel_layout()) - .field("timestamp", &self.timestamp()) - .field("duration", &self.duration()) - .field("offset", &self.offset()) - .field("color_primaries", &self.color_primaries()) - .field("transfer_characteristic", &self.transfer_characteristic()) - .field("matrix_coefficients", &self.matrix_coefficients()) - .field("color_range", &self.color_range()) - .field("chroma_location", &self.chroma_location()) - .finish() - } + /// Sample position for subsampled chroma. + pub fn chroma_location(&self) -> pixel::ChromaLocation { + self.inner.seq_hdr.as_ref().unwrap().chr.try_into().unwrap() } } -pub use dav1d::*; +impl Debug for Picture { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Picture") + .field("width", &self.width()) + .field("height", &self.height()) + .field("bit_depth", &self.bit_depth()) + .field("pixel_layout", &self.pixel_layout()) + .field("timestamp", &self.timestamp()) + .field("duration", &self.duration()) + .field("offset", &self.offset()) + .field("color_primaries", &self.color_primaries()) + .field("transfer_characteristic", &self.transfer_characteristic()) + .field("matrix_coefficients", &self.matrix_coefficients()) + .field("color_range", &self.color_range()) + .field("chroma_location", &self.chroma_location()) + .finish() + } +} From 0d937a9428cee0e5347c05cd1faefe0f881f1c5b Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Thu, 24 Jul 2025 19:45:08 +0100 Subject: [PATCH 40/72] Remove Result return type from rav1d_get_frame_delay --- src/lib.rs | 6 +++--- src/rust_api.rs | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 46bcab877..27a756ed5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -280,9 +280,9 @@ fn get_num_threads(s: &Rav1dSettings) -> NumThreads { } #[cold] -pub(crate) fn rav1d_get_frame_delay(s: &Rav1dSettings) -> Rav1dResult { +pub(crate) fn rav1d_get_frame_delay(s: &Rav1dSettings) -> usize { let NumThreads { n_tc: _, n_fc } = get_num_threads(s); - Ok(n_fc) + n_fc } /// # Safety @@ -296,7 +296,7 @@ pub unsafe extern "C" fn dav1d_get_frame_delay(s: Option> // SAFETY: `s` is safe to `ptr::read`. 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) + Ok(rav1d_get_frame_delay(&s) as c_uint) })() .into() } diff --git a/src/rust_api.rs b/src/rust_api.rs index ecc0b47d2..2eb4b4cee 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -302,8 +302,7 @@ impl Decoder { n_threads: self.n_threads, max_frame_delay: self.max_frame_delay, ..Default::default() - }) - .unwrap() as u32 + }) as u32 } } From f5b77e5f99c6d40bbd841880e18c488de3609a1a Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Thu, 24 Jul 2025 19:59:12 +0100 Subject: [PATCH 41/72] Add `is_unspecified` methods to some structs to make conversions more readable --- src/include/dav1d/headers.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 6fecf1a28..750a8433d 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -562,6 +562,10 @@ impl Rav1dColorPrimaries { pub const SMPTE432: Self = Self(12); pub const EBU3213: Self = Self(22); + fn is_unspecified(self) -> bool { + (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(self.0 as u32)) + } + const fn to_dav1d(self) -> Dav1dColorPrimaries { self.0 as Dav1dColorPrimaries } @@ -584,8 +588,8 @@ impl TryInto for Rav1dColorPrimaries { Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, - Rav1dColorPrimaries(x) => { - if (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(x as u32)) { + other_value => { + if other_value.is_unspecified() { pixel::ColorPrimaries::Unspecified } else { return Err(Rav1dError::InvalidArgument); @@ -671,6 +675,10 @@ impl Rav1dTransferCharacteristics { pub const SMPTE428: Self = Self(17); pub const HLG: Self = Self(18); + fn is_unspecified(self) -> bool { + (19..=DAV1D_TRC_RESERVED).contains(&(self.0 as u32)) + } + const fn to_dav1d(self) -> Dav1dTransferCharacteristics { self.0 as Dav1dTransferCharacteristics } @@ -704,8 +712,8 @@ impl TryInto for Rav1dTransferCharacteristics { } Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, - Rav1dTransferCharacteristics(x) => { - if (19..=DAV1D_TRC_RESERVED).contains(&(x as u32)) { + other_value => { + if other_value.is_unspecified() { pixel::TransferCharacteristic::Unspecified } else { return Err(Rav1dError::InvalidArgument); @@ -773,6 +781,10 @@ impl Rav1dMatrixCoefficients { pub const CHROMAT_CL: Self = Self(13); pub const ICTCP: Self = Self(14); + fn is_unspecified(self) -> bool { + (15..=DAV1D_MC_RESERVED).contains(&(self.0 as u32)) + } + const fn to_dav1d(self) -> Dav1dMatrixCoefficients { self.0 as Dav1dMatrixCoefficients } @@ -805,8 +817,8 @@ impl TryInto for Rav1dMatrixCoefficients { pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance } Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, - Rav1dMatrixCoefficients(x) => { - if (15..=DAV1D_MC_RESERVED).contains(&(x as u32)) { + other_value => { + if other_value.is_unspecified() { pixel::MatrixCoefficients::Unspecified } else { return Err(Rav1dError::InvalidArgument); From a87231a214bbbf95f1c4a5e755426c54b6207121 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Thu, 24 Jul 2025 21:05:45 +0100 Subject: [PATCH 42/72] Replace TryInto impls with cleaner From impls --- src/include/dav1d/headers.rs | 66 ++++++++---------------------------- 1 file changed, 15 insertions(+), 51 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 750a8433d..c654eaa68 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -562,20 +562,14 @@ impl Rav1dColorPrimaries { pub const SMPTE432: Self = Self(12); pub const EBU3213: Self = Self(22); - fn is_unspecified(self) -> bool { - (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(self.0 as u32)) - } - const fn to_dav1d(self) -> Dav1dColorPrimaries { self.0 as Dav1dColorPrimaries } } -impl TryInto for Rav1dColorPrimaries { - type Error = Rav1dError; - - fn try_into(self) -> Result { - Ok(match self { +impl From for pixel::ColorPrimaries { + fn from(val: Rav1dColorPrimaries) -> Self { + match val { Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, Rav1dColorPrimaries::UNKNOWN => pixel::ColorPrimaries::Unspecified, Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, @@ -588,14 +582,8 @@ impl TryInto for Rav1dColorPrimaries { Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, - other_value => { - if other_value.is_unspecified() { - pixel::ColorPrimaries::Unspecified - } else { - return Err(Rav1dError::InvalidArgument); - } - } - }) + _ => pixel::ColorPrimaries::Unspecified, + } } } @@ -675,20 +663,14 @@ impl Rav1dTransferCharacteristics { pub const SMPTE428: Self = Self(17); pub const HLG: Self = Self(18); - fn is_unspecified(self) -> bool { - (19..=DAV1D_TRC_RESERVED).contains(&(self.0 as u32)) - } - const fn to_dav1d(self) -> Dav1dTransferCharacteristics { self.0 as Dav1dTransferCharacteristics } } -impl TryInto for Rav1dTransferCharacteristics { - type Error = Rav1dError; - - fn try_into(self) -> Result { - Ok(match self { +impl From for pixel::TransferCharacteristic { + fn from(val: Rav1dTransferCharacteristics) -> Self { + match val { Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, Rav1dTransferCharacteristics::UNKNOWN => pixel::TransferCharacteristic::Unspecified, Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, @@ -712,14 +694,8 @@ impl TryInto for Rav1dTransferCharacteristics { } Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, - other_value => { - if other_value.is_unspecified() { - pixel::TransferCharacteristic::Unspecified - } else { - return Err(Rav1dError::InvalidArgument); - } - } - }) + _ => pixel::TransferCharacteristic::Unspecified, + } } } @@ -781,20 +757,14 @@ impl Rav1dMatrixCoefficients { pub const CHROMAT_CL: Self = Self(13); pub const ICTCP: Self = Self(14); - fn is_unspecified(self) -> bool { - (15..=DAV1D_MC_RESERVED).contains(&(self.0 as u32)) - } - const fn to_dav1d(self) -> Dav1dMatrixCoefficients { self.0 as Dav1dMatrixCoefficients } } -impl TryInto for Rav1dMatrixCoefficients { - type Error = Rav1dError; - - fn try_into(self) -> Result { - Ok(match self { +impl From for pixel::MatrixCoefficients { + fn from(val: Rav1dMatrixCoefficients) -> Self { + match val { Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, Rav1dMatrixCoefficients::UNKNOWN => pixel::MatrixCoefficients::Unspecified, @@ -817,14 +787,8 @@ impl TryInto for Rav1dMatrixCoefficients { pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance } Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, - other_value => { - if other_value.is_unspecified() { - pixel::MatrixCoefficients::Unspecified - } else { - return Err(Rav1dError::InvalidArgument); - } - } - }) + _ => pixel::MatrixCoefficients::Unspecified, + } } } From 1de85686b50dd088eb3c2f5b503837329c1cc157 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Thu, 24 Jul 2025 21:10:30 +0100 Subject: [PATCH 43/72] Revert "Replace TryInto impls with cleaner From impls" This reverts commit a87231a214bbbf95f1c4a5e755426c54b6207121. --- src/include/dav1d/headers.rs | 66 ++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index c654eaa68..750a8433d 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -562,14 +562,20 @@ impl Rav1dColorPrimaries { pub const SMPTE432: Self = Self(12); pub const EBU3213: Self = Self(22); + fn is_unspecified(self) -> bool { + (23..=DAV1D_COLOR_PRI_RESERVED).contains(&(self.0 as u32)) + } + const fn to_dav1d(self) -> Dav1dColorPrimaries { self.0 as Dav1dColorPrimaries } } -impl From for pixel::ColorPrimaries { - fn from(val: Rav1dColorPrimaries) -> Self { - match val { +impl TryInto for Rav1dColorPrimaries { + type Error = Rav1dError; + + fn try_into(self) -> Result { + Ok(match self { Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, Rav1dColorPrimaries::UNKNOWN => pixel::ColorPrimaries::Unspecified, Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, @@ -582,8 +588,14 @@ impl From for pixel::ColorPrimaries { Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, - _ => pixel::ColorPrimaries::Unspecified, - } + other_value => { + if other_value.is_unspecified() { + pixel::ColorPrimaries::Unspecified + } else { + return Err(Rav1dError::InvalidArgument); + } + } + }) } } @@ -663,14 +675,20 @@ impl Rav1dTransferCharacteristics { pub const SMPTE428: Self = Self(17); pub const HLG: Self = Self(18); + fn is_unspecified(self) -> bool { + (19..=DAV1D_TRC_RESERVED).contains(&(self.0 as u32)) + } + const fn to_dav1d(self) -> Dav1dTransferCharacteristics { self.0 as Dav1dTransferCharacteristics } } -impl From for pixel::TransferCharacteristic { - fn from(val: Rav1dTransferCharacteristics) -> Self { - match val { +impl TryInto for Rav1dTransferCharacteristics { + type Error = Rav1dError; + + fn try_into(self) -> Result { + Ok(match self { Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, Rav1dTransferCharacteristics::UNKNOWN => pixel::TransferCharacteristic::Unspecified, Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, @@ -694,8 +712,14 @@ impl From for pixel::TransferCharacteristic { } Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, - _ => pixel::TransferCharacteristic::Unspecified, - } + other_value => { + if other_value.is_unspecified() { + pixel::TransferCharacteristic::Unspecified + } else { + return Err(Rav1dError::InvalidArgument); + } + } + }) } } @@ -757,14 +781,20 @@ impl Rav1dMatrixCoefficients { pub const CHROMAT_CL: Self = Self(13); pub const ICTCP: Self = Self(14); + fn is_unspecified(self) -> bool { + (15..=DAV1D_MC_RESERVED).contains(&(self.0 as u32)) + } + const fn to_dav1d(self) -> Dav1dMatrixCoefficients { self.0 as Dav1dMatrixCoefficients } } -impl From for pixel::MatrixCoefficients { - fn from(val: Rav1dMatrixCoefficients) -> Self { - match val { +impl TryInto for Rav1dMatrixCoefficients { + type Error = Rav1dError; + + fn try_into(self) -> Result { + Ok(match self { Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, Rav1dMatrixCoefficients::UNKNOWN => pixel::MatrixCoefficients::Unspecified, @@ -787,8 +817,14 @@ impl From for pixel::MatrixCoefficients { pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance } Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, - _ => pixel::MatrixCoefficients::Unspecified, - } + other_value => { + if other_value.is_unspecified() { + pixel::MatrixCoefficients::Unspecified + } else { + return Err(Rav1dError::InvalidArgument); + } + } + }) } } From fa446a336790ae32c3bc16513f5bd8593080031c Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Mon, 28 Jul 2025 18:16:06 +0100 Subject: [PATCH 44/72] Add doc comment to rust-api --- src/lib.rs | 1 + src/rust_api.rs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 27a756ed5..d7ee00c6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,6 +139,7 @@ mod pool; mod qm; mod recon; mod refmvs; +/// This API copies that of `dav1d-rs`, and should function as a drop-in replacement, aside from `dav1d::Error` being renamed to `Rav1dError` pub mod rust_api; mod scan; mod tables; diff --git a/src/rust_api.rs b/src/rust_api.rs index 2eb4b4cee..494a0abed 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -1,6 +1,6 @@ // This whole module was originally copied from https://github.com/rust-av/dav1d-rs/ // (specifically https://github.com/rust-av/dav1d-rs/blob/94b1deaa1e25bf29c77bb5cc8a08ddaf7663eede/src/lib.rs) -// with some modifications. +// with modifications. // `dav1d-rs` is under the MIT license, replicated here: // MIT License @@ -24,7 +24,6 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - use std::ffi::c_void; use std::fmt::{Debug, Formatter}; use std::ops::Deref; From e6f54ccf4989a32af25324fac39c4ca6cfd522c7 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Mon, 28 Jul 2025 18:22:56 +0100 Subject: [PATCH 45/72] Renamed UNKNOWN fields to UNSPECIFIED --- src/include/dav1d/headers.rs | 20 +++++++++++--------- src/obu.rs | 6 +++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 750a8433d..575c67235 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -531,7 +531,8 @@ impl Rav1dFrameType { pub type Dav1dColorPrimaries = c_uint; pub const DAV1D_COLOR_PRI_BT709: Dav1dColorPrimaries = Rav1dColorPrimaries::BT709.to_dav1d(); -pub const DAV1D_COLOR_PRI_UNKNOWN: Dav1dColorPrimaries = Rav1dColorPrimaries::UNKNOWN.to_dav1d(); +pub const DAV1D_COLOR_PRI_UNKNOWN: Dav1dColorPrimaries = + Rav1dColorPrimaries::UNSPECIFIED.to_dav1d(); pub const DAV1D_COLOR_PRI_BT470M: Dav1dColorPrimaries = Rav1dColorPrimaries::BT470M.to_dav1d(); pub const DAV1D_COLOR_PRI_BT470BG: Dav1dColorPrimaries = Rav1dColorPrimaries::BT470BG.to_dav1d(); pub const DAV1D_COLOR_PRI_BT601: Dav1dColorPrimaries = Rav1dColorPrimaries::BT601.to_dav1d(); @@ -550,7 +551,7 @@ pub struct Rav1dColorPrimaries(pub u8); impl Rav1dColorPrimaries { pub const BT709: Self = Self(1); - pub const UNKNOWN: Self = Self(2); + pub const UNSPECIFIED: Self = Self(2); pub const BT470M: Self = Self(4); pub const BT470BG: Self = Self(5); pub const BT601: Self = Self(6); @@ -577,7 +578,7 @@ impl TryInto for Rav1dColorPrimaries { fn try_into(self) -> Result { Ok(match self { Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, - Rav1dColorPrimaries::UNKNOWN => pixel::ColorPrimaries::Unspecified, + Rav1dColorPrimaries::UNSPECIFIED => pixel::ColorPrimaries::Unspecified, Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, Rav1dColorPrimaries::BT470BG => pixel::ColorPrimaries::BT470BG, Rav1dColorPrimaries::BT601 => pixel::ColorPrimaries::BT470BG, @@ -617,7 +618,7 @@ pub type Dav1dTransferCharacteristics = c_uint; pub const DAV1D_TRC_BT709: Dav1dTransferCharacteristics = Rav1dTransferCharacteristics::BT709.to_dav1d(); pub const DAV1D_TRC_UNKNOWN: Dav1dTransferCharacteristics = - Rav1dTransferCharacteristics::UNKNOWN.to_dav1d(); + Rav1dTransferCharacteristics::UNSPECIFIED.to_dav1d(); pub const DAV1D_TRC_BT470M: Dav1dTransferCharacteristics = Rav1dTransferCharacteristics::BT470M.to_dav1d(); pub const DAV1D_TRC_BT470BG: Dav1dTransferCharacteristics = @@ -657,7 +658,7 @@ pub struct Rav1dTransferCharacteristics(pub u8); impl Rav1dTransferCharacteristics { pub const _RESERVED_0: Self = Self(0); pub const BT709: Self = Self(1); - pub const UNKNOWN: Self = Self(2); + pub const UNSPECIFIED: Self = Self(2); pub const _RESERVED_3: Self = Self(3); pub const BT470M: Self = Self(4); pub const BT470BG: Self = Self(5); @@ -690,7 +691,7 @@ impl TryInto for Rav1dTransferCharacteristics { fn try_into(self) -> Result { Ok(match self { Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, - Rav1dTransferCharacteristics::UNKNOWN => pixel::TransferCharacteristic::Unspecified, + Rav1dTransferCharacteristics::UNSPECIFIED => pixel::TransferCharacteristic::Unspecified, Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, Rav1dTransferCharacteristics::BT470BG => pixel::TransferCharacteristic::BT470BG, Rav1dTransferCharacteristics::BT601 => pixel::TransferCharacteristic::ST170M, @@ -740,7 +741,8 @@ impl TryFrom for Rav1dTransferCharacteristics { pub type Dav1dMatrixCoefficients = c_uint; pub const DAV1D_MC_IDENTITY: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::IDENTITY.to_dav1d(); pub const DAV1D_MC_BT709: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::BT709.to_dav1d(); -pub const DAV1D_MC_UNKNOWN: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::UNKNOWN.to_dav1d(); +pub const DAV1D_MC_UNKNOWN: Dav1dMatrixCoefficients = + Rav1dMatrixCoefficients::UNSPECIFIED.to_dav1d(); pub const DAV1D_MC_FCC: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::FCC.to_dav1d(); pub const DAV1D_MC_BT470BG: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::BT470BG.to_dav1d(); pub const DAV1D_MC_BT601: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::BT601.to_dav1d(); @@ -767,7 +769,7 @@ pub struct Rav1dMatrixCoefficients(pub u8); impl Rav1dMatrixCoefficients { pub const IDENTITY: Self = Self(0); pub const BT709: Self = Self(1); - pub const UNKNOWN: Self = Self(2); + pub const UNSPECIFIED: Self = Self(2); pub const _RESERVED_3: Self = Self(3); pub const FCC: Self = Self(4); pub const BT470BG: Self = Self(5); @@ -797,7 +799,7 @@ impl TryInto for Rav1dMatrixCoefficients { Ok(match self { Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, - Rav1dMatrixCoefficients::UNKNOWN => pixel::MatrixCoefficients::Unspecified, + Rav1dMatrixCoefficients::UNSPECIFIED => pixel::MatrixCoefficients::Unspecified, Rav1dMatrixCoefficients::FCC => pixel::MatrixCoefficients::BT470M, Rav1dMatrixCoefficients::BT470BG => pixel::MatrixCoefficients::BT470BG, Rav1dMatrixCoefficients::BT601 => pixel::MatrixCoefficients::BT470BG, diff --git a/src/obu.rs b/src/obu.rs index 59d99bcc3..c2b760605 100644 --- a/src/obu.rs +++ b/src/obu.rs @@ -359,9 +359,9 @@ fn parse_seq_hdr( trc = Rav1dTransferCharacteristics(gb.get_bits(8) as u8); mtrx = Rav1dMatrixCoefficients(gb.get_bits(8) as u8) } else { - pri = Rav1dColorPrimaries::UNKNOWN; - trc = Rav1dTransferCharacteristics::UNKNOWN; - mtrx = Rav1dMatrixCoefficients::UNKNOWN; + pri = Rav1dColorPrimaries::UNSPECIFIED; + trc = Rav1dTransferCharacteristics::UNSPECIFIED; + mtrx = Rav1dMatrixCoefficients::UNSPECIFIED; } let color_range; let layout; From dee53e91b11212c454e281f51abff45786cbeb01 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Tue, 19 Aug 2025 17:32:08 +0100 Subject: [PATCH 46/72] Fixed enums, replaced TryInto's with From impls Signed-off-by: Leo Ring --- src/include/dav1d/headers.rs | 85 ++++++++++++------------------------ 1 file changed, 28 insertions(+), 57 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 34c83b36e..595f31c35 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -569,31 +569,22 @@ impl Rav1dColorPrimaries { } } -impl TryInto for Rav1dColorPrimaries { - type Error = Rav1dError; - - fn try_into(self) -> Result { - Ok(match self { +impl From for pixel::ColorPrimaries { + fn from(val: Rav1dColorPrimaries) -> Self { + match val { Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, - Rav1dColorPrimaries::UNSPECIFIED => pixel::ColorPrimaries::Unspecified, + Rav1dColorPrimaries::Unspecified => pixel::ColorPrimaries::Unspecified, Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, Rav1dColorPrimaries::BT470BG => pixel::ColorPrimaries::BT470BG, Rav1dColorPrimaries::BT601 => pixel::ColorPrimaries::BT470BG, Rav1dColorPrimaries::SMPTE240 => pixel::ColorPrimaries::ST240M, - Rav1dColorPrimaries::FILM => pixel::ColorPrimaries::Film, + Rav1dColorPrimaries::Film => pixel::ColorPrimaries::Film, Rav1dColorPrimaries::BT2020 => pixel::ColorPrimaries::BT2020, Rav1dColorPrimaries::XYZ => pixel::ColorPrimaries::ST428, Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, - other_value => { - if other_value.is_unspecified() { - pixel::ColorPrimaries::Unspecified - } else { - return Err(Rav1dError::InvalidArgument); - } - } - }) + } } } @@ -679,27 +670,25 @@ impl Rav1dTransferCharacteristics { } } -impl TryInto for Rav1dTransferCharacteristics { - type Error = Rav1dError; - - fn try_into(self) -> Result { - Ok(match self { +impl From for pixel::TransferCharacteristic { + fn from(val: Rav1dTransferCharacteristics) -> Self { + match val { Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, - Rav1dTransferCharacteristics::UNSPECIFIED => pixel::TransferCharacteristic::Unspecified, + Rav1dTransferCharacteristics::Unspecified => pixel::TransferCharacteristic::Unspecified, Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, Rav1dTransferCharacteristics::BT470BG => pixel::TransferCharacteristic::BT470BG, Rav1dTransferCharacteristics::BT601 => pixel::TransferCharacteristic::ST170M, Rav1dTransferCharacteristics::SMPTE240 => pixel::TransferCharacteristic::ST240M, - Rav1dTransferCharacteristics::LINEAR => pixel::TransferCharacteristic::Linear, - Rav1dTransferCharacteristics::LOG100 => pixel::TransferCharacteristic::Logarithmic100, - Rav1dTransferCharacteristics::LOG100_SQRT10 => { + Rav1dTransferCharacteristics::Linear => pixel::TransferCharacteristic::Linear, + Rav1dTransferCharacteristics::Log100 => pixel::TransferCharacteristic::Logarithmic100, + Rav1dTransferCharacteristics::Log100Sqrt10 => { pixel::TransferCharacteristic::Logarithmic316 } Rav1dTransferCharacteristics::IEC61966 => pixel::TransferCharacteristic::SRGB, Rav1dTransferCharacteristics::BT1361 => pixel::TransferCharacteristic::BT1886, Rav1dTransferCharacteristics::SRGB => pixel::TransferCharacteristic::SRGB, - Rav1dTransferCharacteristics::BT2020_10BIT => pixel::TransferCharacteristic::BT2020Ten, - Rav1dTransferCharacteristics::BT2020_12BIT => { + Rav1dTransferCharacteristics::BT2020_10Bit => pixel::TransferCharacteristic::BT2020Ten, + Rav1dTransferCharacteristics::BT2020_12Bit => { pixel::TransferCharacteristic::BT2020Twelve } Rav1dTransferCharacteristics::SMPTE2084 => { @@ -707,14 +696,7 @@ impl TryInto for Rav1dTransferCharacteristics { } Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, - other_value => { - if other_value.is_unspecified() { - pixel::TransferCharacteristic::Unspecified - } else { - return Err(Rav1dError::InvalidArgument); - } - } - }) + } } } @@ -784,41 +766,30 @@ impl Rav1dMatrixCoefficients { } } -impl TryInto for Rav1dMatrixCoefficients { - type Error = Rav1dError; - - fn try_into(self) -> Result { - Ok(match self { - Rav1dMatrixCoefficients::IDENTITY => pixel::MatrixCoefficients::Identity, +impl From for pixel::MatrixCoefficients { + fn from(val: Rav1dMatrixCoefficients) -> Self { + match val { + Rav1dMatrixCoefficients::Identity => pixel::MatrixCoefficients::Identity, Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, - Rav1dMatrixCoefficients::UNSPECIFIED => pixel::MatrixCoefficients::Unspecified, + Rav1dMatrixCoefficients::Unspecified => pixel::MatrixCoefficients::Unspecified, Rav1dMatrixCoefficients::FCC => pixel::MatrixCoefficients::BT470M, Rav1dMatrixCoefficients::BT470BG => pixel::MatrixCoefficients::BT470BG, Rav1dMatrixCoefficients::BT601 => pixel::MatrixCoefficients::BT470BG, Rav1dMatrixCoefficients::SMPTE240 => pixel::MatrixCoefficients::ST240M, - Rav1dMatrixCoefficients::SMPTE_YCGCO => pixel::MatrixCoefficients::YCgCo, - Rav1dMatrixCoefficients::BT2020_NCL => { + Rav1dMatrixCoefficients::SMPTE_YCgCo => pixel::MatrixCoefficients::YCgCo, + Rav1dMatrixCoefficients::BT2020NCL => { pixel::MatrixCoefficients::BT2020NonConstantLuminance } - Rav1dMatrixCoefficients::BT2020_CL => { - pixel::MatrixCoefficients::BT2020ConstantLuminance - } + Rav1dMatrixCoefficients::BT2020CL => pixel::MatrixCoefficients::BT2020ConstantLuminance, Rav1dMatrixCoefficients::SMPTE2085 => pixel::MatrixCoefficients::ST2085, - Rav1dMatrixCoefficients::CHROMAT_NCL => { + Rav1dMatrixCoefficients::ChromatNCL => { pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance } - Rav1dMatrixCoefficients::CHROMAT_CL => { + Rav1dMatrixCoefficients::ChromatCL => { pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance } - Rav1dMatrixCoefficients::ICTCP => pixel::MatrixCoefficients::ICtCp, - other_value => { - if other_value.is_unspecified() { - pixel::MatrixCoefficients::Unspecified - } else { - return Err(Rav1dError::InvalidArgument); - } - } - }) + Rav1dMatrixCoefficients::ICtCp => pixel::MatrixCoefficients::ICtCp, + } } } From 9486894cbf874c0cf6e53e434a47602202343ab8 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sun, 21 Dec 2025 22:34:37 +0000 Subject: [PATCH 47/72] Add safety check --- src/rust_api.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 494a0abed..622865d37 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -364,13 +364,12 @@ pub struct Plane(Picture, PlanarImageComponent); impl AsRef<[u8]> for Plane { fn as_ref(&self) -> &[u8] { let (stride, height) = self.0.plane_data_geometry(self.1); - // SAFETY: both stride and height can't be negative, the `stride` and `height` methods panic if they are so there's no undefined behaviour - unsafe { - slice::from_raw_parts( - self.0.plane_data_ptr(self.1) as *const u8, - (stride * height) as usize, - ) + let data = self.0.plane_data_ptr(self.1) as *const u8; + if stride == 0 || data.is_null() { + return &[]; } + // SAFETY: Copied checks from david-rs added in this pull request https://github.com/rust-av/dav1d-rs/pull/121 + unsafe { slice::from_raw_parts(data, stride as usize * height as usize) } } } From 8ce9bf7b8f98663a2322faf8d44a988c47c69d46 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 7 Feb 2026 19:40:59 +0000 Subject: [PATCH 48/72] Fix comments in rust_api --- src/rust_api.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 622865d37..cd7e585ac 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -148,7 +148,7 @@ impl Settings { } } -/// A `dav1d` decoder instance. +/// A `rav1d` decoder instance. pub struct Decoder { ctx: Arc, pending_data: Option, @@ -186,12 +186,12 @@ impl Decoder { /// Send new AV1 data to the decoder. /// - /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// After this returned `Ok(())` or `Err(`[`Rav1dError::TryAgain`]`)` there might be decoded frames /// available via [`Decoder::get_picture`]. /// /// # Panics /// - /// If a previous call returned [`Error::Again`] then this must not be called again until + /// If a previous call returned [`Rav1dError::TryAgain`] then this must not be called again until /// [`Decoder::send_pending_data`] has returned `Ok(())`. pub fn send_data + Send + Sync + 'static>( &mut self, @@ -241,10 +241,10 @@ impl Decoder { /// Sends any pending data to the decoder. /// - /// This has to be called after [`Decoder::send_data`] has returned `Err([Error::Again])` to + /// This has to be called after [`Decoder::send_data`] has returned `Err(`[`Rav1dError::TryAgain`]`)` to /// consume any futher pending data. /// - /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// After this returned `Ok(())` or `Err(`[`Rav1dError::TryAgain`]`)` there might be decoded frames /// available via [`Decoder::get_picture`]. pub fn send_pending_data(&mut self) -> Result<(), Rav1dError> { let mut data = match self.pending_data.take() { @@ -274,11 +274,11 @@ impl Decoder { /// Get the next decoded frame from the decoder. /// - /// If this returns `Err([Error::Again])` then further data has to be sent to the decoder + /// If this returns `Err(`[`Rav1dError::TryAgain`]`)` then further data has to be sent to the decoder /// before further decoded frames become available. /// /// To make most use of frame threading this function should only be called once per submitted - /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should + /// input frame and not until it returns `Err(`[`Rav1dError::TryAgain`]`)`. Calling it in a loop should /// only be done to drain all pending frames at the end. pub fn get_picture(&mut self) -> Result { let mut pic = Rav1dPicture::default(); @@ -310,7 +310,7 @@ impl Drop for Decoder { if let Some(mut pending_data) = self.pending_data.take() { let _ = mem::take(&mut pending_data); } - rav1d_close(self.ctx.clone()); + rav1d_close(&self.ctx.clone()); } } From 55c3e3dba8829b6f2d99300d67264e389c7427b5 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 7 Feb 2026 20:16:25 +0000 Subject: [PATCH 49/72] Remove `'static` on send_data --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index cd7e585ac..84beaf046 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -193,7 +193,7 @@ impl Decoder { /// /// If a previous call returned [`Rav1dError::TryAgain`] then this must not be called again until /// [`Decoder::send_pending_data`] has returned `Ok(())`. - pub fn send_data + Send + Sync + 'static>( + pub fn send_data + Send + Sync>( &mut self, buf: T, offset: Option, From 29356b636306b26b2ca042032d380996d98920a9 Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:20:10 +0000 Subject: [PATCH 50/72] Fix nit in rust_api Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 84beaf046..45c876752 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -231,7 +231,7 @@ impl Decoder { return Err(err); } - if data.data.as_ref().is_some_and(|d| d.len() > 0) { + if data.data.as_ref().is_some_and(|d| !d.is_empty()) { self.pending_data = Some(data); return Err(Rav1dError::TryAgain); } From 9e241d9ee5fb3d1f4d7b3beb7c963a5ab66d5519 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 7 Feb 2026 20:54:38 +0000 Subject: [PATCH 51/72] Cleaned up a series of code issues --- src/rust_api.rs | 87 ++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 45c876752..bec9995a7 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -28,7 +28,7 @@ use std::ffi::c_void; use std::fmt::{Debug, Formatter}; use std::ops::Deref; use std::sync::Arc; -use std::{fmt, mem, slice}; +use std::{fmt, slice}; pub use av_data::pixel; @@ -179,9 +179,6 @@ impl Decoder { /// All currently pending frames are available afterwards via [`Decoder::get_picture`]. pub fn flush(&mut self) { rav1d_flush(&self.ctx); - if let Some(mut pending_data) = self.pending_data.take() { - let _ = mem::take(&mut pending_data); - } } /// Send new AV1 data to the decoder. @@ -220,23 +217,8 @@ impl Decoder { if let Some(duration) = duration { data.m.duration = duration; } - - if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { - if matches!(err, Rav1dError::TryAgain) { - self.pending_data = Some(data); - } else { - let _ = mem::take(&mut data); - } - - return Err(err); - } - - if data.data.as_ref().is_some_and(|d| !d.is_empty()) { - self.pending_data = Some(data); - return Err(Rav1dError::TryAgain); - } - - Ok(()) + self.pending_data = Some(data); + self.send_pending_data() } /// Sends any pending data to the decoder. @@ -247,24 +229,18 @@ impl Decoder { /// After this returned `Ok(())` or `Err(`[`Rav1dError::TryAgain`]`)` there might be decoded frames /// available via [`Decoder::get_picture`]. pub fn send_pending_data(&mut self) -> Result<(), Rav1dError> { - let mut data = match self.pending_data.take() { - None => { - return Ok(()); - } - Some(data) => data, + let Some(mut data) = self.pending_data.take() else { + return Ok(()); }; if let Err(err) = rav1d_send_data(&self.ctx, &mut data) { if matches!(err, Rav1dError::TryAgain) { self.pending_data = Some(data); - } else { - let _ = mem::take(&mut data); } - return Err(err); } - if data.data.as_ref().is_some_and(|d| d.len() > 0) { + if data.data.as_ref().is_some_and(|d| !d.is_empty()) { self.pending_data = Some(data); return Err(Rav1dError::TryAgain); } @@ -282,20 +258,17 @@ impl Decoder { /// only be done to drain all pending frames at the end. pub fn get_picture(&mut self) -> Result { let mut pic = Rav1dPicture::default(); - let ret = rav1d_get_picture(&self.ctx, &mut pic); + rav1d_get_picture(&self.ctx, &mut pic)?; - if let Err(err) = ret { - Err(err) - } else { - Ok(Picture { - inner: Arc::new(pic), - }) - } + Ok(Picture { + inner: Arc::new(pic), + }) } /// Get the decoder delay. pub fn get_frame_delay(&self) -> u32 { - // The only fields this actually needs from Rav1dSettings are n_threads and max_frame_delay so we just pass these in directly + // The only fields this actually needs from `Rav1dSettings` + // are n_threads and max_frame_delay so we just pass these in directly rav1d_get_frame_delay(&Rav1dSettings { n_threads: self.n_threads, @@ -307,10 +280,7 @@ impl Decoder { impl Drop for Decoder { fn drop(&mut self) { - if let Some(mut pending_data) = self.pending_data.take() { - let _ = mem::take(&mut pending_data); - } - rav1d_close(&self.ctx.clone()); + rav1d_close(&self.ctx); } } @@ -359,17 +329,29 @@ impl From for usize { /// /// This can be used like a `&[u8]`. #[derive(Clone)] -pub struct Plane(Picture, PlanarImageComponent); +pub struct Plane { + picture: Picture, + planar_image_component: PlanarImageComponent, +} impl AsRef<[u8]> for Plane { fn as_ref(&self) -> &[u8] { - let (stride, height) = self.0.plane_data_geometry(self.1); - let data = self.0.plane_data_ptr(self.1) as *const u8; + let (stride, height) = self + .picture + .plane_data_geometry(self.planar_image_component); + let data = self.picture.plane_data_ptr(self.planar_image_component) as *const u8; if stride == 0 || data.is_null() { return &[]; } - // SAFETY: Copied checks from david-rs added in this pull request https://github.com/rust-av/dav1d-rs/pull/121 - unsafe { slice::from_raw_parts(data, stride as usize * height as usize) } + // SAFETY: Copied checks from dav1d-rs added in this pull request https://github.com/rust-av/dav1d-rs/pull/121 + unsafe { + slice::from_raw_parts( + data, + (stride as usize) + .checked_mul(height as usize) + .expect("The product of stride and height exceeded usize::MAX"), + ) + } } } @@ -423,7 +405,7 @@ impl Picture { let height = match component { PlanarImageComponent::Y => self.height(), _ => match self.pixel_layout() { - PixelLayout::I420 => (self.height() + 1) / 2, + PixelLayout::I420 => self.height().div_ceil(2), PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), }, }; @@ -432,7 +414,10 @@ impl Picture { /// Plane data of the `component` for the decoded frame. pub fn plane(&self, component: PlanarImageComponent) -> Plane { - Plane(self.clone(), component) + Plane { + picture: self.clone(), + planar_image_component: component, + } } /// Bit depth of the plane data. @@ -491,7 +476,7 @@ impl Picture { /// This is the same offset as the one provided to [`Decoder::send_data`] or `-1` if none was /// provided. pub fn offset(&self) -> i64 { - self.inner.m.offset as i64 + self.inner.m.offset } /// Chromaticity coordinates of the source colour primaries. From 3fa4b7a1578016f41ba6bc365ce5f6c70a18e98d Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 7 Feb 2026 22:57:39 +0000 Subject: [PATCH 52/72] Replace TryFrom with new on BitsPerComponent --- src/rust_api.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index bec9995a7..4b0742e8e 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -367,10 +367,8 @@ impl Deref for Plane { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct BitsPerComponent(pub u8); -impl TryFrom for BitsPerComponent { - type Error = Rav1dError; - - fn try_from(value: u8) -> Result { +impl BitsPerComponent { + pub fn new(value: u8) -> Result { match value { 0 => Ok(BitsPerComponent(8)), 1 => Ok(BitsPerComponent(10)), @@ -433,7 +431,7 @@ impl Picture { /// /// Check [`Picture::bit_depth`] for the number of storage bits. pub fn bits_per_component(&self) -> Option { - self.inner.seq_hdr.as_ref().unwrap().hbd.try_into().ok() + BitsPerComponent::new(self.inner.seq_hdr.as_ref().unwrap().hbd).ok() } /// Width of the frame. From 1c0716c0c1c370e84e8270ad59f747fc43051a89 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 7 Feb 2026 23:07:00 +0000 Subject: [PATCH 53/72] Rename BitsPerComponent::new to from_hbd and add comment --- src/rust_api.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 4b0742e8e..c9d575e06 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -368,8 +368,9 @@ impl Deref for Plane { pub struct BitsPerComponent(pub u8); impl BitsPerComponent { - pub fn new(value: u8) -> Result { - match value { + /// Get the number of bits per component from the high bit depth flag + pub fn from_hbd(hbd: u8) -> Result { + match hbd { 0 => Ok(BitsPerComponent(8)), 1 => Ok(BitsPerComponent(10)), 2 => Ok(BitsPerComponent(12)), @@ -431,7 +432,7 @@ impl Picture { /// /// Check [`Picture::bit_depth`] for the number of storage bits. pub fn bits_per_component(&self) -> Option { - BitsPerComponent::new(self.inner.seq_hdr.as_ref().unwrap().hbd).ok() + BitsPerComponent::from_hbd(self.inner.seq_hdr.as_ref().unwrap().hbd).ok() } /// Width of the frame. From 9af4d23fd04906a04562e5ab95b2e5196cbe38f6 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 7 Feb 2026 23:27:14 +0000 Subject: [PATCH 54/72] Got rid of `Plane`, cleaned up functions in `Picture` --- src/rust_api.rs | 79 +++++++++++++------------------------------------ 1 file changed, 20 insertions(+), 59 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index c9d575e06..e2598b59b 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -24,9 +24,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -use std::ffi::c_void; use std::fmt::{Debug, Formatter}; -use std::ops::Deref; use std::sync::Arc; use std::{fmt, slice}; @@ -325,44 +323,6 @@ impl From for usize { } } -/// A single plane of a decoded frame. -/// -/// This can be used like a `&[u8]`. -#[derive(Clone)] -pub struct Plane { - picture: Picture, - planar_image_component: PlanarImageComponent, -} - -impl AsRef<[u8]> for Plane { - fn as_ref(&self) -> &[u8] { - let (stride, height) = self - .picture - .plane_data_geometry(self.planar_image_component); - let data = self.picture.plane_data_ptr(self.planar_image_component) as *const u8; - if stride == 0 || data.is_null() { - return &[]; - } - // SAFETY: Copied checks from dav1d-rs added in this pull request https://github.com/rust-av/dav1d-rs/pull/121 - unsafe { - slice::from_raw_parts( - data, - (stride as usize) - .checked_mul(height as usize) - .expect("The product of stride and height exceeded usize::MAX"), - ) - } - } -} - -impl Deref for Plane { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - self.as_ref() - } -} - /// Number of bits per component. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct BitsPerComponent(pub u8); @@ -389,18 +349,8 @@ impl Picture { self.inner.stride[s].try_into().unwrap() } - /// Raw pointer to the data of the `component` for the decoded frame. - pub fn plane_data_ptr(&self, component: PlanarImageComponent) -> *mut c_void { - let index: usize = component.into(); - self.inner.data.as_ref().unwrap().data[index] - .as_byte_mut_ptr() - .cast() - } - - /// Plane geometry of the `component` for the decoded frame. - /// - /// This returns the stride and height. - pub fn plane_data_geometry(&self, component: PlanarImageComponent) -> (u32, u32) { + /// Plane data of the `component` for the decoded frame. + pub fn plane_data(&self, component: PlanarImageComponent) -> &[u8] { let height = match component { PlanarImageComponent::Y => self.height(), _ => match self.pixel_layout() { @@ -408,14 +358,25 @@ impl Picture { PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), }, }; - (self.stride(component), height) - } - /// Plane data of the `component` for the decoded frame. - pub fn plane(&self, component: PlanarImageComponent) -> Plane { - Plane { - picture: self.clone(), - planar_image_component: component, + let stride = self.stride(component); + + // Get a raw pointer to the plane data of the `component` for the decoded frame. + let index: usize = component.into(); + let raw_plane_data_pointer = + self.inner.data.as_ref().unwrap().data[index].as_byte_mut_ptr() as *const u8; + + if stride == 0 || raw_plane_data_pointer.is_null() { + return &[]; + } + // SAFETY: Copied checks from dav1d-rs added in this pull request https://github.com/rust-av/dav1d-rs/pull/121 + unsafe { + slice::from_raw_parts( + raw_plane_data_pointer, + (stride as usize) + .checked_mul(height as usize) + .expect("The product of stride and height exceeded usize::MAX"), + ) } } From 8301fad51114ee75d15469084138d5e126095fe2 Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:40:38 +0000 Subject: [PATCH 55/72] Fix imports in rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rust_api.rs b/src/rust_api.rs index e2598b59b..dc805cbe0 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -24,6 +24,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. + use std::fmt::{Debug, Formatter}; use std::sync::Arc; use std::{fmt, slice}; From 739cde4badbd5bfb733ecd3e29c9cc1d9d2bc98e Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:42:47 +0000 Subject: [PATCH 56/72] Fix header comment in rust_api.rs Co-authored-by: Khyber Sen --- src/rust_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index dc805cbe0..a1984856e 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -2,7 +2,7 @@ // (specifically https://github.com/rust-av/dav1d-rs/blob/94b1deaa1e25bf29c77bb5cc8a08ddaf7663eede/src/lib.rs) // with modifications. // `dav1d-rs` is under the MIT license, replicated here: - +// // MIT License // // Copyright (c) 2018 Luca Barbato From 8465178dfa361521190db1c2901abaf984d5a03c Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Sat, 14 Feb 2026 13:54:11 +0000 Subject: [PATCH 57/72] Handle grayscale images better Co-authored-by: Sergey "Shnatsel" Davidoff --- src/rust_api.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index a1984856e..263b55114 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -356,7 +356,8 @@ impl Picture { PlanarImageComponent::Y => self.height(), _ => match self.pixel_layout() { PixelLayout::I420 => self.height().div_ceil(2), - PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), + PixelLayout::I422 | PixelLayout::I444 => self.height(), + PixelLayout::I400 => return &[]; // grayscale images don't have color components }, }; From 8acde6d1b4f3366d13c6be45f009d6e1173b9a24 Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Sat, 14 Feb 2026 13:55:42 +0000 Subject: [PATCH 58/72] Add safety comment in rust_api Co-authored-by: Sergey "Shnatsel" Davidoff --- src/rust_api.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 263b55114..e5180f856 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -371,7 +371,26 @@ impl Picture { if stride == 0 || raw_plane_data_pointer.is_null() { return &[]; } - // SAFETY: Copied checks from dav1d-rs added in this pull request https://github.com/rust-av/dav1d-rs/pull/121 + // SAFETY: The following invariants are upheld: + // 1. Pointer validity: Checked above - if null or stride is 0, we return &[]. + // 2. Pointer alignment: The allocator guarantees RAV1D_PICTURE_ALIGNMENT (64-byte) + // alignment (see Rav1dPictureDataComponentInner::new), which exceeds any + // primitive type's alignment requirements. + // 3. Allocated size: The allocator guarantees the buffer is at least stride * height + // bytes (the allocator callback contract in Dav1dPicAllocator). The checked_mul + // ensures this calculation doesn't overflow. + // 4. Initialization: The allocator is required to initialize the data per the + // alloc_picture_callback safety requirements. + // 5. Lifetime: The returned slice borrows &self, keeping the Arc + // alive for the duration of the borrow. + // 6. No mutable aliases: The Picture is only returned after decoding is complete, + // so the decoder no longer writes to this buffer. The public API only exposes + // shared (&[u8]) access, and no &mut references to this data can exist once + // the Picture is handed to the user. + // + // Past dav1d-rs PRs relevant to this line: + // https://github.com/rust-av/dav1d-rs/pull/121 + // https://github.com/rust-av/dav1d-rs/pull/123 unsafe { slice::from_raw_parts( raw_plane_data_pointer, From 5e31f3a9377c7af3a19dc70a447b6429b6007846 Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Sat, 14 Feb 2026 13:57:02 +0000 Subject: [PATCH 59/72] Improve send_data Co-authored-by: Khyber Sen --- src/rust_api.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index e5180f856..52613e051 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -189,9 +189,9 @@ impl Decoder { /// /// If a previous call returned [`Rav1dError::TryAgain`] then this must not be called again until /// [`Decoder::send_pending_data`] has returned `Ok(())`. - pub fn send_data + Send + Sync>( + pub fn send_data( &mut self, - buf: T, + buf: Box<[u8]>, offset: Option, timestamp: Option, duration: Option, @@ -201,12 +201,7 @@ impl Decoder { "Have pending data that needs to be handled first" ); - let buf = buf.as_ref().to_vec().into_boxed_slice(); - let slice = &*buf; - let len = slice.len(); - - let mut data = Rav1dData::create(len).unwrap(); - data.data = Some(CArc::wrap(CBox::from_box(buf)).unwrap()); + let mut data = Rav1dData::wrap(CRef::Box(buf))?; if let Some(offset) = offset { data.m.offset = offset; } From 10e9ee1685aeedc8d177daddff950a082943c66b Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 14 Feb 2026 14:19:04 +0000 Subject: [PATCH 60/72] Fix some small issues --- src/rust_api.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 52613e051..544e4e109 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -31,8 +31,6 @@ use std::{fmt, slice}; pub use av_data::pixel; -use crate::c_arc::CArc; -use crate::c_box::CBox; use crate::error::Rav1dError; use crate::in_range::InRange; pub use crate::include::dav1d::dav1d::{ @@ -48,7 +46,7 @@ use crate::internal::Rav1dContext; use crate::pixels::Pixels; use crate::{ rav1d_close, rav1d_flush, rav1d_get_frame_delay, rav1d_get_picture, rav1d_open, - rav1d_send_data, Rav1dData, Rav1dSettings, + rav1d_send_data, CRef, Rav1dData, Rav1dSettings, }; /// Settings for creating a new [`Decoder`] instance. @@ -352,7 +350,7 @@ impl Picture { _ => match self.pixel_layout() { PixelLayout::I420 => self.height().div_ceil(2), PixelLayout::I422 | PixelLayout::I444 => self.height(), - PixelLayout::I400 => return &[]; // grayscale images don't have color components + PixelLayout::I400 => return &[], // grayscale images don't have color components }, }; From 73c5faca53e06c627f552d76f6ba84b4791456bc Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 14 Feb 2026 14:22:18 +0000 Subject: [PATCH 61/72] Remove Send Sync assertion from Decoder --- src/rust_api.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 544e4e109..baf6e1923 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -276,8 +276,6 @@ impl Drop for Decoder { } } -static_assertions::assert_impl_all!(Decoder: Send, Sync); - /// A decoded frame. #[derive(Clone)] pub struct Picture { From edcb5a1d356b690ca751c7b50edabe56d2a71fff Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Fri, 20 Feb 2026 17:12:25 +0000 Subject: [PATCH 62/72] Pull error handling out of unsafe block in rust_api --- src/rust_api.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index baf6e1923..91862d969 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -362,6 +362,9 @@ impl Picture { if stride == 0 || raw_plane_data_pointer.is_null() { return &[]; } + let data_length = (stride as usize) + .checked_mul(height as usize) + .expect("The product of stride and height exceeded usize::MAX"); // SAFETY: The following invariants are upheld: // 1. Pointer validity: Checked above - if null or stride is 0, we return &[]. // 2. Pointer alignment: The allocator guarantees RAV1D_PICTURE_ALIGNMENT (64-byte) @@ -382,14 +385,7 @@ impl Picture { // Past dav1d-rs PRs relevant to this line: // https://github.com/rust-av/dav1d-rs/pull/121 // https://github.com/rust-av/dav1d-rs/pull/123 - unsafe { - slice::from_raw_parts( - raw_plane_data_pointer, - (stride as usize) - .checked_mul(height as usize) - .expect("The product of stride and height exceeded usize::MAX"), - ) - } + unsafe { slice::from_raw_parts(raw_plane_data_pointer, data_length) } } /// Bit depth of the plane data. From 2ea4ce695d89b7c4525c88e0252595a588bf2e86 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Fri, 20 Feb 2026 17:13:54 +0000 Subject: [PATCH 63/72] Fix nit --- src/rust_api.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 91862d969..c6100290a 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -356,8 +356,9 @@ impl Picture { // Get a raw pointer to the plane data of the `component` for the decoded frame. let index: usize = component.into(); - let raw_plane_data_pointer = - self.inner.data.as_ref().unwrap().data[index].as_byte_mut_ptr() as *const u8; + let raw_plane_data_pointer = self.inner.data.as_ref().unwrap().data[index] + .as_byte_mut_ptr() + .cast_const(); if stride == 0 || raw_plane_data_pointer.is_null() { return &[]; From 3a50834ce3743bc580f340ba3bfbdbf6a46ab783 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 21 Feb 2026 11:44:37 +0000 Subject: [PATCH 64/72] Add back in Send Sync assertion for Decoder --- Cargo.toml | 1 - src/rust_api.rs | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ec41ea741..94cb6ab89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ paste = "1.0.14" raw-cpuid = "11.0.1" static_assertions = "1.1.0" strum = { version = "0.27", features = ["derive"] } -static_assertions = "1.0.0" to_method = "1.1.0" zerocopy = { version = "0.7.32", features = ["derive"] } diff --git a/src/rust_api.rs b/src/rust_api.rs index c6100290a..776a446f4 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -276,6 +276,8 @@ impl Drop for Decoder { } } +static_assertions::assert_impl_all!(Decoder: Send, Sync); + /// A decoded frame. #[derive(Clone)] pub struct Picture { From df03c0b00c538488612f2c8897a0eff0fc043f7a Mon Sep 17 00:00:00 2001 From: Leo Ring <59373587+leo030303@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:56:35 +0000 Subject: [PATCH 65/72] Safer rewrite of plane_data Co-authored-by: Khyber Sen --- src/rust_api.rs | 54 +++++++++---------------------------------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 776a446f4..46a5a3c26 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -344,51 +344,15 @@ impl Picture { } /// Plane data of the `component` for the decoded frame. - pub fn plane_data(&self, component: PlanarImageComponent) -> &[u8] { - let height = match component { - PlanarImageComponent::Y => self.height(), - _ => match self.pixel_layout() { - PixelLayout::I420 => self.height().div_ceil(2), - PixelLayout::I422 | PixelLayout::I444 => self.height(), - PixelLayout::I400 => return &[], // grayscale images don't have color components - }, - }; - - let stride = self.stride(component); - - // Get a raw pointer to the plane data of the `component` for the decoded frame. - let index: usize = component.into(); - let raw_plane_data_pointer = self.inner.data.as_ref().unwrap().data[index] - .as_byte_mut_ptr() - .cast_const(); - - if stride == 0 || raw_plane_data_pointer.is_null() { - return &[]; - } - let data_length = (stride as usize) - .checked_mul(height as usize) - .expect("The product of stride and height exceeded usize::MAX"); - // SAFETY: The following invariants are upheld: - // 1. Pointer validity: Checked above - if null or stride is 0, we return &[]. - // 2. Pointer alignment: The allocator guarantees RAV1D_PICTURE_ALIGNMENT (64-byte) - // alignment (see Rav1dPictureDataComponentInner::new), which exceeds any - // primitive type's alignment requirements. - // 3. Allocated size: The allocator guarantees the buffer is at least stride * height - // bytes (the allocator callback contract in Dav1dPicAllocator). The checked_mul - // ensures this calculation doesn't overflow. - // 4. Initialization: The allocator is required to initialize the data per the - // alloc_picture_callback safety requirements. - // 5. Lifetime: The returned slice borrows &self, keeping the Arc - // alive for the duration of the borrow. - // 6. No mutable aliases: The Picture is only returned after decoding is complete, - // so the decoder no longer writes to this buffer. The public API only exposes - // shared (&[u8]) access, and no &mut references to this data can exist once - // the Picture is handed to the user. - // - // Past dav1d-rs PRs relevant to this line: - // https://github.com/rust-av/dav1d-rs/pull/121 - // https://github.com/rust-av/dav1d-rs/pull/123 - unsafe { slice::from_raw_parts(raw_plane_data_pointer, data_length) } + pub fn plane_data<'a>(&'a self, component: PlanarImageComponent) -> &'a [u8] { + let data = &self.inner.data.as_ref().unwrap().data; + let component = &data[usize::from(component)]; + let guard = component.slice::(..); + // SAFETY: [`Picture`] is only created after decoding is complete + // (in [`Decoder::get_picture`], which calls [`rav1d_get_picture`]). + // Thus, the decoder no longer writes to this data, + // and there are no other safe public ways to have a `&mut` to this data. + unsafe { guard.unchecked_disjoint_mut() } } /// Bit depth of the plane data. From e7296b8c721ec70b081300880038ac233fb7aea1 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 21 Mar 2026 12:01:55 +0000 Subject: [PATCH 66/72] Fix up last commit --- src/disjoint_mut.rs | 9 +++++++++ src/rust_api.rs | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/disjoint_mut.rs b/src/disjoint_mut.rs index acc02d636..5fe498787 100644 --- a/src/disjoint_mut.rs +++ b/src/disjoint_mut.rs @@ -208,6 +208,15 @@ impl<'a, T: ?Sized + AsMutPtr, V: ?Sized> Deref for DisjointImmutGuard<'a, T, V> } } +impl<'a, T: ?Sized + AsMutPtr, V: ?Sized> DisjointImmutGuard<'a, T, V> { + // # Safety + // + // This is no longer checked at runtime to be legitimately disjoint mut. + pub unsafe fn unchecked_disjoint_mut(&self) -> &'a V { + self.slice + } +} + /// Convert from a mutable pointer to a collection to a mutable pointer to the /// underlying slice without ever creating a mutable reference to the slice. /// diff --git a/src/rust_api.rs b/src/rust_api.rs index 46a5a3c26..53b521b84 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -25,14 +25,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +use std::fmt; use std::fmt::{Debug, Formatter}; use std::sync::Arc; -use std::{fmt, slice}; pub use av_data::pixel; use crate::error::Rav1dError; use crate::in_range::InRange; +use crate::include::common::bitdepth::BitDepth8; pub use crate::include::dav1d::dav1d::{ Rav1dDecodeFrameType as DecodeFrameType, Rav1dInloopFilterType as InloopFilterType, }; @@ -43,7 +44,6 @@ pub use crate::include::dav1d::headers::{ use crate::include::dav1d::picture::Rav1dPicture; pub use crate::include::dav1d::picture::RAV1D_PICTURE_ALIGNMENT as PICTURE_ALIGNMENT; use crate::internal::Rav1dContext; -use crate::pixels::Pixels; use crate::{ rav1d_close, rav1d_flush, rav1d_get_frame_delay, rav1d_get_picture, rav1d_open, rav1d_send_data, CRef, Rav1dData, Rav1dSettings, From f8d14301e2d6e3cecbc226267f176da111d1f472 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 23 Mar 2026 15:24:46 -0700 Subject: [PATCH 67/72] use `TryFrom` (instead of `TryInto`) for `Rav1dChromaSamplePosition` => `pixel::ChromaLocation` conversion --- src/include/dav1d/headers.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 595f31c35..90e9520e0 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -832,12 +832,12 @@ impl From for Dav1dChromaSamplePosition { } } -impl TryInto for Rav1dChromaSamplePosition { +impl TryFrom for pixel::ChromaLocation { type Error = Rav1dError; - fn try_into(self) -> Result { + fn try_from(value: Rav1dChromaSamplePosition) -> Result { // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c - match self { + match value { Rav1dChromaSamplePosition::Unknown | Rav1dChromaSamplePosition::Colocated => { Ok(pixel::ChromaLocation::Center) } From f9e73bde1f8e4099e4fafb371aeedac72d1d7187 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 23 Mar 2026 15:27:39 -0700 Subject: [PATCH 68/72] use `Self::` in conversion functions --- src/include/dav1d/headers.rs | 102 ++++++++++++++++------------------- src/rust_api.rs | 12 ++--- 2 files changed, 51 insertions(+), 63 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 90e9520e0..80dcec380 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -572,18 +572,18 @@ impl Rav1dColorPrimaries { impl From for pixel::ColorPrimaries { fn from(val: Rav1dColorPrimaries) -> Self { match val { - Rav1dColorPrimaries::BT709 => pixel::ColorPrimaries::BT709, - Rav1dColorPrimaries::Unspecified => pixel::ColorPrimaries::Unspecified, - Rav1dColorPrimaries::BT470M => pixel::ColorPrimaries::BT470M, - Rav1dColorPrimaries::BT470BG => pixel::ColorPrimaries::BT470BG, - Rav1dColorPrimaries::BT601 => pixel::ColorPrimaries::BT470BG, - Rav1dColorPrimaries::SMPTE240 => pixel::ColorPrimaries::ST240M, - Rav1dColorPrimaries::Film => pixel::ColorPrimaries::Film, - Rav1dColorPrimaries::BT2020 => pixel::ColorPrimaries::BT2020, - Rav1dColorPrimaries::XYZ => pixel::ColorPrimaries::ST428, - Rav1dColorPrimaries::SMPTE431 => pixel::ColorPrimaries::P3DCI, - Rav1dColorPrimaries::SMPTE432 => pixel::ColorPrimaries::P3Display, - Rav1dColorPrimaries::EBU3213 => pixel::ColorPrimaries::Tech3213, + Rav1dColorPrimaries::BT709 => Self::BT709, + Rav1dColorPrimaries::Unspecified => Self::Unspecified, + Rav1dColorPrimaries::BT470M => Self::BT470M, + Rav1dColorPrimaries::BT470BG => Self::BT470BG, + Rav1dColorPrimaries::BT601 => Self::BT470BG, + Rav1dColorPrimaries::SMPTE240 => Self::ST240M, + Rav1dColorPrimaries::Film => Self::Film, + Rav1dColorPrimaries::BT2020 => Self::BT2020, + Rav1dColorPrimaries::XYZ => Self::ST428, + Rav1dColorPrimaries::SMPTE431 => Self::P3DCI, + Rav1dColorPrimaries::SMPTE432 => Self::P3Display, + Rav1dColorPrimaries::EBU3213 => Self::Tech3213, } } } @@ -673,29 +673,23 @@ impl Rav1dTransferCharacteristics { impl From for pixel::TransferCharacteristic { fn from(val: Rav1dTransferCharacteristics) -> Self { match val { - Rav1dTransferCharacteristics::BT709 => pixel::TransferCharacteristic::BT1886, - Rav1dTransferCharacteristics::Unspecified => pixel::TransferCharacteristic::Unspecified, - Rav1dTransferCharacteristics::BT470M => pixel::TransferCharacteristic::BT470M, - Rav1dTransferCharacteristics::BT470BG => pixel::TransferCharacteristic::BT470BG, - Rav1dTransferCharacteristics::BT601 => pixel::TransferCharacteristic::ST170M, - Rav1dTransferCharacteristics::SMPTE240 => pixel::TransferCharacteristic::ST240M, - Rav1dTransferCharacteristics::Linear => pixel::TransferCharacteristic::Linear, - Rav1dTransferCharacteristics::Log100 => pixel::TransferCharacteristic::Logarithmic100, - Rav1dTransferCharacteristics::Log100Sqrt10 => { - pixel::TransferCharacteristic::Logarithmic316 - } - Rav1dTransferCharacteristics::IEC61966 => pixel::TransferCharacteristic::SRGB, - Rav1dTransferCharacteristics::BT1361 => pixel::TransferCharacteristic::BT1886, - Rav1dTransferCharacteristics::SRGB => pixel::TransferCharacteristic::SRGB, - Rav1dTransferCharacteristics::BT2020_10Bit => pixel::TransferCharacteristic::BT2020Ten, - Rav1dTransferCharacteristics::BT2020_12Bit => { - pixel::TransferCharacteristic::BT2020Twelve - } - Rav1dTransferCharacteristics::SMPTE2084 => { - pixel::TransferCharacteristic::PerceptualQuantizer - } - Rav1dTransferCharacteristics::SMPTE428 => pixel::TransferCharacteristic::ST428, - Rav1dTransferCharacteristics::HLG => pixel::TransferCharacteristic::HybridLogGamma, + Rav1dTransferCharacteristics::BT709 => Self::BT1886, + Rav1dTransferCharacteristics::Unspecified => Self::Unspecified, + Rav1dTransferCharacteristics::BT470M => Self::BT470M, + Rav1dTransferCharacteristics::BT470BG => Self::BT470BG, + Rav1dTransferCharacteristics::BT601 => Self::ST170M, + Rav1dTransferCharacteristics::SMPTE240 => Self::ST240M, + Rav1dTransferCharacteristics::Linear => Self::Linear, + Rav1dTransferCharacteristics::Log100 => Self::Logarithmic100, + Rav1dTransferCharacteristics::Log100Sqrt10 => Self::Logarithmic316, + Rav1dTransferCharacteristics::IEC61966 => Self::SRGB, + Rav1dTransferCharacteristics::BT1361 => Self::BT1886, + Rav1dTransferCharacteristics::SRGB => Self::SRGB, + Rav1dTransferCharacteristics::BT2020_10Bit => Self::BT2020Ten, + Rav1dTransferCharacteristics::BT2020_12Bit => Self::BT2020Twelve, + Rav1dTransferCharacteristics::SMPTE2084 => Self::PerceptualQuantizer, + Rav1dTransferCharacteristics::SMPTE428 => Self::ST428, + Rav1dTransferCharacteristics::HLG => Self::HybridLogGamma, } } } @@ -769,26 +763,20 @@ impl Rav1dMatrixCoefficients { impl From for pixel::MatrixCoefficients { fn from(val: Rav1dMatrixCoefficients) -> Self { match val { - Rav1dMatrixCoefficients::Identity => pixel::MatrixCoefficients::Identity, - Rav1dMatrixCoefficients::BT709 => pixel::MatrixCoefficients::BT709, - Rav1dMatrixCoefficients::Unspecified => pixel::MatrixCoefficients::Unspecified, - Rav1dMatrixCoefficients::FCC => pixel::MatrixCoefficients::BT470M, - Rav1dMatrixCoefficients::BT470BG => pixel::MatrixCoefficients::BT470BG, - Rav1dMatrixCoefficients::BT601 => pixel::MatrixCoefficients::BT470BG, - Rav1dMatrixCoefficients::SMPTE240 => pixel::MatrixCoefficients::ST240M, - Rav1dMatrixCoefficients::SMPTE_YCgCo => pixel::MatrixCoefficients::YCgCo, - Rav1dMatrixCoefficients::BT2020NCL => { - pixel::MatrixCoefficients::BT2020NonConstantLuminance - } - Rav1dMatrixCoefficients::BT2020CL => pixel::MatrixCoefficients::BT2020ConstantLuminance, - Rav1dMatrixCoefficients::SMPTE2085 => pixel::MatrixCoefficients::ST2085, - Rav1dMatrixCoefficients::ChromatNCL => { - pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance - } - Rav1dMatrixCoefficients::ChromatCL => { - pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance - } - Rav1dMatrixCoefficients::ICtCp => pixel::MatrixCoefficients::ICtCp, + Rav1dMatrixCoefficients::Identity => Self::Identity, + Rav1dMatrixCoefficients::BT709 => Self::BT709, + Rav1dMatrixCoefficients::Unspecified => Self::Unspecified, + Rav1dMatrixCoefficients::FCC => Self::BT470M, + Rav1dMatrixCoefficients::BT470BG => Self::BT470BG, + Rav1dMatrixCoefficients::BT601 => Self::BT470BG, + Rav1dMatrixCoefficients::SMPTE240 => Self::ST240M, + Rav1dMatrixCoefficients::SMPTE_YCgCo => Self::YCgCo, + Rav1dMatrixCoefficients::BT2020NCL => Self::BT2020NonConstantLuminance, + Rav1dMatrixCoefficients::BT2020CL => Self::BT2020ConstantLuminance, + Rav1dMatrixCoefficients::SMPTE2085 => Self::ST2085, + Rav1dMatrixCoefficients::ChromatNCL => Self::ChromaticityDerivedNonConstantLuminance, + Rav1dMatrixCoefficients::ChromatCL => Self::ChromaticityDerivedConstantLuminance, + Rav1dMatrixCoefficients::ICtCp => Self::ICtCp, } } } @@ -839,9 +827,9 @@ impl TryFrom for pixel::ChromaLocation { // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c match value { Rav1dChromaSamplePosition::Unknown | Rav1dChromaSamplePosition::Colocated => { - Ok(pixel::ChromaLocation::Center) + Ok(Self::Center) } - Rav1dChromaSamplePosition::Vertical => Ok(pixel::ChromaLocation::Left), + Rav1dChromaSamplePosition::Vertical => Ok(Self::Left), Rav1dChromaSamplePosition::_Reserved => Err(Rav1dError::InvalidArgument), } } diff --git a/src/rust_api.rs b/src/rust_api.rs index 53b521b84..1dfcda5ec 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -299,9 +299,9 @@ impl TryFrom for PlanarImageComponent { type Error = Rav1dError; fn try_from(index: usize) -> Result { match index { - 0 => Ok(PlanarImageComponent::Y), - 1 => Ok(PlanarImageComponent::U), - 2 => Ok(PlanarImageComponent::V), + 0 => Ok(Self::Y), + 1 => Ok(Self::U), + 2 => Ok(Self::V), _ => Err(Rav1dError::InvalidArgument), } } @@ -325,9 +325,9 @@ impl BitsPerComponent { /// Get the number of bits per component from the high bit depth flag pub fn from_hbd(hbd: u8) -> Result { match hbd { - 0 => Ok(BitsPerComponent(8)), - 1 => Ok(BitsPerComponent(10)), - 2 => Ok(BitsPerComponent(12)), + 0 => Ok(Self(8)), + 1 => Ok(Self(10)), + 2 => Ok(Self(12)), _ => Err(Rav1dError::InvalidArgument), } } From 67bfa803d4794dadbdab570f30a7cfc0e1136d43 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 23 Mar 2026 15:30:43 -0700 Subject: [PATCH 69/72] use `fn PlanarImageComponent::as_index` instead of `impl From for usize` --- src/rust_api.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rust_api.rs b/src/rust_api.rs index 1dfcda5ec..d9853bddd 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -307,12 +307,12 @@ impl TryFrom for PlanarImageComponent { } } -impl From for usize { - fn from(component: PlanarImageComponent) -> Self { - match component { - PlanarImageComponent::Y => 0, - PlanarImageComponent::U => 1, - PlanarImageComponent::V => 2, +impl PlanarImageComponent { + pub const fn as_index(&self) -> usize { + match self { + Self::Y => 0, + Self::U => 1, + Self::V => 2, } } } @@ -346,7 +346,7 @@ impl Picture { /// Plane data of the `component` for the decoded frame. pub fn plane_data<'a>(&'a self, component: PlanarImageComponent) -> &'a [u8] { let data = &self.inner.data.as_ref().unwrap().data; - let component = &data[usize::from(component)]; + let component = &data[component.as_index()]; let guard = component.slice::(..); // SAFETY: [`Picture`] is only created after decoding is complete // (in [`Decoder::get_picture`], which calls [`rav1d_get_picture`]). From 080e31f4431a21a5521da91909b8dcf3cfb1bbc9 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 23 Mar 2026 15:45:19 -0700 Subject: [PATCH 70/72] add `enum Rav1dColorRange` --- src/include/dav1d/headers.rs | 45 +++++++++++++++++++++++++++++++++--- src/obu.rs | 34 ++++++++++++++------------- src/rust_api.rs | 5 +--- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 80dcec380..40137b15d 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -843,6 +843,45 @@ impl TryFrom for Rav1dChromaSamplePosition { } } +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum Rav1dColorRange { + Limited, + Full, +} + +impl Rav1dColorRange { + pub const fn is_full(&self) -> bool { + matches!(self, Self::Full) + } + + pub const fn to_dav1d(&self) -> u8 { + self.is_full() as u8 + } +} + +impl Rav1dColorRange { + pub const fn from_is_full(is_full: bool) -> Self { + if is_full { + Self::Full + } else { + Self::Limited + } + } + + pub const fn from_dav1d(value: u8) -> Self { + Self::from_is_full(value != 0) + } +} + +impl From for pixel::YUVRange { + fn from(value: Rav1dColorRange) -> Self { + match value { + Rav1dColorRange::Limited => Self::Limited, + Rav1dColorRange::Full => Self::Full, + } + } +} + #[repr(C)] pub struct Rav1dContentLightLevel { /// Maximum content light level (MaxCLL) in candela per square metre. @@ -1133,7 +1172,7 @@ pub struct Rav1dSequenceHeader { pub mtrx: Rav1dMatrixCoefficients, pub chr: Rav1dChromaSamplePosition, pub hbd: u8, - pub color_range: u8, + pub color_range: Rav1dColorRange, pub num_operating_points: u8, pub operating_points: [Rav1dSequenceHeaderOperatingPoint; RAV1D_MAX_OPERATING_POINTS], pub still_picture: u8, @@ -1367,7 +1406,7 @@ impl From for Rav1dSequenceHeader { mtrx: mtrx.try_into().unwrap(), chr: chr.try_into().unwrap(), hbd, - color_range, + color_range: Rav1dColorRange::from_dav1d(color_range), num_operating_points, operating_points: operating_points.map(|c| c.into()), still_picture, @@ -1482,7 +1521,7 @@ impl From for Dav1dSequenceHeader { mtrx: mtrx.into(), chr: chr.into(), hbd, - color_range, + color_range: color_range.to_dav1d(), num_operating_points, operating_points: operating_points.map(|rust| rust.into()), still_picture, diff --git a/src/obu.rs b/src/obu.rs index 2185fcf45..aad66d864 100644 --- a/src/obu.rs +++ b/src/obu.rs @@ -16,18 +16,19 @@ use crate::include::dav1d::data::Rav1dData; use crate::include::dav1d::dav1d::Rav1dDecodeFrameType; use crate::include::dav1d::headers::{ DRav1d, Dav1dSequenceHeader, Rav1dAdaptiveBoolean, Rav1dChromaSamplePosition, - Rav1dColorPrimaries, Rav1dContentLightLevel, Rav1dFilmGrainData, Rav1dFilterMode, - Rav1dFrameHeader, Rav1dFrameHeaderCdef, Rav1dFrameHeaderDelta, Rav1dFrameHeaderDeltaLF, - Rav1dFrameHeaderDeltaQ, Rav1dFrameHeaderFilmGrain, Rav1dFrameHeaderLoopFilter, - Rav1dFrameHeaderOperatingPoint, Rav1dFrameHeaderQuant, Rav1dFrameHeaderRestoration, - Rav1dFrameHeaderSegmentation, Rav1dFrameHeaderSuperRes, Rav1dFrameHeaderTiling, Rav1dFrameSize, - Rav1dFrameSkipMode, Rav1dFrameType, Rav1dITUTT35, Rav1dLoopfilterModeRefDeltas, - Rav1dMasteringDisplay, Rav1dMatrixCoefficients, Rav1dObuType, Rav1dPixelLayout, Rav1dProfile, - Rav1dRestorationType, Rav1dSegmentationData, Rav1dSegmentationDataSet, Rav1dSequenceHeader, - Rav1dSequenceHeaderOperatingParameterInfo, Rav1dSequenceHeaderOperatingPoint, - Rav1dTransferCharacteristics, Rav1dTxfmMode, Rav1dWarpedMotionParams, Rav1dWarpedMotionType, - RAV1D_MAX_CDEF_STRENGTHS, RAV1D_MAX_OPERATING_POINTS, RAV1D_MAX_TILE_COLS, RAV1D_MAX_TILE_ROWS, - RAV1D_PRIMARY_REF_NONE, RAV1D_REFS_PER_FRAME, + Rav1dColorPrimaries, Rav1dColorRange, Rav1dContentLightLevel, Rav1dFilmGrainData, + Rav1dFilterMode, Rav1dFrameHeader, Rav1dFrameHeaderCdef, Rav1dFrameHeaderDelta, + Rav1dFrameHeaderDeltaLF, Rav1dFrameHeaderDeltaQ, Rav1dFrameHeaderFilmGrain, + Rav1dFrameHeaderLoopFilter, Rav1dFrameHeaderOperatingPoint, Rav1dFrameHeaderQuant, + Rav1dFrameHeaderRestoration, Rav1dFrameHeaderSegmentation, Rav1dFrameHeaderSuperRes, + Rav1dFrameHeaderTiling, Rav1dFrameSize, Rav1dFrameSkipMode, Rav1dFrameType, Rav1dITUTT35, + Rav1dLoopfilterModeRefDeltas, Rav1dMasteringDisplay, Rav1dMatrixCoefficients, Rav1dObuType, + Rav1dPixelLayout, Rav1dProfile, Rav1dRestorationType, Rav1dSegmentationData, + Rav1dSegmentationDataSet, Rav1dSequenceHeader, Rav1dSequenceHeaderOperatingParameterInfo, + Rav1dSequenceHeaderOperatingPoint, Rav1dTransferCharacteristics, Rav1dTxfmMode, + Rav1dWarpedMotionParams, Rav1dWarpedMotionType, RAV1D_MAX_CDEF_STRENGTHS, + RAV1D_MAX_OPERATING_POINTS, RAV1D_MAX_TILE_COLS, RAV1D_MAX_TILE_ROWS, RAV1D_PRIMARY_REF_NONE, + RAV1D_REFS_PER_FRAME, }; use crate::internal::{Rav1dContext, Rav1dState, Rav1dTileGroup, Rav1dTileGroupHeader}; use crate::levels::ObuMetaType; @@ -363,13 +364,13 @@ fn parse_seq_hdr( trc = Default::default(); mtrx = Default::default(); } - let color_range; + let full_color_range; let layout; let ss_ver; let ss_hor; let chr; if monochrome != 0 { - color_range = gb.get_bit() as u8; + full_color_range = gb.get_bit(); layout = Rav1dPixelLayout::I400; ss_ver = 1; ss_hor = ss_ver; @@ -379,7 +380,7 @@ fn parse_seq_hdr( && mtrx == Rav1dMatrixCoefficients::Identity { layout = Rav1dPixelLayout::I444; - color_range = 1; + full_color_range = true; if profile != Rav1dProfile::High && !(profile == Rav1dProfile::Professional && hbd == 2) { return Err(Rav1dError::InvalidArgument); } @@ -389,7 +390,7 @@ fn parse_seq_hdr( ss_ver = Default::default(); chr = Rav1dChromaSamplePosition::Unknown; } else { - color_range = gb.get_bit() as u8; + full_color_range = gb.get_bit(); match profile { Rav1dProfile::Main => { layout = Rav1dPixelLayout::I420; @@ -435,6 +436,7 @@ fn parse_seq_hdr( Rav1dChromaSamplePosition::Unknown }; } + let color_range = Rav1dColorRange::from_is_full(full_color_range); if strict_std_compliance && mtrx == Rav1dMatrixCoefficients::Identity && layout != Rav1dPixelLayout::I444 diff --git a/src/rust_api.rs b/src/rust_api.rs index d9853bddd..cc3f167b9 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -438,10 +438,7 @@ impl Picture { /// YUV color range. pub fn color_range(&self) -> pixel::YUVRange { - match self.inner.seq_hdr.as_ref().unwrap().color_range { - 0 => pixel::YUVRange::Limited, - _ => pixel::YUVRange::Full, - } + self.inner.seq_hdr.as_ref().unwrap().color_range.into() } /// Sample position for subsampled chroma. From a510ef3fd5a1e1e918444a28daee042555ad1666 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 23 Mar 2026 15:53:27 -0700 Subject: [PATCH 71/72] use `use T::*` for `match`s in `impl From`s --- src/include/dav1d/headers.rs | 98 ++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index 40137b15d..5c6ceac6a 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -571,19 +571,20 @@ impl Rav1dColorPrimaries { impl From for pixel::ColorPrimaries { fn from(val: Rav1dColorPrimaries) -> Self { + use Rav1dColorPrimaries::*; match val { - Rav1dColorPrimaries::BT709 => Self::BT709, - Rav1dColorPrimaries::Unspecified => Self::Unspecified, - Rav1dColorPrimaries::BT470M => Self::BT470M, - Rav1dColorPrimaries::BT470BG => Self::BT470BG, - Rav1dColorPrimaries::BT601 => Self::BT470BG, - Rav1dColorPrimaries::SMPTE240 => Self::ST240M, - Rav1dColorPrimaries::Film => Self::Film, - Rav1dColorPrimaries::BT2020 => Self::BT2020, - Rav1dColorPrimaries::XYZ => Self::ST428, - Rav1dColorPrimaries::SMPTE431 => Self::P3DCI, - Rav1dColorPrimaries::SMPTE432 => Self::P3Display, - Rav1dColorPrimaries::EBU3213 => Self::Tech3213, + BT709 => Self::BT709, + Unspecified => Self::Unspecified, + BT470M => Self::BT470M, + BT470BG => Self::BT470BG, + BT601 => Self::BT470BG, + SMPTE240 => Self::ST240M, + Film => Self::Film, + BT2020 => Self::BT2020, + XYZ => Self::ST428, + SMPTE431 => Self::P3DCI, + SMPTE432 => Self::P3Display, + EBU3213 => Self::Tech3213, } } } @@ -672,24 +673,25 @@ impl Rav1dTransferCharacteristics { impl From for pixel::TransferCharacteristic { fn from(val: Rav1dTransferCharacteristics) -> Self { + use Rav1dTransferCharacteristics::*; match val { - Rav1dTransferCharacteristics::BT709 => Self::BT1886, - Rav1dTransferCharacteristics::Unspecified => Self::Unspecified, - Rav1dTransferCharacteristics::BT470M => Self::BT470M, - Rav1dTransferCharacteristics::BT470BG => Self::BT470BG, - Rav1dTransferCharacteristics::BT601 => Self::ST170M, - Rav1dTransferCharacteristics::SMPTE240 => Self::ST240M, - Rav1dTransferCharacteristics::Linear => Self::Linear, - Rav1dTransferCharacteristics::Log100 => Self::Logarithmic100, - Rav1dTransferCharacteristics::Log100Sqrt10 => Self::Logarithmic316, - Rav1dTransferCharacteristics::IEC61966 => Self::SRGB, - Rav1dTransferCharacteristics::BT1361 => Self::BT1886, - Rav1dTransferCharacteristics::SRGB => Self::SRGB, - Rav1dTransferCharacteristics::BT2020_10Bit => Self::BT2020Ten, - Rav1dTransferCharacteristics::BT2020_12Bit => Self::BT2020Twelve, - Rav1dTransferCharacteristics::SMPTE2084 => Self::PerceptualQuantizer, - Rav1dTransferCharacteristics::SMPTE428 => Self::ST428, - Rav1dTransferCharacteristics::HLG => Self::HybridLogGamma, + BT709 => Self::BT1886, + Unspecified => Self::Unspecified, + BT470M => Self::BT470M, + BT470BG => Self::BT470BG, + BT601 => Self::ST170M, + SMPTE240 => Self::ST240M, + Linear => Self::Linear, + Log100 => Self::Logarithmic100, + Log100Sqrt10 => Self::Logarithmic316, + IEC61966 => Self::SRGB, + BT1361 => Self::BT1886, + SRGB => Self::SRGB, + BT2020_10Bit => Self::BT2020Ten, + BT2020_12Bit => Self::BT2020Twelve, + SMPTE2084 => Self::PerceptualQuantizer, + SMPTE428 => Self::ST428, + HLG => Self::HybridLogGamma, } } } @@ -762,21 +764,22 @@ impl Rav1dMatrixCoefficients { impl From for pixel::MatrixCoefficients { fn from(val: Rav1dMatrixCoefficients) -> Self { + use Rav1dMatrixCoefficients::*; match val { - Rav1dMatrixCoefficients::Identity => Self::Identity, - Rav1dMatrixCoefficients::BT709 => Self::BT709, - Rav1dMatrixCoefficients::Unspecified => Self::Unspecified, - Rav1dMatrixCoefficients::FCC => Self::BT470M, - Rav1dMatrixCoefficients::BT470BG => Self::BT470BG, - Rav1dMatrixCoefficients::BT601 => Self::BT470BG, - Rav1dMatrixCoefficients::SMPTE240 => Self::ST240M, - Rav1dMatrixCoefficients::SMPTE_YCgCo => Self::YCgCo, - Rav1dMatrixCoefficients::BT2020NCL => Self::BT2020NonConstantLuminance, - Rav1dMatrixCoefficients::BT2020CL => Self::BT2020ConstantLuminance, - Rav1dMatrixCoefficients::SMPTE2085 => Self::ST2085, - Rav1dMatrixCoefficients::ChromatNCL => Self::ChromaticityDerivedNonConstantLuminance, - Rav1dMatrixCoefficients::ChromatCL => Self::ChromaticityDerivedConstantLuminance, - Rav1dMatrixCoefficients::ICtCp => Self::ICtCp, + Identity => Self::Identity, + BT709 => Self::BT709, + Unspecified => Self::Unspecified, + FCC => Self::BT470M, + BT470BG => Self::BT470BG, + BT601 => Self::BT470BG, + SMPTE240 => Self::ST240M, + SMPTE_YCgCo => Self::YCgCo, + BT2020NCL => Self::BT2020NonConstantLuminance, + BT2020CL => Self::BT2020ConstantLuminance, + SMPTE2085 => Self::ST2085, + ChromatNCL => Self::ChromaticityDerivedNonConstantLuminance, + ChromatCL => Self::ChromaticityDerivedConstantLuminance, + ICtCp => Self::ICtCp, } } } @@ -825,12 +828,11 @@ impl TryFrom for pixel::ChromaLocation { fn try_from(value: Rav1dChromaSamplePosition) -> Result { // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c + use Rav1dChromaSamplePosition::*; match value { - Rav1dChromaSamplePosition::Unknown | Rav1dChromaSamplePosition::Colocated => { - Ok(Self::Center) - } - Rav1dChromaSamplePosition::Vertical => Ok(Self::Left), - Rav1dChromaSamplePosition::_Reserved => Err(Rav1dError::InvalidArgument), + Unknown | Colocated => Ok(Self::Center), + Vertical => Ok(Self::Left), + _Reserved => Err(Rav1dError::InvalidArgument), } } } From b83207523501e8a9485d90eaaf39e0d185577069 Mon Sep 17 00:00:00 2001 From: Leo Ring Date: Sat, 4 Apr 2026 01:40:48 +0100 Subject: [PATCH 72/72] Fixes --- src/include/dav1d/headers.rs | 9 +++++++++ src/rust_api.rs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/include/dav1d/headers.rs b/src/include/dav1d/headers.rs index c3f6bcda3..5c6ceac6a 100644 --- a/src/include/dav1d/headers.rs +++ b/src/include/dav1d/headers.rs @@ -875,6 +875,15 @@ impl Rav1dColorRange { } } +impl From for pixel::YUVRange { + fn from(value: Rav1dColorRange) -> Self { + match value { + Rav1dColorRange::Limited => Self::Limited, + Rav1dColorRange::Full => Self::Full, + } + } +} + #[repr(C)] pub struct Rav1dContentLightLevel { /// Maximum content light level (MaxCLL) in candela per square metre. diff --git a/src/rust_api.rs b/src/rust_api.rs index cc3f167b9..eb8d07c09 100644 --- a/src/rust_api.rs +++ b/src/rust_api.rs @@ -352,7 +352,7 @@ impl Picture { // (in [`Decoder::get_picture`], which calls [`rav1d_get_picture`]). // Thus, the decoder no longer writes to this data, // and there are no other safe public ways to have a `&mut` to this data. - unsafe { guard.unchecked_disjoint_mut() } + unsafe { guard.get_unchecked() } } /// Bit depth of the plane data.