use std::env; use std::fs::File; use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::Path; use mp4::{Mp4Box, Result}; fn main() { let args: Vec = env::args().collect(); if args.len() < 2 { println!("Usage: mp4dump "); std::process::exit(1); } if let Err(err) = dump(&args[1]) { let _ = writeln!(io::stderr(), "{}", err); } } fn dump>(filename: &P) -> Result<()> { let f = File::open(filename)?; let boxes = get_boxes(f)?; // print out boxes for b in boxes.iter() { println!("[{}] size={} {}", b.name, b.size, b.summary); } Ok(()) } #[derive(Debug, Clone, PartialEq, Default)] pub struct Box { name: String, size: u64, summary: String, indent: u32, } fn get_boxes(file: File) -> Result> { let size = file.metadata()?.len(); let reader = BufReader::new(file); let mp4 = mp4::Mp4Reader::read_header(reader, size)?; // collect known boxes let mut boxes = vec![ build_box(&mp4.ftyp), build_box(&mp4.moov), build_box(&mp4.moov.mvhd), ]; if let Some(ref mvex) = &mp4.moov.mvex { boxes.push(build_box(mvex)); if let Some(mehd) = &mvex.mehd { boxes.push(build_box(mehd)); } boxes.push(build_box(&mvex.trex)); } // trak. for track in mp4.tracks().values() { boxes.push(build_box(&track.trak)); boxes.push(build_box(&track.trak.tkhd)); if let Some(ref edts) = track.trak.edts { boxes.push(build_box(edts)); if let Some(ref elst) = edts.elst { boxes.push(build_box(elst)); } } // trak.mdia let mdia = &track.trak.mdia; boxes.push(build_box(mdia)); boxes.push(build_box(&mdia.mdhd)); boxes.push(build_box(&mdia.hdlr)); boxes.push(build_box(&track.trak.mdia.minf)); // trak.mdia.minf let minf = &track.trak.mdia.minf; if let Some(ref vmhd) = &minf.vmhd { boxes.push(build_box(vmhd)); } if let Some(ref smhd) = &minf.smhd { boxes.push(build_box(smhd)); } // trak.mdia.minf.stbl let stbl = &track.trak.mdia.minf.stbl; boxes.push(build_box(stbl)); boxes.push(build_box(&stbl.stsd)); if let Some(ref avc1) = &stbl.stsd.avc1 { boxes.push(build_box(avc1)); } if let Some(ref hev1) = &stbl.stsd.hev1 { boxes.push(build_box(hev1)); } if let Some(ref mp4a) = &stbl.stsd.mp4a { boxes.push(build_box(mp4a)); } boxes.push(build_box(&stbl.stts)); if let Some(ref ctts) = &stbl.ctts { boxes.push(build_box(ctts)); } if let Some(ref stss) = &stbl.stss { boxes.push(build_box(stss)); } boxes.push(build_box(&stbl.stsc)); boxes.push(build_box(&stbl.stsz)); if let Some(ref stco) = &stbl.stco { boxes.push(build_box(stco)); } if let Some(ref co64) = &stbl.co64 { boxes.push(build_box(co64)); } } // If fragmented, add moof boxes. for moof in mp4.moofs.iter() { boxes.push(build_box(moof)); boxes.push(build_box(&moof.mfhd)); for traf in moof.trafs.iter() { boxes.push(build_box(traf)); boxes.push(build_box(&traf.tfhd)); if let Some(ref trun) = &traf.trun { boxes.push(build_box(trun)); } } } Ok(boxes) } fn build_box(m: &M) -> Box { Box { name: m.box_type().to_string(), size: m.box_size(), summary: m.summary().unwrap(), indent: 0, } }