1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct Sgpd {
7 pub grouping_type: FourCC,
8 pub default_length: Option<u32>,
9 pub default_group_description_index: Option<u32>,
10 pub static_group_description: bool,
11 pub static_mapping: bool,
12 pub essential: bool,
13 pub entries: Vec<SgpdEntry>,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct SgpdEntry {
19 pub description_length: Option<u32>,
20 pub entry: AnySampleGroupEntry,
21}
22
23ext!(
24 name: Sgpd,
25 versions: [0, 1, 2, 3],
26 flags: {
27 static_group_description = 0,
28 static_mapping = 1,
29 }
30);
31
32impl PartialOrd for SgpdVersion {
33 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
34 match (self, other) {
35 (SgpdVersion::V0, SgpdVersion::V0) => Some(std::cmp::Ordering::Equal),
36 (SgpdVersion::V0, _) => Some(std::cmp::Ordering::Less),
37 (SgpdVersion::V1, SgpdVersion::V0) => Some(std::cmp::Ordering::Greater),
38 (SgpdVersion::V1, SgpdVersion::V1) => Some(std::cmp::Ordering::Equal),
39 (SgpdVersion::V1, _) => Some(std::cmp::Ordering::Less),
40 (SgpdVersion::V2, SgpdVersion::V2) => Some(std::cmp::Ordering::Equal),
41 (SgpdVersion::V2, SgpdVersion::V3) => Some(std::cmp::Ordering::Less),
42 (SgpdVersion::V2, _) => Some(std::cmp::Ordering::Greater),
43 (SgpdVersion::V3, SgpdVersion::V3) => Some(std::cmp::Ordering::Equal),
44 (SgpdVersion::V3, _) => Some(std::cmp::Ordering::Greater),
45 }
46 }
47}
48
49impl AtomExt for Sgpd {
50 type Ext = SgpdExt;
51
52 const KIND_EXT: FourCC = FourCC::new(b"sgpd");
53
54 fn decode_body_ext<B: Buf>(buf: &mut B, ext: Self::Ext) -> Result<Self> {
55 let grouping_type = FourCC::decode(buf)?;
56 let default_length = if ext.version >= SgpdVersion::V1 {
57 Some(u32::decode(buf)?)
58 } else {
59 None
60 };
61 let default_group_description_index = if ext.version >= SgpdVersion::V2 {
62 Some(u32::decode(buf)?)
63 } else {
64 None
65 };
66 let entry_count = u32::decode(buf)?;
67 if entry_count as u64 > buf.remaining() as u64 {
72 return Err(Error::OutOfBounds);
73 }
74 let mut entries = Vec::with_capacity((entry_count as usize).min(1024));
75 for _ in 0..entry_count {
76 let description_length = if default_length == Some(0) {
80 Some(u32::decode(buf)?)
81 } else {
82 default_length
83 };
84 let entry = AnySampleGroupEntry::decode(grouping_type, description_length, buf)?;
85 entries.push(SgpdEntry {
86 description_length,
87 entry,
88 });
89 }
90 let static_group_description = ext.static_group_description;
91 let static_mapping = ext.static_mapping;
92 let essential = ext.version == SgpdVersion::V3;
93 Ok(Self {
94 grouping_type,
95 default_length,
96 default_group_description_index,
97 static_group_description,
98 static_mapping,
99 essential,
100 entries,
101 })
102 }
103
104 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
105 let version = if self.essential {
106 SgpdVersion::V3
107 } else if self.default_group_description_index.is_some() {
108 SgpdVersion::V2
109 } else if self.default_length.is_some() {
110 SgpdVersion::V1
111 } else {
112 SgpdVersion::V0
113 };
114 let ext = SgpdExt {
115 version,
116 static_group_description: self.static_group_description,
117 static_mapping: self.static_mapping,
118 };
119 self.grouping_type.encode(buf)?;
120 if version >= SgpdVersion::V1 {
121 self.default_length
122 .ok_or(Error::MissingContent("sgpd default_length"))?
123 .encode(buf)?;
124 }
125 if version >= SgpdVersion::V2 {
126 self.default_group_description_index
127 .ok_or(Error::MissingContent(
128 "sgpd default_group_description_index",
129 ))?
130 .encode(buf)?;
131 }
132 (self.entries.len() as u32).encode(buf)?;
133 for entry in &self.entries {
134 if self.default_length == Some(0) {
135 if let Some(description_length) = entry.description_length {
136 description_length.encode(buf)?
137 }
138 }
139 entry.entry.encode(buf)?
140 }
141 Ok(ext)
142 }
143}
144
145const REFS_4CC: FourCC = FourCC::new(b"refs");
146
147#[derive(Debug, Clone, PartialEq, Eq)]
148#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149pub enum AnySampleGroupEntry {
150 DirectReferenceSampleList(u32, Vec<u32>),
151 UnknownGroupingType(FourCC, Vec<u8>),
152}
153
154impl AnySampleGroupEntry {
155 fn decode<B: Buf>(
156 grouping_type: FourCC,
157 description_length: Option<u32>,
158 buf: &mut B,
159 ) -> Result<Self> {
160 match grouping_type {
161 REFS_4CC => {
162 let sample_id = u32::decode(buf)?;
163 let num_direct_reference_samples = u8::decode(buf)? as usize;
164 let mut direct_reference_samples =
165 Vec::with_capacity(std::cmp::min(num_direct_reference_samples, 16));
166 for _ in 0..num_direct_reference_samples {
167 direct_reference_samples.push(u32::decode(buf)?);
168 }
169 Ok(Self::DirectReferenceSampleList(
170 sample_id,
171 direct_reference_samples,
172 ))
173 }
174 _ => {
175 let bytes = match description_length {
176 Some(description_length) => {
177 Vec::decode_exact(buf, description_length as usize)?
178 }
179 None => Vec::decode(buf)?,
180 };
181 Ok(Self::UnknownGroupingType(grouping_type, bytes))
182 }
183 }
184 }
185
186 fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
187 match self {
188 Self::DirectReferenceSampleList(sample_id, direct_reference_samples) => {
189 sample_id.encode(buf)?;
190 let num_direct_reference_samples: u8 = direct_reference_samples
191 .len()
192 .try_into()
193 .map_err(|_| Error::TooLarge(REFS_4CC))?;
194 num_direct_reference_samples.encode(buf)?;
195 for direct_reference_sample in direct_reference_samples {
196 direct_reference_sample.encode(buf)?;
197 }
198 Ok(())
199 }
200 Self::UnknownGroupingType(_, bytes) => bytes.encode(buf),
201 }
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use std::io::Cursor;
209
210 const SIMPLE_SGPD: &[u8] = &[
215 0x00, 0x00, 0x00, 0x1A, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72, 0x6F, 0x6C,
216 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
217 ];
218
219 #[test]
220 fn sgpd_decodes_from_bytes_correctly() {
221 let mut buf = Cursor::new(SIMPLE_SGPD);
222 let sgpd = Sgpd::decode(&mut buf).expect("sgpd should decode successfully");
223 assert_eq!(
224 sgpd,
225 Sgpd {
226 grouping_type: FourCC::from(b"roll"),
227 default_length: Some(2),
228 default_group_description_index: None,
229 static_group_description: false,
230 static_mapping: false,
231 essential: false,
232 entries: vec![SgpdEntry {
233 description_length: Some(2),
234 entry: AnySampleGroupEntry::UnknownGroupingType(
235 FourCC::from(b"roll"),
236 SIMPLE_SGPD[24..].to_vec()
237 )
238 }],
239 }
240 )
241 }
242
243 #[test]
244 fn sgpd_encodes_from_type_correctly() {
245 let sgpd = Sgpd {
246 grouping_type: FourCC::from(b"roll"),
247 default_length: Some(2),
248 default_group_description_index: None,
249 static_group_description: false,
250 static_mapping: false,
251 essential: false,
252 entries: vec![SgpdEntry {
253 description_length: Some(2),
254 entry: AnySampleGroupEntry::UnknownGroupingType(
255 FourCC::from(b"roll"),
256 SIMPLE_SGPD[24..].to_vec(),
257 ),
258 }],
259 };
260 let mut buf = Vec::new();
261 sgpd.encode(&mut buf).expect("encode should be successful");
262 assert_eq!(SIMPLE_SGPD, &buf);
263 }
264
265 #[test]
266 fn sgpd_unknown_entries_respect_description_length() {
267 const MULTIPLE_ENTRIES: &[u8] = &[
268 0x00, 0x00, 0x00, 0x1C, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x74, 0x65,
269 0x73, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0xAA, 0xBB, 0xCC, 0xDD,
270 ];
271
272 let sgpd = Sgpd::decode(&mut Cursor::new(MULTIPLE_ENTRIES))
273 .expect("sgpd should decode successfully");
274
275 assert_eq!(
276 sgpd.entries,
277 vec![
278 SgpdEntry {
279 description_length: Some(2),
280 entry: AnySampleGroupEntry::UnknownGroupingType(
281 FourCC::from(b"test"),
282 vec![0xAA, 0xBB],
283 ),
284 },
285 SgpdEntry {
286 description_length: Some(2),
287 entry: AnySampleGroupEntry::UnknownGroupingType(
288 FourCC::from(b"test"),
289 vec![0xCC, 0xDD],
290 ),
291 },
292 ]
293 );
294 }
295
296 #[test]
297 fn sgpd_rejects_entry_count_past_the_box() {
298 const HUGE_COUNT: &[u8] = &[
301 0x00, 0x00, 0x00, 0x14, 0x73, 0x67, 0x70, 0x64, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
302 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
303 ];
304
305 let err = Sgpd::decode(&mut Cursor::new(HUGE_COUNT)).unwrap_err();
306 assert!(matches!(err, Error::OverDecode(_)), "{err:?}");
307 }
308
309 #[test]
310 fn sgpd_version_0_unknown_entries_still_decode() {
311 const VERSION_0: &[u8] = &[
314 0x00, 0x00, 0x00, 0x18, 0x73, 0x67, 0x70, 0x64, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6F,
315 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFE,
316 ];
317
318 let sgpd = Sgpd::decode(&mut Cursor::new(VERSION_0)).expect("sgpd should decode");
319 assert_eq!(sgpd.entries.len(), 2);
320 assert_eq!(
321 sgpd.entries[0].entry,
322 AnySampleGroupEntry::UnknownGroupingType(
323 FourCC::from(b"roll"),
324 vec![0xFF, 0xFF, 0xFF, 0xFE]
325 )
326 );
327 }
328
329 #[test]
330 fn sgpd_essential_requires_version_3_defaults() {
331 let mut sgpd = Sgpd {
332 grouping_type: FourCC::from(b"test"),
333 default_length: None,
334 default_group_description_index: None,
335 static_group_description: false,
336 static_mapping: false,
337 essential: true,
338 entries: vec![],
339 };
340
341 let err = sgpd.encode(&mut Vec::new()).unwrap_err();
342 assert!(matches!(err, Error::MissingContent("sgpd default_length")));
343
344 sgpd.default_length = Some(0);
345 let err = sgpd.encode(&mut Vec::new()).unwrap_err();
346 assert!(matches!(
347 err,
348 Error::MissingContent("sgpd default_group_description_index")
349 ));
350 }
351
352 const SGPD_ENCODED_C041: &[u8] = &[
354 0x00, 0x00, 0x00, 0x2e, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72, 0x65, 0x66,
355 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
356 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
357 0x00,
358 ];
359
360 #[test]
361 fn sgpd_c041_decode() {
362 let mut buf = Cursor::new(SGPD_ENCODED_C041);
363 let sgpd = Sgpd::decode(&mut buf).expect("sgpd should decode successfully");
364 assert_eq!(
365 sgpd,
366 Sgpd {
367 grouping_type: FourCC::from(b"refs"),
368 default_length: Some(0),
369 default_group_description_index: None,
370 static_group_description: false,
371 static_mapping: false,
372 essential: false,
373 entries: vec![
374 SgpdEntry {
375 description_length: Some(9),
376 entry: AnySampleGroupEntry::DirectReferenceSampleList(0, vec![1])
377 },
378 SgpdEntry {
379 description_length: Some(5),
380 entry: AnySampleGroupEntry::DirectReferenceSampleList(1, vec![])
381 }
382 ],
383 }
384 );
385
386 let mut encoded = Vec::new();
387 sgpd.encode(&mut encoded).unwrap();
388
389 assert_eq!(encoded, SGPD_ENCODED_C041);
390 }
391}