From 958304a9b265cdda627300ea021f94a9a06555db Mon Sep 17 00:00:00 2001 From: Nathan Fiedler Date: Thu, 4 Jun 2020 23:10:33 -0700 Subject: [PATCH] Make the example tolerant of videos missing parts (#5) * Make the example tolerant of videos missing parts Some videos are missing certain parts that the example was assuming would be present. This change makes all such access conditional on the parts being present. Also added the display of the box version and the creation time in a human-readable format. This serves to demonstrate the logic for converting the MP4 epoch (1904-01-01) to Unix epoch (1970-01-01). * Show creation time as Unix time only --- examples/mp4info.rs | 84 ++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/examples/mp4info.rs b/examples/mp4info.rs index bd21737..65f3cda 100644 --- a/examples/mp4info.rs +++ b/examples/mp4info.rs @@ -1,8 +1,8 @@ extern crate mp4; +use mp4::TrackType; use std::env; use std::fs::File; -use mp4::{TrackType}; fn main() { let args: Vec = env::args().collect(); @@ -17,44 +17,71 @@ fn main() { // Print results. println!("File:"); - println!(" file size: {}", bmff.size); - println!(" brands: {:?} {:?}\n", bmff.ftyp.major_brand, bmff.ftyp.compatible_brands); + println!(" file size: {}", bmff.size); + println!( + " brands: {:?} {:?}\n", + bmff.ftyp.major_brand, bmff.ftyp.compatible_brands + ); println!("Movie:"); - println!(" duration: {:?}", moov.mvhd.duration); - println!(" timescale: {:?}\n", moov.mvhd.timescale); + println!(" version: {:?}", moov.mvhd.version); + println!( + " creation time: {}", + creation_time(moov.mvhd.creation_time) + ); + println!(" duration: {:?}", moov.mvhd.duration); + println!(" timescale: {:?}\n", moov.mvhd.timescale); println!("Found {} Tracks", moov.traks.len()); for trak in moov.traks.iter() { let tkhd = trak.tkhd.as_ref().unwrap(); - let mdia = trak.mdia.as_ref().unwrap(); - let hdlr = mdia.hdlr.as_ref().unwrap(); - let mdhd = mdia.mdhd.as_ref().unwrap(); - let stts= mdia.minf.as_ref().unwrap() - .stbl.as_ref().unwrap() - .stts.as_ref().unwrap(); - println!("Track: {:?}", tkhd.track_id); println!(" flags: {:?}", tkhd.flags); println!(" id: {:?}", tkhd.track_id); - println!(" type: {:?}", get_handler_type(hdlr.handler_type.value.as_ref())); println!(" duration: {:?}", tkhd.duration); - println!(" language: {:?}", mdhd.language_string); - - println!(" media:"); - println!(" sample count: {:?}", stts.sample_counts[0]); - println!(" timescale: {:?}", mdhd.timescale); - println!(" duration: {:?} (media timescale units)", mdhd.duration); - println!(" duration: {:?} (ms)", get_duration_ms(mdhd.duration, mdhd.timescale)); if tkhd.width != 0 && tkhd.height != 0 { println!(" width: {:?}", tkhd.width); println!(" height: {:?}", tkhd.height); } - if get_handler_type(hdlr.handler_type.value.as_ref()) == TrackType::Video { - println!(" frame rate: (computed): {:?}", get_framerate(&stts.sample_counts, mdhd.duration, mdhd.timescale)); + if let Some(ref mdia) = trak.mdia { + let hdlr = mdia.hdlr.as_ref().unwrap(); + let mdhd = mdia.mdhd.as_ref().unwrap(); + let stts = mdia + .minf + .as_ref() + .map(|m| m.stbl.as_ref().map(|s| s.stts.as_ref()).flatten()) + .flatten(); + + println!( + " type: {:?}", + get_handler_type(hdlr.handler_type.value.as_ref()) + ); + println!(" language: {:?}", mdhd.language_string); + + println!(" media:"); + if let Some(ref s) = stts { + println!(" sample count: {:?}", s.sample_counts[0]); + } + println!(" timescale: {:?}", mdhd.timescale); + println!( + " duration: {:?} (media timescale units)", + mdhd.duration + ); + println!( + " duration: {:?} (ms)", + get_duration_ms(mdhd.duration, mdhd.timescale) + ); + if get_handler_type(hdlr.handler_type.value.as_ref()) == TrackType::Video { + if let Some(ref s) = stts { + println!( + " frame rate: (computed): {:?}", + get_framerate(&s.sample_counts, mdhd.duration, mdhd.timescale) + ); + } + } } } - }, + } _ => { println!("Usage: mp4info "); } @@ -81,4 +108,13 @@ fn get_framerate(sample_counts: &Vec, duration: u32, timescale: u32) -> Str let sc = (sample_counts[0] as f64) * 1000.0; let ms = (duration as f64 / timescale as f64) * 1000.0; return format!("{:.2}", sc / ms.floor()); -} \ No newline at end of file +} + +fn creation_time(creation_time: u32) -> u32 { + // convert from MP4 epoch (1904-01-01) to Unix epoch (1970-01-01) + if creation_time >= 2082844800 { + creation_time - 2082844800 + } else { + creation_time + } +}