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