From 528ad7781d7b1bad54747b59ed6a86015dbee51c Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sat, 14 Mar 2026 12:46:51 +0000 Subject: [PATCH 1/3] Migration from dav1d to rav1d, part 1:all the straightforward renaming --- Cargo.toml | 4 +- src/codecs/avif/decoder.rs | 75 +++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ded5216414..e2285800a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ num-traits = { version = "0.2.0" } # Optional dependencies color_quant = { version = "1.1", optional = true } -dav1d = { version = "0.11", optional = true } +rav1d = { git = "https://github.com/leo030303/rav1d.git", branch = "add-rust-api", optional = true } exr = { version = "1.74.0", default-features = false, optional = true } gif = { version = "0.14.1", optional = true } image-webp = { version = "0.2.0", optional = true } @@ -98,7 +98,7 @@ webp = ["dep:image-webp"] rayon = ["dep:rayon", "ravif?/threading", "exr?/rayon"] # Enables multi-threading nasm = ["ravif?/asm"] # Enables use of nasm by rav1e (requires nasm to be installed) color_quant = ["dep:color_quant"] # Enables color quantization -avif-native = ["dep:mp4parse", "dep:dav1d"] # Enable native dependency libdav1d +avif-native = ["dep:mp4parse", "dep:rav1d"] # Enable native dependency libdav1d benchmarks = [] # Build some inline benchmarks. Useful only during development (requires nightly Rust) serde = ["dep:serde"] diff --git a/src/codecs/avif/decoder.rs b/src/codecs/avif/decoder.rs index cfdcd63ee3..d6ef272544 100644 --- a/src/codecs/avif/decoder.rs +++ b/src/codecs/avif/decoder.rs @@ -20,8 +20,11 @@ use crate::codecs::avif::ycgco::{ ycgco444_to_rgba8, }; use crate::codecs::avif::yuv::*; -use dav1d::{PixelLayout, PlanarImageComponent}; use mp4parse::{read_avif, ImageMirror, ImageRotation, ParseStrictness}; +use rav1d::rust_api::pixel::MatrixCoefficients; +use rav1d::rust_api::Picture as Rav1dPicture; +use rav1d::rust_api::PlanarImageComponent; +use rav1d::PixelLayout; fn error_map>>(err: E) -> ImageError { ImageError::Decoding(DecodingError::new(ImageFormat::Avif.into(), err)) @@ -32,8 +35,8 @@ fn error_map>>(err: E) -> ImageError { /// Reads one image into the chosen input. pub struct AvifDecoder { inner: PhantomData, - picture: dav1d::Picture, - alpha_picture: Option, + picture: Rav1dPicture, + alpha_picture: Option, icc_profile: Option>, orientation: Orientation, } @@ -81,14 +84,14 @@ impl AvifDecoder { let ctx = read_avif(&mut r, ParseStrictness::Permissive).map_err(error_map)?; let coded = ctx.primary_item_coded_data().unwrap_or_default(); - let mut primary_decoder = dav1d::Decoder::new().map_err(error_map)?; + let mut primary_decoder = rav1d::rust_api::Decoder::new().map_err(error_map)?; primary_decoder .send_data(coded.to_vec(), None, None, None) .map_err(error_map)?; let picture = read_until_ready(&mut primary_decoder)?; let alpha_item = ctx.alpha_item_coded_data().unwrap_or_default(); let alpha_picture = if !alpha_item.is_empty() { - let mut alpha_decoder = dav1d::Decoder::new().map_err(error_map)?; + let mut alpha_decoder = rav1d::rust_api::Decoder::new().map_err(error_map)?; alpha_decoder .send_data(alpha_item.to_vec(), None, None, None) .map_err(error_map)?; @@ -193,7 +196,7 @@ impl Default for Plane16View<'_> { /// This is correct to transmute FFI data for Y plane and Alpha plane fn transmute_y_plane16( - plane: &dav1d::Plane, + plane: &rav1d::Plane, stride: usize, width: usize, height: usize, @@ -233,7 +236,7 @@ fn transmute_y_plane16( /// This is correct to transmute FFI data for Y plane and Alpha plane fn transmute_chroma_plane16( - plane: &dav1d::Plane, + plane: &rav1d::Plane, pixel_layout: PixelLayout, stride: usize, width: usize, @@ -288,22 +291,16 @@ enum YuvMatrixStrategy { } /// Getting one of prebuilt matrix of fails -fn get_matrix( - david_matrix: dav1d::pixel::MatrixCoefficients, -) -> Result { +fn get_matrix(david_matrix: MatrixCoefficients) -> Result { match david_matrix { - dav1d::pixel::MatrixCoefficients::Identity => Ok(YuvMatrixStrategy::Identity), - dav1d::pixel::MatrixCoefficients::BT709 => { - Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt709)) - } + MatrixCoefficients::Identity => Ok(YuvMatrixStrategy::Identity), + MatrixCoefficients::BT709 => Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt709)), // This is arguable, some applications prefer to go with Bt.709 as default, // and some applications prefer Bt.601 as default. // For ex. `Chrome` always prefer Bt.709 even for SD content // However, nowadays standard should be Bt.709 for HD+ size otherwise Bt.601 - dav1d::pixel::MatrixCoefficients::Unspecified => { - Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt709)) - } - dav1d::pixel::MatrixCoefficients::Reserved => Err(ImageError::Unsupported( + MatrixCoefficients::Unspecified => Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt709)), + MatrixCoefficients::Reserved => Err(ImageError::Unsupported( UnsupportedError::from_format_and_kind( ImageFormat::Avif.into(), UnsupportedErrorKind::GenericFeature( @@ -311,23 +308,15 @@ fn get_matrix( ), ), )), - dav1d::pixel::MatrixCoefficients::BT470M => { - Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt470_6)) - } - dav1d::pixel::MatrixCoefficients::BT470BG => { - Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt601)) - } - dav1d::pixel::MatrixCoefficients::ST170M => { - Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Smpte240)) - } - dav1d::pixel::MatrixCoefficients::ST240M => { - Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Smpte240)) - } - dav1d::pixel::MatrixCoefficients::YCgCo => Ok(YuvMatrixStrategy::CgCo), - dav1d::pixel::MatrixCoefficients::BT2020NonConstantLuminance => { + MatrixCoefficients::BT470M => Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt470_6)), + MatrixCoefficients::BT470BG => Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt601)), + MatrixCoefficients::ST170M => Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Smpte240)), + MatrixCoefficients::ST240M => Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Smpte240)), + MatrixCoefficients::YCgCo => Ok(YuvMatrixStrategy::CgCo), + MatrixCoefficients::BT2020NonConstantLuminance => { Ok(YuvMatrixStrategy::KrKb(YuvStandardMatrix::Bt2020)) } - dav1d::pixel::MatrixCoefficients::BT2020ConstantLuminance => { + MatrixCoefficients::BT2020ConstantLuminance => { // This matrix significantly differs from others because linearize values is required // to compute Y instead of Y'. // Actually it is almost everywhere is not implemented. @@ -342,14 +331,14 @@ fn get_matrix( ), )) } - dav1d::pixel::MatrixCoefficients::ST2085 => Err(ImageError::Unsupported( + MatrixCoefficients::ST2085 => Err(ImageError::Unsupported( UnsupportedError::from_format_and_kind( ImageFormat::Avif.into(), UnsupportedErrorKind::GenericFeature("ST2085 matrix is not supported".to_string()), ), )), - dav1d::pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance - | dav1d::pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance => Err( + MatrixCoefficients::ChromaticityDerivedConstantLuminance + | MatrixCoefficients::ChromaticityDerivedNonConstantLuminance => Err( ImageError::Unsupported(UnsupportedError::from_format_and_kind( ImageFormat::Avif.into(), UnsupportedErrorKind::GenericFeature( @@ -357,7 +346,7 @@ fn get_matrix( ), )), ), - dav1d::pixel::MatrixCoefficients::ICtCp => Err(ImageError::Unsupported( + MatrixCoefficients::ICtCp => Err(ImageError::Unsupported( UnsupportedError::from_format_and_kind( ImageFormat::Avif.into(), UnsupportedErrorKind::GenericFeature( @@ -407,8 +396,8 @@ impl ImageDecoder for AvifDecoder { } let yuv_range = match self.picture.color_range() { - dav1d::pixel::YUVRange::Limited => YuvIntensityRange::Tv, - dav1d::pixel::YUVRange::Full => YuvIntensityRange::Pc, + rav1d::rust_api::pixel::YUVRange::Limited => YuvIntensityRange::Tv, + rav1d::rust_api::pixel::YUVRange::Full => YuvIntensityRange::Pc, }; let matrix_strategy = get_matrix(self.picture.matrix_coefficients())?; @@ -704,12 +693,14 @@ impl AvifDecoder { /// `get_picture` and `send_pending_data` yield `Again` as a non-fatal error requesting more data is sent to the decoder /// This ensures that in the case of `Again` all pending data is submitted /// This should be called after `send_data` (which does not yield `Again` when called the first time) -fn read_until_ready(decoder: &mut dav1d::Decoder) -> ImageResult { +fn read_until_ready( + decoder: &mut rav1d::rust_api::Decoder, +) -> ImageResult { loop { match decoder.get_picture() { - Err(dav1d::Error::Again) => match decoder.send_pending_data() { + Err(rav1d::Rav1dError::TryAgain) => match decoder.send_pending_data() { Ok(()) => {} - Err(dav1d::Error::Again) => {} + Err(rav1d::Rav1dError::TryAgain) => {} Err(e) => return Err(error_map(e)), }, r => return r.map_err(error_map), From b3eb3f23b0632536f1676b2c090be23882f01888 Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sat, 14 Mar 2026 12:53:57 +0000 Subject: [PATCH 2/3] dav1d to rav1d conversion, part 2: apply the less trivial changes --- src/codecs/avif/decoder.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/codecs/avif/decoder.rs b/src/codecs/avif/decoder.rs index d6ef272544..17c448ef0d 100644 --- a/src/codecs/avif/decoder.rs +++ b/src/codecs/avif/decoder.rs @@ -86,14 +86,14 @@ impl AvifDecoder { let mut primary_decoder = rav1d::rust_api::Decoder::new().map_err(error_map)?; primary_decoder - .send_data(coded.to_vec(), None, None, None) + .send_data(coded.to_vec().into_boxed_slice(), None, None, None) .map_err(error_map)?; let picture = read_until_ready(&mut primary_decoder)?; let alpha_item = ctx.alpha_item_coded_data().unwrap_or_default(); let alpha_picture = if !alpha_item.is_empty() { let mut alpha_decoder = rav1d::rust_api::Decoder::new().map_err(error_map)?; alpha_decoder - .send_data(alpha_item.to_vec(), None, None, None) + .send_data(alpha_item.to_vec().into_boxed_slice(), None, None, None) .map_err(error_map)?; Some(read_until_ready(&mut alpha_decoder)?) } else { @@ -196,7 +196,7 @@ impl Default for Plane16View<'_> { /// This is correct to transmute FFI data for Y plane and Alpha plane fn transmute_y_plane16( - plane: &rav1d::Plane, + plane_ref: &[u8], stride: usize, width: usize, height: usize, @@ -204,7 +204,6 @@ fn transmute_y_plane16( let mut y_plane_stride = stride >> 1; let mut bind_y = vec![]; - let plane_ref = plane.as_ref(); let mut shape_y_plane = || { y_plane_stride = width; @@ -236,13 +235,12 @@ fn transmute_y_plane16( /// This is correct to transmute FFI data for Y plane and Alpha plane fn transmute_chroma_plane16( - plane: &rav1d::Plane, + plane_ref: &[u8], pixel_layout: PixelLayout, stride: usize, width: usize, height: usize, ) -> Plane16View<'_> { - let plane_ref = plane.as_ref(); let mut chroma_plane_stride = stride >> 1; let mut bind_chroma = vec![]; @@ -425,9 +423,9 @@ impl ImageDecoder for AvifDecoder { } if bit_depth == 8 { - let ref_y = self.picture.plane(PlanarImageComponent::Y); - let ref_u = self.picture.plane(PlanarImageComponent::U); - let ref_v = self.picture.plane(PlanarImageComponent::V); + let ref_y = self.picture.plane_data(PlanarImageComponent::Y); + let ref_u = self.picture.plane_data(PlanarImageComponent::U); + let ref_v = self.picture.plane_data(PlanarImageComponent::V); let image = YuvPlanarImage { y_plane: ref_y.as_ref(), @@ -483,7 +481,7 @@ impl ImageDecoder for AvifDecoder { } let stride = picture.stride(PlanarImageComponent::Y) as usize; - let plane = picture.plane(PlanarImageComponent::Y); + let plane = picture.plane_data(PlanarImageComponent::Y); for (buf, slice) in Iterator::zip( buf.chunks_exact_mut(width as usize * 4), @@ -525,7 +523,7 @@ impl AvifDecoder { yuv_range: YuvIntensityRange, matrix_strategy: YuvMatrixStrategy, ) -> ImageResult<()> { - let y_dav1d_plane = self.picture.plane(PlanarImageComponent::Y); + let y_dav1d_plane = self.picture.plane_data(PlanarImageComponent::Y); let (width, height) = (self.picture.width(), self.picture.height()); let bit_depth = self.picture.bit_depth(); @@ -542,8 +540,8 @@ impl AvifDecoder { height as usize, ); - let u_dav1d_plane = self.picture.plane(PlanarImageComponent::U); - let v_dav1d_plane = self.picture.plane(PlanarImageComponent::V); + let u_dav1d_plane = self.picture.plane_data(PlanarImageComponent::U); + let v_dav1d_plane = self.picture.plane_data(PlanarImageComponent::V); let mut u_plane_view = Plane16View::default(); let mut v_plane_view = Plane16View::default(); @@ -662,7 +660,7 @@ impl AvifDecoder { ))); } - let a_dav1d_plane = picture.plane(PlanarImageComponent::Y); + let a_dav1d_plane = picture.plane_data(PlanarImageComponent::Y); let a_plane_view = transmute_y_plane16( &a_dav1d_plane, picture.stride(PlanarImageComponent::Y) as usize, From 8acd5f6ea67caccf7243c7177a144afb7623c6e4 Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sat, 14 Mar 2026 12:54:39 +0000 Subject: [PATCH 3/3] cargo clippy --fix --- src/codecs/avif/decoder.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/codecs/avif/decoder.rs b/src/codecs/avif/decoder.rs index 17c448ef0d..fc2f2198c2 100644 --- a/src/codecs/avif/decoder.rs +++ b/src/codecs/avif/decoder.rs @@ -428,11 +428,11 @@ impl ImageDecoder for AvifDecoder { let ref_v = self.picture.plane_data(PlanarImageComponent::V); let image = YuvPlanarImage { - y_plane: ref_y.as_ref(), + y_plane: ref_y, y_stride: self.picture.stride(PlanarImageComponent::Y) as usize, - u_plane: ref_u.as_ref(), + u_plane: ref_u, u_stride: self.picture.stride(PlanarImageComponent::U) as usize, - v_plane: ref_v.as_ref(), + v_plane: ref_v, v_stride: self.picture.stride(PlanarImageComponent::V) as usize, width: width as usize, height: height as usize, @@ -534,7 +534,7 @@ impl AvifDecoder { // required criteria: bytemuck allows this align of this data, and stride must be dividable by 2 let y_plane_view = transmute_y_plane16( - &y_dav1d_plane, + y_dav1d_plane, self.picture.stride(PlanarImageComponent::Y) as usize, width as usize, height as usize, @@ -547,14 +547,14 @@ impl AvifDecoder { if self.picture.pixel_layout() != PixelLayout::I400 { u_plane_view = transmute_chroma_plane16( - &u_dav1d_plane, + u_dav1d_plane, self.picture.pixel_layout(), self.picture.stride(PlanarImageComponent::U) as usize, width as usize, height as usize, ); v_plane_view = transmute_chroma_plane16( - &v_dav1d_plane, + v_dav1d_plane, self.picture.pixel_layout(), self.picture.stride(PlanarImageComponent::V) as usize, width as usize, @@ -662,7 +662,7 @@ impl AvifDecoder { let a_dav1d_plane = picture.plane_data(PlanarImageComponent::Y); let a_plane_view = transmute_y_plane16( - &a_dav1d_plane, + a_dav1d_plane, picture.stride(PlanarImageComponent::Y) as usize, width as usize, height as usize,