From fc7ecd62bd21cc65a105f7129ed351e7d3198a13 Mon Sep 17 00:00:00 2001 From: Muaz Ahmad Date: Tue, 24 Oct 2023 16:45:51 +0500 Subject: [PATCH] fragment boxes implementation, generation is limited to common duration, flags and size per and no composition time --- src/muxer/hls/mp4/atoms.rs | 189 ++++++++++++++++++++++++++++++++++ src/muxer/hls/mp4/mp4muxer.rs | 2 + src/muxer/hls/segments.rs | 2 + 3 files changed, 193 insertions(+) diff --git a/src/muxer/hls/mp4/atoms.rs b/src/muxer/hls/mp4/atoms.rs index b5dbf71..6fa86b7 100644 --- a/src/muxer/hls/mp4/atoms.rs +++ b/src/muxer/hls/mp4/atoms.rs @@ -3,6 +3,7 @@ use std::io::Write; use std::fs::File; use crate::util; +use crate::muxer::hls::mp4::samples; pub trait MP4Atom { fn marshall(&self) -> Vec; @@ -1014,6 +1015,192 @@ pub fn dump_init_tree(moov: MOOV) -> Result<(), Box> { Ok(()) } +pub struct MOOF { + mfhd: MFHD, + trafs: [TRAF; 2], +} + +impl MP4Atom for MOOF { + fn marshall(&self) -> Vec { + let mut content = self.mfhd.marshall(); + content.append(&mut self.trafs[0].marshall()); + content.append(&mut self.trafs[1].marshall()); + make_box(content, *b"moof") + } +} + +struct MFHD { + version: u8, + flags: u32, + seq_num: u32, +} + +impl Default for MFHD { + fn default() -> Self { + MFHD { + version: 0, + flags: 0, + seq_num: 0, + } + } +} + +impl MP4Atom for MFHD { + 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.seq_num.to_be_bytes()); + make_box(content, *b"mfhd") + } +} + +struct TRAF { + tfhd: TFHD, + trun: TRUN, +} + +impl MP4Atom for TRAF { + fn marshall(&self) -> Vec { + let mut content = self.tfhd.marshall(); + content.append(&mut self.trun.marshall()); + make_box(content, *b"traf") + } +} + +struct TFHD { + version: u8, + flags: u32, + track_id: u32, + default_duration: u32, +} + +impl MP4Atom for TFHD { + 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_duration.to_be_bytes()); + make_box(content, *b"tfhd") + } +} + +impl Default for TFHD { + fn default() -> Self { + TFHD { + version: 0, + flags: 0x00020008, + track_id: 0, + default_duration: 0, + } + } +} + +struct TRUN { + version: u8, + flags: u32, + num_samples: u32, + offset: u32, + samples: Vec, +} + +impl Default for TRUN { + fn default() -> Self { + TRUN { + version: 0, + flags: 0x00000601, + num_samples: 0, + offset: 0, + samples: Vec::new(), + } + } +} + +impl MP4Atom for TRUN { + 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_samples.to_be_bytes()); + content.extend_from_slice(&self.offset.to_be_bytes()); + for sample in &self.samples { + content.append(&mut sample.marshall()); + } + make_box(content, *b"trun") + } +} + +struct SampleData { + size: u32, + flags: u32, +} + +impl MP4Atom for SampleData { + fn marshall(&self) -> Vec { + let mut content = Vec::new(); + content.extend_from_slice(&self.size.to_be_bytes()); + content.extend_from_slice(&self.flags.to_be_bytes()); + return content; + } +} + +struct MDAT { + v_samples: Vec, + a_samples: Vec, +} + +impl MP4Atom for MDAT { + fn marshall(&self) -> Vec { + let mut content = self.v_samples.clone(); + content.append(&mut self.a_samples.clone()); + make_box(content, *b"mdat") + + } +} + +pub fn new_moof(v_samples: &Vec, default_dur_v: u32, a_samples: &Vec, default_dur_a: u32, mdat_v_offset: usize, mdat_a_offset: usize, moof_idx: usize) -> MOOF { + let mdat_data_start = 120 + v_samples.len() * 8 + a_samples.len() * 8 + 8; + MOOF { + mfhd: MFHD { seq_num: moof_idx as u32, ..Default::default() }, + trafs: [ TRAF { + tfhd: TFHD { + track_id: 1, + default_duration: default_dur_v, + ..Default::default() + }, + trun: new_trun(v_samples, mdat_v_offset + mdat_data_start), + }, TRAF{ + tfhd: TFHD { + track_id: 2, + default_duration: default_dur_a, + ..Default::default() + }, + trun: new_trun(a_samples, mdat_a_offset + mdat_data_start), + } ], + } +} + +fn new_trun(samples: &Vec, data_offset: usize) -> TRUN { + TRUN { + num_samples: samples.len() as u32, + offset: data_offset as u32, + samples: make_sample_table(samples), + ..Default::default() + } +} + +fn make_sample_table(samples: &Vec) -> Vec { + let mut table = Vec::new(); + for sample in samples { + table.push( SampleData { + size: sample.size, + flags: sample.flags, + }); + } + return table; +} + 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()); @@ -1021,3 +1208,5 @@ fn make_box(mut content: Vec, box_name: [u8; 4]) -> Vec { head.append(&mut content); return head; } + + diff --git a/src/muxer/hls/mp4/mp4muxer.rs b/src/muxer/hls/mp4/mp4muxer.rs index b93d26e..fb4216b 100644 --- a/src/muxer/hls/mp4/mp4muxer.rs +++ b/src/muxer/hls/mp4/mp4muxer.rs @@ -74,7 +74,9 @@ impl mp4::MP4Muxer { return Some(segments::Segment { filename: idx.to_string() + ".m4s", segment_video: self.v_samples.get_segment_samples(time), + sample_duration_v: self.v_samples.default_duration, segment_audio: self.a_samples.get_segment_samples(time), + sample_duration_a: self.a_samples.default_duration, }) } return None diff --git a/src/muxer/hls/segments.rs b/src/muxer/hls/segments.rs index 2abbb7e..18f8683 100644 --- a/src/muxer/hls/segments.rs +++ b/src/muxer/hls/segments.rs @@ -4,7 +4,9 @@ use crate::muxer::hls::mp4::samples; pub struct Segment { pub filename: String, pub segment_video: Vec, + pub sample_duration_v: u32, pub segment_audio: Vec, + pub sample_duration_a: u32, } impl Segment {