1 //! Module for parsing ISO Base Media Format aka video/mp4 streams.
2 
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 #[macro_use]
8 extern crate log;
9 
10 extern crate bitreader;
11 extern crate byteorder;
12 extern crate num_traits;
13 use bitreader::{BitReader, ReadInto};
14 use byteorder::{ReadBytesExt, WriteBytesExt};
15 use fallible::TryRead as _;
16 use num_traits::Num;
17 use std::convert::{TryFrom, TryInto as _};
18 use std::io::Cursor;
19 use std::io::{Read, Take};
20 use std::ops::{Range, RangeFrom};
21 
22 #[macro_use]
23 mod macros;
24 
25 mod boxes;
26 use boxes::{BoxType, FourCC};
27 
28 mod fallible;
29 
30 #[cfg(feature = "craw")]
31 mod craw;
32 
33 // Unit tests.
34 #[cfg(test)]
35 mod tests;
36 
37 // Arbitrary buffer size limit used for raw read_bufs on a box.
38 const BUF_SIZE_LIMIT: u64 = 10 * 1024 * 1024;
39 
40 // Max table length. Calculating in worst case for one week long video, one
41 // frame per table entry in 30 fps.
42 const TABLE_SIZE_LIMIT: u32 = 30 * 60 * 60 * 24 * 7;
43 
44 /// A trait to indicate a type can be infallibly converted to `u64`.
45 /// This should only be implemented for infallible conversions, so only unsigned types are valid.
46 trait ToU64 {
to_u64(self) -> u6447     fn to_u64(self) -> u64;
48 }
49 
50 /// Statically verify that the platform `usize` can fit within a `u64`.
51 /// If the size won't fit on the given platform, this will fail at compile time, but if a type
52 /// which can fail TryInto<usize> is used, it may panic.
53 impl ToU64 for usize {
to_u64(self) -> u6454     fn to_u64(self) -> u64 {
55         static_assertions::const_assert!(
56             std::mem::size_of::<usize>() <= std::mem::size_of::<u64>()
57         );
58         self.try_into().expect("usize -> u64 conversion failed")
59     }
60 }
61 
62 /// A trait to indicate a type can be infallibly converted to `usize`.
63 /// This should only be implemented for infallible conversions, so only unsigned types are valid.
64 trait ToUsize {
to_usize(self) -> usize65     fn to_usize(self) -> usize;
66 }
67 
68 /// Statically verify that the given type can fit within a `usize`.
69 /// If the size won't fit on the given platform, this will fail at compile time, but if a type
70 /// which can fail TryInto<usize> is used, it may panic.
71 macro_rules! impl_to_usize_from {
72     ( $from_type:ty ) => {
73         impl ToUsize for $from_type {
74             fn to_usize(self) -> usize {
75                 static_assertions::const_assert!(
76                     std::mem::size_of::<$from_type>() <= std::mem::size_of::<usize>()
77                 );
78                 self.try_into().expect(concat!(
79                     stringify!($from_type),
80                     " -> usize conversion failed"
81                 ))
82             }
83         }
84     };
85 }
86 
87 impl_to_usize_from!(u8);
88 impl_to_usize_from!(u16);
89 impl_to_usize_from!(u32);
90 
91 /// Indicate the current offset (i.e., bytes already read) in a reader
92 pub trait Offset {
offset(&self) -> u6493     fn offset(&self) -> u64;
94 }
95 
96 /// Wraps a reader to track the current offset
97 struct OffsetReader<'a, T: 'a> {
98     reader: &'a mut T,
99     offset: u64,
100 }
101 
102 impl<'a, T> OffsetReader<'a, T> {
new(reader: &'a mut T) -> Self103     fn new(reader: &'a mut T) -> Self {
104         Self { reader, offset: 0 }
105     }
106 }
107 
108 impl<'a, T> Offset for OffsetReader<'a, T> {
offset(&self) -> u64109     fn offset(&self) -> u64 {
110         self.offset
111     }
112 }
113 
114 impl<'a, T: Read> Read for OffsetReader<'a, T> {
read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>115     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
116         let bytes_read = self.reader.read(buf)?;
117         self.offset = self
118             .offset
119             .checked_add(bytes_read.to_u64())
120             .expect("total bytes read too large for offset type");
121         Ok(bytes_read)
122     }
123 }
124 
125 // TODO: all the functions that rely on the mp4parse_fallible feature need to
126 // be updated when Rust supports fallible memory allocation in raw_vec.
127 // See https://github.com/mozilla/mp4parse-rust/issues/146
128 
129 pub type TryVec<T> = fallible::TryVec<T>;
130 pub type TryString = TryVec<u8>;
131 pub type TryHashMap<K, V> = fallible::TryHashMap<K, V>;
132 pub type TryBox<T> = fallible::TryBox<T>;
133 
134 // To ensure we don't use stdlib allocating types by accident
135 #[allow(dead_code)]
136 struct Vec;
137 #[allow(dead_code)]
138 struct Box;
139 #[allow(dead_code)]
140 struct HashMap;
141 #[allow(dead_code)]
142 struct String;
143 
144 /// Describes parser failures.
145 ///
146 /// This enum wraps the standard `io::Error` type, unified with
147 /// our own parser error states and those of crates we use.
148 #[derive(Debug)]
149 pub enum Error {
150     /// Parse error caused by corrupt or malformed data.
151     InvalidData(&'static str),
152     /// Parse error caused by limited parser support rather than invalid data.
153     Unsupported(&'static str),
154     /// Reflect `std::io::ErrorKind::UnexpectedEof` for short data.
155     UnexpectedEOF,
156     /// Propagate underlying errors from `std::io`.
157     Io(std::io::Error),
158     /// read_mp4 terminated without detecting a moov box.
159     NoMoov,
160     /// Out of memory
161     OutOfMemory,
162 }
163 
164 impl std::fmt::Display for Error {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result165     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166         write!(f, "{:?}", self)
167     }
168 }
169 
170 impl std::error::Error for Error {}
171 
172 impl From<bitreader::BitReaderError> for Error {
from(_: bitreader::BitReaderError) -> Error173     fn from(_: bitreader::BitReaderError) -> Error {
174         Error::InvalidData("invalid data")
175     }
176 }
177 
178 impl From<std::io::Error> for Error {
from(err: std::io::Error) -> Error179     fn from(err: std::io::Error) -> Error {
180         match err.kind() {
181             std::io::ErrorKind::UnexpectedEof => Error::UnexpectedEOF,
182             _ => Error::Io(err),
183         }
184     }
185 }
186 
187 impl From<std::string::FromUtf8Error> for Error {
from(_: std::string::FromUtf8Error) -> Error188     fn from(_: std::string::FromUtf8Error) -> Error {
189         Error::InvalidData("invalid utf8")
190     }
191 }
192 
193 impl From<std::num::TryFromIntError> for Error {
from(_: std::num::TryFromIntError) -> Error194     fn from(_: std::num::TryFromIntError) -> Error {
195         Error::Unsupported("integer conversion failed")
196     }
197 }
198 
199 impl From<Error> for std::io::Error {
from(err: Error) -> Self200     fn from(err: Error) -> Self {
201         let kind = match err {
202             Error::InvalidData(_) => std::io::ErrorKind::InvalidData,
203             Error::UnexpectedEOF => std::io::ErrorKind::UnexpectedEof,
204             Error::Io(io_err) => return io_err,
205             _ => std::io::ErrorKind::Other,
206         };
207         Self::new(kind, err)
208     }
209 }
210 
211 /// Result shorthand using our Error enum.
212 pub type Result<T> = std::result::Result<T, Error>;
213 
214 /// Basic ISO box structure.
215 ///
216 /// mp4 files are a sequence of possibly-nested 'box' structures.  Each box
217 /// begins with a header describing the length of the box's data and a
218 /// four-byte box type which identifies the type of the box. Together these
219 /// are enough to interpret the contents of that section of the file.
220 #[derive(Debug, Clone, Copy)]
221 struct BoxHeader {
222     /// Box type.
223     name: BoxType,
224     /// Size of the box in bytes.
225     size: u64,
226     /// Offset to the start of the contained data (or header size).
227     offset: u64,
228     /// Uuid for extended type.
229     uuid: Option<[u8; 16]>,
230 }
231 
232 /// File type box 'ftyp'.
233 #[derive(Debug)]
234 struct FileTypeBox {
235     major_brand: FourCC,
236     minor_version: u32,
237     compatible_brands: TryVec<FourCC>,
238 }
239 
240 /// Movie header box 'mvhd'.
241 #[derive(Debug)]
242 struct MovieHeaderBox {
243     pub timescale: u32,
244     duration: u64,
245 }
246 
247 #[derive(Debug, Clone, Copy)]
248 pub struct Matrix {
249     pub a: i32, // 16.16 fix point
250     pub b: i32, // 16.16 fix point
251     pub u: i32, // 2.30 fix point
252     pub c: i32, // 16.16 fix point
253     pub d: i32, // 16.16 fix point
254     pub v: i32, // 2.30 fix point
255     pub x: i32, // 16.16 fix point
256     pub y: i32, // 16.16 fix point
257     pub w: i32, // 2.30 fix point
258 }
259 
260 /// Track header box 'tkhd'
261 #[derive(Debug, Clone)]
262 pub struct TrackHeaderBox {
263     track_id: u32,
264     pub disabled: bool,
265     pub duration: u64,
266     pub width: u32,
267     pub height: u32,
268     pub matrix: Matrix,
269 }
270 
271 /// Edit list box 'elst'
272 #[derive(Debug)]
273 struct EditListBox {
274     edits: TryVec<Edit>,
275 }
276 
277 #[derive(Debug)]
278 struct Edit {
279     segment_duration: u64,
280     media_time: i64,
281     media_rate_integer: i16,
282     media_rate_fraction: i16,
283 }
284 
285 /// Media header box 'mdhd'
286 #[derive(Debug)]
287 struct MediaHeaderBox {
288     timescale: u32,
289     duration: u64,
290 }
291 
292 // Chunk offset box 'stco' or 'co64'
293 #[derive(Debug)]
294 pub struct ChunkOffsetBox {
295     pub offsets: TryVec<u64>,
296 }
297 
298 // Sync sample box 'stss'
299 #[derive(Debug)]
300 pub struct SyncSampleBox {
301     pub samples: TryVec<u32>,
302 }
303 
304 // Sample to chunk box 'stsc'
305 #[derive(Debug)]
306 pub struct SampleToChunkBox {
307     pub samples: TryVec<SampleToChunk>,
308 }
309 
310 #[derive(Debug)]
311 pub struct SampleToChunk {
312     pub first_chunk: u32,
313     pub samples_per_chunk: u32,
314     pub sample_description_index: u32,
315 }
316 
317 // Sample size box 'stsz'
318 #[derive(Debug)]
319 pub struct SampleSizeBox {
320     pub sample_size: u32,
321     pub sample_sizes: TryVec<u32>,
322 }
323 
324 // Time to sample box 'stts'
325 #[derive(Debug)]
326 pub struct TimeToSampleBox {
327     pub samples: TryVec<Sample>,
328 }
329 
330 #[repr(C)]
331 #[derive(Debug)]
332 pub struct Sample {
333     pub sample_count: u32,
334     pub sample_delta: u32,
335 }
336 
337 #[derive(Debug, Clone, Copy)]
338 pub enum TimeOffsetVersion {
339     Version0(u32),
340     Version1(i32),
341 }
342 
343 #[derive(Debug, Clone)]
344 pub struct TimeOffset {
345     pub sample_count: u32,
346     pub time_offset: TimeOffsetVersion,
347 }
348 
349 #[derive(Debug)]
350 pub struct CompositionOffsetBox {
351     pub samples: TryVec<TimeOffset>,
352 }
353 
354 // Handler reference box 'hdlr'
355 #[derive(Debug)]
356 struct HandlerBox {
357     handler_type: FourCC,
358 }
359 
360 // Sample description box 'stsd'
361 #[derive(Debug)]
362 pub struct SampleDescriptionBox {
363     pub descriptions: TryVec<SampleEntry>,
364 }
365 
366 #[derive(Debug)]
367 pub enum SampleEntry {
368     Audio(AudioSampleEntry),
369     Video(VideoSampleEntry),
370     #[cfg(feature = "craw")]
371     CanonCRAW(craw::CanonCRAWEntry),
372     Unknown,
373 }
374 
375 #[allow(non_camel_case_types)]
376 #[derive(Debug, Default)]
377 pub struct ES_Descriptor {
378     pub audio_codec: CodecType,
379     pub audio_object_type: Option<u16>,
380     pub extended_audio_object_type: Option<u16>,
381     pub audio_sample_rate: Option<u32>,
382     pub audio_channel_count: Option<u16>,
383     pub codec_esds: TryVec<u8>,
384     pub decoder_specific_data: TryVec<u8>, // Data in DECODER_SPECIFIC_TAG
385 }
386 
387 #[allow(non_camel_case_types)]
388 #[derive(Debug)]
389 pub enum AudioCodecSpecific {
390     ES_Descriptor(ES_Descriptor),
391     FLACSpecificBox(FLACSpecificBox),
392     OpusSpecificBox(OpusSpecificBox),
393     ALACSpecificBox(ALACSpecificBox),
394     MP3,
395     LPCM,
396 }
397 
398 #[derive(Debug)]
399 pub struct AudioSampleEntry {
400     pub codec_type: CodecType,
401     data_reference_index: u16,
402     pub channelcount: u32,
403     pub samplesize: u16,
404     pub samplerate: f64,
405     pub codec_specific: AudioCodecSpecific,
406     pub protection_info: TryVec<ProtectionSchemeInfoBox>,
407 }
408 
409 #[derive(Debug)]
410 pub enum VideoCodecSpecific {
411     AVCConfig(TryVec<u8>),
412     VPxConfig(VPxConfigBox),
413     AV1Config(AV1ConfigBox),
414     ESDSConfig(TryVec<u8>),
415 }
416 
417 #[derive(Debug)]
418 pub struct VideoSampleEntry {
419     pub codec_type: CodecType,
420     data_reference_index: u16,
421     pub width: u16,
422     pub height: u16,
423     pub codec_specific: VideoCodecSpecific,
424     pub protection_info: TryVec<ProtectionSchemeInfoBox>,
425 }
426 
427 /// Represent a Video Partition Codec Configuration 'vpcC' box (aka vp9). The meaning of each
428 /// field is covered in detail in "VP Codec ISO Media File Format Binding".
429 #[derive(Debug)]
430 pub struct VPxConfigBox {
431     /// An integer that specifies the VP codec profile.
432     profile: u8,
433     /// An integer that specifies a VP codec level all samples conform to the following table.
434     /// For a description of the various levels, please refer to the VP9 Bitstream Specification.
435     level: u8,
436     /// An integer that specifies the bit depth of the luma and color components. Valid values
437     /// are 8, 10, and 12.
438     pub bit_depth: u8,
439     /// Really an enum defined by the "Colour primaries" section of ISO/IEC 23001-8:2016.
440     pub colour_primaries: u8,
441     /// Really an enum defined by "VP Codec ISO Media File Format Binding".
442     pub chroma_subsampling: u8,
443     /// Really an enum defined by the "Transfer characteristics" section of ISO/IEC 23001-8:2016.
444     transfer_characteristics: u8,
445     /// Really an enum defined by the "Matrix coefficients" section of ISO/IEC 23001-8:2016.
446     /// Available in 'VP Codec ISO Media File Format' version 1 only.
447     matrix_coefficients: Option<u8>,
448     /// Indicates the black level and range of the luma and chroma signals. 0 = legal range
449     /// (e.g. 16-235 for 8 bit sample depth); 1 = full range (e.g. 0-255 for 8-bit sample depth).
450     video_full_range_flag: bool,
451     /// This is not used for VP8 and VP9 . Intended for binary codec initialization data.
452     pub codec_init: TryVec<u8>,
453 }
454 
455 #[derive(Debug)]
456 pub struct AV1ConfigBox {
457     pub profile: u8,
458     pub level: u8,
459     pub tier: u8,
460     pub bit_depth: u8,
461     pub monochrome: bool,
462     pub chroma_subsampling_x: u8,
463     pub chroma_subsampling_y: u8,
464     pub chroma_sample_position: u8,
465     pub initial_presentation_delay_present: bool,
466     pub initial_presentation_delay_minus_one: u8,
467     pub config_obus: TryVec<u8>,
468 }
469 
470 #[derive(Debug)]
471 pub struct FLACMetadataBlock {
472     pub block_type: u8,
473     pub data: TryVec<u8>,
474 }
475 
476 /// Represents a FLACSpecificBox 'dfLa'
477 #[derive(Debug)]
478 pub struct FLACSpecificBox {
479     version: u8,
480     pub blocks: TryVec<FLACMetadataBlock>,
481 }
482 
483 #[derive(Debug)]
484 struct ChannelMappingTable {
485     stream_count: u8,
486     coupled_count: u8,
487     channel_mapping: TryVec<u8>,
488 }
489 
490 /// Represent an OpusSpecificBox 'dOps'
491 #[derive(Debug)]
492 pub struct OpusSpecificBox {
493     pub version: u8,
494     output_channel_count: u8,
495     pre_skip: u16,
496     input_sample_rate: u32,
497     output_gain: i16,
498     channel_mapping_family: u8,
499     channel_mapping_table: Option<ChannelMappingTable>,
500 }
501 
502 /// Represent an ALACSpecificBox 'alac'
503 #[derive(Debug)]
504 pub struct ALACSpecificBox {
505     version: u8,
506     pub data: TryVec<u8>,
507 }
508 
509 #[derive(Debug)]
510 pub struct MovieExtendsBox {
511     pub fragment_duration: Option<MediaScaledTime>,
512 }
513 
514 pub type ByteData = TryVec<u8>;
515 
516 #[derive(Debug, Default)]
517 pub struct ProtectionSystemSpecificHeaderBox {
518     pub system_id: ByteData,
519     pub kid: TryVec<ByteData>,
520     pub data: ByteData,
521 
522     // The entire pssh box (include header) required by Gecko.
523     pub box_content: ByteData,
524 }
525 
526 #[derive(Debug, Default, Clone)]
527 pub struct SchemeTypeBox {
528     pub scheme_type: FourCC,
529     pub scheme_version: u32,
530 }
531 
532 #[derive(Debug, Default)]
533 pub struct TrackEncryptionBox {
534     pub is_encrypted: u8,
535     pub iv_size: u8,
536     pub kid: TryVec<u8>,
537     // Members for pattern encryption schemes
538     pub crypt_byte_block_count: Option<u8>,
539     pub skip_byte_block_count: Option<u8>,
540     pub constant_iv: Option<TryVec<u8>>,
541     // End pattern encryption scheme members
542 }
543 
544 #[derive(Debug, Default)]
545 pub struct ProtectionSchemeInfoBox {
546     pub code_name: TryString,
547     pub scheme_type: Option<SchemeTypeBox>,
548     pub tenc: Option<TrackEncryptionBox>,
549 }
550 
551 /// Represents a userdata box 'udta'.
552 /// Currently, only the metadata atom 'meta'
553 /// is parsed.
554 #[derive(Debug, Default)]
555 pub struct UserdataBox {
556     pub meta: Option<MetadataBox>,
557 }
558 
559 /// Represents possible contents of the
560 /// ©gen or gnre atoms within a metadata box.
561 /// 'udta.meta.ilst' may only have either a
562 /// standard genre box 'gnre' or a custom
563 /// genre box '©gen', but never both at once.
564 #[derive(Debug, PartialEq)]
565 pub enum Genre {
566     /// A standard ID3v1 numbered genre.
567     StandardGenre(u8),
568     /// Any custom genre string.
569     CustomGenre(TryString),
570 }
571 
572 /// Represents the contents of a 'stik'
573 /// atom that indicates content types within
574 /// iTunes.
575 #[derive(Debug, Clone, Eq, PartialEq)]
576 pub enum MediaType {
577     /// Movie is stored as 0 in a 'stik' atom.
578     Movie, // 0
579     /// Normal is stored as 1 in a 'stik' atom.
580     Normal, // 1
581     /// AudioBook is stored as 2 in a 'stik' atom.
582     AudioBook, // 2
583     /// WhackedBookmark is stored as 5 in a 'stik' atom.
584     WhackedBookmark, // 5
585     /// MusicVideo is stored as 6 in a 'stik' atom.
586     MusicVideo, // 6
587     /// ShortFilm is stored as 9 in a 'stik' atom.
588     ShortFilm, // 9
589     /// TVShow is stored as 10 in a 'stik' atom.
590     TVShow, // 10
591     /// Booklet is stored as 11 in a 'stik' atom.
592     Booklet, // 11
593     /// An unknown 'stik' value.
594     Unknown(u8),
595 }
596 
597 /// Represents the parental advisory rating on the track,
598 /// stored within the 'rtng' atom.
599 #[derive(Debug, Clone, Eq, PartialEq)]
600 pub enum AdvisoryRating {
601     /// Clean is always stored as 2 in an 'rtng' atom.
602     Clean, // 2
603     /// A value of 0 in an 'rtng' atom indicates 'Inoffensive'
604     Inoffensive, // 0
605     /// Any non 2 or 0 value in 'rtng' indicates the track is explicit.
606     Explicit(u8),
607 }
608 
609 /// Represents the contents of 'ilst' atoms within
610 /// a metadata box 'meta', parsed as iTunes metadata using
611 /// the conventional tags.
612 #[derive(Debug, Default)]
613 pub struct MetadataBox {
614     /// The album name, '©alb'
615     pub album: Option<TryString>,
616     /// The artist name '©art' or '©ART'
617     pub artist: Option<TryString>,
618     /// The album artist 'aART'
619     pub album_artist: Option<TryString>,
620     /// Track comments '©cmt'
621     pub comment: Option<TryString>,
622     /// The date or year field '©day'
623     ///
624     /// This is stored as an arbitrary string,
625     /// and may not necessarily be in a valid date
626     /// format.
627     pub year: Option<TryString>,
628     /// The track title '©nam'
629     pub title: Option<TryString>,
630     /// The track genre '©gen' or 'gnre'.
631     pub genre: Option<Genre>,
632     /// The track number 'trkn'.
633     pub track_number: Option<u8>,
634     /// The disc number 'disk'
635     pub disc_number: Option<u8>,
636     /// The total number of tracks on the disc,
637     /// stored in 'trkn'
638     pub total_tracks: Option<u8>,
639     /// The total number of discs in the album,
640     /// stored in 'disk'
641     pub total_discs: Option<u8>,
642     /// The composer of the track '©wrt'
643     pub composer: Option<TryString>,
644     /// The encoder used to create this track '©too'
645     pub encoder: Option<TryString>,
646     /// The encoded-by settingo this track '©enc'
647     pub encoded_by: Option<TryString>,
648     /// The tempo or BPM of the track 'tmpo'
649     pub beats_per_minute: Option<u8>,
650     /// Copyright information of the track 'cprt'
651     pub copyright: Option<TryString>,
652     /// Whether or not this track is part of a compilation 'cpil'
653     pub compilation: Option<bool>,
654     /// The advisory rating of this track 'rtng'
655     pub advisory: Option<AdvisoryRating>,
656     /// The personal rating of this track, 'rate'.
657     ///
658     /// This is stored in the box as string data, but
659     /// the format is an integer percentage from 0 - 100,
660     /// where 100 is displayed as 5 stars out of 5.
661     pub rating: Option<TryString>,
662     /// The grouping this track belongs to '©grp'
663     pub grouping: Option<TryString>,
664     /// The media type of this track 'stik'
665     pub media_type: Option<MediaType>, // stik
666     /// Whether or not this track is a podcast 'pcst'
667     pub podcast: Option<bool>,
668     /// The category of ths track 'catg'
669     pub category: Option<TryString>,
670     /// The podcast keyword 'keyw'
671     pub keyword: Option<TryString>,
672     /// The podcast url 'purl'
673     pub podcast_url: Option<TryString>,
674     /// The podcast episode GUID 'egid'
675     pub podcast_guid: Option<TryString>,
676     /// The description of the track 'desc'
677     pub description: Option<TryString>,
678     /// The long description of the track 'ldes'.
679     ///
680     /// Unlike other string fields, the long description field
681     /// can be longer than 256 characters.
682     pub long_description: Option<TryString>,
683     /// The lyrics of the track '©lyr'.
684     ///
685     /// Unlike other string fields, the lyrics field
686     /// can be longer than 256 characters.
687     pub lyrics: Option<TryString>,
688     /// The name of the TV network this track aired on 'tvnn'.
689     pub tv_network_name: Option<TryString>,
690     /// The name of the TV Show for this track 'tvsh'.
691     pub tv_show_name: Option<TryString>,
692     /// The name of the TV Episode for this track 'tven'.
693     pub tv_episode_name: Option<TryString>,
694     /// The number of the TV Episode for this track 'tves'.
695     pub tv_episode_number: Option<u8>,
696     /// The season of the TV Episode of this track 'tvsn'.
697     pub tv_season: Option<u8>,
698     /// The date this track was purchased 'purd'.
699     pub purchase_date: Option<TryString>,
700     /// Whether or not this track supports gapless playback 'pgap'
701     pub gapless_playback: Option<bool>,
702     /// Any cover artwork attached to this track 'covr'
703     ///
704     /// 'covr' is unique in that it may contain multiple 'data' sub-entries,
705     /// each an image file. Here, each subentry's raw binary data is exposed,
706     /// which may contain image data in JPEG or PNG format.
707     pub cover_art: Option<TryVec<TryVec<u8>>>,
708     /// The owner of the track 'ownr'
709     pub owner: Option<TryString>,
710     /// Whether or not this track is HD Video 'hdvd'
711     pub hd_video: Option<bool>,
712     /// The name of the track to sort by 'sonm'
713     pub sort_name: Option<TryString>,
714     /// The name of the album to sort by 'soal'
715     pub sort_album: Option<TryString>,
716     /// The name of the artist to sort by 'soar'
717     pub sort_artist: Option<TryString>,
718     /// The name of the album artist to sort by 'soaa'
719     pub sort_album_artist: Option<TryString>,
720     /// The name of the composer to sort by 'soco'
721     pub sort_composer: Option<TryString>,
722 }
723 
724 /// Internal data structures.
725 #[derive(Debug, Default)]
726 pub struct MediaContext {
727     pub brand: FourCC,
728     pub timescale: Option<MediaTimeScale>,
729     /// Tracks found in the file.
730     pub tracks: TryVec<Track>,
731     pub mvex: Option<MovieExtendsBox>,
732     pub psshs: TryVec<ProtectionSystemSpecificHeaderBox>,
733     pub userdata: Option<Result<UserdataBox>>,
734 
735     #[cfg(feature = "craw")]
736     pub craw: Option<craw::CrawHeader>,
737 }
738 
739 impl MediaContext {
new() -> MediaContext740     pub fn new() -> MediaContext {
741         Default::default()
742     }
743 }
744 
745 #[derive(Debug, Default)]
746 pub struct AvifContext {
747     /// The collected data indicated by the `pitm` box, See ISO 14496-12:2015 § 8.11.4
748     pub primary_item: TryVec<u8>,
749 }
750 
751 impl AvifContext {
new() -> Self752     pub fn new() -> Self {
753         Default::default()
754     }
755 }
756 
757 /// A Media Data Box
758 /// See ISO 14496-12:2015 § 8.1.1
759 struct MediaDataBox {
760     /// Offset of `data` from the beginning of the file. See ConstructionMethod::File
761     offset: u64,
762     data: TryVec<u8>,
763 }
764 
765 impl MediaDataBox {
766     /// Check whether the beginning of `extent` is within the bounds of the `MediaDataBox`.
767     /// We assume extents to not cross box boundaries. If so, this will cause an error
768     /// in `read_extent`.
contains_extent(&self, extent: &ExtentRange) -> bool769     fn contains_extent(&self, extent: &ExtentRange) -> bool {
770         if self.offset <= extent.start() {
771             let start_offset = extent.start() - self.offset;
772             start_offset < self.data.len().to_u64()
773         } else {
774             false
775         }
776     }
777 
778     /// Check whether `extent` covers the `MediaDataBox` exactly.
matches_extent(&self, extent: &ExtentRange) -> bool779     fn matches_extent(&self, extent: &ExtentRange) -> bool {
780         if self.offset == extent.start() {
781             match extent {
782                 ExtentRange::WithLength(range) => {
783                     if let Some(end) = self.offset.checked_add(self.data.len().to_u64()) {
784                         end == range.end
785                     } else {
786                         false
787                     }
788                 }
789                 ExtentRange::ToEnd(_) => true,
790             }
791         } else {
792             false
793         }
794     }
795 
796     /// Copy the range specified by `extent` to the end of `buf` or return an error if the range
797     /// is not fully contained within `MediaDataBox`.
read_extent(&mut self, extent: &ExtentRange, buf: &mut TryVec<u8>) -> Result<()>798     fn read_extent(&mut self, extent: &ExtentRange, buf: &mut TryVec<u8>) -> Result<()> {
799         let start_offset = extent
800             .start()
801             .checked_sub(self.offset)
802             .expect("mdat does not contain extent");
803         let slice = match extent {
804             ExtentRange::WithLength(range) => {
805                 let range_len = range
806                     .end
807                     .checked_sub(range.start)
808                     .expect("range start > end");
809                 let end = start_offset
810                     .checked_add(range_len)
811                     .expect("extent end overflow");
812                 self.data.get(start_offset.try_into()?..end.try_into()?)
813             }
814             ExtentRange::ToEnd(_) => self.data.get(start_offset.try_into()?..),
815         };
816         let slice = slice.ok_or(Error::InvalidData("extent crosses box boundary"))?;
817         buf.extend_from_slice(slice)?;
818         Ok(())
819     }
820 }
821 
822 /// Used for 'infe' boxes within 'iinf' boxes
823 /// See ISO 14496-12:2015 § 8.11.6
824 /// Only versions {2, 3} are supported
825 #[derive(Debug)]
826 struct ItemInfoEntry {
827     item_id: u32,
828     item_type: u32,
829 }
830 
831 /// Potential sizes (in bytes) of variable-sized fields of the 'iloc' box
832 /// See ISO 14496-12:2015 § 8.11.3
833 enum IlocFieldSize {
834     Zero,
835     Four,
836     Eight,
837 }
838 
839 impl IlocFieldSize {
to_bits(&self) -> u8840     fn to_bits(&self) -> u8 {
841         match self {
842             IlocFieldSize::Zero => 0,
843             IlocFieldSize::Four => 32,
844             IlocFieldSize::Eight => 64,
845         }
846     }
847 }
848 
849 impl TryFrom<u8> for IlocFieldSize {
850     type Error = Error;
851 
try_from(value: u8) -> Result<Self>852     fn try_from(value: u8) -> Result<Self> {
853         match value {
854             0 => Ok(Self::Zero),
855             4 => Ok(Self::Four),
856             8 => Ok(Self::Eight),
857             _ => Err(Error::InvalidData("value must be in the set {0, 4, 8}")),
858         }
859     }
860 }
861 
862 #[derive(PartialEq)]
863 enum IlocVersion {
864     Zero,
865     One,
866     Two,
867 }
868 
869 impl TryFrom<u8> for IlocVersion {
870     type Error = Error;
871 
try_from(value: u8) -> Result<Self>872     fn try_from(value: u8) -> Result<Self> {
873         match value {
874             0 => Ok(Self::Zero),
875             1 => Ok(Self::One),
876             2 => Ok(Self::Two),
877             _ => Err(Error::Unsupported("unsupported version in 'iloc' box")),
878         }
879     }
880 }
881 
882 /// Used for 'iloc' boxes
883 /// See ISO 14496-12:2015 § 8.11.3
884 /// `base_offset` is omitted since it is integrated into the ranges in `extents`
885 /// `data_reference_index` is omitted, since only 0 (i.e., this file) is supported
886 #[derive(Debug)]
887 struct ItemLocationBoxItem {
888     item_id: u32,
889     construction_method: ConstructionMethod,
890     /// Unused for ConstructionMethod::Idat
891     extents: TryVec<ItemLocationBoxExtent>,
892 }
893 
894 #[derive(Clone, Copy, Debug)]
895 enum ConstructionMethod {
896     File,
897     Idat,
898     #[allow(dead_code)] // TODO: see https://github.com/mozilla/mp4parse-rust/issues/196
899     Item,
900 }
901 
902 /// `extent_index` is omitted since it's only used for ConstructionMethod::Item which
903 /// is currently not implemented.
904 #[derive(Clone, Debug)]
905 struct ItemLocationBoxExtent {
906     extent_range: ExtentRange,
907 }
908 
909 #[derive(Clone, Debug)]
910 enum ExtentRange {
911     WithLength(Range<u64>),
912     ToEnd(RangeFrom<u64>),
913 }
914 
915 impl ExtentRange {
start(&self) -> u64916     fn start(&self) -> u64 {
917         match self {
918             Self::WithLength(r) => r.start,
919             Self::ToEnd(r) => r.start,
920         }
921     }
922 }
923 
924 #[derive(Debug, PartialEq)]
925 pub enum TrackType {
926     Audio,
927     Video,
928     Metadata,
929     Unknown,
930 }
931 
932 impl Default for TrackType {
default() -> Self933     fn default() -> Self {
934         TrackType::Unknown
935     }
936 }
937 
938 #[derive(Debug, Clone, Copy, PartialEq)]
939 pub enum CodecType {
940     Unknown,
941     MP3,
942     AAC,
943     FLAC,
944     Opus,
945     H264, // 14496-10
946     MP4V, // 14496-2
947     AV1,
948     VP9,
949     VP8,
950     EncryptedVideo,
951     EncryptedAudio,
952     LPCM, // QT
953     ALAC,
954     CRAW, // Canon CRAW
955 }
956 
957 impl Default for CodecType {
default() -> Self958     fn default() -> Self {
959         CodecType::Unknown
960     }
961 }
962 
963 /// The media's global (mvhd) timescale in units per second.
964 #[derive(Debug, Copy, Clone, PartialEq)]
965 pub struct MediaTimeScale(pub u64);
966 
967 /// A time to be scaled by the media's global (mvhd) timescale.
968 #[derive(Debug, Copy, Clone, PartialEq)]
969 pub struct MediaScaledTime(pub u64);
970 
971 /// The track's local (mdhd) timescale.
972 /// Members are timescale units per second and the track id.
973 #[derive(Debug, Copy, Clone, PartialEq)]
974 pub struct TrackTimeScale<T: Num>(pub T, pub usize);
975 
976 /// A time to be scaled by the track's local (mdhd) timescale.
977 /// Members are time in scale units and the track id.
978 #[derive(Debug, Copy, Clone, PartialEq)]
979 pub struct TrackScaledTime<T: Num>(pub T, pub usize);
980 
981 impl<T> std::ops::Add for TrackScaledTime<T>
982 where
983     T: Num,
984 {
985     type Output = TrackScaledTime<T>;
986 
add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T>987     fn add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T> {
988         TrackScaledTime::<T>(self.0 + other.0, self.1)
989     }
990 }
991 
992 #[derive(Debug, Default)]
993 pub struct Track {
994     pub id: usize,
995     pub track_type: TrackType,
996     pub empty_duration: Option<MediaScaledTime>,
997     pub media_time: Option<TrackScaledTime<u64>>,
998     pub timescale: Option<TrackTimeScale<u64>>,
999     pub duration: Option<TrackScaledTime<u64>>,
1000     pub track_id: Option<u32>,
1001     pub tkhd: Option<TrackHeaderBox>, // TODO(kinetik): find a nicer way to export this.
1002     pub stsd: Option<SampleDescriptionBox>,
1003     pub stts: Option<TimeToSampleBox>,
1004     pub stsc: Option<SampleToChunkBox>,
1005     pub stsz: Option<SampleSizeBox>,
1006     pub stco: Option<ChunkOffsetBox>, // It is for stco or co64.
1007     pub stss: Option<SyncSampleBox>,
1008     pub ctts: Option<CompositionOffsetBox>,
1009 }
1010 
1011 impl Track {
new(id: usize) -> Track1012     fn new(id: usize) -> Track {
1013         Track {
1014             id,
1015             ..Default::default()
1016         }
1017     }
1018 }
1019 
1020 pub struct BMFFBox<'a, T: 'a> {
1021     head: BoxHeader,
1022     content: Take<&'a mut T>,
1023 }
1024 
1025 struct BoxIter<'a, T: 'a> {
1026     src: &'a mut T,
1027 }
1028 
1029 impl<'a, T: Read> BoxIter<'a, T> {
new(src: &mut T) -> BoxIter<T>1030     fn new(src: &mut T) -> BoxIter<T> {
1031         BoxIter { src }
1032     }
1033 
next_box(&mut self) -> Result<Option<BMFFBox<T>>>1034     fn next_box(&mut self) -> Result<Option<BMFFBox<T>>> {
1035         let r = read_box_header(self.src);
1036         match r {
1037             Ok(h) => Ok(Some(BMFFBox {
1038                 head: h,
1039                 content: self.src.take(h.size - h.offset),
1040             })),
1041             Err(Error::UnexpectedEOF) => Ok(None),
1042             Err(e) => Err(e),
1043         }
1044     }
1045 }
1046 
1047 impl<'a, T: Read> Read for BMFFBox<'a, T> {
read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>1048     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1049         self.content.read(buf)
1050     }
1051 }
1052 
1053 impl<'a, T: Offset> Offset for BMFFBox<'a, T> {
offset(&self) -> u641054     fn offset(&self) -> u64 {
1055         self.content.get_ref().offset()
1056     }
1057 }
1058 
1059 impl<'a, T: Read> BMFFBox<'a, T> {
bytes_left(&self) -> u641060     fn bytes_left(&self) -> u64 {
1061         self.content.limit()
1062     }
1063 
get_header(&self) -> &BoxHeader1064     fn get_header(&self) -> &BoxHeader {
1065         &self.head
1066     }
1067 
box_iter<'b>(&'b mut self) -> BoxIter<BMFFBox<'a, T>>1068     fn box_iter<'b>(&'b mut self) -> BoxIter<BMFFBox<'a, T>> {
1069         BoxIter::new(self)
1070     }
1071 }
1072 
1073 impl<'a, T: Read + Offset> BMFFBox<'a, T> {
1074     /// Check whether the beginning of `extent` is within the bounds of the `BMFFBox`.
1075     /// We assume extents to not cross box boundaries. If so, this will cause an error
1076     /// in `read_extent`.
contains_extent(&self, extent: &ExtentRange) -> bool1077     fn contains_extent(&self, extent: &ExtentRange) -> bool {
1078         if self.offset() <= extent.start() {
1079             let start_offset = extent.start() - self.offset();
1080             start_offset < self.bytes_left()
1081         } else {
1082             false
1083         }
1084     }
1085 
1086     /// Read the range specified by `extent` into `buf` or return an error if the range is not
1087     /// fully contained within the `BMFFBox`.
read_extent(&mut self, extent: &ExtentRange, buf: &mut TryVec<u8>) -> Result<()>1088     fn read_extent(&mut self, extent: &ExtentRange, buf: &mut TryVec<u8>) -> Result<()> {
1089         let start_offset = extent
1090             .start()
1091             .checked_sub(self.offset())
1092             .expect("box does not contain extent");
1093         skip(self, start_offset)?;
1094         match extent {
1095             ExtentRange::WithLength(range) => {
1096                 let len = range
1097                     .end
1098                     .checked_sub(range.start)
1099                     .expect("range start > end");
1100                 if len > self.bytes_left() {
1101                     return Err(Error::InvalidData("extent crosses box boundary"));
1102                 }
1103                 self.take(len).try_read_to_end(buf)?;
1104             }
1105             ExtentRange::ToEnd(_) => {
1106                 self.try_read_to_end(buf)?;
1107             }
1108         }
1109         Ok(())
1110     }
1111 }
1112 
1113 impl<'a, T> Drop for BMFFBox<'a, T> {
drop(&mut self)1114     fn drop(&mut self) {
1115         if self.content.limit() > 0 {
1116             let name: FourCC = From::from(self.head.name);
1117             debug!("Dropping {} bytes in '{}'", self.content.limit(), name);
1118         }
1119     }
1120 }
1121 
1122 /// Read and parse a box header.
1123 ///
1124 /// Call this first to determine the type of a particular mp4 box
1125 /// and its length. Used internally for dispatching to specific
1126 /// parsers for the internal content, or to get the length to
1127 /// skip unknown or uninteresting boxes.
read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader>1128 fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
1129     let size32 = be_u32(src)?;
1130     let name = BoxType::from(be_u32(src)?);
1131     let size = match size32 {
1132         // valid only for top-level box and indicates it's the last box in the file.  usually mdat.
1133         0 => return Err(Error::Unsupported("unknown sized box")),
1134         1 => {
1135             let size64 = be_u64(src)?;
1136             if size64 < 16 {
1137                 return Err(Error::InvalidData("malformed wide size"));
1138             }
1139             size64
1140         }
1141         2..=7 => return Err(Error::InvalidData("malformed size")),
1142         _ => u64::from(size32),
1143     };
1144     let mut offset = match size32 {
1145         1 => 4 + 4 + 8,
1146         _ => 4 + 4,
1147     };
1148     let uuid = if name == BoxType::UuidBox {
1149         if size >= offset + 16 {
1150             let mut buffer = [0u8; 16];
1151             let count = src.read(&mut buffer)?;
1152             offset += count.to_u64();
1153             if count == 16 {
1154                 Some(buffer)
1155             } else {
1156                 debug!("malformed uuid (short read), skipping");
1157                 None
1158             }
1159         } else {
1160             debug!("malformed uuid, skipping");
1161             None
1162         }
1163     } else {
1164         None
1165     };
1166     assert!(offset <= size);
1167     Ok(BoxHeader {
1168         name,
1169         size,
1170         offset,
1171         uuid,
1172     })
1173 }
1174 
1175 /// Parse the extra header fields for a full box.
read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> Result<(u8, u32)>1176 fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> Result<(u8, u32)> {
1177     let version = src.read_u8()?;
1178     let flags_a = src.read_u8()?;
1179     let flags_b = src.read_u8()?;
1180     let flags_c = src.read_u8()?;
1181     Ok((
1182         version,
1183         u32::from(flags_a) << 16 | u32::from(flags_b) << 8 | u32::from(flags_c),
1184     ))
1185 }
1186 
1187 // Parse the extra fields for a full box whose flag fields must be zero.
read_fullbox_version_no_flags<T: ReadBytesExt>(src: &mut T) -> Result<u8>1188 fn read_fullbox_version_no_flags<T: ReadBytesExt>(src: &mut T) -> Result<u8> {
1189     let (version, flags) = read_fullbox_extra(src)?;
1190 
1191     if flags != 0 {
1192         return Err(Error::Unsupported("expected flags to be 0"));
1193     }
1194 
1195     Ok(version)
1196 }
1197 
1198 /// Skip over the entire contents of a box.
skip_box_content<T: Read>(src: &mut BMFFBox<T>) -> Result<()>1199 fn skip_box_content<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
1200     // Skip the contents of unknown chunks.
1201     let to_skip = {
1202         let header = src.get_header();
1203         debug!("{:?} (skipped)", header);
1204         header
1205             .size
1206             .checked_sub(header.offset)
1207             .expect("header offset > size")
1208     };
1209     assert_eq!(to_skip, src.bytes_left());
1210     skip(src, to_skip)
1211 }
1212 
1213 /// Skip over the remain data of a box.
skip_box_remain<T: Read>(src: &mut BMFFBox<T>) -> Result<()>1214 fn skip_box_remain<T: Read>(src: &mut BMFFBox<T>) -> Result<()> {
1215     let remain = {
1216         let header = src.get_header();
1217         let len = src.bytes_left();
1218         debug!("remain {} (skipped) in {:?}", len, header);
1219         len
1220     };
1221     skip(src, remain)
1222 }
1223 
1224 /// Read the contents of an AVIF file
1225 ///
1226 /// Metadata is accumulated in the passed-through `AvifContext` struct,
1227 /// which can be examined later.
read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()>1228 pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
1229     let mut f = OffsetReader::new(f);
1230 
1231     let mut iter = BoxIter::new(&mut f);
1232 
1233     // 'ftyp' box must occur first; see ISO 14496-12:2015 § 4.3.1
1234     if let Some(mut b) = iter.next_box()? {
1235         if b.head.name == BoxType::FileTypeBox {
1236             let ftyp = read_ftyp(&mut b)?;
1237             if !ftyp.compatible_brands.contains(&FourCC::from(*b"mif1")) {
1238                 return Err(Error::InvalidData("compatible_brands must contain 'mif1'"));
1239             }
1240         } else {
1241             return Err(Error::InvalidData("'ftyp' box must occur first"));
1242         }
1243     }
1244 
1245     let mut read_meta = false;
1246     let mut mdats = TryVec::new();
1247     let mut primary_item_extents = None;
1248     let mut primary_item_extents_data: TryVec<TryVec<u8>> = TryVec::new();
1249 
1250     while let Some(mut b) = iter.next_box()? {
1251         match b.head.name {
1252             BoxType::MetadataBox => {
1253                 if read_meta {
1254                     return Err(Error::InvalidData(
1255                         "There should be zero or one meta boxes per ISO 14496-12:2015 § 8.11.1.1",
1256                     ));
1257                 }
1258                 read_meta = true;
1259                 let primary_item_loc = read_avif_meta(&mut b)?;
1260                 match primary_item_loc.construction_method {
1261                     ConstructionMethod::File => {
1262                         primary_item_extents_data
1263                             .resize_with(primary_item_loc.extents.len(), Default::default)?;
1264                         primary_item_extents = Some(primary_item_loc.extents);
1265                     }
1266                     _ => return Err(Error::Unsupported("unsupported construction_method")),
1267                 }
1268             }
1269             BoxType::MediaDataBox => {
1270                 // See ISO 14496-12:2015 § 8.1.1
1271                 // If we know our primary item location by this point, try to read it out of this
1272                 // mdat directly and avoid a copy
1273                 if let Some(extents) = &primary_item_extents {
1274                     for (extent, data) in extents.iter().zip(primary_item_extents_data.iter_mut()) {
1275                         if b.contains_extent(&extent.extent_range) {
1276                             b.read_extent(&extent.extent_range, data)?;
1277                         }
1278                     }
1279                 }
1280 
1281                 // Store any remaining data for potential later extraction
1282                 if b.bytes_left() > 0 {
1283                     let offset = b.offset();
1284                     let data = b.read_into_try_vec()?;
1285                     mdats.push(MediaDataBox { offset, data })?;
1286                 }
1287             }
1288             _ => skip_box_content(&mut b)?,
1289         }
1290 
1291         check_parser_state!(b.content);
1292     }
1293 
1294     // If the `mdat` box came before the `meta` box, we need to fill in our primary item data
1295     let primary_item_extents =
1296         primary_item_extents.ok_or(Error::InvalidData("primary item extents missing"))?;
1297     for (extent, data) in primary_item_extents
1298         .iter()
1299         .zip(primary_item_extents_data.iter_mut())
1300     {
1301         if data.is_empty() {
1302             // try to find an overlapping mdat
1303             for mdat in mdats.iter_mut() {
1304                 if mdat.matches_extent(&extent.extent_range) {
1305                     data.append(&mut mdat.data)?;
1306                 } else if mdat.contains_extent(&extent.extent_range) {
1307                     mdat.read_extent(&extent.extent_range, data)?;
1308                 }
1309             }
1310         }
1311     }
1312 
1313     context.primary_item = primary_item_extents_data.concat()?;
1314 
1315     Ok(())
1316 }
1317 
1318 /// Parse a metadata box in the context of an AVIF
1319 /// Currently requires the primary item to be an av01 item type and generates
1320 /// an error otherwise.
1321 /// See ISO 14496-12:2015 § 8.11.1
read_avif_meta<T: Read + Offset>(src: &mut BMFFBox<T>) -> Result<ItemLocationBoxItem>1322 fn read_avif_meta<T: Read + Offset>(src: &mut BMFFBox<T>) -> Result<ItemLocationBoxItem> {
1323     let version = read_fullbox_version_no_flags(src)?;
1324 
1325     if version != 0 {
1326         return Err(Error::Unsupported("unsupported meta version"));
1327     }
1328 
1329     let mut primary_item_id = None;
1330     let mut item_infos = None;
1331     let mut iloc_items = None;
1332 
1333     let mut iter = src.box_iter();
1334     while let Some(mut b) = iter.next_box()? {
1335         match b.head.name {
1336             BoxType::ItemInfoBox => {
1337                 if item_infos.is_some() {
1338                     return Err(Error::InvalidData(
1339                         "There should be zero or one iinf boxes per ISO 14496-12:2015 § 8.11.6.1",
1340                     ));
1341                 }
1342                 item_infos = Some(read_iinf(&mut b)?);
1343             }
1344             BoxType::ItemLocationBox => {
1345                 if iloc_items.is_some() {
1346                     return Err(Error::InvalidData(
1347                         "There should be zero or one iloc boxes per ISO 14496-12:2015 § 8.11.3.1",
1348                     ));
1349                 }
1350                 iloc_items = Some(read_iloc(&mut b)?);
1351             }
1352             BoxType::PrimaryItemBox => {
1353                 if primary_item_id.is_some() {
1354                     return Err(Error::InvalidData(
1355                         "There should be zero or one iloc boxes per ISO 14496-12:2015 § 8.11.4.1",
1356                     ));
1357                 }
1358                 primary_item_id = Some(read_pitm(&mut b)?);
1359             }
1360             _ => skip_box_content(&mut b)?,
1361         }
1362 
1363         check_parser_state!(b.content);
1364     }
1365 
1366     let primary_item_id = primary_item_id.ok_or(Error::InvalidData(
1367         "Required pitm box not present in meta box",
1368     ))?;
1369 
1370     if let Some(item_info) = item_infos
1371         .iter()
1372         .flatten()
1373         .find(|x| x.item_id == primary_item_id)
1374     {
1375         if &item_info.item_type.to_be_bytes() != b"av01" {
1376             warn!("primary_item_id type: {}", U32BE(item_info.item_type));
1377             return Err(Error::InvalidData("primary_item_id type is not av01"));
1378         }
1379     } else {
1380         return Err(Error::InvalidData(
1381             "primary_item_id not present in iinf box",
1382         ));
1383     }
1384 
1385     if let Some(loc) = iloc_items
1386         .into_iter()
1387         .flatten()
1388         .find(|loc| loc.item_id == primary_item_id)
1389     {
1390         Ok(loc)
1391     } else {
1392         Err(Error::InvalidData(
1393             "primary_item_id not present in iloc box",
1394         ))
1395     }
1396 }
1397 
1398 /// Parse a Primary Item Box
1399 /// See ISO 14496-12:2015 § 8.11.4
read_pitm<T: Read>(src: &mut BMFFBox<T>) -> Result<u32>1400 fn read_pitm<T: Read>(src: &mut BMFFBox<T>) -> Result<u32> {
1401     let version = read_fullbox_version_no_flags(src)?;
1402 
1403     let item_id = match version {
1404         0 => be_u16(src)?.into(),
1405         1 => be_u32(src)?,
1406         _ => return Err(Error::Unsupported("unsupported pitm version")),
1407     };
1408 
1409     Ok(item_id)
1410 }
1411 
1412 /// Parse an Item Information Box
1413 /// See ISO 14496-12:2015 § 8.11.6
read_iinf<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemInfoEntry>>1414 fn read_iinf<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemInfoEntry>> {
1415     let version = read_fullbox_version_no_flags(src)?;
1416 
1417     match version {
1418         0 | 1 => (),
1419         _ => return Err(Error::Unsupported("unsupported iinf version")),
1420     }
1421 
1422     let entry_count = if version == 0 {
1423         be_u16(src)?.to_usize()
1424     } else {
1425         be_u32(src)?.to_usize()
1426     };
1427     let mut item_infos = TryVec::with_capacity(entry_count)?;
1428 
1429     let mut iter = src.box_iter();
1430     while let Some(mut b) = iter.next_box()? {
1431         if b.head.name != BoxType::ItemInfoEntry {
1432             return Err(Error::InvalidData(
1433                 "iinf box should contain only infe boxes",
1434             ));
1435         }
1436 
1437         item_infos.push(read_infe(&mut b)?)?;
1438 
1439         check_parser_state!(b.content);
1440     }
1441 
1442     Ok(item_infos)
1443 }
1444 
1445 /// A simple wrapper to interpret a u32 as a 4-byte string in big-endian
1446 /// order without requiring any allocation.
1447 struct U32BE(u32);
1448 
1449 impl std::fmt::Display for U32BE {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result1450     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1451         match std::str::from_utf8(&self.0.to_be_bytes()) {
1452             Ok(s) => write!(f, "{}", s),
1453             Err(_) => write!(f, "{:x?}", self.0),
1454         }
1455     }
1456 }
1457 
1458 /// Parse an Item Info Entry
1459 /// See ISO 14496-12:2015 § 8.11.6.2
read_infe<T: Read>(src: &mut BMFFBox<T>) -> Result<ItemInfoEntry>1460 fn read_infe<T: Read>(src: &mut BMFFBox<T>) -> Result<ItemInfoEntry> {
1461     // According to the standard, it seems the flags field should be 0, but
1462     // at least one sample AVIF image has a nonzero value.
1463     let (version, _) = read_fullbox_extra(src)?;
1464 
1465     // mif1 brand (see ISO 23008-12:2017 § 10.2.1) only requires v2 and 3
1466     let item_id = match version {
1467         2 => be_u16(src)?.into(),
1468         3 => be_u32(src)?,
1469         _ => return Err(Error::Unsupported("unsupported version in 'infe' box")),
1470     };
1471 
1472     let item_protection_index = be_u16(src)?;
1473 
1474     if item_protection_index != 0 {
1475         return Err(Error::Unsupported(
1476             "protected items (infe.item_protection_index != 0) are not supported",
1477         ));
1478     }
1479 
1480     let item_type = be_u32(src)?;
1481     debug!("infe item_id {} item_type: {}", item_id, U32BE(item_type));
1482 
1483     // There are some additional fields here, but they're not of interest to us
1484     skip_box_remain(src)?;
1485 
1486     Ok(ItemInfoEntry { item_id, item_type })
1487 }
1488 
1489 /// Parse an item location box inside a meta box
1490 /// See ISO 14496-12:2015 § 8.11.3
read_iloc<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemLocationBoxItem>>1491 fn read_iloc<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemLocationBoxItem>> {
1492     let version: IlocVersion = read_fullbox_version_no_flags(src)?.try_into()?;
1493 
1494     let iloc = src.read_into_try_vec()?;
1495     let mut iloc = BitReader::new(&iloc);
1496 
1497     let offset_size: IlocFieldSize = iloc.read_u8(4)?.try_into()?;
1498     let length_size: IlocFieldSize = iloc.read_u8(4)?.try_into()?;
1499     let base_offset_size: IlocFieldSize = iloc.read_u8(4)?.try_into()?;
1500 
1501     let index_size: Option<IlocFieldSize> = match version {
1502         IlocVersion::One | IlocVersion::Two => Some(iloc.read_u8(4)?.try_into()?),
1503         IlocVersion::Zero => {
1504             let _reserved = iloc.read_u8(4)?;
1505             None
1506         }
1507     };
1508 
1509     let item_count = match version {
1510         IlocVersion::Zero | IlocVersion::One => iloc.read_u32(16)?,
1511         IlocVersion::Two => iloc.read_u32(32)?,
1512     };
1513 
1514     let mut items = TryVec::with_capacity(item_count.to_usize())?;
1515 
1516     for _ in 0..item_count {
1517         let item_id = match version {
1518             IlocVersion::Zero | IlocVersion::One => iloc.read_u32(16)?,
1519             IlocVersion::Two => iloc.read_u32(32)?,
1520         };
1521 
1522         // The spec isn't entirely clear how an `iloc` should be interpreted for version 0,
1523         // which has no `construction_method` field. It does say:
1524         // "For maximum compatibility, version 0 of this box should be used in preference to
1525         //  version 1 with `construction_method==0`, or version 2 when possible."
1526         // We take this to imply version 0 can be interpreted as using file offsets.
1527         let construction_method = match version {
1528             IlocVersion::Zero => ConstructionMethod::File,
1529             IlocVersion::One | IlocVersion::Two => {
1530                 let _reserved = iloc.read_u16(12)?;
1531                 match iloc.read_u16(4)? {
1532                     0 => ConstructionMethod::File,
1533                     1 => ConstructionMethod::Idat,
1534                     2 => return Err(Error::Unsupported("construction_method 'item_offset' is not supported")),
1535                     _ => return Err(Error::InvalidData("construction_method is taken from the set 0, 1 or 2 per ISO 14496-12:2015 § 8.11.3.3"))
1536                 }
1537             }
1538         };
1539 
1540         let data_reference_index = iloc.read_u16(16)?;
1541 
1542         if data_reference_index != 0 {
1543             return Err(Error::Unsupported(
1544                 "external file references (iloc.data_reference_index != 0) are not supported",
1545             ));
1546         }
1547 
1548         let base_offset = iloc.read_u64(base_offset_size.to_bits())?;
1549         let extent_count = iloc.read_u16(16)?;
1550 
1551         if extent_count < 1 {
1552             return Err(Error::InvalidData(
1553                 "extent_count must have a value 1 or greater per ISO 14496-12:2015 § 8.11.3.3",
1554             ));
1555         }
1556 
1557         let mut extents = TryVec::with_capacity(extent_count.to_usize())?;
1558 
1559         for _ in 0..extent_count {
1560             // Parsed but currently ignored, see `ItemLocationBoxExtent`
1561             let _extent_index = match &index_size {
1562                 None | Some(IlocFieldSize::Zero) => None,
1563                 Some(index_size) => {
1564                     debug_assert!(version == IlocVersion::One || version == IlocVersion::Two);
1565                     Some(iloc.read_u64(index_size.to_bits())?)
1566                 }
1567             };
1568 
1569             // Per ISO 14496-12:2015 § 8.11.3.1:
1570             // "If the offset is not identified (the field has a length of zero), then the
1571             //  beginning of the source (offset 0) is implied"
1572             // This behavior will follow from BitReader::read_u64(0) -> 0.
1573             let extent_offset = iloc.read_u64(offset_size.to_bits())?;
1574             let extent_length = iloc.read_u64(length_size.to_bits())?;
1575 
1576             // "If the length is not specified, or specified as zero, then the entire length of
1577             //  the source is implied" (ibid)
1578             let start = base_offset
1579                 .checked_add(extent_offset)
1580                 .ok_or(Error::InvalidData("offset calculation overflow"))?;
1581             let extent_range = if extent_length == 0 {
1582                 ExtentRange::ToEnd(RangeFrom { start })
1583             } else {
1584                 let end = start
1585                     .checked_add(extent_length)
1586                     .ok_or(Error::InvalidData("end calculation overflow"))?;
1587                 ExtentRange::WithLength(Range { start, end })
1588             };
1589 
1590             extents.push(ItemLocationBoxExtent { extent_range })?;
1591         }
1592 
1593         items.push(ItemLocationBoxItem {
1594             item_id,
1595             construction_method,
1596             extents,
1597         })?;
1598     }
1599 
1600     debug_assert_eq!(iloc.remaining(), 0);
1601 
1602     Ok(items)
1603 }
1604 
1605 /// Read the contents of a box, including sub boxes.
1606 ///
1607 /// Metadata is accumulated in the passed-through `MediaContext` struct,
1608 /// which can be examined later.
read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()>1609 pub fn read_mp4<T: Read>(f: &mut T, context: &mut MediaContext) -> Result<()> {
1610     let mut found_ftyp = false;
1611     let mut found_moov = false;
1612     // TODO(kinetik): Top-level parsing should handle zero-sized boxes
1613     // rather than throwing an error.
1614     let mut iter = BoxIter::new(f);
1615     while let Some(mut b) = iter.next_box()? {
1616         // box ordering: ftyp before any variable length box (inc. moov),
1617         // but may not be first box in file if file signatures etc. present
1618         // fragmented mp4 order: ftyp, moov, pairs of moof/mdat (1-multiple), mfra
1619 
1620         // "special": uuid, wide (= 8 bytes)
1621         // isom: moov, mdat, free, skip, udta, ftyp, moof, mfra
1622         // iso2: pdin, meta
1623         // iso3: meco
1624         // iso5: styp, sidx, ssix, prft
1625         // unknown, maybe: id32
1626 
1627         // qt: pnot
1628 
1629         // possibly allow anything where all printable and/or all lowercase printable
1630         // "four printable characters from the ISO 8859-1 character set"
1631         match b.head.name {
1632             BoxType::FileTypeBox => {
1633                 let ftyp = read_ftyp(&mut b)?;
1634                 found_ftyp = true;
1635                 debug!("{:?}", ftyp);
1636                 context.brand = ftyp.major_brand;
1637             }
1638             BoxType::MovieBox => {
1639                 read_moov(&mut b, context)?;
1640                 found_moov = true;
1641             }
1642             _ => skip_box_content(&mut b)?,
1643         };
1644         check_parser_state!(b.content);
1645         if found_moov {
1646             debug!(
1647                 "found moov {}, could stop pure 'moov' parser now",
1648                 if found_ftyp {
1649                     "and ftyp"
1650                 } else {
1651                     "but no ftyp"
1652                 }
1653             );
1654         }
1655     }
1656 
1657     // XXX(kinetik): This isn't perfect, as a "moov" with no contents is
1658     // treated as okay but we haven't found anything useful.  Needs more
1659     // thought for clearer behaviour here.
1660     if found_moov {
1661         Ok(())
1662     } else {
1663         Err(Error::NoMoov)
1664     }
1665 }
1666 
parse_mvhd<T: Read>(f: &mut BMFFBox<T>) -> Result<(MovieHeaderBox, Option<MediaTimeScale>)>1667 fn parse_mvhd<T: Read>(f: &mut BMFFBox<T>) -> Result<(MovieHeaderBox, Option<MediaTimeScale>)> {
1668     let mvhd = read_mvhd(f)?;
1669     if mvhd.timescale == 0 {
1670         return Err(Error::InvalidData("zero timescale in mdhd"));
1671     }
1672     let timescale = Some(MediaTimeScale(u64::from(mvhd.timescale)));
1673     Ok((mvhd, timescale))
1674 }
1675 
read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<()>1676 fn read_moov<T: Read>(f: &mut BMFFBox<T>, context: &mut MediaContext) -> Result<()> {
1677     let mut iter = f.box_iter();
1678     while let Some(mut b) = iter.next_box()? {
1679         match b.head.name {
1680             BoxType::UuidBox => {
1681                 debug!("{:?}", b.head);
1682                 let mut box_known = false;
1683                 #[cfg(feature = "craw")]
1684                 {
1685                     if context.brand == FourCC::from(*b"crx ")
1686                         && b.head.uuid == Some(craw::HEADER_UUID)
1687                     {
1688                         let crawheader = craw::parse_craw_header(&mut b)?;
1689                         context.craw = Some(crawheader);
1690                         box_known = true;
1691                     }
1692                 }
1693                 if !box_known {
1694                     debug!(
1695                         "Unknown UUID box {:?} (skipping)",
1696                         b.head.uuid.as_ref().unwrap()
1697                     );
1698                     skip_box_content(&mut b)?;
1699                 }
1700             }
1701             BoxType::MovieHeaderBox => {
1702                 let (mvhd, timescale) = parse_mvhd(&mut b)?;
1703                 context.timescale = timescale;
1704                 debug!("{:?}", mvhd);
1705             }
1706             BoxType::TrackBox => {
1707                 let mut track = Track::new(context.tracks.len());
1708                 read_trak(&mut b, &mut track, &context.brand)?;
1709                 context.tracks.push(track)?;
1710             }
1711             BoxType::MovieExtendsBox => {
1712                 let mvex = read_mvex(&mut b)?;
1713                 debug!("{:?}", mvex);
1714                 context.mvex = Some(mvex);
1715             }
1716             BoxType::ProtectionSystemSpecificHeaderBox => {
1717                 let pssh = read_pssh(&mut b)?;
1718                 debug!("{:?}", pssh);
1719                 context.psshs.push(pssh)?;
1720             }
1721             BoxType::UserdataBox => {
1722                 let udta = read_udta(&mut b);
1723                 debug!("{:?}", udta);
1724                 context.userdata = Some(udta);
1725             }
1726             _ => skip_box_content(&mut b)?,
1727         };
1728         check_parser_state!(b.content);
1729     }
1730     Ok(())
1731 }
1732 
read_pssh<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSystemSpecificHeaderBox>1733 fn read_pssh<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSystemSpecificHeaderBox> {
1734     let len = src.bytes_left();
1735     let mut box_content = read_buf(src, len)?;
1736     let (system_id, kid, data) = {
1737         let pssh = &mut Cursor::new(&box_content);
1738 
1739         let (version, _) = read_fullbox_extra(pssh)?;
1740 
1741         let system_id = read_buf(pssh, 16)?;
1742 
1743         let mut kid = TryVec::<ByteData>::new();
1744         if version > 0 {
1745             let count = be_u32_with_limit(pssh)?;
1746             for _ in 0..count {
1747                 let item = read_buf(pssh, 16)?;
1748                 kid.push(item)?;
1749             }
1750         }
1751 
1752         let data_size = be_u32_with_limit(pssh)?;
1753         let data = read_buf(pssh, data_size.into())?;
1754 
1755         (system_id, kid, data)
1756     };
1757 
1758     let mut pssh_box = TryVec::new();
1759     write_be_u32(&mut pssh_box, src.head.size.try_into()?)?;
1760     pssh_box.extend_from_slice(b"pssh")?;
1761     pssh_box.append(&mut box_content)?;
1762 
1763     Ok(ProtectionSystemSpecificHeaderBox {
1764         system_id,
1765         kid,
1766         data,
1767         box_content: pssh_box,
1768     })
1769 }
1770 
read_mvex<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieExtendsBox>1771 fn read_mvex<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieExtendsBox> {
1772     let mut iter = src.box_iter();
1773     let mut fragment_duration = None;
1774     while let Some(mut b) = iter.next_box()? {
1775         match b.head.name {
1776             BoxType::MovieExtendsHeaderBox => {
1777                 let duration = read_mehd(&mut b)?;
1778                 fragment_duration = Some(duration);
1779             }
1780             _ => skip_box_content(&mut b)?,
1781         }
1782     }
1783     Ok(MovieExtendsBox { fragment_duration })
1784 }
1785 
read_mehd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaScaledTime>1786 fn read_mehd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaScaledTime> {
1787     let (version, _) = read_fullbox_extra(src)?;
1788     let fragment_duration = match version {
1789         1 => be_u64(src)?,
1790         0 => u64::from(be_u32(src)?),
1791         _ => return Err(Error::InvalidData("unhandled mehd version")),
1792     };
1793     Ok(MediaScaledTime(fragment_duration))
1794 }
1795 
read_trak<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()>1796 fn read_trak<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()> {
1797     let mut iter = f.box_iter();
1798     while let Some(mut b) = iter.next_box()? {
1799         match b.head.name {
1800             BoxType::TrackHeaderBox => {
1801                 let tkhd = read_tkhd(&mut b)?;
1802                 track.track_id = Some(tkhd.track_id);
1803                 track.tkhd = Some(tkhd.clone());
1804                 debug!("{:?}", tkhd);
1805             }
1806             BoxType::EditBox => read_edts(&mut b, track)?,
1807             BoxType::MediaBox => read_mdia(&mut b, track, brand)?,
1808             _ => skip_box_content(&mut b)?,
1809         };
1810         check_parser_state!(b.content);
1811     }
1812     Ok(())
1813 }
1814 
read_edts<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()>1815 fn read_edts<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
1816     let mut iter = f.box_iter();
1817     while let Some(mut b) = iter.next_box()? {
1818         match b.head.name {
1819             BoxType::EditListBox => {
1820                 let elst = read_elst(&mut b)?;
1821                 if elst.edits.is_empty() {
1822                     debug!("empty edit list");
1823                     continue;
1824                 }
1825                 let mut empty_duration = 0;
1826                 let mut idx = 0;
1827                 if elst.edits[idx].media_time == -1 {
1828                     if elst.edits.len() < 2 {
1829                         debug!("expected additional edit, ignoring edit list");
1830                         continue;
1831                     }
1832                     empty_duration = elst.edits[idx].segment_duration;
1833                     idx += 1;
1834                 }
1835                 track.empty_duration = Some(MediaScaledTime(empty_duration));
1836                 let media_time = elst.edits[idx].media_time;
1837                 if media_time < 0 {
1838                     debug!("unexpected negative media time in edit");
1839                 }
1840                 track.media_time = Some(TrackScaledTime::<u64>(
1841                     std::cmp::max(0, media_time) as u64,
1842                     track.id,
1843                 ));
1844                 if elst.edits.len() > 2 {
1845                     debug!("ignoring edit list with {} entries", elst.edits.len());
1846                 }
1847                 debug!("{:?}", elst);
1848             }
1849             _ => skip_box_content(&mut b)?,
1850         };
1851         check_parser_state!(b.content);
1852     }
1853     Ok(())
1854 }
1855 
1856 #[allow(clippy::type_complexity)] // Allow the complex return, maybe rework in future
parse_mdhd<T: Read>( f: &mut BMFFBox<T>, track: &mut Track, ) -> Result<( MediaHeaderBox, Option<TrackScaledTime<u64>>, Option<TrackTimeScale<u64>>, )>1857 fn parse_mdhd<T: Read>(
1858     f: &mut BMFFBox<T>,
1859     track: &mut Track,
1860 ) -> Result<(
1861     MediaHeaderBox,
1862     Option<TrackScaledTime<u64>>,
1863     Option<TrackTimeScale<u64>>,
1864 )> {
1865     let mdhd = read_mdhd(f)?;
1866     let duration = match mdhd.duration {
1867         std::u64::MAX => None,
1868         duration => Some(TrackScaledTime::<u64>(duration, track.id)),
1869     };
1870     if mdhd.timescale == 0 {
1871         return Err(Error::InvalidData("zero timescale in mdhd"));
1872     }
1873     let timescale = Some(TrackTimeScale::<u64>(u64::from(mdhd.timescale), track.id));
1874     Ok((mdhd, duration, timescale))
1875 }
1876 
read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()>1877 fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()> {
1878     let mut iter = f.box_iter();
1879     while let Some(mut b) = iter.next_box()? {
1880         match b.head.name {
1881             BoxType::MediaHeaderBox => {
1882                 let (mdhd, duration, timescale) = parse_mdhd(&mut b, track)?;
1883                 track.duration = duration;
1884                 track.timescale = timescale;
1885                 debug!("{:?}", mdhd);
1886             }
1887             BoxType::HandlerBox => {
1888                 let hdlr = read_hdlr(&mut b)?;
1889 
1890                 match hdlr.handler_type.value.as_ref() {
1891                     b"vide" => track.track_type = TrackType::Video,
1892                     b"soun" => track.track_type = TrackType::Audio,
1893                     b"meta" => track.track_type = TrackType::Metadata,
1894                     _ => (),
1895                 }
1896                 debug!("{:?}", hdlr);
1897             }
1898             BoxType::MediaInformationBox => read_minf(&mut b, track, brand)?,
1899             _ => skip_box_content(&mut b)?,
1900         };
1901         check_parser_state!(b.content);
1902     }
1903     Ok(())
1904 }
1905 
read_minf<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()>1906 fn read_minf<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()> {
1907     let mut iter = f.box_iter();
1908     while let Some(mut b) = iter.next_box()? {
1909         match b.head.name {
1910             BoxType::SampleTableBox => read_stbl(&mut b, track, brand)?,
1911             _ => skip_box_content(&mut b)?,
1912         };
1913         check_parser_state!(b.content);
1914     }
1915     Ok(())
1916 }
1917 
read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()>1918 fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC) -> Result<()> {
1919     let mut iter = f.box_iter();
1920     while let Some(mut b) = iter.next_box()? {
1921         match b.head.name {
1922             BoxType::SampleDescriptionBox => {
1923                 let stsd = read_stsd(&mut b, track, brand)?;
1924                 debug!("{:?}", stsd);
1925                 track.stsd = Some(stsd);
1926             }
1927             BoxType::TimeToSampleBox => {
1928                 let stts = read_stts(&mut b)?;
1929                 debug!("{:?}", stts);
1930                 track.stts = Some(stts);
1931             }
1932             BoxType::SampleToChunkBox => {
1933                 let stsc = read_stsc(&mut b)?;
1934                 debug!("{:?}", stsc);
1935                 track.stsc = Some(stsc);
1936             }
1937             BoxType::SampleSizeBox => {
1938                 let stsz = read_stsz(&mut b)?;
1939                 debug!("{:?}", stsz);
1940                 track.stsz = Some(stsz);
1941             }
1942             BoxType::ChunkOffsetBox => {
1943                 let stco = read_stco(&mut b)?;
1944                 debug!("{:?}", stco);
1945                 track.stco = Some(stco);
1946             }
1947             BoxType::ChunkLargeOffsetBox => {
1948                 let co64 = read_co64(&mut b)?;
1949                 debug!("{:?}", co64);
1950                 track.stco = Some(co64);
1951             }
1952             BoxType::SyncSampleBox => {
1953                 let stss = read_stss(&mut b)?;
1954                 debug!("{:?}", stss);
1955                 track.stss = Some(stss);
1956             }
1957             BoxType::CompositionOffsetBox => {
1958                 let ctts = read_ctts(&mut b)?;
1959                 debug!("{:?}", ctts);
1960                 track.ctts = Some(ctts);
1961             }
1962             _ => skip_box_content(&mut b)?,
1963         };
1964         check_parser_state!(b.content);
1965     }
1966     Ok(())
1967 }
1968 
1969 /// Parse an ftyp box.
read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox>1970 fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
1971     let major = be_u32(src)?;
1972     let minor = be_u32(src)?;
1973     let bytes_left = src.bytes_left();
1974     if bytes_left % 4 != 0 {
1975         return Err(Error::InvalidData("invalid ftyp size"));
1976     }
1977     // Is a brand_count of zero valid?
1978     let brand_count = bytes_left / 4;
1979     let mut brands = TryVec::new();
1980     for _ in 0..brand_count {
1981         brands.push(be_u32(src)?.into())?;
1982     }
1983     Ok(FileTypeBox {
1984         major_brand: From::from(major),
1985         minor_version: minor,
1986         compatible_brands: brands,
1987     })
1988 }
1989 
1990 /// Parse an mvhd box.
read_mvhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieHeaderBox>1991 fn read_mvhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieHeaderBox> {
1992     let (version, _) = read_fullbox_extra(src)?;
1993     match version {
1994         // 64 bit creation and modification times.
1995         1 => {
1996             skip(src, 16)?;
1997         }
1998         // 32 bit creation and modification times.
1999         0 => {
2000             skip(src, 8)?;
2001         }
2002         _ => return Err(Error::InvalidData("unhandled mvhd version")),
2003     }
2004     let timescale = be_u32(src)?;
2005     let duration = match version {
2006         1 => be_u64(src)?,
2007         0 => {
2008             let d = be_u32(src)?;
2009             if d == std::u32::MAX {
2010                 std::u64::MAX
2011             } else {
2012                 u64::from(d)
2013             }
2014         }
2015         _ => return Err(Error::InvalidData("unhandled mvhd version")),
2016     };
2017     // Skip remaining fields.
2018     skip(src, 80)?;
2019     Ok(MovieHeaderBox {
2020         timescale,
2021         duration,
2022     })
2023 }
2024 
2025 /// Parse a tkhd box.
read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox>2026 fn read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
2027     let (version, flags) = read_fullbox_extra(src)?;
2028     let disabled = flags & 0x1u32 == 0 || flags & 0x2u32 == 0;
2029     match version {
2030         // 64 bit creation and modification times.
2031         1 => {
2032             skip(src, 16)?;
2033         }
2034         // 32 bit creation and modification times.
2035         0 => {
2036             skip(src, 8)?;
2037         }
2038         _ => return Err(Error::InvalidData("unhandled tkhd version")),
2039     }
2040     let track_id = be_u32(src)?;
2041     skip(src, 4)?;
2042     let duration = match version {
2043         1 => be_u64(src)?,
2044         0 => u64::from(be_u32(src)?),
2045         _ => return Err(Error::InvalidData("unhandled tkhd version")),
2046     };
2047     // Skip uninteresting fields.
2048     skip(src, 16)?;
2049 
2050     let matrix = Matrix {
2051         a: be_i32(src)?,
2052         b: be_i32(src)?,
2053         u: be_i32(src)?,
2054         c: be_i32(src)?,
2055         d: be_i32(src)?,
2056         v: be_i32(src)?,
2057         x: be_i32(src)?,
2058         y: be_i32(src)?,
2059         w: be_i32(src)?,
2060     };
2061 
2062     let width = be_u32(src)?;
2063     let height = be_u32(src)?;
2064     Ok(TrackHeaderBox {
2065         track_id,
2066         disabled,
2067         duration,
2068         width,
2069         height,
2070         matrix,
2071     })
2072 }
2073 
2074 /// Parse a elst box.
read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox>2075 fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
2076     let (version, _) = read_fullbox_extra(src)?;
2077     let edit_count = be_u32_with_limit(src)?;
2078     let mut edits = TryVec::new();
2079     for _ in 0..edit_count {
2080         let (segment_duration, media_time) = match version {
2081             1 => {
2082                 // 64 bit segment duration and media times.
2083                 (be_u64(src)?, be_i64(src)?)
2084             }
2085             0 => {
2086                 // 32 bit segment duration and media times.
2087                 (u64::from(be_u32(src)?), i64::from(be_i32(src)?))
2088             }
2089             _ => return Err(Error::InvalidData("unhandled elst version")),
2090         };
2091         let media_rate_integer = be_i16(src)?;
2092         let media_rate_fraction = be_i16(src)?;
2093         edits.push(Edit {
2094             segment_duration,
2095             media_time,
2096             media_rate_integer,
2097             media_rate_fraction,
2098         })?;
2099     }
2100 
2101     // Padding could be added in some contents.
2102     skip_box_remain(src)?;
2103 
2104     Ok(EditListBox { edits })
2105 }
2106 
2107 /// Parse a mdhd box.
read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox>2108 fn read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
2109     let (version, _) = read_fullbox_extra(src)?;
2110     let (timescale, duration) = match version {
2111         1 => {
2112             // Skip 64-bit creation and modification times.
2113             skip(src, 16)?;
2114 
2115             // 64 bit duration.
2116             (be_u32(src)?, be_u64(src)?)
2117         }
2118         0 => {
2119             // Skip 32-bit creation and modification times.
2120             skip(src, 8)?;
2121 
2122             // 32 bit duration.
2123             let timescale = be_u32(src)?;
2124             let duration = {
2125                 // Since we convert the 32-bit duration to 64-bit by
2126                 // upcasting, we need to preserve the special all-1s
2127                 // ("unknown") case by hand.
2128                 let d = be_u32(src)?;
2129                 if d == std::u32::MAX {
2130                     std::u64::MAX
2131                 } else {
2132                     u64::from(d)
2133                 }
2134             };
2135             (timescale, duration)
2136         }
2137         _ => return Err(Error::InvalidData("unhandled mdhd version")),
2138     };
2139 
2140     // Skip uninteresting fields.
2141     skip(src, 4)?;
2142 
2143     Ok(MediaHeaderBox {
2144         timescale,
2145         duration,
2146     })
2147 }
2148 
2149 /// Parse a stco box.
read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox>2150 fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
2151     let (_, _) = read_fullbox_extra(src)?;
2152     let offset_count = be_u32_with_limit(src)?;
2153     let mut offsets = TryVec::new();
2154     for _ in 0..offset_count {
2155         offsets.push(be_u32(src)?.into())?;
2156     }
2157 
2158     // Padding could be added in some contents.
2159     skip_box_remain(src)?;
2160 
2161     Ok(ChunkOffsetBox { offsets })
2162 }
2163 
2164 /// Parse a co64 box.
read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox>2165 fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
2166     let (_, _) = read_fullbox_extra(src)?;
2167     let offset_count = be_u32_with_limit(src)?;
2168     let mut offsets = TryVec::new();
2169     for _ in 0..offset_count {
2170         offsets.push(be_u64(src)?)?;
2171     }
2172 
2173     // Padding could be added in some contents.
2174     skip_box_remain(src)?;
2175 
2176     Ok(ChunkOffsetBox { offsets })
2177 }
2178 
2179 /// Parse a stss box.
read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox>2180 fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
2181     let (_, _) = read_fullbox_extra(src)?;
2182     let sample_count = be_u32_with_limit(src)?;
2183     let mut samples = TryVec::new();
2184     for _ in 0..sample_count {
2185         samples.push(be_u32(src)?)?;
2186     }
2187 
2188     // Padding could be added in some contents.
2189     skip_box_remain(src)?;
2190 
2191     Ok(SyncSampleBox { samples })
2192 }
2193 
2194 /// Parse a stsc box.
read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox>2195 fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
2196     let (_, _) = read_fullbox_extra(src)?;
2197     let sample_count = be_u32_with_limit(src)?;
2198     let mut samples = TryVec::new();
2199     for _ in 0..sample_count {
2200         let first_chunk = be_u32(src)?;
2201         let samples_per_chunk = be_u32_with_limit(src)?;
2202         let sample_description_index = be_u32(src)?;
2203         samples.push(SampleToChunk {
2204             first_chunk,
2205             samples_per_chunk,
2206             sample_description_index,
2207         })?;
2208     }
2209 
2210     // Padding could be added in some contents.
2211     skip_box_remain(src)?;
2212 
2213     Ok(SampleToChunkBox { samples })
2214 }
2215 
read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox>2216 fn read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
2217     let (version, _) = read_fullbox_extra(src)?;
2218 
2219     let counts = u64::from(be_u32_with_limit(src)?);
2220 
2221     if src.bytes_left() < counts.checked_mul(8).expect("counts -> bytes overflow") {
2222         return Err(Error::InvalidData("insufficient data in 'ctts' box"));
2223     }
2224 
2225     let mut offsets = TryVec::new();
2226     for _ in 0..counts {
2227         let (sample_count, time_offset) = match version {
2228             // According to spec, Version0 shoule be used when version == 0;
2229             // however, some buggy contents have negative value when version == 0.
2230             // So we always use Version1 here.
2231             0..=1 => {
2232                 let count = be_u32_with_limit(src)?;
2233                 let offset = TimeOffsetVersion::Version1(be_i32(src)?);
2234                 (count, offset)
2235             }
2236             _ => {
2237                 return Err(Error::InvalidData("unsupported version in 'ctts' box"));
2238             }
2239         };
2240         offsets.push(TimeOffset {
2241             sample_count,
2242             time_offset,
2243         })?;
2244     }
2245 
2246     skip_box_remain(src)?;
2247 
2248     Ok(CompositionOffsetBox { samples: offsets })
2249 }
2250 
2251 /// Parse a stsz box.
read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox>2252 fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
2253     let (_, _) = read_fullbox_extra(src)?;
2254     let sample_size = be_u32(src)?;
2255     let sample_count = be_u32_with_limit(src)?;
2256     let mut sample_sizes = TryVec::new();
2257     if sample_size == 0 {
2258         for _ in 0..sample_count {
2259             sample_sizes.push(be_u32(src)?)?;
2260         }
2261     }
2262 
2263     // Padding could be added in some contents.
2264     skip_box_remain(src)?;
2265 
2266     Ok(SampleSizeBox {
2267         sample_size,
2268         sample_sizes,
2269     })
2270 }
2271 
2272 /// Parse a stts box.
read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox>2273 fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
2274     let (_, _) = read_fullbox_extra(src)?;
2275     let sample_count = be_u32_with_limit(src)?;
2276     let mut samples = TryVec::new();
2277     for _ in 0..sample_count {
2278         let sample_count = be_u32_with_limit(src)?;
2279         let sample_delta = be_u32(src)?;
2280         samples.push(Sample {
2281             sample_count,
2282             sample_delta,
2283         })?;
2284     }
2285 
2286     // Padding could be added in some contents.
2287     skip_box_remain(src)?;
2288 
2289     Ok(TimeToSampleBox { samples })
2290 }
2291 
2292 /// Parse a VPx Config Box.
read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox>2293 fn read_vpcc<T: Read>(src: &mut BMFFBox<T>) -> Result<VPxConfigBox> {
2294     let (version, _) = read_fullbox_extra(src)?;
2295     let supported_versions = [0, 1];
2296     if !supported_versions.contains(&version) {
2297         return Err(Error::Unsupported("unknown vpcC version"));
2298     }
2299 
2300     let profile = src.read_u8()?;
2301     let level = src.read_u8()?;
2302     let (
2303         bit_depth,
2304         colour_primaries,
2305         chroma_subsampling,
2306         transfer_characteristics,
2307         matrix_coefficients,
2308         video_full_range_flag,
2309     ) = if version == 0 {
2310         let (bit_depth, colour_primaries) = {
2311             let byte = src.read_u8()?;
2312             ((byte >> 4) & 0x0f, byte & 0x0f)
2313         };
2314         // Note, transfer_characteristics was known as transfer_function in v0
2315         let (chroma_subsampling, transfer_characteristics, video_full_range_flag) = {
2316             let byte = src.read_u8()?;
2317             ((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
2318         };
2319         (
2320             bit_depth,
2321             colour_primaries,
2322             chroma_subsampling,
2323             transfer_characteristics,
2324             None,
2325             video_full_range_flag,
2326         )
2327     } else {
2328         let (bit_depth, chroma_subsampling, video_full_range_flag) = {
2329             let byte = src.read_u8()?;
2330             ((byte >> 4) & 0x0f, (byte >> 1) & 0x07, (byte & 1) == 1)
2331         };
2332         let colour_primaries = src.read_u8()?;
2333         let transfer_characteristics = src.read_u8()?;
2334         let matrix_coefficients = src.read_u8()?;
2335 
2336         (
2337             bit_depth,
2338             colour_primaries,
2339             chroma_subsampling,
2340             transfer_characteristics,
2341             Some(matrix_coefficients),
2342             video_full_range_flag,
2343         )
2344     };
2345 
2346     let codec_init_size = be_u16(src)?;
2347     let codec_init = read_buf(src, codec_init_size.into())?;
2348 
2349     // TODO(rillian): validate field value ranges.
2350     Ok(VPxConfigBox {
2351         profile,
2352         level,
2353         bit_depth,
2354         colour_primaries,
2355         chroma_subsampling,
2356         transfer_characteristics,
2357         matrix_coefficients,
2358         video_full_range_flag,
2359         codec_init,
2360     })
2361 }
2362 
read_av1c<T: Read>(src: &mut BMFFBox<T>) -> Result<AV1ConfigBox>2363 fn read_av1c<T: Read>(src: &mut BMFFBox<T>) -> Result<AV1ConfigBox> {
2364     let marker_byte = src.read_u8()?;
2365     if marker_byte & 0x80 != 0x80 {
2366         return Err(Error::Unsupported("missing av1C marker bit"));
2367     }
2368     if marker_byte & 0x7f != 0x01 {
2369         return Err(Error::Unsupported("missing av1C marker bit"));
2370     }
2371     let profile_byte = src.read_u8()?;
2372     let profile = (profile_byte & 0xe0) >> 5;
2373     let level = profile_byte & 0x1f;
2374     let flags_byte = src.read_u8()?;
2375     let tier = (flags_byte & 0x80) >> 7;
2376     let bit_depth = match flags_byte & 0x60 {
2377         0x60 => 12,
2378         0x40 => 10,
2379         _ => 8,
2380     };
2381     let monochrome = flags_byte & 0x10 == 0x10;
2382     let chroma_subsampling_x = (flags_byte & 0x08) >> 3;
2383     let chroma_subsampling_y = (flags_byte & 0x04) >> 2;
2384     let chroma_sample_position = flags_byte & 0x03;
2385     let delay_byte = src.read_u8()?;
2386     let initial_presentation_delay_present = (delay_byte & 0x10) == 0x10;
2387     let initial_presentation_delay_minus_one = if initial_presentation_delay_present {
2388         delay_byte & 0x0f
2389     } else {
2390         0
2391     };
2392 
2393     let config_obus_size = src.bytes_left();
2394     let config_obus = read_buf(src, config_obus_size)?;
2395 
2396     Ok(AV1ConfigBox {
2397         profile,
2398         level,
2399         tier,
2400         bit_depth,
2401         monochrome,
2402         chroma_subsampling_x,
2403         chroma_subsampling_y,
2404         chroma_sample_position,
2405         initial_presentation_delay_present,
2406         initial_presentation_delay_minus_one,
2407         config_obus,
2408     })
2409 }
2410 
read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock>2411 fn read_flac_metadata<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACMetadataBlock> {
2412     let temp = src.read_u8()?;
2413     let block_type = temp & 0x7f;
2414     let length = be_u24(src)?.into();
2415     if length > src.bytes_left() {
2416         return Err(Error::InvalidData(
2417             "FLACMetadataBlock larger than parent box",
2418         ));
2419     }
2420     let data = read_buf(src, length)?;
2421     Ok(FLACMetadataBlock { block_type, data })
2422 }
2423 
find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()>2424 fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
2425     // Tags for elementary stream description
2426     const ESDESCR_TAG: u8 = 0x03;
2427     const DECODER_CONFIG_TAG: u8 = 0x04;
2428     const DECODER_SPECIFIC_TAG: u8 = 0x05;
2429 
2430     let mut remains = data;
2431 
2432     // Descriptor length should be more than 2 bytes.
2433     while remains.len() > 2 {
2434         let des = &mut Cursor::new(remains);
2435         let tag = des.read_u8()?;
2436 
2437         let mut end: u32 = 0; // It's u8 without declaration type that is incorrect.
2438                               // MSB of extend_or_len indicates more bytes, up to 4 bytes.
2439         for _ in 0..4 {
2440             if des.position() == remains.len().to_u64() {
2441                 // There's nothing more to read, the 0x80 was actually part of
2442                 // the content, and not an extension size.
2443                 end = des.position() as u32;
2444                 break;
2445             }
2446             let extend_or_len = des.read_u8()?;
2447             end = (end << 7) + u32::from(extend_or_len & 0x7F);
2448             if (extend_or_len & 0x80) == 0 {
2449                 end += des.position() as u32;
2450                 break;
2451             }
2452         }
2453 
2454         if end.to_usize() > remains.len() || u64::from(end) < des.position() {
2455             return Err(Error::InvalidData("Invalid descriptor."));
2456         }
2457 
2458         let descriptor = &remains[des.position().try_into()?..end.to_usize()];
2459 
2460         match tag {
2461             ESDESCR_TAG => {
2462                 read_es_descriptor(descriptor, esds)?;
2463             }
2464             DECODER_CONFIG_TAG => {
2465                 read_dc_descriptor(descriptor, esds)?;
2466             }
2467             DECODER_SPECIFIC_TAG => {
2468                 read_ds_descriptor(descriptor, esds)?;
2469             }
2470             _ => {
2471                 debug!("Unsupported descriptor, tag {}", tag);
2472             }
2473         }
2474 
2475         remains = &remains[end.to_usize()..remains.len()];
2476     }
2477 
2478     Ok(())
2479 }
2480 
get_audio_object_type(bit_reader: &mut BitReader) -> Result<u16>2481 fn get_audio_object_type(bit_reader: &mut BitReader) -> Result<u16> {
2482     let mut audio_object_type: u16 = ReadInto::read(bit_reader, 5)?;
2483 
2484     // Extend audio object type, for example, HE-AAC.
2485     if audio_object_type == 31 {
2486         let audio_object_type_ext: u16 = ReadInto::read(bit_reader, 6)?;
2487         audio_object_type = 32 + audio_object_type_ext;
2488     }
2489     Ok(audio_object_type)
2490 }
2491 
read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()>2492 fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
2493     let frequency_table = vec![
2494         (0x0, 96000),
2495         (0x1, 88200),
2496         (0x2, 64000),
2497         (0x3, 48000),
2498         (0x4, 44100),
2499         (0x5, 32000),
2500         (0x6, 24000),
2501         (0x7, 22050),
2502         (0x8, 16000),
2503         (0x9, 12000),
2504         (0xa, 11025),
2505         (0xb, 8000),
2506         (0xc, 7350),
2507     ];
2508 
2509     let bit_reader = &mut BitReader::new(data);
2510 
2511     let mut audio_object_type = get_audio_object_type(bit_reader)?;
2512 
2513     let sample_index: u32 = ReadInto::read(bit_reader, 4)?;
2514 
2515     // Sample frequency could be from table, or retrieved from stream directly
2516     // if index is 0x0f.
2517     let sample_frequency = match sample_index {
2518         0x0F => Some(ReadInto::read(bit_reader, 24)?),
2519         _ => frequency_table
2520             .iter()
2521             .find(|item| item.0 == sample_index)
2522             .map(|x| x.1),
2523     };
2524 
2525     let channel_configuration: u16 = ReadInto::read(bit_reader, 4)?;
2526 
2527     let extended_audio_object_type = match audio_object_type {
2528         5 | 29 => Some(5),
2529         _ => None,
2530     };
2531 
2532     if audio_object_type == 5 || audio_object_type == 29 {
2533         // We have an explicit signaling for BSAC extension, should the decoder
2534         // decode the BSAC extension (all Gecko's AAC decoders do), then this is
2535         // what the stream will actually look like once decoded.
2536         let _extended_sample_index = ReadInto::read(bit_reader, 4)?;
2537         let _extended_sample_frequency: Option<u32> = match _extended_sample_index {
2538             0x0F => Some(ReadInto::read(bit_reader, 24)?),
2539             _ => frequency_table
2540                 .iter()
2541                 .find(|item| item.0 == sample_index)
2542                 .map(|x| x.1),
2543         };
2544         audio_object_type = get_audio_object_type(bit_reader)?;
2545         let _extended_channel_configuration = match audio_object_type {
2546             22 => ReadInto::read(bit_reader, 4)?,
2547             _ => channel_configuration,
2548         };
2549     };
2550 
2551     match audio_object_type {
2552         1..=4 | 6 | 7 | 17 | 19..=23 => {
2553             if sample_frequency.is_none() {
2554                 return Err(Error::Unsupported("unknown frequency"));
2555             }
2556 
2557             // parsing GASpecificConfig
2558 
2559             // If the sampling rate is not one of the rates listed in the right
2560             // column in Table 4.82, the sampling frequency dependent tables
2561             // (code tables, scale factor band tables etc.) must be deduced in
2562             // order for the bitstream payload to be parsed. Since a given
2563             // sampling frequency is associated with only one sampling frequency
2564             // table, and since maximum flexibility is desired in the range of
2565             // possible sampling frequencies, the following table shall be used
2566             // to associate an implied sampling frequency with the desired
2567             // sampling frequency dependent tables.
2568             let sample_frequency_value = match sample_frequency.unwrap() {
2569                 0..=9390 => 8000,
2570                 9391..=11501 => 11025,
2571                 11502..=13855 => 12000,
2572                 13856..=18782 => 16000,
2573                 18783..=23003 => 22050,
2574                 23004..=27712 => 24000,
2575                 27713..=37565 => 32000,
2576                 37566..=46008 => 44100,
2577                 46009..=55425 => 48000,
2578                 55426..=75131 => 64000,
2579                 75132..=92016 => 88200,
2580                 _ => 96000,
2581             };
2582 
2583             bit_reader.skip(1)?; // frameLengthFlag
2584             let depend_on_core_order: u8 = ReadInto::read(bit_reader, 1)?;
2585             if depend_on_core_order > 0 {
2586                 bit_reader.skip(14)?; // codeCoderDelay
2587             }
2588             bit_reader.skip(1)?; // extensionFlag
2589 
2590             let channel_counts = match channel_configuration {
2591                 0 => {
2592                     debug!("Parsing program_config_element for channel counts");
2593 
2594                     bit_reader.skip(4)?; // element_instance_tag
2595                     bit_reader.skip(2)?; // object_type
2596                     bit_reader.skip(4)?; // sampling_frequency_index
2597                     let num_front_channel: u8 = ReadInto::read(bit_reader, 4)?;
2598                     let num_side_channel: u8 = ReadInto::read(bit_reader, 4)?;
2599                     let num_back_channel: u8 = ReadInto::read(bit_reader, 4)?;
2600                     let num_lfe_channel: u8 = ReadInto::read(bit_reader, 2)?;
2601                     bit_reader.skip(3)?; // num_assoc_data
2602                     bit_reader.skip(4)?; // num_valid_cc
2603 
2604                     let mono_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
2605                     if mono_mixdown_present {
2606                         bit_reader.skip(4)?; // mono_mixdown_element_number
2607                     }
2608 
2609                     let stereo_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
2610                     if stereo_mixdown_present {
2611                         bit_reader.skip(4)?; // stereo_mixdown_element_number
2612                     }
2613 
2614                     let matrix_mixdown_idx_present: bool = ReadInto::read(bit_reader, 1)?;
2615                     if matrix_mixdown_idx_present {
2616                         bit_reader.skip(2)?; // matrix_mixdown_idx
2617                         bit_reader.skip(1)?; // pseudo_surround_enable
2618                     }
2619                     let mut _channel_counts = 0;
2620                     _channel_counts += read_surround_channel_count(bit_reader, num_front_channel)?;
2621                     _channel_counts += read_surround_channel_count(bit_reader, num_side_channel)?;
2622                     _channel_counts += read_surround_channel_count(bit_reader, num_back_channel)?;
2623                     _channel_counts += read_surround_channel_count(bit_reader, num_lfe_channel)?;
2624                     _channel_counts
2625                 }
2626                 1..=7 => channel_configuration,
2627                 // Amendment 4 of the AAC standard in 2013 below
2628                 11 => 7,      // 6.1 Amendment 4 of the AAC standard in 2013
2629                 12 | 14 => 8, // 7.1 (a/d) of ITU BS.2159
2630                 _ => {
2631                     return Err(Error::Unsupported("invalid channel configuration"));
2632                 }
2633             };
2634 
2635             esds.audio_object_type = Some(audio_object_type);
2636             esds.extended_audio_object_type = extended_audio_object_type;
2637             esds.audio_sample_rate = Some(sample_frequency_value);
2638             esds.audio_channel_count = Some(channel_counts);
2639             assert!(esds.decoder_specific_data.is_empty());
2640             esds.decoder_specific_data.extend_from_slice(data)?;
2641 
2642             Ok(())
2643         }
2644         _ => Err(Error::Unsupported("unknown aac audio object type")),
2645     }
2646 }
2647 
read_surround_channel_count(bit_reader: &mut BitReader, channels: u8) -> Result<u16>2648 fn read_surround_channel_count(bit_reader: &mut BitReader, channels: u8) -> Result<u16> {
2649     let mut count = 0;
2650     for _ in 0..channels {
2651         let is_cpe: bool = ReadInto::read(bit_reader, 1)?;
2652         count += if is_cpe { 2 } else { 1 };
2653         bit_reader.skip(4)?;
2654     }
2655     Ok(count)
2656 }
2657 
read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()>2658 fn read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
2659     let des = &mut Cursor::new(data);
2660     let object_profile = des.read_u8()?;
2661 
2662     // Skip uninteresting fields.
2663     skip(des, 12)?;
2664 
2665     if data.len().to_u64() > des.position() {
2666         find_descriptor(&data[des.position().try_into()?..data.len()], esds)?;
2667     }
2668 
2669     esds.audio_codec = match object_profile {
2670         0x40 | 0x41 => CodecType::AAC,
2671         0x6B => CodecType::MP3,
2672         _ => CodecType::Unknown,
2673     };
2674 
2675     Ok(())
2676 }
2677 
read_es_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()>2678 fn read_es_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
2679     let des = &mut Cursor::new(data);
2680 
2681     skip(des, 2)?;
2682 
2683     let esds_flags = des.read_u8()?;
2684 
2685     // Stream dependency flag, first bit from left most.
2686     if esds_flags & 0x80 > 0 {
2687         // Skip uninteresting fields.
2688         skip(des, 2)?;
2689     }
2690 
2691     // Url flag, second bit from left most.
2692     if esds_flags & 0x40 > 0 {
2693         // Skip uninteresting fields.
2694         let skip_es_len = u64::from(des.read_u8()?) + 2;
2695         skip(des, skip_es_len)?;
2696     }
2697 
2698     if data.len().to_u64() > des.position() {
2699         find_descriptor(&data[des.position().try_into()?..data.len()], esds)?;
2700     }
2701 
2702     Ok(())
2703 }
2704 
read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor>2705 fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
2706     let (_, _) = read_fullbox_extra(src)?;
2707 
2708     // Subtract 4 extra to offset the members of fullbox not accounted for in
2709     // head.offset
2710     let esds_size = src
2711         .head
2712         .size
2713         .checked_sub(src.head.offset + 4)
2714         .expect("offset invalid");
2715     let esds_array = read_buf(src, esds_size)?;
2716 
2717     let mut es_data = ES_Descriptor::default();
2718     find_descriptor(&esds_array, &mut es_data)?;
2719 
2720     es_data.codec_esds = esds_array;
2721 
2722     Ok(es_data)
2723 }
2724 
2725 /// Parse `FLACSpecificBox`.
read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox>2726 fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
2727     let (version, flags) = read_fullbox_extra(src)?;
2728     if version != 0 {
2729         return Err(Error::Unsupported("unknown dfLa (FLAC) version"));
2730     }
2731     if flags != 0 {
2732         return Err(Error::InvalidData("no-zero dfLa (FLAC) flags"));
2733     }
2734     let mut blocks = TryVec::new();
2735     while src.bytes_left() > 0 {
2736         let block = read_flac_metadata(src)?;
2737         blocks.push(block)?;
2738     }
2739     // The box must have at least one meta block, and the first block
2740     // must be the METADATA_BLOCK_STREAMINFO
2741     if blocks.is_empty() {
2742         return Err(Error::InvalidData("FLACSpecificBox missing metadata"));
2743     } else if blocks[0].block_type != 0 {
2744         return Err(Error::InvalidData(
2745             "FLACSpecificBox must have STREAMINFO metadata first",
2746         ));
2747     } else if blocks[0].data.len() != 34 {
2748         return Err(Error::InvalidData(
2749             "FLACSpecificBox STREAMINFO block is the wrong size",
2750         ));
2751     }
2752     Ok(FLACSpecificBox { version, blocks })
2753 }
2754 
2755 /// Parse `OpusSpecificBox`.
read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox>2756 fn read_dops<T: Read>(src: &mut BMFFBox<T>) -> Result<OpusSpecificBox> {
2757     let version = src.read_u8()?;
2758     if version != 0 {
2759         return Err(Error::Unsupported("unknown dOps (Opus) version"));
2760     }
2761 
2762     let output_channel_count = src.read_u8()?;
2763     let pre_skip = be_u16(src)?;
2764     let input_sample_rate = be_u32(src)?;
2765     let output_gain = be_i16(src)?;
2766     let channel_mapping_family = src.read_u8()?;
2767 
2768     let channel_mapping_table = if channel_mapping_family == 0 {
2769         None
2770     } else {
2771         let stream_count = src.read_u8()?;
2772         let coupled_count = src.read_u8()?;
2773         let channel_mapping = read_buf(src, output_channel_count.into())?;
2774 
2775         Some(ChannelMappingTable {
2776             stream_count,
2777             coupled_count,
2778             channel_mapping,
2779         })
2780     };
2781 
2782     // TODO(kinetik): validate field value ranges.
2783     Ok(OpusSpecificBox {
2784         version,
2785         output_channel_count,
2786         pre_skip,
2787         input_sample_rate,
2788         output_gain,
2789         channel_mapping_family,
2790         channel_mapping_table,
2791     })
2792 }
2793 
2794 /// Re-serialize the Opus codec-specific config data as an `OpusHead` packet.
2795 ///
2796 /// Some decoders expect the initialization data in the format used by the
2797 /// Ogg and WebM encapsulations. To support this we prepend the `OpusHead`
2798 /// tag and byte-swap the data from big- to little-endian relative to the
2799 /// dOps box.
serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>( opus: &OpusSpecificBox, dst: &mut W, ) -> Result<()>2800 pub fn serialize_opus_header<W: byteorder::WriteBytesExt + std::io::Write>(
2801     opus: &OpusSpecificBox,
2802     dst: &mut W,
2803 ) -> Result<()> {
2804     match dst.write(b"OpusHead") {
2805         Err(e) => return Err(Error::from(e)),
2806         Ok(bytes) => {
2807             if bytes != 8 {
2808                 return Err(Error::InvalidData("Couldn't write OpusHead tag."));
2809             }
2810         }
2811     }
2812     // In mp4 encapsulation, the version field is 0, but in ogg
2813     // it is 1. While decoders generally accept zero as well, write
2814     // out the version of the header we're supporting rather than
2815     // whatever we parsed out of mp4.
2816     dst.write_u8(1)?;
2817     dst.write_u8(opus.output_channel_count)?;
2818     dst.write_u16::<byteorder::LittleEndian>(opus.pre_skip)?;
2819     dst.write_u32::<byteorder::LittleEndian>(opus.input_sample_rate)?;
2820     dst.write_i16::<byteorder::LittleEndian>(opus.output_gain)?;
2821     dst.write_u8(opus.channel_mapping_family)?;
2822     match opus.channel_mapping_table {
2823         None => {}
2824         Some(ref table) => {
2825             dst.write_u8(table.stream_count)?;
2826             dst.write_u8(table.coupled_count)?;
2827             match dst.write(&table.channel_mapping) {
2828                 Err(e) => return Err(Error::from(e)),
2829                 Ok(bytes) => {
2830                     if bytes != table.channel_mapping.len() {
2831                         return Err(Error::InvalidData(
2832                             "Couldn't write channel mapping table data.",
2833                         ));
2834                     }
2835                 }
2836             }
2837         }
2838     };
2839     Ok(())
2840 }
2841 
2842 /// Parse `ALACSpecificBox`.
read_alac<T: Read>(src: &mut BMFFBox<T>) -> Result<ALACSpecificBox>2843 fn read_alac<T: Read>(src: &mut BMFFBox<T>) -> Result<ALACSpecificBox> {
2844     let (version, flags) = read_fullbox_extra(src)?;
2845     if version != 0 {
2846         return Err(Error::Unsupported("unknown alac (ALAC) version"));
2847     }
2848     if flags != 0 {
2849         return Err(Error::InvalidData("no-zero alac (ALAC) flags"));
2850     }
2851 
2852     let length = match src.bytes_left() {
2853         x @ 24 | x @ 48 => x,
2854         _ => {
2855             return Err(Error::InvalidData(
2856                 "ALACSpecificBox magic cookie is the wrong size",
2857             ))
2858         }
2859     };
2860     let data = read_buf(src, length)?;
2861 
2862     Ok(ALACSpecificBox { version, data })
2863 }
2864 
2865 /// Parse a hdlr box.
read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox>2866 fn read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox> {
2867     let (_, _) = read_fullbox_extra(src)?;
2868 
2869     // Skip uninteresting fields.
2870     skip(src, 4)?;
2871 
2872     let handler_type = FourCC::from(be_u32(src)?);
2873 
2874     // Skip uninteresting fields.
2875     skip(src, 12)?;
2876 
2877     // Skip name.
2878     skip_box_remain(src)?;
2879 
2880     Ok(HandlerBox { handler_type })
2881 }
2882 
2883 /// Parse an video description inside an stsd box.
read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>, brand: &FourCC) -> Result<SampleEntry>2884 fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>, brand: &FourCC) -> Result<SampleEntry> {
2885     let name = src.get_header().name;
2886     let codec_type = match name {
2887         BoxType::AVCSampleEntry | BoxType::AVC3SampleEntry => CodecType::H264,
2888         BoxType::MP4VideoSampleEntry => CodecType::MP4V,
2889         BoxType::VP8SampleEntry => CodecType::VP8,
2890         BoxType::VP9SampleEntry => CodecType::VP9,
2891         BoxType::AV1SampleEntry => CodecType::AV1,
2892         BoxType::CanonCRAWEntry => {
2893             if brand == &FourCC::from(*b"crx ") {
2894                 CodecType::CRAW
2895             } else {
2896                 debug!("Unsupported CRAW codec found in '{:?}'.", brand);
2897                 CodecType::Unknown
2898             }
2899         }
2900         BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
2901         _ => {
2902             debug!("Unsupported video codec, box {:?} found", name);
2903             CodecType::Unknown
2904         }
2905     };
2906 
2907     // Skip uninteresting fields.
2908     skip(src, 6)?;
2909 
2910     let data_reference_index = be_u16(src)?;
2911 
2912     // Skip uninteresting fields.
2913     skip(src, 16)?;
2914     let width = be_u16(src)?;
2915     let height = be_u16(src)?;
2916 
2917     #[cfg(feature = "craw")]
2918     {
2919         if codec_type == CodecType::CRAW {
2920             return craw::read_craw_entry(src, width, height, data_reference_index);
2921         }
2922     }
2923 
2924     // Skip uninteresting fields.
2925     skip(src, 50)?;
2926 
2927     // Skip clap/pasp/etc. for now.
2928     let mut codec_specific = None;
2929     let mut protection_info = TryVec::new();
2930     let mut iter = src.box_iter();
2931     while let Some(mut b) = iter.next_box()? {
2932         match b.head.name {
2933             BoxType::AVCConfigurationBox => {
2934                 if (name != BoxType::AVCSampleEntry
2935                     && name != BoxType::AVC3SampleEntry
2936                     && name != BoxType::ProtectedVisualSampleEntry)
2937                     || codec_specific.is_some()
2938                 {
2939                     return Err(Error::InvalidData("malformed video sample entry"));
2940                 }
2941                 let avcc_size = b
2942                     .head
2943                     .size
2944                     .checked_sub(b.head.offset)
2945                     .expect("offset invalid");
2946                 let avcc = read_buf(&mut b.content, avcc_size)?;
2947                 debug!("{:?} (avcc)", avcc);
2948                 // TODO(kinetik): Parse avcC box?  For now we just stash the data.
2949                 codec_specific = Some(VideoCodecSpecific::AVCConfig(avcc));
2950             }
2951             BoxType::VPCodecConfigurationBox => {
2952                 // vpcC
2953                 if (name != BoxType::VP8SampleEntry
2954                     && name != BoxType::VP9SampleEntry
2955                     && name != BoxType::ProtectedVisualSampleEntry)
2956                     || codec_specific.is_some()
2957                 {
2958                     return Err(Error::InvalidData("malformed video sample entry"));
2959                 }
2960                 let vpcc = read_vpcc(&mut b)?;
2961                 codec_specific = Some(VideoCodecSpecific::VPxConfig(vpcc));
2962             }
2963             BoxType::AV1CodecConfigurationBox => {
2964                 if name != BoxType::AV1SampleEntry {
2965                     return Err(Error::InvalidData("malformed video sample entry"));
2966                 }
2967                 let av1c = read_av1c(&mut b)?;
2968                 codec_specific = Some(VideoCodecSpecific::AV1Config(av1c));
2969             }
2970             BoxType::ESDBox => {
2971                 if name != BoxType::MP4VideoSampleEntry || codec_specific.is_some() {
2972                     return Err(Error::InvalidData("malformed video sample entry"));
2973                 }
2974                 let (_, _) = read_fullbox_extra(&mut b.content)?;
2975                 // Subtract 4 extra to offset the members of fullbox not
2976                 // accounted for in head.offset
2977                 let esds_size = b
2978                     .head
2979                     .size
2980                     .checked_sub(b.head.offset + 4)
2981                     .expect("offset invalid");
2982                 let esds = read_buf(&mut b.content, esds_size)?;
2983                 codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
2984             }
2985             BoxType::ProtectionSchemeInfoBox => {
2986                 if name != BoxType::ProtectedVisualSampleEntry {
2987                     return Err(Error::InvalidData("malformed video sample entry"));
2988                 }
2989                 let sinf = read_sinf(&mut b)?;
2990                 debug!("{:?} (sinf)", sinf);
2991                 protection_info.push(sinf)?;
2992             }
2993             _ => {
2994                 debug!("Unsupported video codec, box {:?} found", b.head.name);
2995                 skip_box_content(&mut b)?;
2996             }
2997         }
2998         check_parser_state!(b.content);
2999     }
3000 
3001     Ok(
3002         codec_specific.map_or(SampleEntry::Unknown, |codec_specific| {
3003             SampleEntry::Video(VideoSampleEntry {
3004                 codec_type,
3005                 data_reference_index,
3006                 width,
3007                 height,
3008                 codec_specific,
3009                 protection_info,
3010             })
3011         }),
3012     )
3013 }
3014 
read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor>3015 fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
3016     let mut codec_specific = None;
3017     let mut iter = src.box_iter();
3018     while let Some(mut b) = iter.next_box()? {
3019         match b.head.name {
3020             BoxType::ESDBox => {
3021                 let esds = read_esds(&mut b)?;
3022                 codec_specific = Some(esds);
3023             }
3024             _ => skip_box_content(&mut b)?,
3025         }
3026     }
3027 
3028     codec_specific.ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
3029 }
3030 
3031 /// Parse an audio description inside an stsd box.
read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry>3032 fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry> {
3033     let name = src.get_header().name;
3034 
3035     // Skip uninteresting fields.
3036     skip(src, 6)?;
3037 
3038     let data_reference_index = be_u16(src)?;
3039 
3040     // XXX(kinetik): This is "reserved" in BMFF, but some old QT MOV variant
3041     // uses it, need to work out if we have to support it.  Without checking
3042     // here and reading extra fields after samplerate (or bailing with an
3043     // error), the parser loses sync completely.
3044     let version = be_u16(src)?;
3045 
3046     // Skip uninteresting fields.
3047     skip(src, 6)?;
3048 
3049     let mut channelcount = u32::from(be_u16(src)?);
3050     let samplesize = be_u16(src)?;
3051 
3052     // Skip uninteresting fields.
3053     skip(src, 4)?;
3054 
3055     let mut samplerate = f64::from(be_u32(src)? >> 16); // 16.16 fixed point;
3056 
3057     match version {
3058         0 => (),
3059         1 => {
3060             // Quicktime sound sample description version 1.
3061             // Skip uninteresting fields.
3062             skip(src, 16)?;
3063         }
3064         2 => {
3065             // Quicktime sound sample description version 2.
3066             skip(src, 4)?;
3067             samplerate = f64::from_bits(be_u64(src)?);
3068             channelcount = be_u32(src)?;
3069             skip(src, 20)?;
3070         }
3071         _ => {
3072             return Err(Error::Unsupported(
3073                 "unsupported non-isom audio sample entry",
3074             ))
3075         }
3076     }
3077 
3078     let (mut codec_type, mut codec_specific) = match name {
3079         BoxType::MP3AudioSampleEntry => (CodecType::MP3, Some(AudioCodecSpecific::MP3)),
3080         BoxType::LPCMAudioSampleEntry => (CodecType::LPCM, Some(AudioCodecSpecific::LPCM)),
3081         _ => (CodecType::Unknown, None),
3082     };
3083     let mut protection_info = TryVec::new();
3084     let mut iter = src.box_iter();
3085     while let Some(mut b) = iter.next_box()? {
3086         match b.head.name {
3087             BoxType::ESDBox => {
3088                 if (name != BoxType::MP4AudioSampleEntry
3089                     && name != BoxType::ProtectedAudioSampleEntry)
3090                     || codec_specific.is_some()
3091                 {
3092                     return Err(Error::InvalidData("malformed audio sample entry"));
3093                 }
3094                 let esds = read_esds(&mut b)?;
3095                 codec_type = esds.audio_codec;
3096                 codec_specific = Some(AudioCodecSpecific::ES_Descriptor(esds));
3097             }
3098             BoxType::FLACSpecificBox => {
3099                 if (name != BoxType::FLACSampleEntry && name != BoxType::ProtectedAudioSampleEntry)
3100                     || codec_specific.is_some()
3101                 {
3102                     return Err(Error::InvalidData("malformed audio sample entry"));
3103                 }
3104                 let dfla = read_dfla(&mut b)?;
3105                 codec_type = CodecType::FLAC;
3106                 codec_specific = Some(AudioCodecSpecific::FLACSpecificBox(dfla));
3107             }
3108             BoxType::OpusSpecificBox => {
3109                 if (name != BoxType::OpusSampleEntry && name != BoxType::ProtectedAudioSampleEntry)
3110                     || codec_specific.is_some()
3111                 {
3112                     return Err(Error::InvalidData("malformed audio sample entry"));
3113                 }
3114                 let dops = read_dops(&mut b)?;
3115                 codec_type = CodecType::Opus;
3116                 codec_specific = Some(AudioCodecSpecific::OpusSpecificBox(dops));
3117             }
3118             BoxType::ALACSpecificBox => {
3119                 if name != BoxType::ALACSpecificBox || codec_specific.is_some() {
3120                     return Err(Error::InvalidData("malformed audio sample entry"));
3121                 }
3122                 let alac = read_alac(&mut b)?;
3123                 codec_type = CodecType::ALAC;
3124                 codec_specific = Some(AudioCodecSpecific::ALACSpecificBox(alac));
3125             }
3126             BoxType::QTWaveAtom => {
3127                 let qt_esds = read_qt_wave_atom(&mut b)?;
3128                 codec_type = qt_esds.audio_codec;
3129                 codec_specific = Some(AudioCodecSpecific::ES_Descriptor(qt_esds));
3130             }
3131             BoxType::ProtectionSchemeInfoBox => {
3132                 if name != BoxType::ProtectedAudioSampleEntry {
3133                     return Err(Error::InvalidData("malformed audio sample entry"));
3134                 }
3135                 let sinf = read_sinf(&mut b)?;
3136                 debug!("{:?} (sinf)", sinf);
3137                 codec_type = CodecType::EncryptedAudio;
3138                 protection_info.push(sinf)?;
3139             }
3140             _ => {
3141                 debug!("Unsupported audio codec, box {:?} found", b.head.name);
3142                 skip_box_content(&mut b)?;
3143             }
3144         }
3145         check_parser_state!(b.content);
3146     }
3147 
3148     Ok(
3149         codec_specific.map_or(SampleEntry::Unknown, |codec_specific| {
3150             SampleEntry::Audio(AudioSampleEntry {
3151                 codec_type,
3152                 data_reference_index,
3153                 channelcount,
3154                 samplesize,
3155                 samplerate,
3156                 codec_specific,
3157                 protection_info,
3158             })
3159         }),
3160     )
3161 }
3162 
3163 /// Parse a stsd box.
read_stsd<T: Read>( src: &mut BMFFBox<T>, track: &mut Track, brand: &FourCC, ) -> Result<SampleDescriptionBox>3164 fn read_stsd<T: Read>(
3165     src: &mut BMFFBox<T>,
3166     track: &mut Track,
3167     brand: &FourCC,
3168 ) -> Result<SampleDescriptionBox> {
3169     let (_, _) = read_fullbox_extra(src)?;
3170 
3171     let description_count = be_u32(src)?;
3172     let mut descriptions = TryVec::new();
3173 
3174     {
3175         let mut iter = src.box_iter();
3176         while let Some(mut b) = iter.next_box()? {
3177             let description = match track.track_type {
3178                 TrackType::Video => read_video_sample_entry(&mut b, brand),
3179                 TrackType::Audio => read_audio_sample_entry(&mut b),
3180                 TrackType::Metadata => Err(Error::Unsupported("metadata track")),
3181                 TrackType::Unknown => Err(Error::Unsupported("unknown track type")),
3182             };
3183             let description = match description {
3184                 Ok(desc) => desc,
3185                 Err(Error::Unsupported(_)) => {
3186                     // read_{audio,video}_desc may have returned Unsupported
3187                     // after partially reading the box content, so we can't
3188                     // simply use skip_box_content here.
3189                     let to_skip = b.bytes_left();
3190                     skip(&mut b, to_skip)?;
3191                     SampleEntry::Unknown
3192                 }
3193                 Err(e) => return Err(e),
3194             };
3195             descriptions.push(description)?;
3196             check_parser_state!(b.content);
3197             if descriptions.len() == description_count.to_usize() {
3198                 break;
3199             }
3200         }
3201     }
3202 
3203     // Padding could be added in some contents.
3204     skip_box_remain(src)?;
3205 
3206     Ok(SampleDescriptionBox { descriptions })
3207 }
3208 
read_sinf<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSchemeInfoBox>3209 fn read_sinf<T: Read>(src: &mut BMFFBox<T>) -> Result<ProtectionSchemeInfoBox> {
3210     let mut sinf = ProtectionSchemeInfoBox::default();
3211 
3212     let mut iter = src.box_iter();
3213     while let Some(mut b) = iter.next_box()? {
3214         match b.head.name {
3215             BoxType::OriginalFormatBox => {
3216                 let frma = read_frma(&mut b)?;
3217                 sinf.code_name = frma;
3218             }
3219             BoxType::SchemeTypeBox => {
3220                 sinf.scheme_type = Some(read_schm(&mut b)?);
3221             }
3222             BoxType::SchemeInformationBox => {
3223                 // We only need tenc box in schi box so far.
3224                 sinf.tenc = read_schi(&mut b)?;
3225             }
3226             _ => skip_box_content(&mut b)?,
3227         }
3228         check_parser_state!(b.content);
3229     }
3230 
3231     Ok(sinf)
3232 }
3233 
read_schi<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TrackEncryptionBox>>3234 fn read_schi<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TrackEncryptionBox>> {
3235     let mut tenc = None;
3236     let mut iter = src.box_iter();
3237     while let Some(mut b) = iter.next_box()? {
3238         match b.head.name {
3239             BoxType::TrackEncryptionBox => {
3240                 if tenc.is_some() {
3241                     return Err(Error::InvalidData(
3242                         "tenc box should be only one at most in sinf box",
3243                     ));
3244                 }
3245                 tenc = Some(read_tenc(&mut b)?);
3246             }
3247             _ => skip_box_content(&mut b)?,
3248         }
3249     }
3250 
3251     Ok(tenc)
3252 }
3253 
read_tenc<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackEncryptionBox>3254 fn read_tenc<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackEncryptionBox> {
3255     let (version, _) = read_fullbox_extra(src)?;
3256 
3257     // reserved byte
3258     skip(src, 1)?;
3259     // the next byte is used to signal the default pattern in version >= 1
3260     let (default_crypt_byte_block, default_skip_byte_block) = match version {
3261         0 => {
3262             skip(src, 1)?;
3263             (None, None)
3264         }
3265         _ => {
3266             let pattern_byte = src.read_u8()?;
3267             let crypt_bytes = pattern_byte >> 4;
3268             let skip_bytes = pattern_byte & 0x0f;
3269             (Some(crypt_bytes), Some(skip_bytes))
3270         }
3271     };
3272     let default_is_encrypted = src.read_u8()?;
3273     let default_iv_size = src.read_u8()?;
3274     let default_kid = read_buf(src, 16)?;
3275     // If default_is_encrypted == 1 && default_iv_size == 0 we expect a default_constant_iv
3276     let default_constant_iv = match (default_is_encrypted, default_iv_size) {
3277         (1, 0) => {
3278             let default_constant_iv_size = src.read_u8()?;
3279             Some(read_buf(src, default_constant_iv_size.into())?)
3280         }
3281         _ => None,
3282     };
3283 
3284     Ok(TrackEncryptionBox {
3285         is_encrypted: default_is_encrypted,
3286         iv_size: default_iv_size,
3287         kid: default_kid,
3288         crypt_byte_block_count: default_crypt_byte_block,
3289         skip_byte_block_count: default_skip_byte_block,
3290         constant_iv: default_constant_iv,
3291     })
3292 }
3293 
read_frma<T: Read>(src: &mut BMFFBox<T>) -> Result<TryString>3294 fn read_frma<T: Read>(src: &mut BMFFBox<T>) -> Result<TryString> {
3295     read_buf(src, 4)
3296 }
3297 
read_schm<T: Read>(src: &mut BMFFBox<T>) -> Result<SchemeTypeBox>3298 fn read_schm<T: Read>(src: &mut BMFFBox<T>) -> Result<SchemeTypeBox> {
3299     // Flags can be used to signal presence of URI in the box, but we don't
3300     // use the URI so don't bother storing the flags.
3301     let (_, _) = read_fullbox_extra(src)?;
3302     let scheme_type = FourCC::from(be_u32(src)?);
3303     let scheme_version = be_u32(src)?;
3304     // Null terminated scheme URI may follow, but we don't use it right now.
3305     skip_box_remain(src)?;
3306     Ok(SchemeTypeBox {
3307         scheme_type,
3308         scheme_version,
3309     })
3310 }
3311 
3312 /// Parse a metadata box inside a moov, trak, or mdia box.
read_udta<T: Read>(src: &mut BMFFBox<T>) -> Result<UserdataBox>3313 fn read_udta<T: Read>(src: &mut BMFFBox<T>) -> Result<UserdataBox> {
3314     let mut iter = src.box_iter();
3315     let mut udta = UserdataBox { meta: None };
3316 
3317     while let Some(mut b) = iter.next_box()? {
3318         match b.head.name {
3319             BoxType::MetadataBox => {
3320                 let meta = read_meta(&mut b)?;
3321                 udta.meta = Some(meta);
3322             }
3323             _ => skip_box_content(&mut b)?,
3324         };
3325         check_parser_state!(b.content);
3326     }
3327     Ok(udta)
3328 }
3329 
3330 /// Parse a metadata box inside a udta box
read_meta<T: Read>(src: &mut BMFFBox<T>) -> Result<MetadataBox>3331 fn read_meta<T: Read>(src: &mut BMFFBox<T>) -> Result<MetadataBox> {
3332     let (_, _) = read_fullbox_extra(src)?;
3333     let mut iter = src.box_iter();
3334     let mut meta = MetadataBox::default();
3335     while let Some(mut b) = iter.next_box()? {
3336         match b.head.name {
3337             BoxType::MetadataItemListEntry => read_ilst(&mut b, &mut meta)?,
3338             _ => skip_box_content(&mut b)?,
3339         };
3340         check_parser_state!(b.content);
3341     }
3342     Ok(meta)
3343 }
3344 
3345 /// Parse a metadata box inside a udta box
read_ilst<T: Read>(src: &mut BMFFBox<T>, meta: &mut MetadataBox) -> Result<()>3346 fn read_ilst<T: Read>(src: &mut BMFFBox<T>, meta: &mut MetadataBox) -> Result<()> {
3347     let mut iter = src.box_iter();
3348     while let Some(mut b) = iter.next_box()? {
3349         match b.head.name {
3350             BoxType::AlbumEntry => meta.album = read_ilst_string_data(&mut b)?,
3351             BoxType::ArtistEntry | BoxType::ArtistLowercaseEntry => {
3352                 meta.artist = read_ilst_string_data(&mut b)?
3353             }
3354             BoxType::AlbumArtistEntry => meta.album_artist = read_ilst_string_data(&mut b)?,
3355             BoxType::CommentEntry => meta.comment = read_ilst_string_data(&mut b)?,
3356             BoxType::DateEntry => meta.year = read_ilst_string_data(&mut b)?,
3357             BoxType::TitleEntry => meta.title = read_ilst_string_data(&mut b)?,
3358             BoxType::CustomGenreEntry => {
3359                 meta.genre = read_ilst_string_data(&mut b)?.map(Genre::CustomGenre)
3360             }
3361             BoxType::StandardGenreEntry => {
3362                 meta.genre = read_ilst_u8_data(&mut b)?
3363                     .and_then(|gnre| Some(Genre::StandardGenre(gnre.get(1).copied()?)))
3364             }
3365             BoxType::ComposerEntry => meta.composer = read_ilst_string_data(&mut b)?,
3366             BoxType::EncoderEntry => meta.encoder = read_ilst_string_data(&mut b)?,
3367             BoxType::EncodedByEntry => meta.encoded_by = read_ilst_string_data(&mut b)?,
3368             BoxType::CopyrightEntry => meta.copyright = read_ilst_string_data(&mut b)?,
3369             BoxType::GroupingEntry => meta.grouping = read_ilst_string_data(&mut b)?,
3370             BoxType::CategoryEntry => meta.category = read_ilst_string_data(&mut b)?,
3371             BoxType::KeywordEntry => meta.keyword = read_ilst_string_data(&mut b)?,
3372             BoxType::PodcastUrlEntry => meta.podcast_url = read_ilst_string_data(&mut b)?,
3373             BoxType::PodcastGuidEntry => meta.podcast_guid = read_ilst_string_data(&mut b)?,
3374             BoxType::DescriptionEntry => meta.description = read_ilst_string_data(&mut b)?,
3375             BoxType::LongDescriptionEntry => meta.long_description = read_ilst_string_data(&mut b)?,
3376             BoxType::LyricsEntry => meta.lyrics = read_ilst_string_data(&mut b)?,
3377             BoxType::TVNetworkNameEntry => meta.tv_network_name = read_ilst_string_data(&mut b)?,
3378             BoxType::TVEpisodeNameEntry => meta.tv_episode_name = read_ilst_string_data(&mut b)?,
3379             BoxType::TVShowNameEntry => meta.tv_show_name = read_ilst_string_data(&mut b)?,
3380             BoxType::PurchaseDateEntry => meta.purchase_date = read_ilst_string_data(&mut b)?,
3381             BoxType::RatingEntry => meta.rating = read_ilst_string_data(&mut b)?,
3382             BoxType::OwnerEntry => meta.owner = read_ilst_string_data(&mut b)?,
3383             BoxType::HDVideoEntry => meta.hd_video = read_ilst_bool_data(&mut b)?,
3384             BoxType::SortNameEntry => meta.sort_name = read_ilst_string_data(&mut b)?,
3385             BoxType::SortArtistEntry => meta.sort_artist = read_ilst_string_data(&mut b)?,
3386             BoxType::SortAlbumEntry => meta.sort_album = read_ilst_string_data(&mut b)?,
3387             BoxType::SortAlbumArtistEntry => {
3388                 meta.sort_album_artist = read_ilst_string_data(&mut b)?
3389             }
3390             BoxType::SortComposerEntry => meta.sort_composer = read_ilst_string_data(&mut b)?,
3391             BoxType::TrackNumberEntry => {
3392                 if let Some(trkn) = read_ilst_u8_data(&mut b)? {
3393                     meta.track_number = trkn.get(3).copied();
3394                     meta.total_tracks = trkn.get(5).copied();
3395                 };
3396             }
3397             BoxType::DiskNumberEntry => {
3398                 if let Some(disk) = read_ilst_u8_data(&mut b)? {
3399                     meta.disc_number = disk.get(3).copied();
3400                     meta.total_discs = disk.get(5).copied();
3401                 };
3402             }
3403             BoxType::TempoEntry => {
3404                 meta.beats_per_minute =
3405                     read_ilst_u8_data(&mut b)?.and_then(|tmpo| tmpo.get(1).copied())
3406             }
3407             BoxType::CompilationEntry => meta.compilation = read_ilst_bool_data(&mut b)?,
3408             BoxType::AdvisoryEntry => {
3409                 meta.advisory = read_ilst_u8_data(&mut b)?.and_then(|rtng| {
3410                     Some(match rtng.get(0)? {
3411                         2 => AdvisoryRating::Clean,
3412                         0 => AdvisoryRating::Inoffensive,
3413                         r => AdvisoryRating::Explicit(*r),
3414                     })
3415                 })
3416             }
3417             BoxType::MediaTypeEntry => {
3418                 meta.media_type = read_ilst_u8_data(&mut b)?.and_then(|stik| {
3419                     Some(match stik.get(0)? {
3420                         0 => MediaType::Movie,
3421                         1 => MediaType::Normal,
3422                         2 => MediaType::AudioBook,
3423                         5 => MediaType::WhackedBookmark,
3424                         6 => MediaType::MusicVideo,
3425                         9 => MediaType::ShortFilm,
3426                         10 => MediaType::TVShow,
3427                         11 => MediaType::Booklet,
3428                         s => MediaType::Unknown(*s),
3429                     })
3430                 })
3431             }
3432             BoxType::PodcastEntry => meta.podcast = read_ilst_bool_data(&mut b)?,
3433             BoxType::TVSeasonNumberEntry => {
3434                 meta.tv_season = read_ilst_u8_data(&mut b)?.and_then(|tvsn| tvsn.get(3).copied())
3435             }
3436             BoxType::TVEpisodeNumberEntry => {
3437                 meta.tv_episode_number =
3438                     read_ilst_u8_data(&mut b)?.and_then(|tves| tves.get(3).copied())
3439             }
3440             BoxType::GaplessPlaybackEntry => meta.gapless_playback = read_ilst_bool_data(&mut b)?,
3441             BoxType::CoverArtEntry => meta.cover_art = read_ilst_multiple_u8_data(&mut b).ok(),
3442             _ => skip_box_content(&mut b)?,
3443         };
3444         check_parser_state!(b.content);
3445     }
3446     Ok(())
3447 }
3448 
read_ilst_bool_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<bool>>3449 fn read_ilst_bool_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<bool>> {
3450     Ok(read_ilst_u8_data(src)?.and_then(|d| Some(d.get(0)? == &1)))
3451 }
3452 
read_ilst_string_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TryString>>3453 fn read_ilst_string_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TryString>> {
3454     read_ilst_u8_data(src)
3455 }
3456 
read_ilst_u8_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TryVec<u8>>>3457 fn read_ilst_u8_data<T: Read>(src: &mut BMFFBox<T>) -> Result<Option<TryVec<u8>>> {
3458     // For all non-covr atoms, there must only be one data atom.
3459     Ok(read_ilst_multiple_u8_data(src)?.pop())
3460 }
3461 
read_ilst_multiple_u8_data<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<TryVec<u8>>>3462 fn read_ilst_multiple_u8_data<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<TryVec<u8>>> {
3463     let mut iter = src.box_iter();
3464     let mut data = TryVec::new();
3465     while let Some(mut b) = iter.next_box()? {
3466         match b.head.name {
3467             BoxType::MetadataItemDataEntry => {
3468                 data.push(read_ilst_data(&mut b)?)?;
3469             }
3470             _ => skip_box_content(&mut b)?,
3471         };
3472         check_parser_state!(b.content);
3473     }
3474     Ok(data)
3475 }
3476 
read_ilst_data<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<u8>>3477 fn read_ilst_data<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<u8>> {
3478     // Skip past the padding bytes
3479     skip(&mut src.content, src.head.offset)?;
3480     let size = src.content.limit();
3481     read_buf(&mut src.content, size)
3482 }
3483 
3484 /// Skip a number of bytes that we don't care to parse.
skip<T: Read>(src: &mut T, bytes: u64) -> Result<()>3485 fn skip<T: Read>(src: &mut T, bytes: u64) -> Result<()> {
3486     std::io::copy(&mut src.take(bytes), &mut std::io::sink())?;
3487     Ok(())
3488 }
3489 
3490 /// Read size bytes into a Vector or return error.
read_buf<T: Read>(src: &mut T, size: u64) -> Result<TryVec<u8>>3491 fn read_buf<T: Read>(src: &mut T, size: u64) -> Result<TryVec<u8>> {
3492     if size > BUF_SIZE_LIMIT {
3493         return Err(Error::InvalidData("read_buf size exceeds BUF_SIZE_LIMIT"));
3494     }
3495 
3496     let buf = src.take(size).read_into_try_vec()?;
3497     if buf.len().to_u64() != size {
3498         return Err(Error::InvalidData("failed buffer read"));
3499     }
3500 
3501     Ok(buf)
3502 }
3503 
be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16>3504 fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> {
3505     src.read_i16::<byteorder::BigEndian>().map_err(From::from)
3506 }
3507 
be_i32<T: ReadBytesExt>(src: &mut T) -> Result<i32>3508 fn be_i32<T: ReadBytesExt>(src: &mut T) -> Result<i32> {
3509     src.read_i32::<byteorder::BigEndian>().map_err(From::from)
3510 }
3511 
be_i64<T: ReadBytesExt>(src: &mut T) -> Result<i64>3512 fn be_i64<T: ReadBytesExt>(src: &mut T) -> Result<i64> {
3513     src.read_i64::<byteorder::BigEndian>().map_err(From::from)
3514 }
3515 
be_u16<T: ReadBytesExt>(src: &mut T) -> Result<u16>3516 fn be_u16<T: ReadBytesExt>(src: &mut T) -> Result<u16> {
3517     src.read_u16::<byteorder::BigEndian>().map_err(From::from)
3518 }
3519 
be_u24<T: ReadBytesExt>(src: &mut T) -> Result<u32>3520 fn be_u24<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
3521     src.read_u24::<byteorder::BigEndian>().map_err(From::from)
3522 }
3523 
be_u32<T: ReadBytesExt>(src: &mut T) -> Result<u32>3524 fn be_u32<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
3525     src.read_u32::<byteorder::BigEndian>().map_err(From::from)
3526 }
3527 
3528 /// Using in reading table size and return error if it exceeds limitation.
be_u32_with_limit<T: ReadBytesExt>(src: &mut T) -> Result<u32>3529 fn be_u32_with_limit<T: ReadBytesExt>(src: &mut T) -> Result<u32> {
3530     be_u32(src).and_then(|v| {
3531         if v > TABLE_SIZE_LIMIT {
3532             return Err(Error::OutOfMemory);
3533         }
3534         Ok(v)
3535     })
3536 }
3537 
be_u64<T: ReadBytesExt>(src: &mut T) -> Result<u64>3538 fn be_u64<T: ReadBytesExt>(src: &mut T) -> Result<u64> {
3539     src.read_u64::<byteorder::BigEndian>().map_err(From::from)
3540 }
3541 
write_be_u32<T: WriteBytesExt>(des: &mut T, num: u32) -> Result<()>3542 fn write_be_u32<T: WriteBytesExt>(des: &mut T, num: u32) -> Result<()> {
3543     des.write_u32::<byteorder::BigEndian>(num)
3544         .map_err(From::from)
3545 }
3546