1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-12-22 12:06:33 +00:00

mdia/mdhd/hdlr box parsing.

This commit is contained in:
Alf 2020-01-19 23:17:03 -08:00
parent b50097b784
commit 56e49bea57

View file

@ -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<TkhdBox>,
edts: Option<EdtsBox>,
mdia: Option<MdiaBox>,
}
impl TrakBox {
@ -148,6 +150,50 @@ struct ElstEntry {
media_rate_fraction: u16,
}
#[derive(Debug, Default)]
struct MdiaBox {
mdhd: Option<MdhdBox>,
hdlr: Option<HdlrBox>,
}
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<BMFF> {
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<File>, _offset: u64, size: u32) -> Result<Tr
}
"mdia" => {
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<File>, _offset: u64, size: u32) -> Result<Ed
f.seek(SeekFrom::Current(remaining_bytes - HEADER_SIZE as i64)).unwrap();
Ok(edts)
}
fn parse_elst_box(f: &mut BufReader<File>, _offset: u64, size: u32) -> Result<ElstBox> {
let current = f.seek(SeekFrom::Current(0)).unwrap(); // Current cursor position.
@ -511,3 +560,121 @@ fn parse_elst_box(f: &mut BufReader<File>, _offset: u64, size: u32) -> Result<El
entries,
})
}
fn parse_mdia_box(f: &mut BufReader<File>, _offset: u64, size: u32) -> Result<MdiaBox> {
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<File>, _offset: u64, size: u32) -> Result<MdhdBox> {
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::<byteorder::BigEndian>().unwrap();
let modification_time = f.read_u32::<byteorder::BigEndian>().unwrap();
let timescale = f.read_u32::<byteorder::BigEndian>().unwrap();
let duration = f.read_u32::<byteorder::BigEndian>().unwrap();
let language = f.read_u16::<byteorder::BigEndian>().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::<String>();
return lang_str;
}
fn parse_hdlr_box(f: &mut BufReader<File>, _offset: u64, size: u32) -> Result<HdlrBox> {
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::<byteorder::BigEndian>().unwrap(); // skip.
let handler = f.read_u32::<byteorder::BigEndian>().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,
})
}