diff --git a/Cargo.toml b/Cargo.toml index 378b39e1d7..b862642399 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,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/memorysafety/rav1d", 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 } @@ -105,7 +105,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 8eb54bd652..2687e287c8 100644 --- a/src/codecs/avif/decoder.rs +++ b/src/codecs/avif/decoder.rs @@ -21,8 +21,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)) @@ -33,8 +36,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, limits: Limits, @@ -87,16 +90,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 { @@ -223,7 +226,7 @@ impl Default for Plane16View<'_> { /// This is correct to transmute FFI data for Y plane and Alpha plane fn transmute_y_plane16<'data>( - plane: &'data dav1d::Plane, + plane_ref: &'data [u8], stride: u32, width: u32, height: u32, @@ -232,7 +235,6 @@ fn transmute_y_plane16<'data>( 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; @@ -265,14 +267,13 @@ fn transmute_y_plane16<'data>( /// This is correct to transmute FFI data for Y plane and Alpha plane fn transmute_chroma_plane16<'data>( - plane: &'data dav1d::Plane, + plane_ref: &'data [u8], pixel_layout: PixelLayout, stride: u32, width: u32, height: u32, limits: &mut Limits, ) -> Result, ImageError> { - let plane_ref = plane.as_ref(); let mut chroma_plane_stride = stride >> 1; let mut bind_chroma = vec![]; @@ -330,22 +331,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( @@ -353,23 +348,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. @@ -384,14 +371,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( @@ -399,7 +386,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( @@ -412,6 +399,9 @@ fn get_matrix( impl ImageDecoder for AvifDecoder { fn set_limits(&mut self, limits: Limits) -> ImageResult<()> { + limits.check_support(&crate::LimitSupport::default())?; + let layout = self.prepare_image()?; + limits.check_layout_dimensions(&layout)?; self.limits = limits; Ok(()) } @@ -453,8 +443,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())?; @@ -487,11 +477,11 @@ impl ImageDecoder for AvifDecoder { let ref_v = self.picture.plane(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, @@ -592,7 +582,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), width, height, @@ -606,7 +596,7 @@ 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), width, @@ -614,7 +604,7 @@ impl AvifDecoder { &mut self.limits, )?; v_plane_view = transmute_chroma_plane16( - &v_dav1d_plane, + v_dav1d_plane, self.picture.pixel_layout(), self.picture.stride(PlanarImageComponent::V), width, @@ -723,7 +713,7 @@ impl AvifDecoder { let a_dav1d_plane = picture.plane(PlanarImageComponent::Y); let a_plane_view = transmute_y_plane16( - &a_dav1d_plane, + a_dav1d_plane, picture.stride(PlanarImageComponent::Y), width, height, @@ -753,12 +743,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), diff --git a/src/codecs/avif/ycgco.rs b/src/codecs/avif/ycgco.rs index 0a3faab471..8b9dd8e063 100644 --- a/src/codecs/avif/ycgco.rs +++ b/src/codecs/avif/ycgco.rs @@ -286,13 +286,13 @@ where macro_rules! define_ycgco_half_chroma { ($name: ident, $invoker: ident, $storage: ident, $cn: expr, $bp: expr, $description: expr) => { #[doc = concat!($description, " - - # Arguments - - * `image`: see [YuvPlanarImage] - * `rgb`: RGB image layout - * `range`: see [YuvIntensityRange] - * `matrix`: see [YuvStandardMatrix]")] + +# Arguments + +* `image`: see [YuvPlanarImage] +* `rgb`: RGB image layout +* `range`: see [YuvIntensityRange] +* `matrix`: see [YuvStandardMatrix]")] pub(crate) fn $name( image: YuvPlanarImage<$storage>, rgb: &mut [$storage], @@ -369,14 +369,14 @@ define_ycgco_half_chroma!( macro_rules! define_ycgcg_full_chroma { ($name: ident, $storage: ident, $cn: expr, $bp: expr, $description: expr) => { #[doc = concat!($description, " - - # Arguments - - * `image`: see [YuvPlanarImage] - * `rgba`: RGB image layout - * `range`: see [YuvIntensityRange] - * `matrix`: see [YuvStandardMatrix] - ")] + +# Arguments + +* `image`: see [YuvPlanarImage] +* `rgba`: RGB image layout +* `range`: see [YuvIntensityRange] +* `matrix`: see [YuvStandardMatrix] +")] pub(crate) fn $name( image: YuvPlanarImage<$storage>, rgba: &mut [$storage],