diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index 88adfe0..bf6f1cf 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -9,19 +9,52 @@ pub struct TrunBox { pub version: u8, pub flags: u32, pub sample_count: u32, - pub data_offset: i32, + pub data_offset: Option, + pub first_sample_flags: Option, + #[serde(skip_serializing)] + pub sample_durations: Vec, #[serde(skip_serializing)] pub sample_sizes: Vec, + #[serde(skip_serializing)] + pub sample_flags: Vec, + #[serde(skip_serializing)] + pub sample_cts: Vec, } impl TrunBox { + pub const FLAG_DATA_OFFSET: u32 = 0x01; + pub const FLAG_FIRST_SAMPLE_FLAGS: u32 = 0x04; + pub const FLAG_SAMPLE_DURATION: u32 = 0x100; + pub const FLAG_SAMPLE_SIZE: u32 = 0x200; + pub const FLAG_SAMPLE_FLAGS: u32 = 0x400; + pub const FLAG_SAMPLE_CTS: u32 = 0x800; + pub fn get_type(&self) -> BoxType { BoxType::TrunBox } pub fn get_size(&self) -> u64 { - HEADER_SIZE + HEADER_EXT_SIZE + 8 + (4 * self.sample_sizes.len() as u64) + let mut sum = HEADER_SIZE + HEADER_EXT_SIZE + 4; + if TrunBox::FLAG_DATA_OFFSET & self.flags > 0 { + sum += 4; + } + if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & self.flags > 0 { + sum += 4; + } + if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { + sum += 4 * self.sample_count as u64; + } + if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 { + sum += 4 * self.sample_count as u64; + } + if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 { + sum += 4 * self.sample_count as u64; + } + if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 { + sum += 4 * self.sample_count as u64; + } + sum } } @@ -52,12 +85,43 @@ impl ReadBox<&mut R> for TrunBox { let (version, flags) = read_box_header_ext(reader)?; let sample_count = reader.read_u32::()?; - let data_offset = reader.read_i32::()?; + let data_offset = if TrunBox::FLAG_DATA_OFFSET & flags > 0 { + Some(reader.read_i32::()?) + } else { + None + }; + + let first_sample_flags = if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 { + Some(reader.read_u32::()?) + } else { + None + }; + + let mut sample_durations = Vec::with_capacity(sample_count as usize); let mut sample_sizes = Vec::with_capacity(sample_count as usize); + let mut sample_flags = Vec::with_capacity(sample_count as usize); + let mut sample_cts = Vec::with_capacity(sample_count as usize); for _ in 0..sample_count { - let sample_size = reader.read_u32::()?; - sample_sizes.push(sample_size); + if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 { + let duration = reader.read_u32::()?; + sample_durations.push(duration); + } + + if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 { + let sample_size = reader.read_u32::()?; + sample_sizes.push(sample_size); + } + + if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 { + let sample_flag = reader.read_u32::()?; + sample_flags.push(sample_flag); + } + + if TrunBox::FLAG_SAMPLE_CTS & flags > 0 { + let cts = reader.read_u32::()?; + sample_cts.push(cts); + } } skip_bytes_to(reader, start + size)?; @@ -67,7 +131,11 @@ impl ReadBox<&mut R> for TrunBox { flags, sample_count, data_offset, + first_sample_flags, + sample_durations, sample_sizes, + sample_flags, + sample_cts, }) } } @@ -80,10 +148,26 @@ impl WriteBox<&mut W> for TrunBox { write_box_header_ext(writer, self.version, self.flags)?; writer.write_u32::(self.sample_count)?; - writer.write_i32::(self.data_offset)?; + if let Some(v) = self.data_offset{ + writer.write_i32::(v)?; + } + if let Some(v) = self.first_sample_flags { + writer.write_u32::(v)?; + } assert_eq!(self.sample_count, self.sample_sizes.len() as u32); - for sample_number in self.sample_sizes.iter() { - writer.write_u32::(*sample_number)?; + for i in 0..self.sample_count as usize { + if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { + writer.write_u32::(self.sample_durations[i])?; + } + if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 { + writer.write_u32::(self.sample_sizes[i])?; + } + if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 { + writer.write_u32::(self.sample_flags[i])?; + } + if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 { + writer.write_u32::(self.sample_cts[i])?; + } } Ok(size) @@ -101,9 +185,13 @@ mod tests { let src_box = TrunBox { version: 0, flags: 0, - data_offset: 0, + data_offset: None, sample_count: 0, sample_sizes: vec![], + sample_flags: vec![], + first_sample_flags: None, + sample_durations: vec![], + sample_cts: vec![], }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); @@ -122,10 +210,14 @@ mod tests { fn test_trun_many_sizes() { let src_box = TrunBox { version: 0, - flags: 0, - data_offset: 0, + flags: TrunBox::FLAG_SAMPLE_DURATION | TrunBox::FLAG_SAMPLE_SIZE | TrunBox::FLAG_SAMPLE_FLAGS | TrunBox::FLAG_SAMPLE_CTS, + data_offset: None, sample_count: 9, sample_sizes: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730], + sample_flags: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730], + first_sample_flags: None, + sample_durations: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730], + sample_cts: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730], }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); diff --git a/src/track.rs b/src/track.rs index c4e0eef..46e846c 100644 --- a/src/track.rs +++ b/src/track.rs @@ -361,25 +361,39 @@ impl Mp4Track { )); } + /// return `(traf_idx, sample_idx_in_trun)` + fn find_traf_idx_and_sample_idx(&self, sample_id: u32) -> Option<(usize, usize)>{ + let global_idx = sample_id - 1; + let mut offset = 0; + for traf_idx in 0..self.trafs.len() { + if let Some(trun) = &self.trafs[traf_idx].trun { + let sample_count = trun.sample_count; + if sample_count > (global_idx - offset) { + return Some((traf_idx, (global_idx - offset) as _)); + } + offset += sample_count; + } + } + None + } + fn sample_size(&self, sample_id: u32) -> Result { if self.trafs.len() > 0 { - let sample_sizes_count = self.sample_count() / self.trafs.len() as u32; - let traf_idx = (sample_id - 1) / sample_sizes_count; - if let Some(trun) = &self.trafs[traf_idx as usize].trun { - if let Some(size) = trun.sample_sizes.get((sample_id - (sample_sizes_count * traf_idx)) as usize - 1) { + if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { + if let Some(size) = self.trafs[traf_idx].trun.as_ref().unwrap().sample_sizes.get(sample_idx) { Ok(*size) } else { - return Err(Error::EntryInTrunNotFound( + Err(Error::EntryInTrunNotFound( self.track_id(), BoxType::TrunBox, sample_id, - )); + )) } } else { - return Err(Error::BoxInTrafNotFound( + Err(Error::BoxInTrafNotFound( self.track_id(), BoxType::TrafBox, - )); + )) } } else { let stsz = &self.trak.mdia.minf.stbl.stsz; @@ -413,9 +427,14 @@ impl Mp4Track { fn sample_offset(&self, sample_id: u32) -> Result { if self.trafs.len() > 0 { - let sample_sizes_count = self.sample_count() / self.trafs.len() as u32; - let traf_idx = (sample_id - 1) / sample_sizes_count; - Ok(self.trafs[(sample_id - (sample_sizes_count * traf_idx)) as usize].tfhd.base_data_offset as u64) + if let Some((traf_idx, _sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { + Ok(self.trafs[traf_idx].tfhd.base_data_offset as u64) + } else { + Err(Error::BoxInTrafNotFound( + self.track_id(), + BoxType::TrafBox, + )) + } } else { let stsc_index = self.stsc_index(sample_id);