From 56e49bea57792bb3073d2d25449971d9073e0305 Mon Sep 17 00:00:00 2001 From: Alf Date: Sun, 19 Jan 2020 23:17:03 -0800 Subject: [PATCH] mdia/mdhd/hdlr box parsing. --- src/lib.rs | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 169 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 13711b5..8397044 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ use std::io::{BufReader, Read, SeekFrom}; use std::fs::File; use std::fmt; use std::convert::TryInto; +use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; use byteorder::{ReadBytesExt, BigEndian}; const HEADER_SIZE: u32 = 8; @@ -79,6 +80,7 @@ struct MvhdBox { struct TrakBox { tkhd: Option, edts: Option, + mdia: Option, } impl TrakBox { @@ -148,6 +150,50 @@ struct ElstEntry { media_rate_fraction: u16, } +#[derive(Debug, Default)] +struct MdiaBox { + mdhd: Option, + hdlr: Option, +} + +impl MdiaBox { + fn new() -> MdiaBox { + Default::default() + } +} + +#[derive(Debug, Default)] +struct MdhdBox { + version: u8, + flags: u32, + creation_time: u32, + modification_time: u32, + timescale: u32, + duration: u32, + language: u16, + language_string: String, +} + +impl MdhdBox { + fn new() -> MdhdBox { + Default::default() + } +} + +#[derive(Debug, Default)] +struct HdlrBox { + version: u8, + flags: u32, + handler_type: FourCC, + name: String, +} + +impl HdlrBox { + fn new() -> HdlrBox { + Default::default() + } +} + #[derive(Default, PartialEq, Clone)] pub struct FourCC { @@ -220,7 +266,7 @@ fn read_boxes(f: File) -> Result { start = (size as u32 - HEADER_SIZE) as u64; } "moov" => { - start = (size as u32 - HEADER_SIZE) as u64; +// start = (size as u32 - HEADER_SIZE) as u64; let moov = parse_moov_box(&mut reader, 0, size as u32).unwrap(); bmff.moov = Some(moov); } @@ -382,7 +428,9 @@ fn parse_trak_box(f: &mut BufReader, _offset: u64, size: u32) -> Result { println!("found mdia"); - start = (s as u32 - HEADER_SIZE) as u64; + let mdia = parse_mdia_box(f, 0, s as u32).unwrap(); + trak.mdia = Some(mdia); +// start = (s as u32 - HEADER_SIZE) as u64; } _ => break } @@ -482,6 +530,7 @@ fn parse_edts_box(f: &mut BufReader, _offset: u64, size: u32) -> Result, _offset: u64, size: u32) -> Result { let current = f.seek(SeekFrom::Current(0)).unwrap(); // Current cursor position. @@ -511,3 +560,121 @@ fn parse_elst_box(f: &mut BufReader, _offset: u64, size: u32) -> Result, _offset: u64, size: u32) -> Result { + let current = f.seek(SeekFrom::Current(0)).unwrap(); // Current cursor position. + let mut mdia = MdiaBox::new(); + + let mut start = 0u64; + while start < size as u64 { + // Get box header. + let header = read_box_header(f, start).unwrap(); + let BoxHeader{ name, size: s, offset } = header; + + let mut b = BMFFBox::new(); + b.head = BoxHeader{ + name: name.try_into().unwrap(), + size: s as u64, + offset: offset as u64, + }; + + match b.head.name.as_ref() { + "mdhd" => { + let mdhd = parse_mdhd_box(f, 0, s as u32).unwrap(); + mdia.mdhd = Some(mdhd); + } + "hdlr" => { + let hdlr = parse_hdlr_box(f, 0, s as u32).unwrap(); + mdia.hdlr = Some(hdlr); + } + _ => break + } + } + + // Skip remaining bytes. + let after = f.seek(SeekFrom::Current(0)).unwrap(); + let remaining_bytes = (size as u64 - (after - current)) as i64; + f.seek(SeekFrom::Current(remaining_bytes - HEADER_SIZE as i64)).unwrap(); + Ok(mdia) +} + +fn parse_mdhd_box(f: &mut BufReader, _offset: u64, size: u32) -> Result { + let current = f.seek(SeekFrom::Current(0)).unwrap(); // Current cursor position. + + let version = f.read_u8().unwrap(); + let flags_a = f.read_u8().unwrap(); + let flags_b = f.read_u8().unwrap(); + let flags_c = f.read_u8().unwrap(); + let flags = u32::from(flags_a) << 16 | u32::from(flags_b) << 8 | u32::from(flags_c); + let creation_time = f.read_u32::().unwrap(); + let modification_time = f.read_u32::().unwrap(); + let timescale = f.read_u32::().unwrap(); + let duration = f.read_u32::().unwrap(); + let language = f.read_u16::().unwrap(); + let language_string = get_language_string(language); + + // Skip remaining bytes. + let after = f.seek(SeekFrom::Current(0)).unwrap(); + let remaining_bytes = (size as u64 - (after - current)) as i64; + f.seek(SeekFrom::Current(remaining_bytes - HEADER_SIZE as i64)).unwrap(); + + Ok(MdhdBox { + version, + flags, + creation_time, + modification_time, + timescale, + duration, + language, + language_string, + }) +} + +fn get_language_string(language: u16) -> String { + let mut lang: [u16; 3] = [0; 3]; + + lang[0] = ((language >> 10) & 0x1F) + 0x60; + lang[1] = ((language >> 5) & 0x1F) + 0x60; + lang[2] = ((language) & 0x1F) + 0x60; + + // Decode utf-16 encoded bytes into a string. + let lang_str = decode_utf16(lang.iter().cloned()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::(); + + return lang_str; +} + +fn parse_hdlr_box(f: &mut BufReader, _offset: u64, size: u32) -> Result { + let current = f.seek(SeekFrom::Current(0)).unwrap(); // Current cursor position. + + let version = f.read_u8().unwrap(); + let flags_a = f.read_u8().unwrap(); + let flags_b = f.read_u8().unwrap(); + let flags_c = f.read_u8().unwrap(); + let flags = u32::from(flags_a) << 16 | u32::from(flags_b) << 8 | u32::from(flags_c); + f.read_u32::().unwrap(); // skip. + let handler = f.read_u32::().unwrap(); + + let n = f.seek(SeekFrom::Current(12)).unwrap(); // 12 bytes reserved. + let buf_size = (size as u64 - (n - current)) - HEADER_SIZE as u64; + let mut buf = vec![0u8; buf_size as usize]; + f.read_exact(&mut buf).unwrap(); + + let handler_string = match String::from_utf8(buf) { + Ok(t) => t, + _ => String::from("null"), + }; + + // Skip remaining bytes. + let after = f.seek(SeekFrom::Current(0)).unwrap(); + let remaining_bytes = (size as u64 - (after - current)) as i64; + f.seek(SeekFrom::Current(remaining_bytes - HEADER_SIZE as i64)).unwrap(); + + Ok(HdlrBox { + version, + flags, + handler_type: From::from(handler), + name: handler_string, + }) +}