diff --git a/src/muxer/hls/mp4/atoms.rs b/src/muxer/hls/mp4/atoms.rs index 61dc0f9..b5dbf71 100644 --- a/src/muxer/hls/mp4/atoms.rs +++ b/src/muxer/hls/mp4/atoms.rs @@ -191,7 +191,7 @@ struct TKHD { impl MP4Atom for TKHD { fn marshall(&self) -> Vec { - let content = Vec::new(); + let mut content = Vec::new(); content.push(self.version); content.extend_from_slice(&self.flags.to_be_bytes()[1..]); if self.version == 1 { @@ -268,7 +268,7 @@ impl MP4Atom for ELST { 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 { + for edit in &self.edits { content.append(&mut edit.marshall()); } make_box(content, *b"elst") @@ -292,6 +292,15 @@ struct MDIA { minf: MINF, } +impl MP4Atom for MDIA { + fn marshall(&self) -> Vec { + let mut content = self.mdhd.marshall(); + content.append(&mut self.hdlr.marshall()); + content.append(&mut self.minf.marshall()); + make_box(content, *b"mdia") + } +} + struct MDHD { version: u8, flags: u32, @@ -299,7 +308,31 @@ struct MDHD { modify_time: u64, time_scale: u32, duration: u64, - language: u32, + language: u16, +} + +impl MP4Atom for MDHD { + 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.language.to_be_bytes()); + content.append(&mut util::blank_vec(2)); + make_box(content, *b"mdhd") + } } impl Default for MDHD { @@ -323,6 +356,20 @@ struct HDLR { name: String, } +impl MP4Atom for HDLR { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.push(self.version); + content.extend_from_slice(&self.flags.to_be_bytes()[1..]); + content.append(&mut util::blank_vec(4)); + content.extend_from_slice(&self.handler.to_be_bytes()); + content.append(&mut util::blank_vec(12)); + content.extend_from_slice(&self.name.as_bytes()); + content.push(0); + make_box(content, *b"hdlr") + } +} + impl Default for HDLR { fn default() -> Self { HDLR { @@ -339,12 +386,30 @@ enum MINF { Audio(MINF_A), } +impl MP4Atom for MINF { + fn marshall(&self) -> Vec { + match self { + MINF::Video(x) => x.marshall(), + MINF::Audio(x) => x.marshall() + } + } +} + struct MINF_V { vmhd: VMHD, dinf: DINF, stbl: STBL, } +impl MP4Atom for MINF_V { + fn marshall(&self) -> Vec { + let mut content = self.vmhd.marshall(); + content.append(&mut self.dinf.marshall()); + content.append(&mut self.stbl.marshall()); + make_box(content, *b"minf") + } +} + struct VMHD { version: u8, flags: u32, @@ -352,6 +417,19 @@ struct VMHD { opcolor: [u16; 3], } +impl MP4Atom for VMHD { + 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.mode.to_be_bytes()); + for col in &self.opcolor { + content.extend_from_slice(&col.to_be_bytes()); + } + make_box(content, *b"vmhd") + } +} + impl Default for VMHD { fn default() -> Self { VMHD { @@ -369,12 +447,32 @@ struct MINF_A { stbl: STBL, } +impl MP4Atom for MINF_A { + fn marshall(&self) -> Vec { + let mut content = self.smhd.marshall(); + content.append(&mut self.dinf.marshall()); + content.append(&mut self.stbl.marshall()); + make_box(content, *b"minf") + } +} + struct SMHD { version: u8, flags: u32, balance: u16, } +impl MP4Atom for SMHD { + 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.balance.to_be_bytes()); + content.append(&mut util::blank_vec(2)); + make_box(content, *b"smhd") + } +} + impl Default for SMHD { fn default() -> Self { SMHD { @@ -389,6 +487,12 @@ struct DINF { dref: DREF, } +impl MP4Atom for DINF { + fn marshall(&self) -> Vec { + make_box(self.dref.marshall(), *b"dinf") + } +} + impl Default for DINF { fn default() -> Self { DINF { @@ -404,6 +508,19 @@ struct DREF { refs: Vec } +impl MP4Atom for DREF { + 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_refs.to_be_bytes()); + for i in &self.refs { + content.append(&mut i.marshall()); + } + make_box(content, *b"dref") + } +} + impl Default for DREF { fn default() -> Self { DREF { @@ -424,18 +541,49 @@ enum Refs { RefURN(URN), } +impl MP4Atom for Refs { + fn marshall(&self) -> Vec { + match self { + Refs::RefURL(x) => x.marshall(), + Refs::RefURN(x) => x.marshall() + } + } +} + struct URL { version: u8, flags: u32, url: String, } +impl MP4Atom for URL { + 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.url.as_bytes()); + content.push(0); + make_box(content, *b"url ") + } +} + struct URN { version: u8, flags: u32, urn: String, } +impl MP4Atom for URN { + 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.urn.as_bytes()); + content.push(0); + make_box(content, *b"urn ") + } +} + struct STBL { stsd: STSD, stts: STTS, @@ -445,6 +593,20 @@ struct STBL { opts: Vec>, } +impl MP4Atom for STBL { + fn marshall(&self) -> Vec { + let mut content = self.stsd.marshall(); + content.append(&mut self.stts.marshall()); + content.append(&mut self.stsc.marshall()); + content.append(&mut self.stsz.marshall()); + content.append(&mut self.stco.marshall()); + for opt in &self.opts { + content.extend_from_slice(opt.as_slice()); + } + make_box(content, *b"stbl") + } +} + pub struct STSD { pub version: u8, pub flags: u32, @@ -452,12 +614,33 @@ pub struct STSD { pub entry: SampleEntry, } +impl MP4Atom for STSD { + 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_entries.to_be_bytes()); + content.append(&mut self.entry.marshall()); + make_box(content, *b"stsd") + } +} + pub enum SampleEntry { Visual(VisualSampleEntry), Sound(SoundSampleEntry), } +impl MP4Atom for SampleEntry { + fn marshall(&self) -> Vec { + match self { + SampleEntry::Visual(x) => x.marshall(), + SampleEntry::Sound(x) => x.marshall() + } + } +} + pub struct VisualSampleEntry { + pub sample_name: [u8; 4], pub dref_idx: u16, pub width: u16, pub height: u16, @@ -468,7 +651,30 @@ pub struct VisualSampleEntry { pub codec_config: CodecConfig, } +impl MP4Atom for VisualSampleEntry { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.append(&mut util::blank_vec(6)); + content.extend_from_slice(&self.dref_idx.to_be_bytes()); + content.append(&mut util::blank_vec(16)); + content.extend_from_slice(&self.width.to_be_bytes()); + content.extend_from_slice(&self.height.to_be_bytes()); + content.extend_from_slice(&self.resolution.to_be_bytes()); + content.append(&mut util::blank_vec(4)); + content.extend_from_slice(&self.sample_per_frame.to_be_bytes()); + content.extend_from_slice(&(self.encoder_name.len() as u8).to_be_bytes()); + let mut encoder_bytes = vec![0u8; 31]; + encoder_bytes.splice(..self.encoder_name.len(), self.encoder_name.bytes()); + content.append(&mut encoder_bytes); + content.extend_from_slice(&self.pixel_depth.to_be_bytes()); + content.extend_from_slice(&(0xffff as u16).to_be_bytes()); + content.append(&mut self.codec_config.marshall()); + make_box(content, self.sample_name) + } +} + pub struct SoundSampleEntry { + pub sample_name: [u8; 4], pub dref_idx: u16, pub channels: u16, pub sample_size: u16, @@ -476,11 +682,34 @@ pub struct SoundSampleEntry { pub codec_config: CodecConfig, } +impl MP4Atom for SoundSampleEntry { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.append(&mut util::blank_vec(6)); + content.extend_from_slice(&self.dref_idx.to_be_bytes()); + content.append(&mut util::blank_vec(8)); + content.extend_from_slice(&self.channels.to_be_bytes()); + content.extend_from_slice(&self.sample_size.to_be_bytes()); + content.append(&mut util::blank_vec(4)); + content.extend_from_slice(&self.sample_rate.to_be_bytes()); + content.append(&mut self.codec_config.marshall()); + make_box(content, self.sample_name) + } +} + pub struct CodecConfig { pub atom_name: [u8; 4], pub data: Vec, } +impl MP4Atom for CodecConfig { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.extend_from_slice(&self.data.as_slice()); + make_box(content, self.atom_name) + } +} + struct STTS { version: u8, flags: u32, @@ -488,6 +717,20 @@ struct STTS { entries: Vec, } +impl MP4Atom for STTS { + 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_entries.to_be_bytes()); + for entry in &self.entries { + content.extend_from_slice(&entry.count_consec.to_be_bytes()); + content.extend_from_slice(&entry.duration.to_be_bytes()); + } + make_box(content, *b"stts") + } +} + impl Default for STTS { fn default() -> Self { STTS { @@ -511,6 +754,21 @@ struct STSC { entries: Vec, } +impl MP4Atom for STSC { + 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_entries.to_be_bytes()); + for entry in &self.entries { + content.extend_from_slice(&entry.chunk_idx.to_be_bytes()); + content.extend_from_slice(&entry.samples_per.to_be_bytes()); + content.extend_from_slice(&entry.data_ref_idx.to_be_bytes()); + } + make_box(content, *b"stsc") + } +} + impl Default for STSC { fn default() -> Self { STSC { @@ -536,6 +794,20 @@ struct STSZ { entries: Vec, } +impl MP4Atom for STSZ { + 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.common_size.to_be_bytes()); + content.extend_from_slice(&self.num_entries.to_be_bytes()); + for entry in &self.entries { + content.extend_from_slice(&entry.to_be_bytes()); + } + make_box(content, *b"stsz") + } +} + impl Default for STSZ { fn default() -> Self { STSZ { @@ -555,6 +827,19 @@ struct STCO { entries: Vec, } +impl MP4Atom for STCO { + 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_entries.to_be_bytes()); + for entry in &self.entries { + content.extend_from_slice(&entry.to_be_bytes()); + } + make_box(content, *b"stco") + } +} + impl Default for STCO { fn default() -> Self { STCO { @@ -674,7 +959,11 @@ fn new_mdia(stsd: STSD, metadata: &Arc) -> MDIA { } } let minf = new_minf(stsd, metadata); - todo!(); + return MDIA { + mdhd: mdhd, + hdlr: hdlr, + minf: minf, + } } fn new_minf(stsd: STSD, metadata: &Arc) -> MINF { diff --git a/src/muxer/hls/mp4/mp4muxer.rs b/src/muxer/hls/mp4/mp4muxer.rs index 61ef65b..d93c927 100644 --- a/src/muxer/hls/mp4/mp4muxer.rs +++ b/src/muxer/hls/mp4/mp4muxer.rs @@ -7,8 +7,8 @@ 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 stsd_v = self.handle_v_cc()?; + let stsd_a = self.handle_a_cc()?; let init_tree = mp4::atoms::construct_moov(stsd_v, stsd_a, &self.metadata); mp4::atoms::dump_init_tree(init_tree)?; Ok(()) @@ -47,6 +47,7 @@ fn get_av1_stsd(mut sample: Vec, metadata: &Arc) -> mp4::ato dummy_mp4_cc_binding.append(&mut av1c); let cc = mp4::atoms::CodecConfig {atom_name: *b"av1C", data: dummy_mp4_cc_binding}; let v_sample_entry = mp4::atoms::VisualSampleEntry { + sample_name: *b"av01", dref_idx: 1, width: metadata.video.width as u16, height: metadata.video.height as u16, @@ -73,11 +74,12 @@ fn get_opus_stsd(sample: Vec, metadata: &Arc) -> mp4::atoms: let output_gain = u16::from_le_bytes(sample[16..18].try_into().unwrap()); opus_binding.splice(8..10, output_gain.to_be_bytes()); opus_binding[10] = sample[18]; - if opus_binding[18] == 1 { + if sample[18] == 1 { opus_binding.append(&mut sample[19..].to_vec()); } let a_sample_entry = mp4::atoms::SoundSampleEntry { + sample_name: *b"Opus", dref_idx: 1, channels: metadata.audio.channels as u16, sample_size: 16,