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 let mut entries = Vec::with_capacity((entry_count as usize).min(1024));
68 for _ in 0..entry_count {
69 let description_length = if default_length == Some(0) {
73 Some(u32::decode(buf)?)
74 } else {
75 default_length
76 };
77 let entry = AnySampleGroupEntry::decode(grouping_type, description_length, buf)?;
78 entries.push(SgpdEntry {
79 description_length,
80 entry,
81 });
82 }
83 let static_group_description = ext.static_group_description;
84 let static_mapping = ext.static_mapping;
85 let essential = ext.version == SgpdVersion::V3;
86 Ok(Self {
87 grouping_type,
88 default_length,
89 default_group_description_index,
90 static_group_description,
91 static_mapping,
92 essential,
93 entries,
94 })
95 }
96
97 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
98 let version = if self.essential {
99 SgpdVersion::V3
100 } else if self.default_group_description_index.is_some() {
101 SgpdVersion::V2
102 } else if self.default_length.is_some() {
103 SgpdVersion::V1
104 } else {
105 SgpdVersion::V0
106 };
107 let ext = SgpdExt {
108 version,
109 static_group_description: self.static_group_description,
110 static_mapping: self.static_mapping,
111 };
112 self.grouping_type.encode(buf)?;
113 if version >= SgpdVersion::V1 {
114 self.default_length
115 .ok_or(Error::MissingContent("sgpd default_length"))?
116 .encode(buf)?;
117 }
118 if version >= SgpdVersion::V2 {
119 self.default_group_description_index
120 .ok_or(Error::MissingContent(
121 "sgpd default_group_description_index",
122 ))?
123 .encode(buf)?;
124 }
125 (self.entries.len() as u32).encode(buf)?;
126 for entry in &self.entries {
127 if self.default_length == Some(0) {
128 if let Some(description_length) = entry.description_length {
129 description_length.encode(buf)?
130 }
131 }
132 entry.entry.encode(buf)?
133 }
134 Ok(ext)
135 }
136}
137
138const REFS_4CC: FourCC = FourCC::new(b"refs");
139
140#[derive(Debug, Clone, PartialEq, Eq)]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub enum AnySampleGroupEntry {
143 DirectReferenceSampleList(u32, Vec<u32>),
144 UnknownGroupingType(FourCC, Vec<u8>),
145}
146
147impl AnySampleGroupEntry {
148 fn decode<B: Buf>(
149 grouping_type: FourCC,
150 description_length: Option<u32>,
151 buf: &mut B,
152 ) -> Result<Self> {
153 match grouping_type {
154 REFS_4CC => {
155 let sample_id = u32::decode(buf)?;
156 let num_direct_reference_samples = u8::decode(buf)? as usize;
157 let mut direct_reference_samples =
158 Vec::with_capacity(std::cmp::min(num_direct_reference_samples, 16));
159 for _ in 0..num_direct_reference_samples {
160 direct_reference_samples.push(u32::decode(buf)?);
161 }
162 Ok(Self::DirectReferenceSampleList(
163 sample_id,
164 direct_reference_samples,
165 ))
166 }
167 _ => {
168 let bytes = match description_length {
169 Some(description_length) => {
170 Vec::decode_exact(buf, description_length as usize)?
171 }
172 None => Vec::decode(buf)?,
173 };
174 Ok(Self::UnknownGroupingType(grouping_type, bytes))
175 }
176 }
177 }
178
179 fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
180 match self {
181 Self::DirectReferenceSampleList(sample_id, direct_reference_samples) => {
182 sample_id.encode(buf)?;
183 let num_direct_reference_samples: u8 = direct_reference_samples
184 .len()
185 .try_into()
186 .map_err(|_| Error::TooLarge(REFS_4CC))?;
187 num_direct_reference_samples.encode(buf)?;
188 for direct_reference_sample in direct_reference_samples {
189 direct_reference_sample.encode(buf)?;
190 }
191 Ok(())
192 }
193 Self::UnknownGroupingType(_, bytes) => bytes.encode(buf),
194 }
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use std::io::Cursor;
202
203 const SIMPLE_SGPD: &[u8] = &[
208 0x00, 0x00, 0x00, 0x1A, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72, 0x6F, 0x6C,
209 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
210 ];
211
212 #[test]
213 fn sgpd_decodes_from_bytes_correctly() {
214 let mut buf = Cursor::new(SIMPLE_SGPD);
215 let sgpd = Sgpd::decode(&mut buf).expect("sgpd should decode successfully");
216 assert_eq!(
217 sgpd,
218 Sgpd {
219 grouping_type: FourCC::from(b"roll"),
220 default_length: Some(2),
221 default_group_description_index: None,
222 static_group_description: false,
223 static_mapping: false,
224 essential: false,
225 entries: vec![SgpdEntry {
226 description_length: Some(2),
227 entry: AnySampleGroupEntry::UnknownGroupingType(
228 FourCC::from(b"roll"),
229 SIMPLE_SGPD[24..].to_vec()
230 )
231 }],
232 }
233 )
234 }
235
236 #[test]
237 fn sgpd_encodes_from_type_correctly() {
238 let sgpd = Sgpd {
239 grouping_type: FourCC::from(b"roll"),
240 default_length: Some(2),
241 default_group_description_index: None,
242 static_group_description: false,
243 static_mapping: false,
244 essential: false,
245 entries: vec![SgpdEntry {
246 description_length: Some(2),
247 entry: AnySampleGroupEntry::UnknownGroupingType(
248 FourCC::from(b"roll"),
249 SIMPLE_SGPD[24..].to_vec(),
250 ),
251 }],
252 };
253 let mut buf = Vec::new();
254 sgpd.encode(&mut buf).expect("encode should be successful");
255 assert_eq!(SIMPLE_SGPD, &buf);
256 }
257
258 #[test]
259 fn sgpd_unknown_entries_respect_description_length() {
260 const MULTIPLE_ENTRIES: &[u8] = &[
261 0x00, 0x00, 0x00, 0x1C, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x74, 0x65,
262 0x73, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0xAA, 0xBB, 0xCC, 0xDD,
263 ];
264
265 let sgpd = Sgpd::decode(&mut Cursor::new(MULTIPLE_ENTRIES))
266 .expect("sgpd should decode successfully");
267
268 assert_eq!(
269 sgpd.entries,
270 vec![
271 SgpdEntry {
272 description_length: Some(2),
273 entry: AnySampleGroupEntry::UnknownGroupingType(
274 FourCC::from(b"test"),
275 vec![0xAA, 0xBB],
276 ),
277 },
278 SgpdEntry {
279 description_length: Some(2),
280 entry: AnySampleGroupEntry::UnknownGroupingType(
281 FourCC::from(b"test"),
282 vec![0xCC, 0xDD],
283 ),
284 },
285 ]
286 );
287 }
288
289 #[test]
290 fn sgpd_essential_requires_version_3_defaults() {
291 let mut sgpd = Sgpd {
292 grouping_type: FourCC::from(b"test"),
293 default_length: None,
294 default_group_description_index: None,
295 static_group_description: false,
296 static_mapping: false,
297 essential: true,
298 entries: vec![],
299 };
300
301 let err = sgpd.encode(&mut Vec::new()).unwrap_err();
302 assert!(matches!(err, Error::MissingContent("sgpd default_length")));
303
304 sgpd.default_length = Some(0);
305 let err = sgpd.encode(&mut Vec::new()).unwrap_err();
306 assert!(matches!(
307 err,
308 Error::MissingContent("sgpd default_group_description_index")
309 ));
310 }
311
312 const SGPD_ENCODED_C041: &[u8] = &[
314 0x00, 0x00, 0x00, 0x2e, 0x73, 0x67, 0x70, 0x64, 0x01, 0x00, 0x00, 0x00, 0x72, 0x65, 0x66,
315 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
316 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
317 0x00,
318 ];
319
320 #[test]
321 fn sgpd_c041_decode() {
322 let mut buf = Cursor::new(SGPD_ENCODED_C041);
323 let sgpd = Sgpd::decode(&mut buf).expect("sgpd should decode successfully");
324 assert_eq!(
325 sgpd,
326 Sgpd {
327 grouping_type: FourCC::from(b"refs"),
328 default_length: Some(0),
329 default_group_description_index: None,
330 static_group_description: false,
331 static_mapping: false,
332 essential: false,
333 entries: vec![
334 SgpdEntry {
335 description_length: Some(9),
336 entry: AnySampleGroupEntry::DirectReferenceSampleList(0, vec![1])
337 },
338 SgpdEntry {
339 description_length: Some(5),
340 entry: AnySampleGroupEntry::DirectReferenceSampleList(1, vec![])
341 }
342 ],
343 }
344 );
345
346 let mut encoded = Vec::new();
347 sgpd.encode(&mut encoded).unwrap();
348
349 assert_eq!(encoded, SGPD_ENCODED_C041);
350 }
351}