1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::decoder::gainmap::GainMapMetadata;
16 use crate::decoder::track::*;
17 use crate::decoder::Extent;
18 use crate::decoder::GenericIO;
19 use crate::image::YuvRange;
20 use crate::image::MAX_PLANE_COUNT;
21 use crate::internal_utils::stream::*;
22 use crate::internal_utils::*;
23 use crate::utils::clap::CleanAperture;
24 use crate::*;
25 
26 #[derive(Debug, PartialEq)]
27 pub enum BoxSize {
28     FixedSize(usize), // In bytes, header exclusive.
29     UntilEndOfStream, // The box goes on until the end of the input stream.
30 }
31 
32 #[derive(Debug)]
33 struct BoxHeader {
34     size: BoxSize,
35     box_type: String,
36 }
37 
38 impl BoxHeader {
size(&self) -> usize39     fn size(&self) -> usize {
40         match self.size {
41             BoxSize::FixedSize(size) => size, // not reached.
42             BoxSize::UntilEndOfStream => 0,
43         }
44     }
45 }
46 
47 #[derive(Debug, Default)]
48 pub struct FileTypeBox {
49     pub major_brand: String,
50     // minor_version "is informative only" (section 4.3.1 of ISO/IEC 14496-12)
51     compatible_brands: Vec<String>,
52 }
53 
54 impl FileTypeBox {
has_brand(&self, brand: &str) -> bool55     fn has_brand(&self, brand: &str) -> bool {
56         // As of 2024, section 4.3.1 of ISO/IEC 14496-12 does not explictly say that the file is
57         // compliant with the specification defining the major brand, but "the major_brand should be
58         // repeated in the compatible_brands". Later versions of the specification may explicitly
59         // consider the major brand as one of the compatible brands, even if not repeated.
60         if self.major_brand.as_str() == brand {
61             return true;
62         }
63         self.compatible_brands.iter().any(|x| x.as_str() == brand)
64     }
65 
has_brand_any(&self, brands: &[&str]) -> bool66     fn has_brand_any(&self, brands: &[&str]) -> bool {
67         brands.iter().any(|brand| self.has_brand(brand))
68     }
69 
is_avif(&self) -> bool70     pub fn is_avif(&self) -> bool {
71         // "avio" also exists but does not identify the file as AVIF on its own. See
72         // https://aomediacodec.github.io/av1-avif/v1.1.0.html#image-and-image-collection-brand
73         if self.has_brand_any(&["avif", "avis"]) {
74             return true;
75         }
76         match (cfg!(feature = "heic"), cfg!(android_soong)) {
77             (false, _) => false,
78             (true, false) => self.has_brand("heic"),
79             (true, true) => {
80                 // This is temporary. For the Android Framework, recognize HEIC files only if they
81                 // also contain a gainmap.
82                 self.has_brand("heic") && self.has_tmap()
83             }
84         }
85     }
86 
needs_meta(&self) -> bool87     pub fn needs_meta(&self) -> bool {
88         self.has_brand_any(&[
89             "avif",
90             #[cfg(feature = "heic")]
91             "heic",
92         ])
93     }
94 
needs_moov(&self) -> bool95     pub fn needs_moov(&self) -> bool {
96         self.has_brand_any(&[
97             "avis",
98             #[cfg(feature = "heic")]
99             "hevc",
100             #[cfg(feature = "heic")]
101             "msf1",
102         ])
103     }
104 
has_tmap(&self) -> bool105     pub fn has_tmap(&self) -> bool {
106         self.has_brand("tmap")
107     }
108 }
109 
110 #[derive(Debug, Default)]
111 pub struct ItemLocationEntry {
112     pub item_id: u32,
113     pub construction_method: u8,
114     pub base_offset: u64,
115     pub extent_count: u16,
116     pub extents: Vec<Extent>,
117 }
118 
119 #[derive(Debug, Default)]
120 pub struct ItemLocationBox {
121     offset_size: u8,
122     length_size: u8,
123     base_offset_size: u8,
124     index_size: u8,
125     pub items: Vec<ItemLocationEntry>,
126 }
127 
128 #[derive(Clone, Debug)]
129 pub struct ImageSpatialExtents {
130     pub width: u32,
131     pub height: u32,
132 }
133 
134 #[derive(Clone, Debug, Default)]
135 pub struct PixelInformation {
136     pub plane_depths: Vec<u8>,
137 }
138 
139 #[derive(Clone, Debug, Default, PartialEq)]
140 pub struct Av1CodecConfiguration {
141     pub seq_profile: u8,
142     pub seq_level_idx0: u8,
143     pub seq_tier0: u8,
144     pub high_bitdepth: bool,
145     pub twelve_bit: bool,
146     pub monochrome: bool,
147     pub chroma_subsampling_x: u8,
148     pub chroma_subsampling_y: u8,
149     pub chroma_sample_position: ChromaSamplePosition,
150     pub raw_data: Vec<u8>,
151 }
152 
153 #[derive(Clone, Debug, Default, PartialEq)]
154 pub struct HevcCodecConfiguration {
155     pub bitdepth: u8,
156     pub nal_length_size: u8,
157     pub vps: Vec<u8>,
158     pub sps: Vec<u8>,
159     pub pps: Vec<u8>,
160 }
161 
162 impl CodecConfiguration {
depth(&self) -> u8163     pub fn depth(&self) -> u8 {
164         match self {
165             Self::Av1(config) => match config.twelve_bit {
166                 true => 12,
167                 false => match config.high_bitdepth {
168                     true => 10,
169                     false => 8,
170                 },
171             },
172             Self::Hevc(config) => config.bitdepth,
173         }
174     }
175 
pixel_format(&self) -> PixelFormat176     pub fn pixel_format(&self) -> PixelFormat {
177         match self {
178             Self::Av1(config) => {
179                 if config.monochrome {
180                     PixelFormat::Yuv400
181                 } else if config.chroma_subsampling_x == 1 && config.chroma_subsampling_y == 1 {
182                     PixelFormat::Yuv420
183                 } else if config.chroma_subsampling_x == 1 {
184                     PixelFormat::Yuv422
185                 } else {
186                     PixelFormat::Yuv444
187                 }
188             }
189             Self::Hevc(_) => {
190                 // It is okay to always return Yuv420 here since that is the only format that
191                 // android_mediacodec returns.
192                 // TODO: b/370549923 - Identify the correct YUV subsampling type from the codec
193                 // configuration data.
194                 PixelFormat::Yuv420
195             }
196         }
197     }
198 
chroma_sample_position(&self) -> ChromaSamplePosition199     pub fn chroma_sample_position(&self) -> ChromaSamplePosition {
200         match self {
201             Self::Av1(config) => config.chroma_sample_position,
202             Self::Hevc(_) => {
203                 // It is okay to always return ChromaSamplePosition::default() here since that is
204                 // the only format that android_mediacodec returns.
205                 // TODO: b/370549923 - Identify the correct chroma sample position from the codec
206                 // configuration data.
207                 ChromaSamplePosition::default()
208             }
209         }
210     }
211 
raw_data(&self) -> Vec<u8>212     pub fn raw_data(&self) -> Vec<u8> {
213         match self {
214             Self::Av1(config) => config.raw_data.clone(),
215             Self::Hevc(config) => {
216                 // For HEVC, the codec specific data consists of the following 3 NAL units in
217                 // order: VPS, SPS and PPS. Each unit should be preceded by a start code of
218                 // "\x00\x00\x00\x01".
219                 // https://developer.android.com/reference/android/media/MediaCodec#CSD
220                 let mut data: Vec<u8> = Vec::new();
221                 for nal_unit in [&config.vps, &config.sps, &config.pps] {
222                     // Start code.
223                     data.extend_from_slice(&[0, 0, 0, 1]);
224                     // Data.
225                     data.extend_from_slice(&nal_unit[..]);
226                 }
227                 data
228             }
229         }
230     }
231 
profile(&self) -> u8232     pub fn profile(&self) -> u8 {
233         match self {
234             Self::Av1(config) => config.seq_profile,
235             Self::Hevc(_) => {
236                 // TODO: b/370549923 - Identify the correct profile from the codec configuration
237                 // data.
238                 0
239             }
240         }
241     }
242 
nal_length_size(&self) -> u8243     pub fn nal_length_size(&self) -> u8 {
244         match self {
245             Self::Av1(_) => 0, // Unused. This function is only used for HEVC.
246             Self::Hevc(config) => config.nal_length_size,
247         }
248     }
249 
is_avif(&self) -> bool250     pub fn is_avif(&self) -> bool {
251         matches!(self, Self::Av1(_))
252     }
253 
is_heic(&self) -> bool254     pub fn is_heic(&self) -> bool {
255         matches!(self, Self::Hevc(_))
256     }
257 }
258 
259 #[derive(Clone, Debug, Default)]
260 pub struct Nclx {
261     pub color_primaries: ColorPrimaries,
262     pub transfer_characteristics: TransferCharacteristics,
263     pub matrix_coefficients: MatrixCoefficients,
264     pub yuv_range: YuvRange,
265 }
266 
267 #[derive(Clone, Debug)]
268 pub enum ColorInformation {
269     Icc(Vec<u8>),
270     Nclx(Nclx),
271     Unknown,
272 }
273 
274 /// cbindgen:rename-all=CamelCase
275 #[derive(Clone, Copy, Debug, Default, PartialEq)]
276 #[repr(C)]
277 pub struct PixelAspectRatio {
278     pub h_spacing: u32,
279     pub v_spacing: u32,
280 }
281 
282 /// cbindgen:field-names=[maxCLL, maxPALL]
283 #[repr(C)]
284 #[derive(Clone, Copy, Debug, Default)]
285 pub struct ContentLightLevelInformation {
286     pub max_cll: u16,
287     pub max_pall: u16,
288 }
289 
290 #[derive(Clone, Debug, PartialEq)]
291 pub enum CodecConfiguration {
292     Av1(Av1CodecConfiguration),
293     Hevc(HevcCodecConfiguration),
294 }
295 
296 impl Default for CodecConfiguration {
default() -> Self297     fn default() -> Self {
298         Self::Av1(Av1CodecConfiguration::default())
299     }
300 }
301 
302 #[derive(Clone, Debug)]
303 pub enum ItemProperty {
304     ImageSpatialExtents(ImageSpatialExtents),
305     PixelInformation(PixelInformation),
306     CodecConfiguration(CodecConfiguration),
307     ColorInformation(ColorInformation),
308     PixelAspectRatio(PixelAspectRatio),
309     AuxiliaryType(String),
310     CleanAperture(CleanAperture),
311     ImageRotation(u8),
312     ImageMirror(u8),
313     OperatingPointSelector(u8),
314     LayerSelector(u16),
315     AV1LayeredImageIndexing([usize; 3]),
316     ContentLightLevelInformation(ContentLightLevelInformation),
317     Unknown(String),
318 }
319 
320 // Section 8.11.14 of ISO/IEC 14496-12.
321 #[derive(Debug, Default)]
322 pub struct ItemPropertyAssociation {
323     pub item_id: u32,
324     pub associations: Vec<(
325         u16,  // 1-based property_index
326         bool, // essential
327     )>,
328 }
329 
330 #[derive(Debug, Default)]
331 pub struct ItemInfo {
332     pub item_id: u32,
333     item_protection_index: u16,
334     pub item_type: String,
335     item_name: String,
336     pub content_type: String,
337 }
338 
339 #[derive(Debug, Default)]
340 pub struct ItemPropertyBox {
341     pub properties: Vec<ItemProperty>,
342     pub associations: Vec<ItemPropertyAssociation>,
343 }
344 
345 #[derive(Debug)]
346 pub struct ItemReference {
347     // Read this reference as "{from_item_id} is a {reference_type} for {to_item_id}"
348     // (except for dimg where it is in the opposite direction).
349     pub from_item_id: u32,
350     pub to_item_id: u32,
351     pub reference_type: String,
352     pub index: u32, // 0-based index of the reference within the iref type.
353 }
354 
355 #[derive(Debug, Default)]
356 pub struct MetaBox {
357     pub iinf: Vec<ItemInfo>,
358     pub iloc: ItemLocationBox,
359     pub primary_item_id: u32, // pitm
360     pub iprp: ItemPropertyBox,
361     pub iref: Vec<ItemReference>,
362     pub idat: Vec<u8>,
363 }
364 
365 #[derive(Debug)]
366 pub struct AvifBoxes {
367     pub ftyp: FileTypeBox,
368     pub meta: MetaBox,
369     pub tracks: Vec<Track>,
370 }
371 
parse_header(stream: &mut IStream, top_level: bool) -> AvifResult<BoxHeader>372 fn parse_header(stream: &mut IStream, top_level: bool) -> AvifResult<BoxHeader> {
373     // Section 4.2.2 of ISO/IEC 14496-12.
374     let start_offset = stream.offset;
375     // unsigned int(32) size;
376     let mut size = stream.read_u32()? as u64;
377     // unsigned int(32) type = boxtype;
378     let box_type = stream.read_string(4)?;
379     if size == 1 {
380         // unsigned int(64) largesize;
381         size = stream.read_u64()?;
382     }
383     if box_type == "uuid" {
384         // unsigned int(8) usertype[16] = extended_type;
385         stream.skip(16)?;
386     }
387     if size == 0 {
388         // Section 4.2.2 of ISO/IEC 14496-12.
389         //   if size is 0, then this box shall be in a top-level box (i.e. not contained in another
390         //   box), and be the last box in its 'file', and its payload extends to the end of that
391         //   enclosing 'file'. This is normally only used for a MediaDataBox.
392         if !top_level {
393             return Err(AvifError::BmffParseFailed(
394                 "non-top-level box with size 0".into(),
395             ));
396         }
397         return Ok(BoxHeader {
398             box_type,
399             size: BoxSize::UntilEndOfStream,
400         });
401     }
402     checked_decr!(size, u64_from_usize(stream.offset - start_offset)?);
403     let size = usize_from_u64(size)?;
404     if !top_level && size > stream.bytes_left()? {
405         return Err(AvifError::BmffParseFailed("possibly truncated box".into()));
406     }
407     Ok(BoxHeader {
408         box_type,
409         size: BoxSize::FixedSize(size),
410     })
411 }
412 
413 // Reads a truncated ftyp box. Populates as many brands as it can read.
parse_truncated_ftyp(stream: &mut IStream) -> FileTypeBox414 fn parse_truncated_ftyp(stream: &mut IStream) -> FileTypeBox {
415     // Section 4.3.2 of ISO/IEC 14496-12.
416     // unsigned int(32) major_brand;
417     let major_brand = match stream.read_string(4) {
418         Ok(major_brand) => major_brand,
419         Err(_) => return FileTypeBox::default(),
420     };
421     let mut compatible_brands: Vec<String> = Vec::new();
422     // unsigned int(32) compatible_brands[];  // to end of the box
423     while stream.has_bytes_left().unwrap_or_default() {
424         match stream.read_string(4) {
425             Ok(brand) => compatible_brands.push(brand),
426             Err(_) => break,
427         }
428     }
429     FileTypeBox {
430         major_brand,
431         compatible_brands,
432     }
433 }
434 
parse_ftyp(stream: &mut IStream) -> AvifResult<FileTypeBox>435 fn parse_ftyp(stream: &mut IStream) -> AvifResult<FileTypeBox> {
436     // Section 4.3.2 of ISO/IEC 14496-12.
437     // unsigned int(32) major_brand;
438     let major_brand = stream.read_string(4)?;
439     // unsigned int(4) minor_version;
440     stream.skip_u32()?;
441     if stream.bytes_left()? % 4 != 0 {
442         return Err(AvifError::BmffParseFailed(format!(
443             "Box[ftyp] contains a compatible brands section that isn't divisible by 4 {}",
444             stream.bytes_left()?
445         )));
446     }
447     let mut compatible_brands: Vec<String> = create_vec_exact(stream.bytes_left()? / 4)?;
448     // unsigned int(32) compatible_brands[];  // to end of the box
449     while stream.has_bytes_left()? {
450         compatible_brands.push(stream.read_string(4)?);
451     }
452     Ok(FileTypeBox {
453         major_brand,
454         compatible_brands,
455     })
456 }
457 
parse_hdlr(stream: &mut IStream) -> AvifResult<()>458 fn parse_hdlr(stream: &mut IStream) -> AvifResult<()> {
459     // Section 8.4.3.2 of ISO/IEC 14496-12.
460     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
461     // unsigned int(32) pre_defined = 0;
462     let predefined = stream.read_u32()?;
463     if predefined != 0 {
464         return Err(AvifError::BmffParseFailed(
465             "Box[hdlr] contains a pre_defined value that is nonzero".into(),
466         ));
467     }
468     // unsigned int(32) handler_type;
469     let handler_type = stream.read_string(4)?;
470     if handler_type != "pict" {
471         // Section 6.2 of ISO/IEC 23008-12:
472         //   The handler type for the MetaBox shall be 'pict'.
473         // https://aomediacodec.github.io/av1-avif/v1.1.0.html#image-sequences does not apply
474         // because this function is only called for the MetaBox but it would work too:
475         //   The track handler for an AV1 Image Sequence shall be pict.
476         return Err(AvifError::BmffParseFailed(
477             "Box[hdlr] handler_type is not 'pict'".into(),
478         ));
479     }
480     // const unsigned int(32)[3] reserved = 0;
481     if stream.read_u32()? != 0 || stream.read_u32()? != 0 || stream.read_u32()? != 0 {
482         return Err(AvifError::BmffParseFailed(
483             "Box[hdlr] contains invalid reserved bits".into(),
484         ));
485     }
486     // string name;
487     // Verify that a valid string is here, but don't bother to store it:
488     //   name gives a human-readable name for the track type (for debugging and inspection
489     //   purposes).
490     stream.read_c_string()?;
491     Ok(())
492 }
493 
parse_iloc(stream: &mut IStream) -> AvifResult<ItemLocationBox>494 fn parse_iloc(stream: &mut IStream) -> AvifResult<ItemLocationBox> {
495     // Section 8.11.3.2 of ISO/IEC 14496-12.
496     let (version, _flags) = stream.read_version_and_flags()?;
497     if version > 2 {
498         return Err(AvifError::BmffParseFailed(format!(
499             "Box[iloc] has an unsupported version: {version}"
500         )));
501     }
502     let mut iloc = ItemLocationBox::default();
503     let mut bits = stream.sub_bit_stream(2)?;
504     // unsigned int(4) offset_size;
505     iloc.offset_size = bits.read(4)? as u8;
506     // unsigned int(4) length_size;
507     iloc.length_size = bits.read(4)? as u8;
508     // unsigned int(4) base_offset_size;
509     iloc.base_offset_size = bits.read(4)? as u8;
510     iloc.index_size = if version == 1 || version == 2 {
511         // unsigned int(4) index_size;
512         bits.read(4)? as u8
513     } else {
514         // unsigned int(4) reserved;
515         bits.skip(4)?;
516         0
517     };
518     assert_eq!(bits.remaining_bits()?, 0);
519 
520     // Section 8.11.3.3 of ISO/IEC 14496-12.
521     for size in [
522         iloc.offset_size,
523         iloc.length_size,
524         iloc.base_offset_size,
525         iloc.index_size,
526     ] {
527         if ![0u8, 4, 8].contains(&size) {
528             return Err(AvifError::BmffParseFailed(format!(
529                 "Box[iloc] has invalid size: {size}"
530             )));
531         }
532     }
533 
534     let item_count: u32 = if version < 2 {
535         // unsigned int(16) item_count;
536         stream.read_u16()? as u32
537     } else {
538         // unsigned int(32) item_count;
539         stream.read_u32()?
540     };
541     for _i in 0..item_count {
542         let mut entry = ItemLocationEntry {
543             item_id: if version < 2 {
544                 // unsigned int(16) item_ID;
545                 stream.read_u16()? as u32
546             } else {
547                 // unsigned int(32) item_ID;
548                 stream.read_u32()?
549             },
550             ..ItemLocationEntry::default()
551         };
552         if entry.item_id == 0 {
553             return Err(AvifError::BmffParseFailed(format!(
554                 "Box[iloc] has invalid item id: {}",
555                 entry.item_id
556             )));
557         }
558         if version == 1 || version == 2 {
559             let mut bits = stream.sub_bit_stream(2)?;
560             // unsigned int(12) reserved = 0;
561             if bits.read(12)? != 0 {
562                 return Err(AvifError::BmffParseFailed(
563                     "Box[iloc] has invalid reserved bits".into(),
564                 ));
565             }
566             // unsigned int(4) construction_method;
567             entry.construction_method = bits.read(4)? as u8;
568             // 0: file offset, 1: idat offset, 2: item offset.
569             if entry.construction_method != 0 && entry.construction_method != 1 {
570                 return Err(AvifError::BmffParseFailed(format!(
571                     "Box[iloc] has unknown construction_method: {}",
572                     entry.construction_method
573                 )));
574             }
575         }
576         // unsigned int(16) data_reference_index;
577         stream.skip(2)?;
578         // unsigned int(base_offset_size*8) base_offset;
579         entry.base_offset = stream.read_uxx(iloc.base_offset_size)?;
580         // unsigned int(16) extent_count;
581         entry.extent_count = stream.read_u16()?;
582         for _j in 0..entry.extent_count {
583             // unsigned int(index_size*8) item_reference_index;
584             stream.skip(iloc.index_size as usize)?; // Only used for construction_method 2.
585             let extent = Extent {
586                 // unsigned int(offset_size*8) extent_offset;
587                 offset: stream.read_uxx(iloc.offset_size)?,
588                 // unsigned int(length_size*8) extent_length;
589                 size: usize_from_u64(stream.read_uxx(iloc.length_size)?)?,
590             };
591             entry.extents.push(extent);
592         }
593         iloc.items.push(entry);
594     }
595     Ok(iloc)
596 }
597 
598 // Returns the primary item ID.
parse_pitm(stream: &mut IStream) -> AvifResult<u32>599 fn parse_pitm(stream: &mut IStream) -> AvifResult<u32> {
600     // Section 8.11.4.2 of ISO/IEC 14496-12.
601     let (version, _flags) = stream.read_version_and_flags()?;
602     if version == 0 {
603         // unsigned int(16) item_ID;
604         Ok(stream.read_u16()? as u32)
605     } else {
606         // unsigned int(32) item_ID;
607         Ok(stream.read_u32()?)
608     }
609 }
610 
parse_ispe(stream: &mut IStream) -> AvifResult<ItemProperty>611 fn parse_ispe(stream: &mut IStream) -> AvifResult<ItemProperty> {
612     // Section 6.5.3.2 of ISO/IEC 23008-12.
613     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
614     let ispe = ImageSpatialExtents {
615         // unsigned int(32) image_width;
616         width: stream.read_u32()?,
617         // unsigned int(32) image_height;
618         height: stream.read_u32()?,
619     };
620     Ok(ItemProperty::ImageSpatialExtents(ispe))
621 }
622 
parse_pixi(stream: &mut IStream) -> AvifResult<ItemProperty>623 fn parse_pixi(stream: &mut IStream) -> AvifResult<ItemProperty> {
624     // Section 6.5.6.2 of ISO/IEC 23008-12.
625     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
626     // unsigned int (8) num_channels;
627     let num_channels = stream.read_u8()? as usize;
628     if num_channels == 0 || num_channels > MAX_PLANE_COUNT {
629         return Err(AvifError::BmffParseFailed(format!(
630             "Invalid plane count {num_channels} in pixi box"
631         )));
632     }
633     let mut pixi = PixelInformation {
634         plane_depths: create_vec_exact(num_channels)?,
635     };
636     for _ in 0..num_channels {
637         // unsigned int (8) bits_per_channel;
638         pixi.plane_depths.push(stream.read_u8()?);
639         if pixi.plane_depths.last().unwrap() != pixi.plane_depths.first().unwrap() {
640             return Err(AvifError::UnsupportedDepth);
641         }
642     }
643     Ok(ItemProperty::PixelInformation(pixi))
644 }
645 
646 #[allow(non_snake_case)]
parse_av1C(stream: &mut IStream) -> AvifResult<ItemProperty>647 fn parse_av1C(stream: &mut IStream) -> AvifResult<ItemProperty> {
648     let raw_data = stream.get_immutable_vec(stream.bytes_left()?)?;
649     // See https://aomediacodec.github.io/av1-isobmff/v1.2.0.html#av1codecconfigurationbox-syntax.
650     let mut bits = stream.sub_bit_stream(4)?;
651     // unsigned int (1) marker = 1;
652     let marker = bits.read(1)?;
653     if marker != 1 {
654         return Err(AvifError::BmffParseFailed(format!(
655             "Invalid marker ({marker}) in av1C"
656         )));
657     }
658     // unsigned int (7) version = 1;
659     let version = bits.read(7)?;
660     if version != 1 {
661         return Err(AvifError::BmffParseFailed(format!(
662             "Invalid version ({version}) in av1C"
663         )));
664     }
665     let av1C = Av1CodecConfiguration {
666         // unsigned int(3) seq_profile;
667         // unsigned int(5) seq_level_idx_0;
668         seq_profile: bits.read(3)? as u8,
669         seq_level_idx0: bits.read(5)? as u8,
670         // unsigned int(1) seq_tier_0;
671         // unsigned int(1) high_bitdepth;
672         // unsigned int(1) twelve_bit;
673         // unsigned int(1) monochrome;
674         // unsigned int(1) chroma_subsampling_x;
675         // unsigned int(1) chroma_subsampling_y;
676         // unsigned int(2) chroma_sample_position;
677         seq_tier0: bits.read(1)? as u8,
678         high_bitdepth: bits.read_bool()?,
679         twelve_bit: bits.read_bool()?,
680         monochrome: bits.read_bool()?,
681         chroma_subsampling_x: bits.read(1)? as u8,
682         chroma_subsampling_y: bits.read(1)? as u8,
683         chroma_sample_position: bits.read(2)?.into(),
684         raw_data,
685     };
686 
687     // unsigned int(3) reserved = 0;
688     if bits.read(3)? != 0 {
689         return Err(AvifError::BmffParseFailed(
690             "Invalid reserved bits in av1C".into(),
691         ));
692     }
693     // unsigned int(1) initial_presentation_delay_present;
694     if bits.read(1)? == 1 {
695         // unsigned int(4) initial_presentation_delay_minus_one;
696         bits.read(4)?;
697     } else {
698         // unsigned int(4) reserved = 0;
699         if bits.read(4)? != 0 {
700             return Err(AvifError::BmffParseFailed(
701                 "Invalid reserved bits in av1C".into(),
702             ));
703         }
704     }
705     assert_eq!(bits.remaining_bits()?, 0);
706 
707     // https://aomediacodec.github.io/av1-avif/v1.1.0.html#av1-configuration-item-property:
708     //   - Sequence Header OBUs should not be present in the AV1CodecConfigurationBox.
709     // This is ignored.
710     //   - If a Sequence Header OBU is present in the AV1CodecConfigurationBox, it shall match the
711     //     Sequence Header OBU in the AV1 Image Item Data.
712     // This is not enforced.
713     //   - The values of the fields in the AV1CodecConfigurationBox shall match those of the
714     //     Sequence Header OBU in the AV1 Image Item Data.
715     // This is not enforced (?).
716     //   - Metadata OBUs, if present, shall match the values given in other item properties, such as
717     //     the PixelInformationProperty or ColourInformationBox.
718     // This is not enforced.
719 
720     // unsigned int(8) configOBUs[];
721 
722     Ok(ItemProperty::CodecConfiguration(CodecConfiguration::Av1(
723         av1C,
724     )))
725 }
726 
727 #[allow(non_snake_case)]
728 #[cfg(feature = "heic")]
parse_hvcC(stream: &mut IStream) -> AvifResult<ItemProperty>729 fn parse_hvcC(stream: &mut IStream) -> AvifResult<ItemProperty> {
730     // unsigned int(8) configurationVersion;
731     let configuration_version = stream.read_u8()?;
732     if configuration_version != 0 && configuration_version != 1 {
733         return Err(AvifError::BmffParseFailed(format!(
734             "Unknown configurationVersion({configuration_version}) in hvcC. Expected 0 or 1."
735         )));
736     }
737     let mut bits = stream.sub_bit_stream(21)?;
738     // unsigned int(2) general_profile_space;
739     // unsigned int(1) general_tier_flag;
740     // unsigned int(5) general_profile_idc;
741     // unsigned int(32) general_profile_compatibility_flags;
742     // unsigned int(48) general_constraint_indicator_flags;
743     // unsigned int(8) general_level_idc;
744     // bit(4) reserved = '1111'b;
745     // unsigned int(12) min_spatial_segmentation_idc;
746     // bit(6) reserved = '111111'b;
747     // unsigned int(2) parallelismType;
748     // bit(6) reserved = '111111'b;
749     // unsigned int(2) chroma_format_idc;
750     // bit(5) reserved = '11111'b;
751     bits.skip(2 + 1 + 5 + 32 + 48 + 8 + 4 + 12 + 6 + 2 + 6 + 2 + 5)?;
752     // unsigned int(3) bit_depth_luma_minus8;
753     let bitdepth = bits.read(3)? as u8 + 8;
754     // bit(5) reserved = '11111'b;
755     // unsigned int(3) bit_depth_chroma_minus8;
756     // unsigned int(16) avgFrameRate;
757     // unsigned int(2) constantFrameRate;
758     // unsigned int(3) numTemporalLayers;
759     // unsigned int(1) temporalIdNested;
760     bits.skip(5 + 3 + 16 + 2 + 3 + 1)?;
761     // unsigned int(2) lengthSizeMinusOne;
762     let nal_length_size = 1 + bits.read(2)? as u8;
763     assert!(bits.remaining_bits()? == 0);
764 
765     // unsigned int(8) numOfArrays;
766     let num_of_arrays = stream.read_u8()?;
767     let mut vps: Vec<u8> = Vec::new();
768     let mut sps: Vec<u8> = Vec::new();
769     let mut pps: Vec<u8> = Vec::new();
770     for _i in 0..num_of_arrays {
771         // unsigned int(1) array_completeness;
772         // bit(1) reserved = 0;
773         // unsigned int(6) NAL_unit_type;
774         stream.skip(1)?;
775         // unsigned int(16) numNalus;
776         let num_nalus = stream.read_u16()?;
777         for _j in 0..num_nalus {
778             // unsigned int(16) nalUnitLength;
779             let nal_unit_length = stream.read_u16()?;
780             let nal_unit = stream.get_slice(nal_unit_length as usize)?;
781             let nal_unit_type = (nal_unit[0] >> 1) & 0x3f;
782             match nal_unit_type {
783                 32 => vps = nal_unit.to_vec(),
784                 33 => sps = nal_unit.to_vec(),
785                 34 => pps = nal_unit.to_vec(),
786                 _ => {}
787             }
788         }
789     }
790     Ok(ItemProperty::CodecConfiguration(CodecConfiguration::Hevc(
791         HevcCodecConfiguration {
792             bitdepth,
793             nal_length_size,
794             vps,
795             pps,
796             sps,
797         },
798     )))
799 }
800 
parse_colr(stream: &mut IStream) -> AvifResult<ItemProperty>801 fn parse_colr(stream: &mut IStream) -> AvifResult<ItemProperty> {
802     // Section 12.1.5.2 of ISO/IEC 14496-12.
803 
804     // unsigned int(32) colour_type;
805     let color_type = stream.read_string(4)?;
806     if color_type == "rICC" || color_type == "prof" {
807         if stream.bytes_left()? == 0 {
808             // Section 12.1.5.3 of ISO/IEC 14496-12:
809             //   ICC_profile: an ICC profile as defined in ISO 15076-1 or ICC.1 is supplied.
810             // Section 7.2.1 of ICC.1:2010:
811             //   The profile header is 128 bytes in length and contains 18 fields.
812             // So an empty ICC profile is invalid.
813             return Err(AvifError::BmffParseFailed(format!(
814                 "colr box contains 0 bytes of {color_type}"
815             )));
816         }
817         // ICC_profile; // restricted ("rICC") or unrestricted ("prof") ICC profile
818         return Ok(ItemProperty::ColorInformation(ColorInformation::Icc(
819             stream.get_slice(stream.bytes_left()?)?.to_vec(),
820         )));
821     }
822     if color_type == "nclx" {
823         let mut nclx = Nclx {
824             // unsigned int(16) colour_primaries;
825             color_primaries: stream.read_u16()?.into(),
826             // unsigned int(16) transfer_characteristics;
827             transfer_characteristics: stream.read_u16()?.into(),
828             // unsigned int(16) matrix_coefficients;
829             matrix_coefficients: stream.read_u16()?.into(),
830             ..Nclx::default()
831         };
832         let mut bits = stream.sub_bit_stream(1)?;
833         // unsigned int(1) full_range_flag;
834         nclx.yuv_range = if bits.read_bool()? { YuvRange::Full } else { YuvRange::Limited };
835         // unsigned int(7) reserved = 0;
836         if bits.read(7)? != 0 {
837             return Err(AvifError::BmffParseFailed(
838                 "colr box contains invalid reserved bits".into(),
839             ));
840         }
841         return Ok(ItemProperty::ColorInformation(ColorInformation::Nclx(nclx)));
842     }
843     Ok(ItemProperty::ColorInformation(ColorInformation::Unknown))
844 }
845 
parse_pasp(stream: &mut IStream) -> AvifResult<ItemProperty>846 fn parse_pasp(stream: &mut IStream) -> AvifResult<ItemProperty> {
847     // Section 12.1.4.2 of ISO/IEC 14496-12.
848     let pasp = PixelAspectRatio {
849         // unsigned int(32) hSpacing;
850         h_spacing: stream.read_u32()?,
851         // unsigned int(32) vSpacing;
852         v_spacing: stream.read_u32()?,
853     };
854     Ok(ItemProperty::PixelAspectRatio(pasp))
855 }
856 
857 #[allow(non_snake_case)]
parse_auxC(stream: &mut IStream) -> AvifResult<ItemProperty>858 fn parse_auxC(stream: &mut IStream) -> AvifResult<ItemProperty> {
859     // Section 6.5.8.2 of ISO/IEC 23008-12.
860     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
861     // string aux_type;
862     let auxiliary_type = stream.read_c_string()?;
863     // template unsigned int(8) aux_subtype[];
864     // until the end of the box, the semantics depend on the aux_type value
865     Ok(ItemProperty::AuxiliaryType(auxiliary_type))
866 }
867 
parse_clap(stream: &mut IStream) -> AvifResult<ItemProperty>868 fn parse_clap(stream: &mut IStream) -> AvifResult<ItemProperty> {
869     // Section 12.1.4.2 of ISO/IEC 14496-12.
870     let clap = CleanAperture {
871         // unsigned int(32) cleanApertureWidthN;
872         // unsigned int(32) cleanApertureWidthD;
873         width: stream.read_ufraction()?,
874         // unsigned int(32) cleanApertureHeightN;
875         // unsigned int(32) cleanApertureHeightD;
876         height: stream.read_ufraction()?,
877         // unsigned int(32) horizOffN;
878         // unsigned int(32) horizOffD;
879         horiz_off: stream.read_ufraction()?,
880         // unsigned int(32) vertOffN;
881         // unsigned int(32) vertOffD;
882         vert_off: stream.read_ufraction()?,
883     };
884     Ok(ItemProperty::CleanAperture(clap))
885 }
886 
parse_irot(stream: &mut IStream) -> AvifResult<ItemProperty>887 fn parse_irot(stream: &mut IStream) -> AvifResult<ItemProperty> {
888     // Section 6.5.10.2 of ISO/IEC 23008-12.
889     let mut bits = stream.sub_bit_stream(1)?;
890     // unsigned int (6) reserved = 0;
891     if bits.read(6)? != 0 {
892         return Err(AvifError::BmffParseFailed(
893             "invalid reserved bits in irot".into(),
894         ));
895     }
896     // unsigned int (2) angle;
897     let angle = bits.read(2)? as u8;
898     Ok(ItemProperty::ImageRotation(angle))
899 }
900 
parse_imir(stream: &mut IStream) -> AvifResult<ItemProperty>901 fn parse_imir(stream: &mut IStream) -> AvifResult<ItemProperty> {
902     // Section 6.5.12.1 of ISO/IEC 23008-12.
903     let mut bits = stream.sub_bit_stream(1)?;
904     // unsigned int(7) reserved = 0;
905     if bits.read(7)? != 0 {
906         return Err(AvifError::BmffParseFailed(
907             "invalid reserved bits in imir".into(),
908         ));
909     }
910     // unsigned int(1) axis;
911     let axis = bits.read(1)? as u8;
912     Ok(ItemProperty::ImageMirror(axis))
913 }
914 
parse_a1op(stream: &mut IStream) -> AvifResult<ItemProperty>915 fn parse_a1op(stream: &mut IStream) -> AvifResult<ItemProperty> {
916     // https://aomediacodec.github.io/av1-avif/v1.1.0.html#operating-point-selector-property-syntax
917 
918     // unsigned int(8) op_index;
919     let op_index = stream.read_u8()?;
920     if op_index > 31 {
921         // 31 is AV1's maximum operating point value (operating_points_cnt_minus_1).
922         return Err(AvifError::BmffParseFailed(format!(
923             "Invalid op_index ({op_index}) in a1op"
924         )));
925     }
926     Ok(ItemProperty::OperatingPointSelector(op_index))
927 }
928 
parse_lsel(stream: &mut IStream) -> AvifResult<ItemProperty>929 fn parse_lsel(stream: &mut IStream) -> AvifResult<ItemProperty> {
930     // Section 6.5.11.1 of ISO/IEC 23008-12.
931 
932     // unsigned int(16) layer_id;
933     let layer_id = stream.read_u16()?;
934 
935     // https://aomediacodec.github.io/av1-avif/v1.1.0.html#layer-selector-property:
936     //   The layer_id indicates the value of the spatial_id to render. The value shall be between 0
937     //   and 3, or the special value 0xFFFF.
938     if layer_id != 0xFFFF && layer_id >= 4 {
939         return Err(AvifError::BmffParseFailed(format!(
940             "Invalid layer_id ({layer_id}) in lsel"
941         )));
942     }
943     Ok(ItemProperty::LayerSelector(layer_id))
944 }
945 
parse_a1lx(stream: &mut IStream) -> AvifResult<ItemProperty>946 fn parse_a1lx(stream: &mut IStream) -> AvifResult<ItemProperty> {
947     // https://aomediacodec.github.io/av1-avif/v1.1.0.html#layered-image-indexing-property-syntax
948     let mut bits = stream.sub_bit_stream(1)?;
949     // unsigned int(7) reserved = 0;
950     if bits.read(7)? != 0 {
951         return Err(AvifError::BmffParseFailed(
952             "Invalid reserved bits in a1lx".into(),
953         ));
954     }
955     // unsigned int(1) large_size;
956     let large_size = bits.read_bool()?;
957     let mut layer_sizes: [usize; 3] = [0; 3];
958     for layer_size in &mut layer_sizes {
959         if large_size {
960             *layer_size = usize_from_u32(stream.read_u32()?)?;
961         } else {
962             *layer_size = usize_from_u16(stream.read_u16()?)?;
963         }
964     }
965     Ok(ItemProperty::AV1LayeredImageIndexing(layer_sizes))
966 }
967 
parse_clli(stream: &mut IStream) -> AvifResult<ItemProperty>968 fn parse_clli(stream: &mut IStream) -> AvifResult<ItemProperty> {
969     // Section 12.1.6.2 of ISO/IEC 14496-12.
970     let clli = ContentLightLevelInformation {
971         // unsigned int(16) max_content_light_level
972         max_cll: stream.read_u16()?,
973         // unsigned int(16) max_pic_average_light_level
974         max_pall: stream.read_u16()?,
975     };
976     Ok(ItemProperty::ContentLightLevelInformation(clli))
977 }
978 
parse_ipco(stream: &mut IStream) -> AvifResult<Vec<ItemProperty>>979 fn parse_ipco(stream: &mut IStream) -> AvifResult<Vec<ItemProperty>> {
980     // Section 8.11.14.2 of ISO/IEC 14496-12.
981     let mut properties: Vec<ItemProperty> = Vec::new();
982     while stream.has_bytes_left()? {
983         let header = parse_header(stream, /*top_level=*/ false)?;
984         let mut sub_stream = stream.sub_stream(&header.size)?;
985         match header.box_type.as_str() {
986             "ispe" => properties.push(parse_ispe(&mut sub_stream)?),
987             "pixi" => properties.push(parse_pixi(&mut sub_stream)?),
988             "av1C" => properties.push(parse_av1C(&mut sub_stream)?),
989             "colr" => properties.push(parse_colr(&mut sub_stream)?),
990             "pasp" => properties.push(parse_pasp(&mut sub_stream)?),
991             "auxC" => properties.push(parse_auxC(&mut sub_stream)?),
992             "clap" => properties.push(parse_clap(&mut sub_stream)?),
993             "irot" => properties.push(parse_irot(&mut sub_stream)?),
994             "imir" => properties.push(parse_imir(&mut sub_stream)?),
995             "a1op" => properties.push(parse_a1op(&mut sub_stream)?),
996             "lsel" => properties.push(parse_lsel(&mut sub_stream)?),
997             "a1lx" => properties.push(parse_a1lx(&mut sub_stream)?),
998             "clli" => properties.push(parse_clli(&mut sub_stream)?),
999             #[cfg(feature = "heic")]
1000             "hvcC" => properties.push(parse_hvcC(&mut sub_stream)?),
1001             _ => properties.push(ItemProperty::Unknown(header.box_type)),
1002         }
1003     }
1004     Ok(properties)
1005 }
1006 
parse_ipma(stream: &mut IStream) -> AvifResult<Vec<ItemPropertyAssociation>>1007 fn parse_ipma(stream: &mut IStream) -> AvifResult<Vec<ItemPropertyAssociation>> {
1008     // Section 8.11.14.2 of ISO/IEC 14496-12.
1009     let (version, flags) = stream.read_version_and_flags()?;
1010     // unsigned int(32) entry_count;
1011     let entry_count = stream.read_u32()?;
1012     let mut ipma: Vec<ItemPropertyAssociation> = create_vec_exact(usize_from_u32(entry_count)?)?;
1013     for _i in 0..entry_count {
1014         let mut entry = ItemPropertyAssociation::default();
1015         // ISO/IEC 23008-12, First edition, 2017-12, Section 9.3.1:
1016         //   Each ItemPropertyAssociation box shall be ordered by increasing item_ID, and there
1017         //   shall be at most one association box for each item_ID, in any
1018         //   ItemPropertyAssociation box.
1019         if version < 1 {
1020             // unsigned int(16) item_ID;
1021             entry.item_id = stream.read_u16()? as u32;
1022         } else {
1023             // unsigned int(32) item_ID;
1024             entry.item_id = stream.read_u32()?;
1025         }
1026         if entry.item_id == 0 {
1027             return Err(AvifError::BmffParseFailed(format!(
1028                 "invalid item id ({}) in ipma",
1029                 entry.item_id
1030             )));
1031         }
1032         if !ipma.is_empty() {
1033             let previous_item_id = ipma.last().unwrap().item_id;
1034             if entry.item_id <= previous_item_id {
1035                 return Err(AvifError::BmffParseFailed(
1036                     "ipma item ids are not ordered by increasing id".into(),
1037                 ));
1038             }
1039         }
1040         // unsigned int(8) association_count;
1041         let association_count = stream.read_u8()?;
1042         for _j in 0..association_count {
1043             let mut bits = stream.sub_bit_stream(if flags & 0x1 == 1 { 2 } else { 1 })?;
1044             // bit(1) essential;
1045             let essential = bits.read_bool()?;
1046             if flags & 0x1 == 1 {
1047                 // unsigned int(15) property_index;
1048                 entry.associations.push((bits.read(15)? as u16, essential));
1049             } else {
1050                 //unsigned int(7) property_index;
1051                 entry.associations.push((bits.read(7)? as u16, essential));
1052             }
1053         }
1054         ipma.push(entry);
1055     }
1056     Ok(ipma)
1057 }
1058 
parse_iprp(stream: &mut IStream) -> AvifResult<ItemPropertyBox>1059 fn parse_iprp(stream: &mut IStream) -> AvifResult<ItemPropertyBox> {
1060     // Section 8.11.14.2 of ISO/IEC 14496-12.
1061     let header = parse_header(stream, /*top_level=*/ false)?;
1062     if header.box_type != "ipco" {
1063         return Err(AvifError::BmffParseFailed(
1064             "First box in iprp is not ipco".into(),
1065         ));
1066     }
1067     let mut iprp = ItemPropertyBox::default();
1068     // Parse ipco box.
1069     {
1070         let mut sub_stream = stream.sub_stream(&header.size)?;
1071         iprp.properties = parse_ipco(&mut sub_stream)?;
1072     }
1073     // Parse ipma boxes.
1074     while stream.has_bytes_left()? {
1075         let header = parse_header(stream, /*top_level=*/ false)?;
1076         if header.box_type != "ipma" {
1077             return Err(AvifError::BmffParseFailed(
1078                 "Found non ipma box in iprp".into(),
1079             ));
1080         }
1081         let mut sub_stream = stream.sub_stream(&header.size)?;
1082         iprp.associations.append(&mut parse_ipma(&mut sub_stream)?);
1083     }
1084     Ok(iprp)
1085 }
1086 
parse_infe(stream: &mut IStream) -> AvifResult<ItemInfo>1087 fn parse_infe(stream: &mut IStream) -> AvifResult<ItemInfo> {
1088     // Section 8.11.6.2 of ISO/IEC 14496-12.
1089     let (version, _flags) = stream.read_version_and_flags()?;
1090     if version != 2 && version != 3 {
1091         return Err(AvifError::BmffParseFailed(
1092             "infe box version 2 or 3 expected.".into(),
1093         ));
1094     }
1095 
1096     // TODO: check flags. ISO/IEC 23008-12:2017, Section 9.2 says:
1097     // The flags field of ItemInfoEntry with version greater than or equal to 2 is specified
1098     // as follows:
1099     //   (flags & 1) equal to 1 indicates that the item is not intended to be a part of the
1100     //   presentation. For example, when (flags & 1) is equal to 1 for an image item, the
1101     //   image item should not be displayed. (flags & 1) equal to 0 indicates that the item
1102     //   is intended to be a part of the presentation.
1103     //
1104     // See also Section 6.4.2.
1105     let mut entry = ItemInfo::default();
1106     if version == 2 {
1107         // unsigned int(16) item_ID;
1108         entry.item_id = stream.read_u16()? as u32;
1109     } else {
1110         // unsigned int(32) item_ID;
1111         entry.item_id = stream.read_u32()?;
1112     }
1113     if entry.item_id == 0 {
1114         return Err(AvifError::BmffParseFailed(format!(
1115             "Invalid item id ({}) found in infe",
1116             entry.item_id
1117         )));
1118     }
1119     // unsigned int(16) item_protection_index;
1120     entry.item_protection_index = stream.read_u16()?;
1121     // unsigned int(32) item_type;
1122     entry.item_type = stream.read_string(4)?;
1123 
1124     // utf8string item_name;
1125     entry.item_name = stream.read_c_string()?;
1126 
1127     if entry.item_type == "mime" {
1128         // utf8string content_type;
1129         entry.content_type = stream.read_c_string()?;
1130         // utf8string content_encoding; //optional
1131     }
1132     // if (item_type == 'uri ') {
1133     //  utf8string item_uri_type;
1134     // }
1135     Ok(entry)
1136 }
1137 
parse_iinf(stream: &mut IStream) -> AvifResult<Vec<ItemInfo>>1138 fn parse_iinf(stream: &mut IStream) -> AvifResult<Vec<ItemInfo>> {
1139     // Section 8.11.6.2 of ISO/IEC 14496-12.
1140     let (version, _flags) = stream.read_version_and_flags()?;
1141     if version > 1 {
1142         return Err(AvifError::BmffParseFailed(format!(
1143             "Unsupported version {} in iinf box",
1144             version
1145         )));
1146     }
1147     let entry_count: u32 = if version == 0 {
1148         // unsigned int(16) entry_count;
1149         stream.read_u16()? as u32
1150     } else {
1151         // unsigned int(32) entry_count;
1152         stream.read_u32()?
1153     };
1154     let mut iinf: Vec<ItemInfo> = create_vec_exact(usize_from_u32(entry_count)?)?;
1155     for _i in 0..entry_count {
1156         let header = parse_header(stream, /*top_level=*/ false)?;
1157         if header.box_type != "infe" {
1158             return Err(AvifError::BmffParseFailed(
1159                 "Found non infe box in iinf".into(),
1160             ));
1161         }
1162         let mut sub_stream = stream.sub_stream(&header.size)?;
1163         iinf.push(parse_infe(&mut sub_stream)?);
1164     }
1165     Ok(iinf)
1166 }
1167 
parse_iref(stream: &mut IStream) -> AvifResult<Vec<ItemReference>>1168 fn parse_iref(stream: &mut IStream) -> AvifResult<Vec<ItemReference>> {
1169     // Section 8.11.12.2 of ISO/IEC 14496-12.
1170     let (version, _flags) = stream.read_version_and_flags()?;
1171     let mut iref: Vec<ItemReference> = Vec::new();
1172     // versions > 1 are not supported. ignore them.
1173     if version > 1 {
1174         return Ok(iref);
1175     }
1176     while stream.has_bytes_left()? {
1177         let header = parse_header(stream, /*top_level=*/ false)?;
1178         let from_item_id: u32 = if version == 0 {
1179             // unsigned int(16) from_item_ID;
1180             stream.read_u16()? as u32
1181         } else {
1182             // unsigned int(32) from_item_ID;
1183             stream.read_u32()?
1184         };
1185         if from_item_id == 0 {
1186             return Err(AvifError::BmffParseFailed(
1187                 "invalid from_item_id (0) in iref".into(),
1188             ));
1189         }
1190         // unsigned int(16) reference_count;
1191         let reference_count = stream.read_u16()?;
1192         for index in 0..reference_count {
1193             let to_item_id: u32 = if version == 0 {
1194                 // unsigned int(16) to_item_ID;
1195                 stream.read_u16()? as u32
1196             } else {
1197                 // unsigned int(32) to_item_ID;
1198                 stream.read_u32()?
1199             };
1200             if to_item_id == 0 {
1201                 return Err(AvifError::BmffParseFailed(
1202                     "invalid to_item_id (0) in iref".into(),
1203                 ));
1204             }
1205             iref.push(ItemReference {
1206                 from_item_id,
1207                 to_item_id,
1208                 reference_type: header.box_type.clone(),
1209                 index: index as u32,
1210             });
1211         }
1212     }
1213     Ok(iref)
1214 }
1215 
parse_idat(stream: &mut IStream) -> AvifResult<Vec<u8>>1216 fn parse_idat(stream: &mut IStream) -> AvifResult<Vec<u8>> {
1217     // Section 8.11.11.2 of ISO/IEC 14496-12.
1218     if !stream.has_bytes_left()? {
1219         return Err(AvifError::BmffParseFailed("Invalid idat size (0)".into()));
1220     }
1221     let mut idat: Vec<u8> = Vec::with_capacity(stream.bytes_left()?);
1222     idat.extend_from_slice(stream.get_slice(stream.bytes_left()?)?);
1223     Ok(idat)
1224 }
1225 
parse_meta(stream: &mut IStream) -> AvifResult<MetaBox>1226 fn parse_meta(stream: &mut IStream) -> AvifResult<MetaBox> {
1227     // Section 8.11.1.2 of ISO/IEC 14496-12.
1228     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
1229     let mut meta = MetaBox::default();
1230 
1231     // Parse the first hdlr box.
1232     {
1233         let header = parse_header(stream, /*top_level=*/ false)?;
1234         if header.box_type != "hdlr" {
1235             return Err(AvifError::BmffParseFailed(
1236                 "first box in meta is not hdlr".into(),
1237             ));
1238         }
1239         parse_hdlr(&mut stream.sub_stream(&header.size)?)?;
1240     }
1241 
1242     let mut boxes_seen: HashSet<String> = HashSet::with_hasher(NonRandomHasherState);
1243     boxes_seen.insert(String::from("hdlr"));
1244     while stream.has_bytes_left()? {
1245         let header = parse_header(stream, /*top_level=*/ false)?;
1246         match header.box_type.as_str() {
1247             "hdlr" | "iloc" | "pitm" | "iprp" | "iinf" | "iref" | "idat" => {
1248                 if boxes_seen.contains(&header.box_type) {
1249                     return Err(AvifError::BmffParseFailed(format!(
1250                         "duplicate {} box in meta.",
1251                         header.box_type
1252                     )));
1253                 }
1254                 boxes_seen.insert(header.box_type.clone());
1255             }
1256             _ => {}
1257         }
1258         let mut sub_stream = stream.sub_stream(&header.size)?;
1259         match header.box_type.as_str() {
1260             "iloc" => meta.iloc = parse_iloc(&mut sub_stream)?,
1261             "pitm" => meta.primary_item_id = parse_pitm(&mut sub_stream)?,
1262             "iprp" => meta.iprp = parse_iprp(&mut sub_stream)?,
1263             "iinf" => meta.iinf = parse_iinf(&mut sub_stream)?,
1264             "iref" => meta.iref = parse_iref(&mut sub_stream)?,
1265             "idat" => meta.idat = parse_idat(&mut sub_stream)?,
1266             _ => {}
1267         }
1268     }
1269     Ok(meta)
1270 }
1271 
parse_tkhd(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1272 fn parse_tkhd(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1273     // Section 8.3.2.2 of ISO/IEC 14496-12.
1274     let (version, _flags) = stream.read_version_and_flags()?;
1275     if version == 1 {
1276         // unsigned int(64) creation_time;
1277         stream.skip_u64()?;
1278         // unsigned int(64) modification_time;
1279         stream.skip_u64()?;
1280         // unsigned int(32) track_ID;
1281         track.id = stream.read_u32()?;
1282         // const unsigned int(32) reserved = 0;
1283         if stream.read_u32()? != 0 {
1284             return Err(AvifError::BmffParseFailed(
1285                 "Invalid reserved bits in tkhd".into(),
1286             ));
1287         }
1288         // unsigned int(64) duration;
1289         track.track_duration = stream.read_u64()?;
1290     } else if version == 0 {
1291         // unsigned int(32) creation_time;
1292         stream.skip_u32()?;
1293         // unsigned int(32) modification_time;
1294         stream.skip_u32()?;
1295         // unsigned int(32) track_ID;
1296         track.id = stream.read_u32()?;
1297         // const unsigned int(32) reserved = 0;
1298         if stream.read_u32()? != 0 {
1299             return Err(AvifError::BmffParseFailed(
1300                 "Invalid reserved bits in tkhd".into(),
1301             ));
1302         }
1303         // unsigned int(32) duration;
1304         track.track_duration = stream.read_u32()? as u64;
1305     } else {
1306         return Err(AvifError::BmffParseFailed(format!(
1307             "unsupported version ({version}) in trak"
1308         )));
1309     }
1310 
1311     // const unsigned int(32)[2] reserved = 0;
1312     if stream.read_u32()? != 0 || stream.read_u32()? != 0 {
1313         return Err(AvifError::BmffParseFailed(
1314             "Invalid reserved bits in tkhd".into(),
1315         ));
1316     }
1317     // The following fields should be 0 but are ignored instead.
1318     // template int(16) layer = 0;
1319     stream.skip(2)?;
1320     // template int(16) alternate_group = 0;
1321     stream.skip(2)?;
1322     // template int(16) volume = {if track_is_audio 0x0100 else 0};
1323     stream.skip(2)?;
1324     // const unsigned int(16) reserved = 0;
1325     if stream.read_u16()? != 0 {
1326         return Err(AvifError::BmffParseFailed(
1327             "Invalid reserved bits in tkhd".into(),
1328         ));
1329     }
1330     // template int(32)[9] matrix= { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 }; // unity matrix
1331     stream.skip(4 * 9)?;
1332 
1333     // unsigned int(32) width;
1334     track.width = stream.read_u32()? >> 16;
1335     // unsigned int(32) height;
1336     track.height = stream.read_u32()? >> 16;
1337 
1338     if track.width == 0 || track.height == 0 {
1339         return Err(AvifError::BmffParseFailed(
1340             "invalid track dimensions".into(),
1341         ));
1342     }
1343     Ok(())
1344 }
1345 
parse_mdhd(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1346 fn parse_mdhd(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1347     // Section 8.4.2.2 of ISO/IEC 14496-12.
1348     let (version, _flags) = stream.read_version_and_flags()?;
1349     if version == 1 {
1350         // unsigned int(64) creation_time;
1351         stream.skip_u64()?;
1352         // unsigned int(64) modification_time;
1353         stream.skip_u64()?;
1354         // unsigned int(32) timescale;
1355         track.media_timescale = stream.read_u32()?;
1356         // unsigned int(64) duration;
1357         track.media_duration = stream.read_u64()?;
1358     } else if version == 0 {
1359         // unsigned int(32) creation_time;
1360         stream.skip_u32()?;
1361         // unsigned int(32) modification_time;
1362         stream.skip_u32()?;
1363         // unsigned int(32) timescale;
1364         track.media_timescale = stream.read_u32()?;
1365         // unsigned int(32) duration;
1366         track.media_duration = stream.read_u32()? as u64;
1367     } else {
1368         return Err(AvifError::BmffParseFailed(format!(
1369             "unsupported version ({version}) in mdhd"
1370         )));
1371     }
1372 
1373     let mut bits = stream.sub_bit_stream(4)?;
1374     // bit(1) pad = 0;
1375     if bits.read(1)? != 0 {
1376         return Err(AvifError::BmffParseFailed(
1377             "Invalid reserved bits in mdhd".into(),
1378         ));
1379     }
1380     // unsigned int(5)[3] language; // ISO-639-2/T language code
1381     bits.skip(5 * 3)?;
1382     // unsigned int(16) pre_defined = 0; ("Readers should expect any value")
1383     bits.skip(2)?;
1384     Ok(())
1385 }
1386 
parse_stco( stream: &mut IStream, sample_table: &mut SampleTable, large_offset: bool, ) -> AvifResult<()>1387 fn parse_stco(
1388     stream: &mut IStream,
1389     sample_table: &mut SampleTable,
1390     large_offset: bool,
1391 ) -> AvifResult<()> {
1392     // Section 8.7.5.2 of ISO/IEC 14496-12.
1393     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
1394     // unsigned int(32) entry_count;
1395     let entry_count = usize_from_u32(stream.read_u32()?)?;
1396     sample_table.chunk_offsets = create_vec_exact(entry_count)?;
1397     for _ in 0..entry_count {
1398         let chunk_offset: u64 = if large_offset {
1399             // unsigned int(64) chunk_offset;
1400             stream.read_u64()?
1401         } else {
1402             // unsigned int(32) chunk_offset;
1403             stream.read_u32()? as u64
1404         };
1405         sample_table.chunk_offsets.push(chunk_offset);
1406     }
1407     Ok(())
1408 }
1409 
parse_stsc(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()>1410 fn parse_stsc(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()> {
1411     // Section 8.7.4.2 of ISO/IEC 14496-12.
1412     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
1413     // unsigned int(32) entry_count;
1414     let entry_count = usize_from_u32(stream.read_u32()?)?;
1415     sample_table.sample_to_chunk = create_vec_exact(entry_count)?;
1416     for i in 0..entry_count {
1417         let stsc = SampleToChunk {
1418             // unsigned int(32) first_chunk;
1419             first_chunk: stream.read_u32()?,
1420             // unsigned int(32) samples_per_chunk;
1421             samples_per_chunk: stream.read_u32()?,
1422             // unsigned int(32) sample_description_index;
1423             sample_description_index: stream.read_u32()?,
1424         };
1425         if i == 0 {
1426             if stsc.first_chunk != 1 {
1427                 return Err(AvifError::BmffParseFailed(
1428                     "stsc does not begin with chunk 1.".into(),
1429                 ));
1430             }
1431         } else if stsc.first_chunk <= sample_table.sample_to_chunk.last().unwrap().first_chunk {
1432             return Err(AvifError::BmffParseFailed(
1433                 "stsc chunks are not strictly increasing.".into(),
1434             ));
1435         }
1436         if stsc.sample_description_index == 0 {
1437             return Err(AvifError::BmffParseFailed(format!(
1438                 "sample_description_index is {} in stsc chunk.",
1439                 stsc.sample_description_index
1440             )));
1441         }
1442         sample_table.sample_to_chunk.push(stsc);
1443     }
1444     Ok(())
1445 }
1446 
parse_stsz(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()>1447 fn parse_stsz(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()> {
1448     // Section 8.7.3.2.1 of ISO/IEC 14496-12.
1449     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
1450     // unsigned int(32) sample_size;
1451     let sample_size = stream.read_u32()?;
1452     // unsigned int(32) sample_count;
1453     let sample_count = usize_from_u32(stream.read_u32()?)?;
1454 
1455     if sample_size > 0 {
1456         sample_table.sample_size = SampleSize::FixedSize(sample_size);
1457         return Ok(());
1458     }
1459     let mut sample_sizes: Vec<u32> = create_vec_exact(sample_count)?;
1460     for _ in 0..sample_count {
1461         // unsigned int(32) entry_size;
1462         sample_sizes.push(stream.read_u32()?);
1463     }
1464     sample_table.sample_size = SampleSize::Sizes(sample_sizes);
1465     Ok(())
1466 }
1467 
parse_stss(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()>1468 fn parse_stss(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()> {
1469     // Section 8.6.2.2 of ISO/IEC 14496-12.
1470     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
1471     // unsigned int(32) entry_count;
1472     let entry_count = usize_from_u32(stream.read_u32()?)?;
1473     sample_table.sync_samples = create_vec_exact(entry_count)?;
1474     for _ in 0..entry_count {
1475         // unsigned int(32) sample_number;
1476         sample_table.sync_samples.push(stream.read_u32()?);
1477     }
1478     Ok(())
1479 }
1480 
parse_stts(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()>1481 fn parse_stts(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()> {
1482     // Section 8.6.1.2.2 of ISO/IEC 14496-12.
1483     let (_version, _flags) = stream.read_and_enforce_version_and_flags(0)?;
1484     // unsigned int(32) entry_count;
1485     let entry_count = usize_from_u32(stream.read_u32()?)?;
1486     sample_table.time_to_sample = create_vec_exact(entry_count)?;
1487     for _ in 0..entry_count {
1488         let stts = TimeToSample {
1489             // unsigned int(32) sample_count;
1490             sample_count: stream.read_u32()?,
1491             // unsigned int(32) sample_delta;
1492             sample_delta: stream.read_u32()?,
1493         };
1494         sample_table.time_to_sample.push(stts);
1495     }
1496     Ok(())
1497 }
1498 
parse_sample_entry(stream: &mut IStream, format: String) -> AvifResult<SampleDescription>1499 fn parse_sample_entry(stream: &mut IStream, format: String) -> AvifResult<SampleDescription> {
1500     // Section 8.5.2.2 of ISO/IEC 14496-12.
1501     let mut sample_entry = SampleDescription {
1502         format,
1503         ..SampleDescription::default()
1504     };
1505     // const unsigned int(8) reserved[6] = 0;
1506     if stream.read_u8()? != 0
1507         || stream.read_u8()? != 0
1508         || stream.read_u8()? != 0
1509         || stream.read_u8()? != 0
1510         || stream.read_u8()? != 0
1511         || stream.read_u8()? != 0
1512     {
1513         return Err(AvifError::BmffParseFailed(
1514             "Invalid reserved bits in SampleEntry of stsd".into(),
1515         ));
1516     }
1517     // unsigned int(16) data_reference_index;
1518     stream.skip(2)?;
1519 
1520     if sample_entry.format == "av01" {
1521         // https://aomediacodec.github.io/av1-isobmff/v1.2.0.html#av1sampleentry-syntax:
1522         //   class AV1SampleEntry extends VisualSampleEntry('av01'){
1523         //     AV1CodecConfigurationBox config;
1524         //   }
1525         // https://aomediacodec.github.io/av1-isobmff/v1.2.0.html#av1codecconfigurationbox-syntax:
1526         //   class AV1CodecConfigurationBox extends Box('av1C'){
1527         //     AV1CodecConfigurationRecord av1Config;
1528         //   }
1529 
1530         // Section 12.1.3.2 of ISO/IEC 14496-12:
1531         //   class VisualSampleEntry(codingname) extends SampleEntry(codingname)
1532 
1533         // unsigned int(16) pre_defined = 0; ("Readers should expect any value")
1534         stream.skip(2)?;
1535         // const unsigned int(16) reserved = 0;
1536         if stream.read_u16()? != 0 {
1537             return Err(AvifError::BmffParseFailed(
1538                 "Invalid reserved bits in VisualSampleEntry of stsd".into(),
1539             ));
1540         }
1541         // unsigned int(32) pre_defined[3] = 0;
1542         stream.skip(4 * 3)?;
1543         // unsigned int(16) width;
1544         stream.skip(2)?;
1545         // unsigned int(16) height;
1546         stream.skip(2)?;
1547         // template unsigned int(32) horizresolution = 0x00480000; // 72 dpi
1548         stream.skip_u32()?;
1549         // template unsigned int(32) vertresolution = 0x00480000; // 72 dpi
1550         stream.skip_u32()?;
1551         // const unsigned int(32) reserved = 0;
1552         if stream.read_u32()? != 0 {
1553             return Err(AvifError::BmffParseFailed(
1554                 "Invalid reserved bits in VisualSampleEntry of stsd".into(),
1555             ));
1556         }
1557         // template unsigned int(16) frame_count;
1558         stream.skip(2)?;
1559         // uint(8) compressorname[32];
1560         stream.skip(32)?;
1561         // template unsigned int(16) depth = 0x0018;
1562         if stream.read_u16()? != 0x0018 {
1563             return Err(AvifError::BmffParseFailed(
1564                 "Invalid depth in VisualSampleEntry of stsd".into(),
1565             ));
1566         }
1567         // unsigned int(16) pre_defined = 0; ("Readers should expect any value")
1568         stream.skip(2)?;
1569 
1570         // other boxes from derived specifications
1571         // CleanApertureBox clap; // optional
1572         // PixelAspectRatioBox pasp; // optional
1573 
1574         // Now read any of 'av1C', 'clap', 'pasp' etc.
1575         sample_entry.properties = parse_ipco(&mut stream.sub_stream(&BoxSize::UntilEndOfStream)?)?;
1576 
1577         if !sample_entry
1578             .properties
1579             .iter()
1580             .any(|p| matches!(p, ItemProperty::CodecConfiguration(_)))
1581         {
1582             return Err(AvifError::BmffParseFailed(
1583                 "AV1SampleEntry must contain an AV1CodecConfigurationRecord".into(),
1584             ));
1585         }
1586     }
1587     Ok(sample_entry)
1588 }
1589 
parse_stsd(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()>1590 fn parse_stsd(stream: &mut IStream, sample_table: &mut SampleTable) -> AvifResult<()> {
1591     // Section 8.5.2.2 of ISO/IEC 14496-12.
1592     let (version, _flags) = stream.read_version_and_flags()?;
1593     if version != 0 && version != 1 {
1594         // Section 8.5.2.3 of ISO/IEC 14496-12:
1595         //   version is set to zero. A version number of 1 shall be treated as a version of 0.
1596         return Err(AvifError::BmffParseFailed(
1597             "stsd box version 0 or 1 expected.".into(),
1598         ));
1599     }
1600     // unsigned int(32) entry_count;
1601     let entry_count = usize_from_u32(stream.read_u32()?)?;
1602     sample_table.sample_descriptions = create_vec_exact(entry_count)?;
1603     for _ in 0..entry_count {
1604         // aligned(8) abstract class SampleEntry (unsigned int(32) format) extends Box(format)
1605         let header = parse_header(stream, /*top_level=*/ false)?;
1606         let sample_entry =
1607             parse_sample_entry(&mut stream.sub_stream(&header.size)?, header.box_type)?;
1608         sample_table.sample_descriptions.push(sample_entry);
1609     }
1610     Ok(())
1611 }
1612 
parse_stbl(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1613 fn parse_stbl(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1614     // Section 8.5.1.2 of ISO/IEC 14496-12.
1615     if track.sample_table.is_some() {
1616         return Err(AvifError::BmffParseFailed(
1617             "duplicate stbl for track.".into(),
1618         ));
1619     }
1620     let mut sample_table = SampleTable::default();
1621     let mut boxes_seen: HashSet<String> = HashSet::with_hasher(NonRandomHasherState);
1622     while stream.has_bytes_left()? {
1623         let header = parse_header(stream, /*top_level=*/ false)?;
1624         if boxes_seen.contains(&header.box_type) {
1625             return Err(AvifError::BmffParseFailed(format!(
1626                 "duplicate box in stbl: {}",
1627                 header.box_type
1628             )));
1629         }
1630         let mut skipped_box = false;
1631         let mut sub_stream = stream.sub_stream(&header.size)?;
1632         match header.box_type.as_str() {
1633             "stco" => {
1634                 if boxes_seen.contains("co64") {
1635                     return Err(AvifError::BmffParseFailed(
1636                         "exactly one of co64 or stco is allowed in stbl".into(),
1637                     ));
1638                 }
1639                 parse_stco(&mut sub_stream, &mut sample_table, false)?;
1640             }
1641             "co64" => {
1642                 if boxes_seen.contains("stco") {
1643                     return Err(AvifError::BmffParseFailed(
1644                         "exactly one of co64 or stco is allowed in stbl".into(),
1645                     ));
1646                 }
1647                 parse_stco(&mut sub_stream, &mut sample_table, true)?;
1648             }
1649             "stsc" => parse_stsc(&mut sub_stream, &mut sample_table)?,
1650             "stsz" => parse_stsz(&mut sub_stream, &mut sample_table)?,
1651             "stss" => parse_stss(&mut sub_stream, &mut sample_table)?,
1652             "stts" => parse_stts(&mut sub_stream, &mut sample_table)?,
1653             "stsd" => parse_stsd(&mut sub_stream, &mut sample_table)?,
1654             _ => skipped_box = true,
1655         }
1656         // For boxes that are skipped, we do not need to validate if they occur exactly once or
1657         // not.
1658         if !skipped_box {
1659             boxes_seen.insert(header.box_type.clone());
1660         }
1661     }
1662     track.sample_table = Some(sample_table);
1663     Ok(())
1664 }
1665 
parse_minf(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1666 fn parse_minf(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1667     // Section 8.4.4.2 of ISO/IEC 14496-12.
1668     while stream.has_bytes_left()? {
1669         let header = parse_header(stream, /*top_level=*/ false)?;
1670         let mut sub_stream = stream.sub_stream(&header.size)?;
1671         if header.box_type == "stbl" {
1672             parse_stbl(&mut sub_stream, track)?;
1673         }
1674     }
1675     Ok(())
1676 }
1677 
parse_mdia(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1678 fn parse_mdia(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1679     // Section 8.4.1.2 of ISO/IEC 14496-12.
1680     while stream.has_bytes_left()? {
1681         let header = parse_header(stream, /*top_level=*/ false)?;
1682         let mut sub_stream = stream.sub_stream(&header.size)?;
1683         match header.box_type.as_str() {
1684             "mdhd" => parse_mdhd(&mut sub_stream, track)?,
1685             "minf" => parse_minf(&mut sub_stream, track)?,
1686             _ => {}
1687         }
1688     }
1689     Ok(())
1690 }
1691 
parse_tref(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1692 fn parse_tref(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1693     // Section 8.3.3.2 of ISO/IEC 14496-12.
1694 
1695     // TrackReferenceTypeBox [];
1696     while stream.has_bytes_left()? {
1697         // aligned(8) class TrackReferenceTypeBox (reference_type) extends Box(reference_type)
1698         let header = parse_header(stream, /*top_level=*/ false)?;
1699         let mut sub_stream = stream.sub_stream(&header.size)?;
1700         match header.box_type.as_str() {
1701             "auxl" => {
1702                 // unsigned int(32) track_IDs[];
1703                 // Use only the first one and skip the rest.
1704                 track.aux_for_id = Some(sub_stream.read_u32()?);
1705             }
1706             "prem" => {
1707                 // unsigned int(32) track_IDs[];
1708                 // Use only the first one and skip the rest.
1709                 track.prem_by_id = Some(sub_stream.read_u32()?);
1710             }
1711             _ => {}
1712         }
1713     }
1714     Ok(())
1715 }
1716 
parse_elst(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1717 fn parse_elst(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1718     if track.elst_seen {
1719         return Err(AvifError::BmffParseFailed(
1720             "more than one elst box was found for track".into(),
1721         ));
1722     }
1723     track.elst_seen = true;
1724 
1725     // Section 8.6.6.2 of ISO/IEC 14496-12.
1726     let (version, flags) = stream.read_version_and_flags()?;
1727 
1728     // Section 8.6.6.3 of ISO/IEC 14496-12:
1729     //   flags - the following values are defined. The values of flags greater than 1 are reserved
1730     //     RepeatEdits 1
1731     if (flags & 1) == 0 {
1732         // The only EditList feature that we support is repetition count for animated images. So in
1733         // this case, we know that the repetition count is zero and we do not care about the rest
1734         // of this box.
1735         track.is_repeating = false;
1736         return Ok(());
1737     }
1738     track.is_repeating = true;
1739 
1740     // unsigned int(32) entry_count;
1741     let entry_count = stream.read_u32()?;
1742     if entry_count != 1 {
1743         return Err(AvifError::BmffParseFailed(format!(
1744             "elst has entry_count ({entry_count}) != 1"
1745         )));
1746     }
1747 
1748     if version == 1 {
1749         // unsigned int(64) segment_duration;
1750         track.segment_duration = stream.read_u64()?;
1751         // int(64) media_time;
1752         stream.skip(8)?;
1753     } else if version == 0 {
1754         // unsigned int(32) segment_duration;
1755         track.segment_duration = stream.read_u32()? as u64;
1756         // int(32) media_time;
1757         stream.skip(4)?;
1758     } else {
1759         return Err(AvifError::BmffParseFailed(
1760             "unsupported version in elst".into(),
1761         ));
1762     }
1763     // int(16) media_rate_integer;
1764     stream.skip(2)?;
1765     // int(16) media_rate_fraction;
1766     stream.skip(2)?;
1767 
1768     if track.segment_duration == 0 {
1769         return Err(AvifError::BmffParseFailed(
1770             "invalid value for segment_duration (0)".into(),
1771         ));
1772     }
1773     Ok(())
1774 }
1775 
parse_edts(stream: &mut IStream, track: &mut Track) -> AvifResult<()>1776 fn parse_edts(stream: &mut IStream, track: &mut Track) -> AvifResult<()> {
1777     if track.elst_seen {
1778         // This function always exits with track.elst_seen set to true. So it is sufficient to
1779         // check track.elst_seen to verify the uniqueness of the edts box.
1780         return Err(AvifError::BmffParseFailed(
1781             "multiple edts boxes found for track.".into(),
1782         ));
1783     }
1784 
1785     // Section 8.6.5.2 of ISO/IEC 14496-12.
1786     while stream.has_bytes_left()? {
1787         let header = parse_header(stream, /*top_level=*/ false)?;
1788         let mut sub_stream = stream.sub_stream(&header.size)?;
1789         if header.box_type == "elst" {
1790             parse_elst(&mut sub_stream, track)?;
1791         }
1792     }
1793 
1794     if !track.elst_seen {
1795         return Err(AvifError::BmffParseFailed(
1796             "elst box was not found in edts".into(),
1797         ));
1798     }
1799     Ok(())
1800 }
1801 
parse_trak(stream: &mut IStream) -> AvifResult<Track>1802 fn parse_trak(stream: &mut IStream) -> AvifResult<Track> {
1803     let mut track = Track::default();
1804     let mut tkhd_seen = false;
1805     // Section 8.3.1.2 of ISO/IEC 14496-12.
1806     while stream.has_bytes_left()? {
1807         let header = parse_header(stream, /*top_level=*/ false)?;
1808         let mut sub_stream = stream.sub_stream(&header.size)?;
1809         match header.box_type.as_str() {
1810             "tkhd" => {
1811                 if tkhd_seen {
1812                     return Err(AvifError::BmffParseFailed(
1813                         "trak box contains multiple tkhd boxes".into(),
1814                     ));
1815                 }
1816                 parse_tkhd(&mut sub_stream, &mut track)?;
1817                 tkhd_seen = true;
1818             }
1819             "mdia" => parse_mdia(&mut sub_stream, &mut track)?,
1820             "tref" => parse_tref(&mut sub_stream, &mut track)?,
1821             "edts" => parse_edts(&mut sub_stream, &mut track)?,
1822             "meta" => track.meta = Some(parse_meta(&mut sub_stream)?),
1823             _ => {}
1824         }
1825     }
1826     if !tkhd_seen {
1827         return Err(AvifError::BmffParseFailed(
1828             "trak box did not contain a tkhd box".into(),
1829         ));
1830     }
1831     Ok(track)
1832 }
1833 
parse_moov(stream: &mut IStream) -> AvifResult<Vec<Track>>1834 fn parse_moov(stream: &mut IStream) -> AvifResult<Vec<Track>> {
1835     let mut tracks: Vec<Track> = Vec::new();
1836     // Section 8.2.1.2 of ISO/IEC 14496-12.
1837     while stream.has_bytes_left()? {
1838         let header = parse_header(stream, /*top_level=*/ false)?;
1839         let mut sub_stream = stream.sub_stream(&header.size)?;
1840         if header.box_type == "trak" {
1841             tracks.push(parse_trak(&mut sub_stream)?);
1842         }
1843     }
1844     if tracks.is_empty() {
1845         return Err(AvifError::BmffParseFailed(
1846             "moov box does not contain any tracks".into(),
1847         ));
1848     }
1849     Ok(tracks)
1850 }
1851 
parse(io: &mut GenericIO) -> AvifResult<AvifBoxes>1852 pub fn parse(io: &mut GenericIO) -> AvifResult<AvifBoxes> {
1853     let mut ftyp: Option<FileTypeBox> = None;
1854     let mut meta: Option<MetaBox> = None;
1855     let mut tracks: Option<Vec<Track>> = None;
1856     let mut parse_offset: u64 = 0;
1857     loop {
1858         // Read just enough to get the longest possible valid box header (4+4+8+16 bytes).
1859         let header_data = io.read(parse_offset, 32)?;
1860         if header_data.is_empty() {
1861             // No error and size is 0. We have reached the end of the stream.
1862             break;
1863         }
1864         let mut header_stream = IStream::create(header_data);
1865         let header = parse_header(&mut header_stream, /*top_level=*/ true)?;
1866         parse_offset = parse_offset
1867             .checked_add(header_stream.offset as u64)
1868             .ok_or(AvifError::BmffParseFailed("invalid parse offset".into()))?;
1869 
1870         // Read the rest of the box if necessary.
1871         match header.box_type.as_str() {
1872             "ftyp" | "meta" | "moov" => {
1873                 if ftyp.is_none() && header.box_type != "ftyp" {
1874                     // Section 6.3.4 of ISO/IEC 14496-12:
1875                     //   The FileTypeBox shall occur before any variable-length box. Only a
1876                     //   fixed-size box such as a file signature, if required, may precede it.
1877                     return Err(AvifError::BmffParseFailed(format!(
1878                         "expected ftyp box. found {}.",
1879                         header.box_type,
1880                     )));
1881                 }
1882                 let box_data = match header.size {
1883                     BoxSize::UntilEndOfStream => io.read(parse_offset, usize::MAX)?,
1884                     BoxSize::FixedSize(size) => io.read_exact(parse_offset, size)?,
1885                 };
1886                 let mut box_stream = IStream::create(box_data);
1887                 match header.box_type.as_str() {
1888                     "ftyp" => {
1889                         ftyp = Some(parse_ftyp(&mut box_stream)?);
1890                         if !ftyp.unwrap_ref().is_avif() {
1891                             return Err(AvifError::InvalidFtyp);
1892                         }
1893                     }
1894                     "meta" => meta = Some(parse_meta(&mut box_stream)?),
1895                     "moov" => tracks = Some(parse_moov(&mut box_stream)?),
1896                     _ => {} // Not reached.
1897                 }
1898                 if ftyp.is_some() {
1899                     let ftyp = ftyp.unwrap_ref();
1900                     if (!ftyp.needs_meta() || meta.is_some())
1901                         && (!ftyp.needs_moov() || tracks.is_some())
1902                     {
1903                         // Enough information has been parsed to consider parse a success.
1904                         break;
1905                     }
1906                 }
1907             }
1908             _ => {}
1909         }
1910         if header.size == BoxSize::UntilEndOfStream {
1911             // There is no other box after this one because it goes till the end of the stream.
1912             break;
1913         }
1914         parse_offset = parse_offset
1915             .checked_add(header.size() as u64)
1916             .ok_or(AvifError::BmffParseFailed("invalid parse offset".into()))?;
1917     }
1918     if ftyp.is_none() {
1919         return Err(AvifError::InvalidFtyp);
1920     }
1921     let ftyp = ftyp.unwrap();
1922     if (ftyp.needs_meta() && meta.is_none()) || (ftyp.needs_moov() && tracks.is_none()) {
1923         return Err(AvifError::TruncatedData);
1924     }
1925     Ok(AvifBoxes {
1926         ftyp,
1927         meta: meta.unwrap_or_default(),
1928         tracks: tracks.unwrap_or_default(),
1929     })
1930 }
1931 
peek_compatible_file_type(data: &[u8]) -> AvifResult<bool>1932 pub fn peek_compatible_file_type(data: &[u8]) -> AvifResult<bool> {
1933     let mut stream = IStream::create(data);
1934     let header = parse_header(&mut stream, /*top_level=*/ true)?;
1935     if header.box_type != "ftyp" {
1936         // Section 6.3.4 of ISO/IEC 14496-12:
1937         //   The FileTypeBox shall occur before any variable-length box.
1938         //   Only a fixed-size box such as a file signature, if required, may precede it.
1939         return Ok(false);
1940     }
1941     let header_size = match header.size {
1942         BoxSize::FixedSize(size) => size,
1943         // The 'ftyp' box goes on till the end of the file. Either there is no brand requiring
1944         // anything in the file but a FileTypebox (so not AVIF), or it is invalid.
1945         BoxSize::UntilEndOfStream => return Ok(false),
1946     };
1947     let ftyp = if header_size > stream.bytes_left()? {
1948         let mut header_stream = stream.sub_stream(&BoxSize::FixedSize(stream.bytes_left()?))?;
1949         parse_truncated_ftyp(&mut header_stream)
1950     } else {
1951         let mut header_stream = stream.sub_stream(&header.size)?;
1952         parse_ftyp(&mut header_stream)?
1953     };
1954     Ok(ftyp.is_avif())
1955 }
1956 
parse_tmap(stream: &mut IStream) -> AvifResult<Option<GainMapMetadata>>1957 pub fn parse_tmap(stream: &mut IStream) -> AvifResult<Option<GainMapMetadata>> {
1958     // Experimental, not yet specified.
1959 
1960     // unsigned int(8) version = 0;
1961     let version = stream.read_u8()?;
1962     if version != 0 {
1963         return Ok(None); // Unsupported version.
1964     }
1965     // unsigned int(16) minimum_version;
1966     let minimum_version = stream.read_u16()?;
1967     let supported_version = 0;
1968     if minimum_version > supported_version {
1969         return Ok(None); // Unsupported version.
1970     }
1971     // unsigned int(16) writer_version;
1972     let writer_version = stream.read_u16()?;
1973 
1974     let mut metadata = GainMapMetadata::default();
1975     let mut bits = stream.sub_bit_stream(1)?;
1976     // unsigned int(1) is_multichannel;
1977     let is_multichannel = bits.read_bool()?;
1978     let channel_count = if is_multichannel { 3 } else { 1 };
1979     // unsigned int(1) use_base_colour_space;
1980     metadata.use_base_color_space = bits.read_bool()?;
1981     // unsigned int(6) reserved;
1982     bits.skip(6)?;
1983 
1984     // unsigned int(32) base_hdr_headroom_numerator;
1985     // unsigned int(32) base_hdr_headroom_denominator;
1986     metadata.base_hdr_headroom = stream.read_ufraction()?;
1987     // unsigned int(32) alternate_hdr_headroom_numerator;
1988     // unsigned int(32) alternate_hdr_headroom_denominator;
1989     metadata.alternate_hdr_headroom = stream.read_ufraction()?;
1990     for i in 0..channel_count {
1991         // int(32) gain_map_min_numerator;
1992         // unsigned int(32) gain_map_min_denominator
1993         metadata.min[i] = stream.read_fraction()?;
1994         // int(32) gain_map_max_numerator;
1995         // unsigned int(32) gain_map_max_denominator;
1996         metadata.max[i] = stream.read_fraction()?;
1997         // unsigned int(32) gamma_numerator;
1998         // unsigned int(32) gamma_denominator;
1999         metadata.gamma[i] = stream.read_ufraction()?;
2000         // int(32) base_offset_numerator;
2001         // unsigned int(32) base_offset_denominator;
2002         metadata.base_offset[i] = stream.read_fraction()?;
2003         // int(32) alternate_offset_numerator;
2004         // unsigned int(32) alternate_offset_denominator;
2005         metadata.alternate_offset[i] = stream.read_fraction()?;
2006     }
2007 
2008     // Fill the remaining values by copying those from the first channel.
2009     for i in channel_count..3 {
2010         metadata.min[i] = metadata.min[0];
2011         metadata.max[i] = metadata.max[0];
2012         metadata.gamma[i] = metadata.gamma[0];
2013         metadata.base_offset[i] = metadata.base_offset[0];
2014         metadata.alternate_offset[i] = metadata.alternate_offset[0];
2015     }
2016     if writer_version <= supported_version && stream.has_bytes_left()? {
2017         return Err(AvifError::InvalidToneMappedImage(
2018             "invalid trailing bytes in tmap box".into(),
2019         ));
2020     }
2021     Ok(Some(metadata))
2022 }
2023 
2024 #[cfg(test)]
2025 mod tests {
2026     use crate::parser::mp4box;
2027     use crate::AvifResult;
2028 
2029     #[test]
peek_compatible_file_type() -> AvifResult<()>2030     fn peek_compatible_file_type() -> AvifResult<()> {
2031         let buf = [
2032             0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, //
2033             0x61, 0x76, 0x69, 0x66, 0x00, 0x00, 0x00, 0x00, //
2034             0x61, 0x76, 0x69, 0x66, 0x6d, 0x69, 0x66, 0x31, //
2035             0x6d, 0x69, 0x61, 0x66, 0x4d, 0x41, 0x31, 0x41, //
2036             0x00, 0x00, 0x00, 0xf2, 0x6d, 0x65, 0x74, 0x61, //
2037             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, //
2038         ];
2039         // Peeking should succeed starting from byte length 12. Since that is the end offset of the
2040         // first valid AVIF brand.
2041         let min_required_bytes = 12;
2042         for i in 0..buf.len() {
2043             let res = mp4box::peek_compatible_file_type(&buf[..i]);
2044             if i < min_required_bytes {
2045                 // Not enough bytes. The return should either be an error or false.
2046                 assert!(res.is_err() || !res.unwrap());
2047             } else {
2048                 assert!(res?);
2049             }
2050         }
2051         Ok(())
2052     }
2053 }
2054