From 358b69f450b6fc3d94d1f213e71b365cfd1d6234 Mon Sep 17 00:00:00 2001 From: Muaz Ahmad Date: Thu, 19 Oct 2023 16:41:29 +0500 Subject: [PATCH] most atoms now have binary marshalling --- src/muxer/hls/mp4/atoms.rs | 174 +++++++++++++++++++++++++++++++++- src/muxer/hls/mp4/mp4muxer.rs | 2 + src/util/mod.rs | 4 + 3 files changed, 176 insertions(+), 4 deletions(-) diff --git a/src/muxer/hls/mp4/atoms.rs b/src/muxer/hls/mp4/atoms.rs index 640c71a..61dc0f9 100644 --- a/src/muxer/hls/mp4/atoms.rs +++ b/src/muxer/hls/mp4/atoms.rs @@ -1,10 +1,10 @@ use std::sync::Arc; +use std::io::Write; +use std::fs::File; use crate::util; -trait MP4Atom { - fn size(&self) -> u32; - +pub trait MP4Atom { fn marshall(&self) -> Vec; } @@ -20,6 +20,22 @@ struct WindowMatrix { w: u32, } +impl MP4Atom for WindowMatrix { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.extend_from_slice(&self.a.to_be_bytes()); + content.extend_from_slice(&self.b.to_be_bytes()); + content.extend_from_slice(&self.u.to_be_bytes()); + content.extend_from_slice(&self.c.to_be_bytes()); + content.extend_from_slice(&self.d.to_be_bytes()); + content.extend_from_slice(&self.v.to_be_bytes()); + content.extend_from_slice(&self.x.to_be_bytes()); + content.extend_from_slice(&self.y.to_be_bytes()); + content.extend_from_slice(&self.w.to_be_bytes()); + return content; + } +} + impl Default for WindowMatrix { fn default() -> Self { WindowMatrix { @@ -37,14 +53,31 @@ impl Default for WindowMatrix { } struct Edits { + long_version: bool, duration: u64, - start: i64, + start: u64, play_rate: u32, } +impl MP4Atom for Edits { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + if self.long_version { + content.extend_from_slice(&self.duration.to_be_bytes()); + content.extend_from_slice(&self.start.to_be_bytes()); + } else { + content.extend_from_slice(&(self.duration as u32).to_be_bytes()); + content.extend_from_slice(&(self.start as u32).to_be_bytes()); + } + content.extend_from_slice(&self.play_rate.to_be_bytes()); + return content; + } +} + impl Default for Edits { fn default() -> Self { Edits { + long_version: false, duration: 0, start: 0, play_rate: 1 << 16, @@ -58,6 +91,16 @@ pub struct MOOV { mvex: MVEX, } +impl MP4Atom for MOOV { + fn marshall(&self) -> Vec { + let mut out = self.mvhd.marshall(); + out.append(&mut self.traks[0].marshall()); + out.append(&mut self.traks[1].marshall()); + out.append(&mut self.mvex.marshall()); + make_box(out, *b"moov") + } +} + struct MVHD { version: u8, flags: u32, @@ -71,6 +114,34 @@ struct MVHD { next_track_id: u32, } +impl MP4Atom for MVHD { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.push(self.version); + content.extend_from_slice(&self.flags.to_be_bytes()[1..]); + if self.version == 1 { + content.extend_from_slice(&self.create_time.to_be_bytes()); + content.extend_from_slice(&self.modify_time.to_be_bytes()); + } else { + content.extend_from_slice(&(self.create_time as u32).to_be_bytes()); + content.extend_from_slice(&(self.modify_time as u32).to_be_bytes()); + } + content.extend_from_slice(&self.time_scale.to_be_bytes()); + if self.version == 1 { + content.extend_from_slice(&self.duration.to_be_bytes()); + } else { + content.extend_from_slice(&(self.duration as u32).to_be_bytes()); + } + content.extend_from_slice(&self.playrate.to_be_bytes()); + content.extend_from_slice(&self.volume.to_be_bytes()); + content.append(&mut util::blank_vec(10)); + content.append(&mut self.matrix.marshall()); + content.append(&mut util::blank_vec(24)); + content.extend_from_slice(&self.next_track_id.to_be_bytes()); + make_box(content, *b"mvhd") + } +} + impl Default for MVHD { fn default() -> Self { MVHD { @@ -94,6 +165,15 @@ struct TRAK { mdia: MDIA, } +impl MP4Atom for TRAK { + fn marshall(&self) -> Vec { + let mut content = self.tkhd.marshall(); + content.append(&mut self.edts.marshall()); + content.append(&mut self.mdia.marshall()); + make_box(content, *b"trak") + } +} + struct TKHD { version: u8, flags: u32, @@ -109,6 +189,37 @@ struct TKHD { height: u32, } +impl MP4Atom for TKHD { + fn marshall(&self) -> Vec { + let content = Vec::new(); + content.push(self.version); + content.extend_from_slice(&self.flags.to_be_bytes()[1..]); + if self.version == 1 { + content.extend_from_slice(&self.create_time.to_be_bytes()); + content.extend_from_slice(&self.modify_time.to_be_bytes()); + } else { + content.extend_from_slice(&(self.create_time as u32).to_be_bytes()); + content.extend_from_slice(&(self.modify_time as u32).to_be_bytes()); + } + content.extend_from_slice(&self.track_id.to_be_bytes()); + content.append(&mut util::blank_vec(8)); + if self.version == 1 { + content.extend_from_slice(&self.duration.to_be_bytes()); + } else { + content.extend_from_slice(&(self.duration as u32).to_be_bytes()); + } + content.append(&mut util::blank_vec(4)); + content.extend_from_slice(&self.layer.to_be_bytes()); + content.extend_from_slice(&self.alt_group.to_be_bytes()); + content.extend_from_slice(&self.volume.to_be_bytes()); + content.append(&mut util::blank_vec(2)); + content.append(&mut self.matrix.marshall()); + content.extend_from_slice(&self.width.to_be_bytes()); + content.extend_from_slice(&self.height.to_be_bytes()); + make_box(content, *b"tkhd") + } +} + impl Default for TKHD { fn default() -> Self { TKHD { @@ -132,6 +243,12 @@ struct EDTS { elst: ELST, } +impl MP4Atom for EDTS { + fn marshall(&self) -> Vec { + make_box(self.elst.marshall(), *b"edts") + } +} + impl Default for EDTS { fn default() -> Self { EDTS {elst: ELST {..Default::default()}} @@ -145,6 +262,19 @@ struct ELST { edits: Vec, } +impl MP4Atom for ELST { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.push(self.version); + content.extend_from_slice(&self.flags.to_be_bytes()[1..]); + content.extend_from_slice(&self.num_edits.to_be_bytes()); + for edit in self.edits { + content.append(&mut edit.marshall()); + } + make_box(content, *b"elst") + } +} + impl Default for ELST { fn default() -> Self { ELST { @@ -440,6 +570,14 @@ struct MVEX { trexs: [TREX; 2], } +impl MP4Atom for MVEX { + fn marshall(&self) -> Vec { + let mut content = self.trexs[0].marshall(); + content.append(&mut self.trexs[1].marshall()); + make_box(content, *b"mvex") + } +} + impl Default for MVEX { fn default() -> Self { MVEX { @@ -458,6 +596,20 @@ struct TREX { default_flags: u32, } +impl MP4Atom for TREX { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.push(self.version); + content.extend_from_slice(&self.flags.to_be_bytes()[1..]); + content.extend_from_slice(&self.track_id.to_be_bytes()); + content.extend_from_slice(&self.default_desc_idx.to_be_bytes()); + content.extend_from_slice(&self.default_duration.to_be_bytes()); + content.extend_from_slice(&self.default_size.to_be_bytes()); + content.extend_from_slice(&self.default_flags.to_be_bytes()); + make_box(content, *b"trex") + } +} + impl Default for TREX { fn default() -> Self { TREX { @@ -566,3 +718,17 @@ fn new_stbl(stsd: STSD, metadata: &Arc) -> STBL { } } +pub fn dump_init_tree(moov: MOOV) -> Result<(), Box> { + let content = moov.marshall(); + let mut f = File::create("init.mp4")?; + f.write_all(content.as_slice())?; + Ok(()) +} + +fn make_box(mut content: Vec, box_name: [u8; 4]) -> Vec { + let mut head = vec![0u8; 8]; + head.splice(..4, ((content.len() + 8) as u32).to_be_bytes()); + head.splice(4..8, box_name); + head.append(&mut content); + return head; +} diff --git a/src/muxer/hls/mp4/mp4muxer.rs b/src/muxer/hls/mp4/mp4muxer.rs index 0172001..61ef65b 100644 --- a/src/muxer/hls/mp4/mp4muxer.rs +++ b/src/muxer/hls/mp4/mp4muxer.rs @@ -3,12 +3,14 @@ use std::sync::Arc; use crate::util; use crate::muxer::hls::mp4; +use crate::muxer::hls::mp4::atoms::MP4Atom; impl mp4::MP4Muxer { pub fn gen_init(&mut self) -> Result<(), Box> { let stsd_v = self.handle_a_cc()?; let stsd_a = self.handle_v_cc()?; let init_tree = mp4::atoms::construct_moov(stsd_v, stsd_a, &self.metadata); + mp4::atoms::dump_init_tree(init_tree)?; Ok(()) } diff --git a/src/util/mod.rs b/src/util/mod.rs index 3000ffd..8e1c94d 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -224,3 +224,7 @@ pub fn thread_freeze(err_sender: mpsc::Sender>, err err_sender.send(err).unwrap(); thread::park(); } + +pub fn blank_vec(n: usize) -> Vec { + return vec![0u8; n]; +}