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 reference_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 reference_type_and_size = u32::decode(buf)?;
51 let reference_type = (reference_type_and_size & 0x8000_0000) == 0x8000_0000;
52 let reference_size = reference_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 reference_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 let reference_type_and_size: u32 = match reference.reference_type {
105 true => 0x8000_0000 | reference.reference_size,
106 false => reference.reference_size,
107 };
108 reference_type_and_size.encode(buf)?;
109 reference.subsegment_duration.encode(buf)?;
110 let sap_flag_and_type_and_delta_time = match reference.starts_with_sap {
111 true => {
112 0x8000_0000
113 | ((reference.sap_type as u32 & 0b111) << 28)
114 | (reference.sap_delta_time & 0x0FFF_FFFF)
115 }
116 false => {
117 ((reference.sap_type as u32 & 0b111) << 28)
118 | (reference.sap_delta_time & 0x0FFF_FFFF)
119 }
120 };
121 sap_flag_and_type_and_delta_time.encode(buf)?;
122 }
123 Ok(SidxExt { version })
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 const ENCODED_SIDX: &[u8] = &[
133 0x00, 0x00, 0x00, 0x2c, 0x73, 0x69, 0x64, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x01, 0x00, 0x04, 0xfc, 0x80, 0x00, 0x00, 0x13, 0x80, 0x90, 0x00, 0x00, 0x00,
136 ];
137
138 #[test]
162 fn test_sidx_v0_decode() {
163 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_SIDX);
164 let sidx = Sidx::decode(buf).expect("failed to decode sidx");
165 assert_eq!(
166 sidx,
167 Sidx {
168 reference_id: 1,
169 timescale: 100,
170 earliest_presentation_time: 0,
171 first_offset: 0,
172 references: vec![SegmentReference {
173 reference_type: false,
174 reference_size: 326784,
175 subsegment_duration: 4992,
176 starts_with_sap: true,
177 sap_type: 1,
178 sap_delta_time: 0,
179 }],
180 }
181 );
182 }
183
184 #[test]
185 fn test_sidx_v0_encode() {
186 let mut buf = Vec::new();
187 let sidx = Sidx {
188 reference_id: 1,
189 timescale: 100,
190 earliest_presentation_time: 0,
191 first_offset: 0,
192 references: vec![SegmentReference {
193 reference_type: false,
194 reference_size: 326784,
195 subsegment_duration: 4992,
196 starts_with_sap: true,
197 sap_type: 1,
198 sap_delta_time: 0,
199 }],
200 };
201 sidx.encode(&mut buf).unwrap();
202
203 assert_eq!(buf.as_slice(), ENCODED_SIDX);
204 }
205}