diff --git a/src/muxer/hls/mp4/atoms.rs b/src/muxer/hls/mp4/atoms.rs index ccc9148..640c71a 100644 --- a/src/muxer/hls/mp4/atoms.rs +++ b/src/muxer/hls/mp4/atoms.rs @@ -1,3 +1,7 @@ +use std::sync::Arc; + +use crate::util; + trait MP4Atom { fn size(&self) -> u32; @@ -16,12 +20,38 @@ struct WindowMatrix { w: u32, } +impl Default for WindowMatrix { + fn default() -> Self { + WindowMatrix { + a: 1 << 16, + b: 0, + u: 0, + c: 0, + d: 1 << 16, + v: 0, + x: 0, + y: 0, + w: 1 << 30, + } + } +} + struct Edits { duration: u64, - start: u64, + start: i64, play_rate: u32, } +impl Default for Edits { + fn default() -> Self { + Edits { + duration: 0, + start: 0, + play_rate: 1 << 16, + } + } +} + pub struct MOOV { mvhd: MVHD, traks: [TRAK; 2], @@ -41,6 +71,23 @@ struct MVHD { next_track_id: u32, } +impl Default for MVHD { + fn default() -> Self { + MVHD { + version: 0, + flags: 0, + create_time: 0, + modify_time: 0, + time_scale: 1000, + duration: 0, + playrate: 1 << 16, + volume: 1 << 8, + matrix: WindowMatrix {..Default::default()}, + next_track_id: 2, + } + } +} + struct TRAK { tkhd: TKHD, edts: EDTS, @@ -53,7 +100,6 @@ struct TKHD { create_time: u64, modify_time: u64, track_id: u32, - time_scale: u32, duration: u64, layer: u16, alt_group: u16, @@ -63,10 +109,35 @@ struct TKHD { height: u32, } +impl Default for TKHD { + fn default() -> Self { + TKHD { + version: 0, + flags: 1, + create_time: 0, + modify_time: 0, + track_id: 0, + duration: 0, + layer: 0, + alt_group: 0, + volume: 0, + matrix: WindowMatrix {..Default::default()}, + width: 0, + height: 0, + } + } +} + struct EDTS { elst: ELST, } +impl Default for EDTS { + fn default() -> Self { + EDTS {elst: ELST {..Default::default()}} + } +} + struct ELST { version: u8, flags: u32, @@ -74,6 +145,17 @@ struct ELST { edits: Vec, } +impl Default for ELST { + fn default() -> Self { + ELST { + version: 0, + flags: 0, + num_edits: 1, + edits: vec![Edits {..Default::default() }], + } + } +} + struct MDIA { mdhd: MDHD, hdlr: HDLR, @@ -90,6 +172,20 @@ struct MDHD { language: u32, } +impl Default for MDHD { + fn default() -> Self { + MDHD { + version: 0, + flags: 0, + create_time: 0, + modify_time: 0, + time_scale: 0, + duration: 0, + language: 21956, + } + } +} + struct HDLR { version: u8, flags: u32, @@ -97,6 +193,17 @@ struct HDLR { name: String, } +impl Default for HDLR { + fn default() -> Self { + HDLR { + version: 0, + flags: 0, + handler: 0, + name: String::from(""), + } + } +} + enum MINF { Video(MINF_V), Audio(MINF_A), @@ -115,6 +222,17 @@ struct VMHD { opcolor: [u16; 3], } +impl Default for VMHD { + fn default() -> Self { + VMHD { + version: 0, + flags: 0, + mode: 0, + opcolor: [0,0,0], + } + } +} + struct MINF_A { smhd: SMHD, dinf: DINF, @@ -127,10 +245,28 @@ struct SMHD { balance: u16, } +impl Default for SMHD { + fn default() -> Self { + SMHD { + version: 0, + flags: 0, + balance: 0, + } + } +} + struct DINF { dref: DREF, } +impl Default for DINF { + fn default() -> Self { + DINF { + dref: DREF {..Default::default() }, + } + } +} + struct DREF { version: u8, flags: u32, @@ -138,6 +274,21 @@ struct DREF { refs: Vec } +impl Default for DREF { + fn default() -> Self { + DREF { + version: 0, + flags: 0, + num_refs: 1, + refs: vec![Refs::RefURL(URL { + version: 0, + flags: 1, + url: String::from(""), + })], + } + } +} + enum Refs { RefURL(URL), RefURN(URN), @@ -207,6 +358,17 @@ struct STTS { entries: Vec, } +impl Default for STTS { + fn default() -> Self { + STTS { + version: 0, + flags: 0, + num_entries: 0, + entries: Vec::new(), + } + } +} + struct STTSEntry { count_consec: u32, duration: u32, @@ -219,6 +381,17 @@ struct STSC { entries: Vec, } +impl Default for STSC { + fn default() -> Self { + STSC { + version: 0, + flags: 0, + num_entries: 0, + entries: Vec::new(), + } + } +} + struct STSCEntry { chunk_idx: u32, samples_per: u32, @@ -233,6 +406,18 @@ struct STSZ { entries: Vec, } +impl Default for STSZ { + fn default() -> Self { + STSZ { + version: 0, + flags: 0, + common_size: 0, + num_entries: 0, + entries: Vec::new(), + } + } +} + struct STCO { version: u8, flags: u32, @@ -240,10 +425,29 @@ struct STCO { entries: Vec, } +impl Default for STCO { + fn default() -> Self { + STCO { + version: 0, + flags: 0, + num_entries: 0, + entries: Vec::new(), + } + } +} + struct MVEX { trexs: [TREX; 2], } +impl Default for MVEX { + fn default() -> Self { + MVEX { + trexs: [TREX {track_id: 1, ..Default::default()}, TREX{track_id: 2, ..Default::default()}], + } + } +} + struct TREX { version: u8, flags: u32, @@ -254,3 +458,111 @@ struct TREX { default_flags: u32, } +impl Default for TREX { + fn default() -> Self { + TREX { + version: 0, + flags: 0, + track_id: 0, + default_desc_idx: 1, + default_duration: 0, + default_size: 0, + default_flags: 0, + } + } +} + +pub fn construct_moov(stsd_v: STSD, stsd_a: STSD, metadata: &Arc) -> MOOV { + let mvhd = MVHD {..Default::default() }; + let traks = [new_trak(stsd_v, &metadata), new_trak(stsd_a, &metadata)]; + let mvex = MVEX {..Default::default() }; + return MOOV { + mvhd: mvhd, + traks: traks, + mvex: mvex, + } +} + +fn new_trak(stsd: STSD, metadata: &Arc) -> TRAK { + let mut tkhd = TKHD {..Default::default() }; + match stsd.entry { + SampleEntry::Visual(_) => { + tkhd.width = metadata.video.width << 16; + tkhd.height = metadata.video.height << 16; + tkhd.track_id = 1; + }, + SampleEntry::Sound(_) => { + tkhd.alt_group = 1; + tkhd.volume = 1 << 8; + tkhd.track_id = 2; + } + } + let edts = EDTS { ..Default::default()}; + let mdia = new_mdia(stsd, metadata); + return TRAK { + tkhd: tkhd, + edts: edts, + mdia: mdia, + } +} + +fn new_mdia(stsd: STSD, metadata: &Arc) -> MDIA { + let mut mdhd = MDHD {..Default::default() }; + let mut hdlr = HDLR {..Default::default() }; + match stsd.entry { + SampleEntry::Visual(_) => { + mdhd.time_scale = (metadata.video.framerate * 1000.0) as u32; + hdlr.handler = u32::from_be_bytes(*b"vide"); + hdlr.name = String::from("VideoHandler"); + }, + SampleEntry::Sound(_) => { + mdhd.time_scale = metadata.audio.samplerate; + hdlr.handler = u32::from_be_bytes(*b"soun"); + hdlr.name = String::from("SoundHandler"); + } + } + let minf = new_minf(stsd, metadata); + todo!(); +} + +fn new_minf(stsd: STSD, metadata: &Arc) -> MINF { + match stsd.entry { + SampleEntry::Visual(_) => MINF::Video(new_minf_v(stsd, metadata)), + SampleEntry::Sound(_) => MINF::Audio(new_minf_a(stsd, metadata)) + } +} + +fn new_minf_v(stsd: STSD, metadata: &Arc) -> MINF_V { + let vmhd = VMHD {..Default::default() }; + let dinf = DINF {..Default::default() }; + let stbl = new_stbl(stsd, metadata); + return MINF_V { + vmhd: vmhd, + dinf: dinf, + stbl: stbl, + } +} + + +fn new_minf_a(stsd: STSD, metadata: &Arc) -> MINF_A { + let smhd = SMHD {..Default::default() }; + let dinf = DINF {..Default::default() }; + let stbl = new_stbl(stsd, metadata); + return MINF_A { + smhd: smhd, + dinf: dinf, + stbl: stbl, + } +} + +fn new_stbl(stsd: STSD, metadata: &Arc) -> STBL { + STBL { + stsd: stsd, + stts: STTS{..Default::default()}, + stsc: STSC{..Default::default()}, + stsz: STSZ{..Default::default()}, + stco: STCO{..Default::default()}, + opts: Vec::new(), + } +} + diff --git a/src/muxer/hls/mp4/mp4muxer.rs b/src/muxer/hls/mp4/mp4muxer.rs index 92f585d..0172001 100644 --- a/src/muxer/hls/mp4/mp4muxer.rs +++ b/src/muxer/hls/mp4/mp4muxer.rs @@ -8,7 +8,7 @@ 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 = self.construct_moov(stsd_v, stsd_a); + let init_tree = mp4::atoms::construct_moov(stsd_v, stsd_a, &self.metadata); Ok(()) } @@ -33,10 +33,6 @@ impl mp4::MP4Muxer { _ => Err(Box::new(util::MuxerError::InvalidCodec)) } } - - fn construct_moov(&self, stsd_v: mp4::atoms::STSD, stsd_a: mp4::atoms::STSD) -> mp4::atoms::MOOV { - todo!(); - } } fn get_av1_stsd(mut sample: Vec, metadata: &Arc) -> mp4::atoms::STSD { @@ -47,7 +43,7 @@ fn get_av1_stsd(mut sample: Vec, metadata: &Arc) -> mp4::ato // More complicated to parse than is worth doing. let mut dummy_mp4_cc_binding = vec![0x81u8, 0x05, 0x0d, 0x00]; dummy_mp4_cc_binding.append(&mut av1c); - let cc = mp4::atoms::CodecConfig {atom_name: "av1C".as_bytes().try_into().unwrap(), data: dummy_mp4_cc_binding}; + let cc = mp4::atoms::CodecConfig {atom_name: *b"av1C", data: dummy_mp4_cc_binding}; let v_sample_entry = mp4::atoms::VisualSampleEntry { dref_idx: 1, width: metadata.video.width as u16, @@ -84,7 +80,7 @@ fn get_opus_stsd(sample: Vec, metadata: &Arc) -> mp4::atoms: channels: metadata.audio.channels as u16, sample_size: 16, sample_rate: metadata.audio.samplerate, - codec_config: mp4::atoms::CodecConfig { atom_name: "dOps".as_bytes().try_into().unwrap(), data: opus_binding} + codec_config: mp4::atoms::CodecConfig { atom_name: *b"dOps", data: opus_binding} }; return mp4::atoms::STSD { version: 0,