fragment boxes implementation, generation is limited to common duration, flags and size per and no composition time
This commit is contained in:
parent
f70f8c05cb
commit
fc7ecd62bd
3 changed files with 193 additions and 0 deletions
|
@ -3,6 +3,7 @@ use std::io::Write;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
use crate::muxer::hls::mp4::samples;
|
||||||
|
|
||||||
pub trait MP4Atom {
|
pub trait MP4Atom {
|
||||||
fn marshall(&self) -> Vec<u8>;
|
fn marshall(&self) -> Vec<u8>;
|
||||||
|
@ -1014,6 +1015,192 @@ pub fn dump_init_tree(moov: MOOV) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MOOF {
|
||||||
|
mfhd: MFHD,
|
||||||
|
trafs: [TRAF; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MP4Atom for MOOF {
|
||||||
|
fn marshall(&self) -> Vec<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<SampleData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8>,
|
||||||
|
a_samples: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MP4Atom for MDAT {
|
||||||
|
fn marshall(&self) -> Vec<u8> {
|
||||||
|
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<samples::Sample>, default_dur_v: u32, a_samples: &Vec<samples::Sample>, 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<samples::Sample>, 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<samples::Sample>) -> Vec<SampleData> {
|
||||||
|
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<u8>, box_name: [u8; 4]) -> Vec<u8> {
|
fn make_box(mut content: Vec<u8>, box_name: [u8; 4]) -> Vec<u8> {
|
||||||
let mut head = vec![0u8; 8];
|
let mut head = vec![0u8; 8];
|
||||||
head.splice(..4, ((content.len() + 8) as u32).to_be_bytes());
|
head.splice(..4, ((content.len() + 8) as u32).to_be_bytes());
|
||||||
|
@ -1021,3 +1208,5 @@ fn make_box(mut content: Vec<u8>, box_name: [u8; 4]) -> Vec<u8> {
|
||||||
head.append(&mut content);
|
head.append(&mut content);
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,9 @@ impl mp4::MP4Muxer {
|
||||||
return Some(segments::Segment {
|
return Some(segments::Segment {
|
||||||
filename: idx.to_string() + ".m4s",
|
filename: idx.to_string() + ".m4s",
|
||||||
segment_video: self.v_samples.get_segment_samples(time),
|
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),
|
segment_audio: self.a_samples.get_segment_samples(time),
|
||||||
|
sample_duration_a: self.a_samples.default_duration,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -4,7 +4,9 @@ use crate::muxer::hls::mp4::samples;
|
||||||
pub struct Segment {
|
pub struct Segment {
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
pub segment_video: Vec<samples::Sample>,
|
pub segment_video: Vec<samples::Sample>,
|
||||||
|
pub sample_duration_v: u32,
|
||||||
pub segment_audio: Vec<samples::Sample>,
|
pub segment_audio: Vec<samples::Sample>,
|
||||||
|
pub sample_duration_a: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Segment {
|
impl Segment {
|
||||||
|
|
Loading…
Reference in a new issue