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..fc2f2198c2 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,16 +84,16 @@ 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) + .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 = 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) + .send_data(alpha_item.to_vec().into_boxed_slice(), None, None, None) .map_err(error_map)?; Some(read_until_ready(&mut alpha_decoder)?) } else { @@ -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_ref: &[u8], stride: usize, width: usize, height: usize, @@ -201,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; @@ -233,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: &dav1d::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![]; @@ -288,22 +289,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 +306,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 +329,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 +344,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 +394,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())?; @@ -436,16 +423,16 @@ 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(), + 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, @@ -494,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), @@ -536,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(); @@ -547,27 +534,27 @@ 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, ); - 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(); 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, @@ -673,9 +660,9 @@ 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, + a_dav1d_plane, picture.stride(PlanarImageComponent::Y) as usize, width as usize, height as usize, @@ -704,12 +691,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),