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