diff --git a/mp4parse/src/lib.rs b/mp4parse/src/lib.rs index d9c6273c..1b96679b 100644 --- a/mp4parse/src/lib.rs +++ b/mp4parse/src/lib.rs @@ -956,6 +956,8 @@ impl FileTypeBox { /// Movie header box 'mvhd'. #[derive(Debug)] struct MovieHeaderBox { + creation: u64, + modification: u64, pub timescale: u32, #[allow(dead_code)] // See https://github.com/mozilla/mp4parse-rust/issues/340 duration: u64, @@ -1503,9 +1505,14 @@ pub enum XmlBox { BinaryXmlBox(TryVec), } +#[derive(Debug)] +pub struct UtcSecondsSince1904(pub u64); + /// Internal data structures. #[derive(Debug, Default)] pub struct MediaContext { + pub creation: Option, + pub modification: Option, pub timescale: Option, /// Tracks found in the file. pub tracks: TryVec, @@ -4115,16 +4122,12 @@ pub fn read_mp4(f: &mut T) -> Result { context.ok_or(Error::MoovMissing) } -/// Parse a Movie Header Box -/// See ISOBMFF (ISO 14496-12:2020) ยง 8.2.2 -fn parse_mvhd(f: &mut BMFFBox) -> Result> { - let mvhd = read_mvhd(f)?; - debug!("{:?}", mvhd); +fn validate_timescale(mvhd: &MovieHeaderBox) -> Result> { if mvhd.timescale == 0 { - return Status::MvhdBadTimescale.into(); + Err(Error::InvalidData(Status::MdhdBadTimescale)) + } else { + Ok(Some(MediaTimeScale(u64::from(mvhd.timescale)))) } - let timescale = Some(MediaTimeScale(u64::from(mvhd.timescale))); - Ok(timescale) } /// Parse a Movie Box @@ -4134,6 +4137,8 @@ fn parse_mvhd(f: &mut BMFFBox) -> Result> { /// such as with tests/test_case_1185230.mp4. fn read_moov(f: &mut BMFFBox, context: Option) -> Result { let MediaContext { + mut creation, + mut modification, mut timescale, mut tracks, mut mvex, @@ -4147,7 +4152,11 @@ fn read_moov(f: &mut BMFFBox, context: Option) -> Resu while let Some(mut b) = iter.next_box()? { match b.head.name { BoxType::MovieHeaderBox => { - timescale = parse_mvhd(&mut b)?; + let mvhd = read_mvhd(&mut b)?; + debug!("{:?}", mvhd); + creation = Some(UtcSecondsSince1904(mvhd.creation)); + modification = Some(UtcSecondsSince1904(mvhd.modification)); + timescale = validate_timescale(&mvhd)?; } BoxType::TrackBox => { let mut track = Track::new(tracks.len()); @@ -4178,6 +4187,8 @@ fn read_moov(f: &mut BMFFBox, context: Option) -> Resu } Ok(MediaContext { + creation, + modification, timescale, tracks, mvex, @@ -4490,28 +4501,32 @@ fn read_ftyp(src: &mut BMFFBox) -> Result { /// Parse an mvhd box. fn read_mvhd(src: &mut BMFFBox) -> Result { let (version, _) = read_fullbox_extra(src)?; + let to_u64 = |n| { + if n == std::u32::MAX { + std::u64::MAX + } else { + u64::from(n) + } + }; + let creation; + let modification; match version { // 64 bit creation and modification times. 1 => { - skip(src, 16)?; + creation = be_u64(src)?; + modification = be_u64(src)?; } // 32 bit creation and modification times. 0 => { - skip(src, 8)?; + creation = to_u64(be_u32(src)?); + modification = to_u64(be_u32(src)?); } _ => return Status::MvhdBadVersion.into(), } let timescale = be_u32(src)?; let duration = match version { 1 => be_u64(src)?, - 0 => { - let d = be_u32(src)?; - if d == u32::MAX { - u64::MAX - } else { - u64::from(d) - } - } + 0 => to_u64(be_u32(src)?), _ => unreachable!("Should have returned Status::MvhdBadVersion"), }; // Skip remaining valid fields. @@ -4520,6 +4535,8 @@ fn read_mvhd(src: &mut BMFFBox) -> Result { // Padding could be added in some contents. skip_box_remain(src)?; Ok(MovieHeaderBox { + creation, + modification, timescale, duration, }) diff --git a/mp4parse/src/tests.rs b/mp4parse/src/tests.rs index 964d4f77..bf98ca95 100644 --- a/mp4parse/src/tests.rs +++ b/mp4parse/src/tests.rs @@ -401,7 +401,7 @@ fn read_mvhd_invalid_timescale() { let mut stream = iter.next_box().unwrap().unwrap(); assert_eq!(stream.head.name, BoxType::MovieHeaderBox); assert_eq!(stream.head.size, 120); - let r = super::parse_mvhd(&mut stream); + let r = super::validate_timescale(&super::read_mvhd(&mut stream).unwrap()); assert!(r.is_err()); }