1use crate::*;
2
3ext! {
7 name: Sidx,
8 versions: [0, 1],
9 flags: {}
10}
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct SegmentReference {
15 pub reference_type: bool,
16 pub referenced_size: u32,
17 pub subsegment_duration: u32,
18 pub starts_with_sap: bool,
19 pub sap_type: u8,
20 pub sap_delta_time: u32,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Default)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Sidx {
26 pub reference_id: u32,
27 pub timescale: u32,
28 pub earliest_presentation_time: u64,
29 pub first_offset: u64,
30 pub references: Vec<SegmentReference>,
31}
32
33impl AtomExt for Sidx {
34 type Ext = SidxExt;
35
36 const KIND_EXT: FourCC = FourCC::new(b"sidx");
37
38 fn decode_body_ext<B: Buf>(buf: &mut B, ext: SidxExt) -> Result<Self> {
39 let reference_id = u32::decode(buf)?;
40 let timescale = u32::decode(buf)?;
41 let (earliest_presentation_time, first_offset) = if ext.version == SidxVersion::V0 {
42 (u32::decode(buf)?.into(), u32::decode(buf)?.into())
43 } else {
44 (u64::decode(buf)?, u64::decode(buf)?)
45 };
46 let _reserved = u16::decode(buf)?;
47 let reference_count = u16::decode(buf)?;
48 let mut references = Vec::with_capacity(std::cmp::min(reference_count as usize, 128));
49 for _ in 0..reference_count {
50 let referenced_type_and_size = u32::decode(buf)?;
51 let reference_type = (referenced_type_and_size & 0x8000_0000) == 0x8000_0000;
52 let referenced_size = referenced_type_and_size & 0x7FFF_FFFF;
53 let subsegment_duration = u32::decode(buf)?;
54 let sap_flag_and_type_and_delta_time = u32::decode(buf)?;
55 let starts_with_sap = (sap_flag_and_type_and_delta_time & 0x8000_0000) == 0x8000_0000;
56 let sap_type = ((sap_flag_and_type_and_delta_time >> 28) & 0b111) as u8;
57 let sap_delta_time = sap_flag_and_type_and_delta_time & 0x0FFF_FFFF;
58 let reference = SegmentReference {
59 reference_type,
60 referenced_size,
61 subsegment_duration,
62 starts_with_sap,
63 sap_type,
64 sap_delta_time,
65 };
66 references.push(reference);
67 }
68
69 Ok(Sidx {
70 reference_id,
71 timescale,
72 earliest_presentation_time,
73 first_offset,
74 references,
75 })
76 }
77
78 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<SidxExt> {
79 self.reference_id.encode(buf)?;
80 self.timescale.encode(buf)?;
81 let version = match (
82 u32::try_from(self.earliest_presentation_time),
83 u32::try_from(self.first_offset),
84 ) {
85 (Ok(earliest_presentation_time), Ok(first_offset)) => {
86 earliest_presentation_time.encode(buf)?;
87 first_offset.encode(buf)?;
88 SidxVersion::V0
89 }
90 _ => {
91 self.earliest_presentation_time.encode(buf)?;
92 self.first_offset.encode(buf)?;
93 SidxVersion::V1
94 }
95 };
96 0u16.encode(buf)?; let reference_count: u16 = self
98 .references
99 .len()
100 .try_into()
101 .map_err(|_| Error::TooLarge(Self::KIND))?;
102 reference_count.encode(buf)?;
103 for reference in &self.references {
104 if reference.referenced_size > 0x7FFF_FFFF
105 || reference.sap_type > 0b111
106 || reference.sap_delta_time > 0x0FFF_FFFF
107 {
108 return Err(Error::TooLarge(Self::KIND));
109 }
110
111 let referenced_type_and_size: u32 = match reference.reference_type {
112 true => 0x8000_0000 | reference.referenced_size,
113 false => reference.referenced_size,
114 };
115 referenced_type_and_size.encode(buf)?;
116 reference.subsegment_duration.encode(buf)?;
117 let sap_flag_and_type_and_delta_time = match reference.starts_with_sap {
118 true => {
119 0x8000_0000 | ((reference.sap_type as u32) << 28) | reference.sap_delta_time
120 }
121 false => ((reference.sap_type as u32) << 28) | reference.sap_delta_time,
122 };
123 sap_flag_and_type_and_delta_time.encode(buf)?;
124 }
125 Ok(SidxExt { version })
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 const ENCODED_SIDX: &[u8] = &[
135 0x00, 0x00, 0x00, 0x2c, 0x73, 0x69, 0x64, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x01, 0x00, 0x04, 0xfc, 0x80, 0x00, 0x00, 0x13, 0x80, 0x90, 0x00, 0x00, 0x00,
138 ];
139
140 #[test]
164 fn test_sidx_v0_decode() {
165 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_SIDX);
166 let sidx = Sidx::decode(buf).expect("failed to decode sidx");
167 assert_eq!(
168 sidx,
169 Sidx {
170 reference_id: 1,
171 timescale: 100,
172 earliest_presentation_time: 0,
173 first_offset: 0,
174 references: vec![SegmentReference {
175 reference_type: false,
176 referenced_size: 326784,
177 subsegment_duration: 4992,
178 starts_with_sap: true,
179 sap_type: 1,
180 sap_delta_time: 0,
181 }],
182 }
183 );
184 }
185
186 #[test]
187 fn test_sidx_v0_encode() {
188 let mut buf = Vec::new();
189 let sidx = Sidx {
190 reference_id: 1,
191 timescale: 100,
192 earliest_presentation_time: 0,
193 first_offset: 0,
194 references: vec![SegmentReference {
195 reference_type: false,
196 referenced_size: 326784,
197 subsegment_duration: 4992,
198 starts_with_sap: true,
199 sap_type: 1,
200 sap_delta_time: 0,
201 }],
202 };
203 sidx.encode(&mut buf).unwrap();
204
205 assert_eq!(buf.as_slice(), ENCODED_SIDX);
206 }
207
208 #[test]
209 fn test_sidx_encode_rejects_oversized_reference_fields() {
210 fn assert_too_large(reference: SegmentReference) {
211 let sidx = Sidx {
212 references: vec![reference],
213 ..Default::default()
214 };
215 let mut buf = Vec::new();
216
217 assert!(matches!(
218 sidx.encode(&mut buf),
219 Err(Error::TooLarge(kind)) if kind == Sidx::KIND
220 ));
221 }
222
223 let reference = SegmentReference {
224 reference_type: false,
225 referenced_size: 0,
226 subsegment_duration: 0,
227 starts_with_sap: false,
228 sap_type: 0,
229 sap_delta_time: 0,
230 };
231
232 assert_too_large(SegmentReference {
233 referenced_size: 0x8000_0000,
234 ..reference.clone()
235 });
236 assert_too_large(SegmentReference {
237 sap_type: 0b1000,
238 ..reference.clone()
239 });
240 assert_too_large(SegmentReference {
241 sap_delta_time: 0x1000_0000,
242 ..reference
243 });
244 }
245}