1use crate::*;
2
3ext! {
4 name: Tfra,
5 versions: [0, 1],
6 flags: {}
7}
8
9#[derive(Debug, Clone, PartialEq, Eq, Default)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct FragmentInfo {
12 pub time: u64,
13 pub moof_offset: u64,
14 pub traf_number: u32,
15 pub trun_number: u32,
16 pub sample_delta: u32,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Default)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct Tfra {
22 pub track_id: u32,
23 pub entries: Vec<FragmentInfo>,
24}
25impl Tfra {
26 fn determine_required_lengths(&self) -> (u32, u32, u32, TfraVersion) {
27 let mut length_size_of_traf_num = 0;
28 let mut length_size_of_trun_num = 0;
29 let mut length_size_of_sample_num = 0;
30 let mut version = TfraVersion::V0;
31 for entry in &self.entries {
32 if entry.time > u32::MAX.into() || entry.moof_offset > u32::MAX.into() {
33 version = TfraVersion::V1;
34 }
35 length_size_of_traf_num = std::cmp::max(
36 length_size_of_traf_num,
37 determine_required_length(entry.traf_number),
38 );
39 length_size_of_trun_num = std::cmp::max(
40 length_size_of_trun_num,
41 determine_required_length(entry.trun_number),
42 );
43 length_size_of_sample_num = std::cmp::max(
44 length_size_of_sample_num,
45 determine_required_length(entry.sample_delta),
46 );
47 }
48 (
49 length_size_of_traf_num,
50 length_size_of_trun_num,
51 length_size_of_sample_num,
52 version,
53 )
54 }
55}
56
57fn determine_required_length(value: u32) -> u32 {
58 if value > u24::MAX {
60 3
61 } else if value > u16::MAX.into() {
62 2
63 } else if value > u8::MAX.into() {
64 1
65 } else {
66 0
67 }
68}
69
70fn decode_variable_unsigned_int<B: Buf>(buf: &mut B, num_bits_minus_one: u32) -> Result<u32> {
71 match num_bits_minus_one {
72 0 => Ok(u8::decode(buf)? as u32),
73 1 => Ok(u16::decode(buf)? as u32),
74 2 => Ok(u24::decode(buf)?.into()),
75 3 => u32::decode(buf),
76 _ => Err(Error::InvalidSize),
77 }
78}
79
80fn encode_variable_unsigned_int<B: BufMut>(
81 buf: &mut B,
82 value: u32,
83 num_bits_minus_one: u32,
84) -> Result<()> {
85 match num_bits_minus_one {
86 0 => (value as u8).encode(buf),
87 1 => (value as u16).encode(buf),
88 2 => {
89 let v: u24 = value.try_into().expect("should have already been checked");
90 v.encode(buf)
91 }
92 3 => value.encode(buf),
93 _ => Err(Error::InvalidSize),
94 }
95}
96
97impl AtomExt for Tfra {
98 const KIND_EXT: FourCC = FourCC::new(b"tfra");
99
100 type Ext = TfraExt;
101
102 fn decode_body_ext<B: Buf>(buf: &mut B, ext: TfraExt) -> Result<Self> {
103 let track_id = u32::decode(buf)?;
104 let lengths = u32::decode(buf)?;
105 let length_size_of_sample_num = lengths & 0b11;
107 let length_size_of_trun_num = (lengths >> 2) & 0b11;
108 let length_size_of_traf_num = (lengths >> 4) & 0b11;
109 let number_of_entry = u32::decode(buf)?;
110 let mut entries = Vec::with_capacity(std::cmp::min(128, number_of_entry as usize));
112 for _ in 0..number_of_entry {
113 let (time, moof_offset) = match ext.version {
114 TfraVersion::V1 => (u64::decode(buf)?, u64::decode(buf)?),
115 TfraVersion::V0 => (u32::decode(buf)?.into(), u32::decode(buf)?.into()),
116 };
117 let fragment_info = FragmentInfo {
118 time,
119 moof_offset,
120 traf_number: decode_variable_unsigned_int(buf, length_size_of_traf_num)?,
121 trun_number: decode_variable_unsigned_int(buf, length_size_of_trun_num)?,
122 sample_delta: decode_variable_unsigned_int(buf, length_size_of_sample_num)?,
123 };
124 entries.push(fragment_info);
125 }
126 Ok(Tfra { track_id, entries })
127 }
128
129 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<TfraExt> {
130 self.track_id.encode(buf)?;
131 let (length_size_of_traf_num, length_size_of_trun_num, length_size_of_sample_num, version) =
132 self.determine_required_lengths();
133 ((length_size_of_traf_num << 4)
134 | (length_size_of_trun_num << 2)
135 | (length_size_of_sample_num))
136 .encode(buf)?;
137 let number_of_entry: u32 = self
138 .entries
139 .len()
140 .try_into()
141 .map_err(|_| Error::TooLarge(Self::KIND))?;
142 number_of_entry.encode(buf)?;
143 for entry in &self.entries {
144 match version {
145 TfraVersion::V1 => {
146 entry.time.encode(buf)?;
147 entry.moof_offset.encode(buf)?
148 }
149 TfraVersion::V0 => {
150 (entry.time as u32).encode(buf)?;
151 (entry.moof_offset as u32).encode(buf)?;
152 }
153 }
154 encode_variable_unsigned_int(buf, entry.traf_number, length_size_of_traf_num)?;
155 encode_variable_unsigned_int(buf, entry.trun_number, length_size_of_trun_num)?;
156 encode_variable_unsigned_int(buf, entry.sample_delta, length_size_of_sample_num)?;
157 }
158 Ok(version.into())
159 }
160}
161
162#[cfg(test)]
163mod tests {
164
165 use super::*;
166
167 const ENCODED_TFRA: &[u8] = &[
172 0x00, 0x00, 0x00, 0x2c, 0x74, 0x66, 0x72, 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x68, 0x45, 0x01, 0x02, 0xFF, 0xFF,
175 ];
176
177 #[test]
178 fn test_tfra_v1_decode() {
179 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_TFRA);
180 let tfra = Tfra::decode(buf).expect("failed to decode tfra");
181 assert_eq!(
182 tfra,
183 Tfra {
184 track_id: 3,
185 entries: vec![FragmentInfo {
186 time: 0,
187 moof_offset: 1099512244293,
188 traf_number: 1,
189 trun_number: 2,
190 sample_delta: 65535
191 }]
192 }
193 );
194 }
195
196 #[test]
197 fn test_tfra_v1_encode() {
198 let tfra = Tfra {
199 track_id: 3,
200 entries: vec![FragmentInfo {
201 time: 0,
202 moof_offset: 1099512244293,
203 traf_number: 1,
204 trun_number: 2,
205 sample_delta: 65535,
206 }],
207 };
208
209 let mut buf = Vec::new();
210 tfra.encode(&mut buf).unwrap();
211 assert_eq!(buf, ENCODED_TFRA);
212 }
213}