mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-12-31 15:48:39 +00:00
mdia/mdhd/hdlr box parsing.
This commit is contained in:
parent
b50097b784
commit
56e49bea57
1 changed files with 169 additions and 2 deletions
171
src/lib.rs
171
src/lib.rs
|
@ -5,6 +5,7 @@ use std::io::{BufReader, Read, SeekFrom};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
|
||||||
use byteorder::{ReadBytesExt, BigEndian};
|
use byteorder::{ReadBytesExt, BigEndian};
|
||||||
|
|
||||||
const HEADER_SIZE: u32 = 8;
|
const HEADER_SIZE: u32 = 8;
|
||||||
|
@ -79,6 +80,7 @@ struct MvhdBox {
|
||||||
struct TrakBox {
|
struct TrakBox {
|
||||||
tkhd: Option<TkhdBox>,
|
tkhd: Option<TkhdBox>,
|
||||||
edts: Option<EdtsBox>,
|
edts: Option<EdtsBox>,
|
||||||
|
mdia: Option<MdiaBox>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrakBox {
|
impl TrakBox {
|
||||||
|
@ -148,6 +150,50 @@ struct ElstEntry {
|
||||||
media_rate_fraction: u16,
|
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)]
|
#[derive(Default, PartialEq, Clone)]
|
||||||
pub struct FourCC {
|
pub struct FourCC {
|
||||||
|
@ -220,7 +266,7 @@ fn read_boxes(f: File) -> Result<BMFF> {
|
||||||
start = (size as u32 - HEADER_SIZE) as u64;
|
start = (size as u32 - HEADER_SIZE) as u64;
|
||||||
}
|
}
|
||||||
"moov" => {
|
"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();
|
let moov = parse_moov_box(&mut reader, 0, size as u32).unwrap();
|
||||||
bmff.moov = Some(moov);
|
bmff.moov = Some(moov);
|
||||||
}
|
}
|
||||||
|
@ -382,7 +428,9 @@ fn parse_trak_box(f: &mut BufReader<File>, _offset: u64, size: u32) -> Result<Tr
|
||||||
}
|
}
|
||||||
"mdia" => {
|
"mdia" => {
|
||||||
println!("found 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
|
_ => 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();
|
f.seek(SeekFrom::Current(remaining_bytes - HEADER_SIZE as i64)).unwrap();
|
||||||
Ok(edts)
|
Ok(edts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_elst_box(f: &mut BufReader<File>, _offset: u64, size: u32) -> Result<ElstBox> {
|
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.
|
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,
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue