Skip to content

Commit b28450e

Browse files
committed
avif: Use mp4parse metadata to delay dav1d decoding until read_image
1 parent eb6cec5 commit b28450e

1 file changed

Lines changed: 103 additions & 81 deletions

File tree

src/codecs/avif/decoder.rs

Lines changed: 103 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Decoding of AVIF images.
22
use crate::error::{
3-
DecodingError, ImageFormatHint, LimitError, LimitErrorKind, UnsupportedError,
4-
UnsupportedErrorKind,
3+
DecodingError, LimitError, LimitErrorKind, UnsupportedError, UnsupportedErrorKind,
54
};
65
use crate::{ColorType, ImageDecoder, ImageError, ImageFormat, ImageResult};
76
///
@@ -20,7 +19,7 @@ use crate::codecs::avif::ycgco::{
2019
};
2120
use crate::codecs::avif::yuv::*;
2221
use dav1d::{PixelLayout, PlanarImageComponent};
23-
use mp4parse::{read_avif, ParseStrictness};
22+
use mp4parse::{read_avif, AvifContext, ParseStrictness};
2423

2524
fn error_map<E: Into<Box<dyn Error + Send + Sync>>>(err: E) -> ImageError {
2625
ImageError::Decoding(DecodingError::new(ImageFormat::Avif.into(), err))
@@ -31,9 +30,13 @@ fn error_map<E: Into<Box<dyn Error + Send + Sync>>>(err: E) -> ImageError {
3130
/// Reads one image into the chosen input.
3231
pub struct AvifDecoder<R> {
3332
inner: PhantomData<R>,
34-
picture: dav1d::Picture,
35-
alpha_picture: Option<dav1d::Picture>,
33+
width: u32,
34+
height: u32,
35+
bit_depth: u8,
36+
ctx: AvifContext,
3637
icc_profile: Option<Vec<u8>>,
38+
exif_metadata: Option<Vec<u8>>,
39+
xmp_metadata: Option<Vec<u8>>,
3740
}
3841

3942
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -77,46 +80,28 @@ impl<R: Read> AvifDecoder<R> {
7780
/// Create a new decoder that reads its input from `r`.
7881
pub fn new(mut r: R) -> ImageResult<Self> {
7982
let ctx = read_avif(&mut r, ParseStrictness::Normal).map_err(error_map)?;
80-
let coded = ctx.primary_item_coded_data().unwrap_or_default();
81-
82-
let mut primary_decoder = dav1d::Decoder::new().map_err(error_map)?;
83-
primary_decoder
84-
.send_data(coded.to_vec(), None, None, None)
85-
.map_err(error_map)?;
86-
let picture = read_until_ready(&mut primary_decoder)?;
87-
let alpha_item = ctx.alpha_item_coded_data().unwrap_or_default();
88-
let alpha_picture = if !alpha_item.is_empty() {
89-
let mut alpha_decoder = dav1d::Decoder::new().map_err(error_map)?;
90-
alpha_decoder
91-
.send_data(alpha_item.to_vec(), None, None, None)
92-
.map_err(error_map)?;
93-
Some(read_until_ready(&mut alpha_decoder)?)
94-
} else {
95-
None
96-
};
83+
let dimensions = ctx.spatial_extents().unwrap();
84+
let av1_config = ctx.av1_config().unwrap();
9785
let icc_profile = ctx
9886
.icc_colour_information()
9987
.map(|x| x.ok().unwrap_or_default())
10088
.map(|x| x.to_vec());
89+
let exif_metadata = ctx
90+
.exif_metadata()
91+
.map(|v| v.to_vec());
92+
let xmp_metadata = ctx
93+
.xmp_metadata()
94+
.map(|v| v.to_vec());
10195

102-
match picture.bit_depth() {
103-
8 => (),
104-
10 | 12 => (),
105-
_ => {
106-
return ImageResult::Err(ImageError::Decoding(DecodingError::new(
107-
ImageFormatHint::Exact(ImageFormat::Avif),
108-
format!(
109-
"Avif format does not support {} bit depth",
110-
picture.bit_depth()
111-
),
112-
)))
113-
}
114-
};
11596
Ok(AvifDecoder {
11697
inner: PhantomData,
117-
picture,
118-
alpha_picture,
98+
width: dimensions.image_width,
99+
height: dimensions.image_height,
100+
bit_depth: av1_config.bit_depth,
101+
ctx,
119102
icc_profile,
103+
exif_metadata,
104+
xmp_metadata,
120105
})
121106
}
122107
}
@@ -328,11 +313,11 @@ fn get_matrix(
328313

329314
impl<R: Read> ImageDecoder for AvifDecoder<R> {
330315
fn dimensions(&self) -> (u32, u32) {
331-
(self.picture.width(), self.picture.height())
316+
(self.width, self.height)
332317
}
333318

334319
fn color_type(&self) -> ColorType {
335-
if self.picture.bit_depth() == 8 {
320+
if self.bit_depth == 8 {
336321
ColorType::Rgba8
337322
} else {
338323
ColorType::Rgba16
@@ -343,14 +328,16 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
343328
Ok(self.icc_profile.clone())
344329
}
345330

346-
fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
347-
assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
331+
fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
332+
Ok(self.exif_metadata.clone())
333+
}
348334

349-
let bit_depth = self.picture.bit_depth();
335+
fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
336+
Ok(self.xmp_metadata.clone())
337+
}
350338

351-
// Normally this should never happen,
352-
// if this happens then there is an incorrect implementation somewhere else
353-
assert!(bit_depth == 8 || bit_depth == 10 || bit_depth == 12);
339+
fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
340+
assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
354341

355342
let (width, height) = self.dimensions();
356343
// This is suspicious if this happens, better fail early
@@ -360,54 +347,75 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
360347
)));
361348
}
362349

363-
let yuv_range = match self.picture.color_range() {
350+
let coded = self.ctx.primary_item_coded_data().unwrap_or_default();
351+
352+
let mut primary_decoder = dav1d::Decoder::new().map_err(error_map)?;
353+
primary_decoder
354+
.send_data(coded.to_vec(), None, None, None)
355+
.map_err(error_map)?;
356+
let picture = read_until_ready(&mut primary_decoder)?;
357+
let alpha_item = self.ctx.alpha_item_coded_data().unwrap_or_default();
358+
let alpha_picture = if !alpha_item.is_empty() {
359+
let mut alpha_decoder = dav1d::Decoder::new().map_err(error_map)?;
360+
alpha_decoder
361+
.send_data(alpha_item.to_vec(), None, None, None)
362+
.map_err(error_map)?;
363+
Some(read_until_ready(&mut alpha_decoder)?)
364+
} else {
365+
None
366+
};
367+
368+
assert_eq!(width, picture.width());
369+
assert_eq!(height, picture.height());
370+
assert_eq!(self.bit_depth as usize, picture.bit_depth());
371+
372+
let yuv_range = match picture.color_range() {
364373
dav1d::pixel::YUVRange::Limited => YuvIntensityRange::Tv,
365374
dav1d::pixel::YUVRange::Full => YuvIntensityRange::Pc,
366375
};
367376

368-
let matrix_strategy = get_matrix(self.picture.matrix_coefficients())?;
377+
let matrix_strategy = get_matrix(picture.matrix_coefficients())?;
369378

370379
// Identity matrix should be possible only on 4:4:4
371380
if matrix_strategy == YuvMatrixStrategy::Identity
372-
&& self.picture.pixel_layout() != PixelLayout::I444
381+
&& picture.pixel_layout() != PixelLayout::I444
373382
{
374383
return Err(ImageError::Decoding(DecodingError::new(
375384
ImageFormat::Avif.into(),
376-
AvifDecoderError::YuvLayoutOnIdentityMatrix(self.picture.pixel_layout()),
385+
AvifDecoderError::YuvLayoutOnIdentityMatrix(picture.pixel_layout()),
377386
)));
378387
}
379388

380-
if matrix_strategy == YuvMatrixStrategy::CgCo
381-
&& self.picture.pixel_layout() == PixelLayout::I400
389+
if matrix_strategy == YuvMatrixStrategy::CgCo && picture.pixel_layout() == PixelLayout::I400
382390
{
383391
return Err(ImageError::Decoding(DecodingError::new(
384392
ImageFormat::Avif.into(),
385393
AvifDecoderError::UnsupportedLayoutAndMatrix(
386-
self.picture.pixel_layout(),
394+
picture.pixel_layout(),
387395
matrix_strategy,
388396
),
389397
)));
390398
}
391399

392-
if bit_depth == 8 {
393-
let ref_y = self.picture.plane(PlanarImageComponent::Y);
394-
let ref_u = self.picture.plane(PlanarImageComponent::U);
395-
let ref_v = self.picture.plane(PlanarImageComponent::V);
400+
if self.bit_depth == 8 {
401+
let ref_y = picture.plane(PlanarImageComponent::Y);
402+
let ref_u = picture.plane(PlanarImageComponent::U);
403+
let ref_v = picture.plane(PlanarImageComponent::V);
396404

397405
let image = YuvPlanarImage {
398406
y_plane: ref_y.as_ref(),
399-
y_stride: self.picture.stride(PlanarImageComponent::Y) as usize,
407+
y_stride: picture.stride(PlanarImageComponent::Y) as usize,
400408
u_plane: ref_u.as_ref(),
401-
u_stride: self.picture.stride(PlanarImageComponent::U) as usize,
409+
u_stride: picture.stride(PlanarImageComponent::U) as usize,
402410
v_plane: ref_v.as_ref(),
403-
v_stride: self.picture.stride(PlanarImageComponent::V) as usize,
411+
v_stride: picture.stride(PlanarImageComponent::V) as usize,
404412
width: width as usize,
405413
height: height as usize,
406414
};
407415

408416
match matrix_strategy {
409417
YuvMatrixStrategy::KrKb(standard) => {
410-
let worker = match self.picture.pixel_layout() {
418+
let worker = match picture.pixel_layout() {
411419
PixelLayout::I400 => yuv400_to_rgba8,
412420
PixelLayout::I420 => yuv420_to_rgba8,
413421
PixelLayout::I422 => yuv422_to_rgba8,
@@ -417,7 +425,7 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
417425
worker(image, buf, yuv_range, standard)?;
418426
}
419427
YuvMatrixStrategy::CgCo => {
420-
let worker = match self.picture.pixel_layout() {
428+
let worker = match picture.pixel_layout() {
421429
PixelLayout::I400 => unreachable!(),
422430
PixelLayout::I420 => ycgco420_to_rgba8,
423431
PixelLayout::I422 => ycgco422_to_rgba8,
@@ -427,7 +435,7 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
427435
worker(image, buf, yuv_range)?;
428436
}
429437
YuvMatrixStrategy::Identity => {
430-
let worker = match self.picture.pixel_layout() {
438+
let worker = match picture.pixel_layout() {
431439
PixelLayout::I400 => unreachable!(),
432440
PixelLayout::I420 => unreachable!(),
433441
PixelLayout::I422 => unreachable!(),
@@ -439,7 +447,7 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
439447
}
440448

441449
// Squashing alpha plane into a picture
442-
if let Some(picture) = self.alpha_picture {
450+
if let Some(picture) = alpha_picture {
443451
if picture.pixel_layout() != PixelLayout::I400 {
444452
return Err(ImageError::Decoding(DecodingError::new(
445453
ImageFormat::Avif.into(),
@@ -463,11 +471,23 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
463471
// // 8+ bit-depth case
464472
if let Ok(buf) = bytemuck::try_cast_slice_mut(buf) {
465473
let target_slice: &mut [u16] = buf;
466-
self.process_16bit_picture(target_slice, yuv_range, matrix_strategy)?;
474+
self.process_16bit_picture(
475+
picture,
476+
alpha_picture,
477+
target_slice,
478+
yuv_range,
479+
matrix_strategy,
480+
)?;
467481
} else {
468482
// If buffer from Decoder is unaligned
469483
let mut aligned_store = vec![0u16; buf.len() / 2];
470-
self.process_16bit_picture(&mut aligned_store, yuv_range, matrix_strategy)?;
484+
self.process_16bit_picture(
485+
picture,
486+
alpha_picture,
487+
&mut aligned_store,
488+
yuv_range,
489+
matrix_strategy,
490+
)?;
471491
let buf_chunks = buf.as_chunks_mut::<2>().0.iter_mut();
472492
for (dst, src) in buf_chunks.zip(aligned_store.iter()) {
473493
*dst = src.to_ne_bytes();
@@ -486,14 +506,16 @@ impl<R: Read> ImageDecoder for AvifDecoder<R> {
486506
impl<R: Read> AvifDecoder<R> {
487507
fn process_16bit_picture(
488508
&self,
509+
picture: dav1d::Picture,
510+
alpha_picture: Option<dav1d::Picture>,
489511
target: &mut [u16],
490512
yuv_range: YuvIntensityRange,
491513
matrix_strategy: YuvMatrixStrategy,
492514
) -> ImageResult<()> {
493-
let y_dav1d_plane = self.picture.plane(PlanarImageComponent::Y);
515+
let y_dav1d_plane = picture.plane(PlanarImageComponent::Y);
494516

495-
let (width, height) = (self.picture.width(), self.picture.height());
496-
let bit_depth = self.picture.bit_depth();
517+
let (width, height) = (picture.width(), picture.height());
518+
let bit_depth = picture.bit_depth();
497519

498520
// dav1d may return not aligned and not correctly constrained data,
499521
// or at least I can't find guarantees on that
@@ -502,28 +524,28 @@ impl<R: Read> AvifDecoder<R> {
502524

503525
let y_plane_view = transmute_y_plane16(
504526
&y_dav1d_plane,
505-
self.picture.stride(PlanarImageComponent::Y) as usize,
527+
picture.stride(PlanarImageComponent::Y) as usize,
506528
width as usize,
507529
height as usize,
508530
);
509531

510-
let u_dav1d_plane = self.picture.plane(PlanarImageComponent::U);
511-
let v_dav1d_plane = self.picture.plane(PlanarImageComponent::V);
532+
let u_dav1d_plane = picture.plane(PlanarImageComponent::U);
533+
let v_dav1d_plane = picture.plane(PlanarImageComponent::V);
512534
let mut u_plane_view = Plane16View::default();
513535
let mut v_plane_view = Plane16View::default();
514536

515-
if self.picture.pixel_layout() != PixelLayout::I400 {
537+
if picture.pixel_layout() != PixelLayout::I400 {
516538
u_plane_view = transmute_chroma_plane16(
517539
&u_dav1d_plane,
518-
self.picture.pixel_layout(),
519-
self.picture.stride(PlanarImageComponent::U) as usize,
540+
picture.pixel_layout(),
541+
picture.stride(PlanarImageComponent::U) as usize,
520542
width as usize,
521543
height as usize,
522544
);
523545
v_plane_view = transmute_chroma_plane16(
524546
&v_dav1d_plane,
525-
self.picture.pixel_layout(),
526-
self.picture.stride(PlanarImageComponent::V) as usize,
547+
picture.pixel_layout(),
548+
picture.stride(PlanarImageComponent::V) as usize,
527549
width as usize,
528550
height as usize,
529551
);
@@ -542,7 +564,7 @@ impl<R: Read> AvifDecoder<R> {
542564

543565
match matrix_strategy {
544566
YuvMatrixStrategy::KrKb(standard) => {
545-
let worker = match self.picture.pixel_layout() {
567+
let worker = match picture.pixel_layout() {
546568
PixelLayout::I400 => {
547569
if bit_depth == 10 {
548570
yuv400_to_rgba10
@@ -575,7 +597,7 @@ impl<R: Read> AvifDecoder<R> {
575597
worker(image, target, yuv_range, standard)?;
576598
}
577599
YuvMatrixStrategy::CgCo => {
578-
let worker = match self.picture.pixel_layout() {
600+
let worker = match picture.pixel_layout() {
579601
PixelLayout::I400 => unreachable!(),
580602
PixelLayout::I420 => {
581603
if bit_depth == 10 {
@@ -602,7 +624,7 @@ impl<R: Read> AvifDecoder<R> {
602624
worker(image, target, yuv_range)?;
603625
}
604626
YuvMatrixStrategy::Identity => {
605-
let worker = match self.picture.pixel_layout() {
627+
let worker = match picture.pixel_layout() {
606628
PixelLayout::I400 => unreachable!(),
607629
PixelLayout::I420 => unreachable!(),
608630
PixelLayout::I422 => unreachable!(),
@@ -619,7 +641,7 @@ impl<R: Read> AvifDecoder<R> {
619641
}
620642

621643
// Squashing alpha plane into a picture
622-
if let Some(picture) = &self.alpha_picture {
644+
if let Some(picture) = &alpha_picture {
623645
if picture.pixel_layout() != PixelLayout::I400 {
624646
return Err(ImageError::Decoding(DecodingError::new(
625647
ImageFormat::Avif.into(),
@@ -646,7 +668,7 @@ impl<R: Read> AvifDecoder<R> {
646668
}
647669

648670
// Expand current bit depth to target 16
649-
let target_expand_bits = 16u32 - self.picture.bit_depth() as u32;
671+
let target_expand_bits = 16u32 - picture.bit_depth() as u32;
650672
for item in target.iter_mut() {
651673
*item = (*item).rotate_left(target_expand_bits);
652674
}

0 commit comments

Comments
 (0)