mp4_atom/moov/trak/mdia/minf/stbl/stsd/
uncv.rs

1use crate::*;
2
3use super::{Btrt, Pasp, Visual};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub struct Uncv {
8    pub visual: Visual,
9    pub cmpd: Option<Cmpd>,
10    pub uncc: UncC,
11    pub btrt: Option<Btrt>,
12    pub ccst: Option<Ccst>,
13    pub pasp: Option<Pasp>,
14}
15
16impl Atom for Uncv {
17    const KIND: FourCC = FourCC::new(b"uncv");
18
19    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
20        let visual = Visual::decode(buf)?;
21
22        let mut ccst = None;
23        let mut cmpd = None;
24        let mut uncc = None;
25        let mut btrt = None;
26        let mut pasp = None;
27        while let Some(atom) = Any::decode_maybe(buf)? {
28            match atom {
29                Any::Cmpd(atom) => cmpd = atom.into(),
30                Any::UncC(atom) => uncc = atom.into(),
31                Any::Btrt(atom) => btrt = atom.into(),
32                Any::Ccst(atom) => ccst = atom.into(),
33                Any::Pasp(atom) => pasp = atom.into(),
34                _ => tracing::warn!("unknown atom: {:?}", atom),
35            }
36        }
37
38        Ok(Uncv {
39            visual,
40            cmpd,
41            uncc: uncc.ok_or(Error::MissingBox(UncC::KIND))?,
42            btrt,
43            ccst,
44            pasp,
45        })
46    }
47
48    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
49        self.visual.encode(buf)?;
50        if self.cmpd.is_some() {
51            self.cmpd.encode(buf)?;
52        }
53        self.uncc.encode(buf)?;
54        if self.btrt.is_some() {
55            self.btrt.encode(buf)?;
56        }
57        if self.ccst.is_some() {
58            self.ccst.encode(buf)?;
59        }
60        if self.pasp.is_some() {
61            self.pasp.encode(buf)?;
62        }
63
64        Ok(())
65    }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub struct Component {
71    pub component_type: u16,
72    pub component_type_uri: Option<String>,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Default)]
76#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
77pub struct Cmpd {
78    pub components: Vec<Component>,
79}
80
81impl Atom for Cmpd {
82    const KIND: FourCC = FourCC::new(b"cmpd");
83
84    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
85        let component_count = u32::decode(buf)?;
86        let mut components: Vec<Component> = Vec::with_capacity(component_count as usize);
87        for _ in 0..component_count {
88            let component_type = u16::decode(buf)?;
89            if component_type >= 0x8000 {
90                let component_type_uri = String::decode(buf)?;
91                components.push(Component {
92                    component_type,
93                    component_type_uri: Some(component_type_uri),
94                });
95            } else {
96                components.push(Component {
97                    component_type,
98                    component_type_uri: None,
99                });
100            }
101        }
102        Ok(Cmpd { components })
103    }
104
105    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
106        let component_count: u32 = self.components.len() as u32;
107        component_count.encode(buf)?;
108        for component in &self.components {
109            component.component_type.encode(buf)?;
110            if component.component_type >= 0x8000 {
111                let component_type_uri = component
112                    .component_type_uri
113                    .as_ref()
114                    .expect("Expected valid URI when component_type is >= 0x8000");
115                component_type_uri.as_str().encode(buf)?;
116            }
117        }
118        Ok(())
119    }
120}
121
122#[derive(Debug, Clone, PartialEq, Eq)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124pub struct UncompressedComponent {
125    pub component_index: u16,
126    pub component_bit_depth_minus_one: u8,
127    pub component_format: u8,
128    pub component_align_size: u8,
129}
130
131ext! {
132    name: UncC,
133    versions: [0, 1],
134    flags: {}
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
138#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
139pub enum UncC {
140    V1 {
141        profile: FourCC,
142    },
143    V0 {
144        profile: FourCC,
145        components: Vec<UncompressedComponent>,
146        sampling_type: u8,   // TODO: enum?
147        interleave_type: u8, // TODO: enum?
148        block_size: u8,
149        components_little_endian: bool,
150        block_pad_lsb: bool,
151        block_little_endian: bool,
152        block_reversed: bool,
153        pad_unknown: bool,
154        pixel_size: u32,
155        row_align_size: u32,
156        tile_align_size: u32,
157        num_tile_cols_minus_one: u32,
158        num_tile_rows_minus_one: u32,
159    },
160}
161
162impl AtomExt for UncC {
163    const KIND_EXT: FourCC = FourCC::new(b"uncC");
164
165    type Ext = UncCExt;
166
167    fn decode_body_ext<B: Buf>(buf: &mut B, ext: UncCExt) -> Result<Self> {
168        match ext.version {
169            UncCVersion::V1 => Ok(UncC::V1 {
170                profile: FourCC::decode(buf)?,
171            }),
172            UncCVersion::V0 => {
173                let profile = FourCC::decode(buf)?;
174                let component_count = u32::decode(buf)?;
175                let mut components = Vec::with_capacity(component_count as usize);
176                for _ in 0..component_count {
177                    components.push(UncompressedComponent {
178                        component_index: u16::decode(buf)?,
179                        component_bit_depth_minus_one: u8::decode(buf)?,
180                        component_format: u8::decode(buf)?,
181                        component_align_size: u8::decode(buf)?,
182                    });
183                }
184                let sampling_type = u8::decode(buf)?;
185                let interleave_type = u8::decode(buf)?;
186                let block_size = u8::decode(buf)?;
187                let flag_bits = u8::decode(buf)?;
188                let components_little_endian = flag_bits & 0x80 == 0x80;
189                let block_pad_lsb = flag_bits & 0x40 == 0x40;
190                let block_little_endian = flag_bits & 0x20 == 0x20;
191                let block_reversed = flag_bits & 0x10 == 0x10;
192                let pad_unknown = flag_bits & 0x08 == 0x08;
193                let pixel_size = u32::decode(buf)?;
194                let row_align_size = u32::decode(buf)?;
195                let tile_align_size = u32::decode(buf)?;
196                let num_tile_cols_minus_one = u32::decode(buf)?;
197                let num_tile_rows_minus_one = u32::decode(buf)?;
198                Ok(UncC::V0 {
199                    profile,
200                    components,
201                    sampling_type,
202                    interleave_type,
203                    block_size,
204                    components_little_endian,
205                    block_pad_lsb,
206                    block_little_endian,
207                    block_reversed,
208                    pad_unknown,
209                    pixel_size,
210                    row_align_size,
211                    tile_align_size,
212                    num_tile_cols_minus_one,
213                    num_tile_rows_minus_one,
214                })
215            }
216        }
217    }
218
219    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<UncCExt> {
220        match self {
221            UncC::V1 { profile } => {
222                profile.encode(buf)?;
223                Ok(UncCExt {
224                    version: UncCVersion::V1,
225                })
226            }
227            UncC::V0 {
228                profile,
229                components,
230                sampling_type,
231                interleave_type,
232                block_size,
233                components_little_endian,
234                block_pad_lsb,
235                block_little_endian,
236                block_reversed,
237                pad_unknown,
238                pixel_size,
239                row_align_size,
240                tile_align_size,
241                num_tile_cols_minus_one,
242                num_tile_rows_minus_one,
243            } => {
244                profile.encode(buf)?;
245                let component_count: u32 = components.len() as u32;
246                component_count.encode(buf)?;
247                for component in components {
248                    component.component_index.encode(buf)?;
249                    component.component_bit_depth_minus_one.encode(buf)?;
250                    component.component_format.encode(buf)?;
251                    component.component_align_size.encode(buf)?;
252                }
253                sampling_type.encode(buf)?;
254                interleave_type.encode(buf)?;
255                block_size.encode(buf)?;
256                let mut flags: u8 = 0x00;
257                if *components_little_endian {
258                    flags |= 0x80u8;
259                }
260                if *block_pad_lsb {
261                    flags |= 0x40u8;
262                }
263                if *block_little_endian {
264                    flags |= 0x20u8;
265                }
266                if *block_reversed {
267                    flags |= 0x10u8;
268                }
269                if *pad_unknown {
270                    flags |= 0x08u8;
271                }
272                flags.encode(buf)?;
273                pixel_size.encode(buf)?;
274                row_align_size.encode(buf)?;
275                tile_align_size.encode(buf)?;
276                num_tile_cols_minus_one.encode(buf)?;
277                num_tile_rows_minus_one.encode(buf)?;
278                Ok(UncCExt {
279                    version: UncCVersion::V0,
280                })
281            }
282        }
283    }
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289
290    const ENCODED_CMPD: &[u8] = &[
291        0x00, 0x00, 0x00, 0x12, 0x63, 0x6d, 0x70, 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
292        0x05, 0x00, 0x06,
293    ];
294
295    const ENCODED_UNCC: &[u8] = &[
296        0x00, 0x00, 0x00, 0x3b, 0x75, 0x6e, 0x63, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297        0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x00,
298        0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300    ];
301
302    #[test]
303    fn test_cmpd_decode() {
304        let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_CMPD);
305
306        let cmpd = Cmpd::decode(buf).expect("failed to decode cmpd");
307
308        assert_eq!(
309            cmpd,
310            Cmpd {
311                components: vec![
312                    Component {
313                        component_type: 4,
314                        component_type_uri: None
315                    },
316                    Component {
317                        component_type: 5,
318                        component_type_uri: None
319                    },
320                    Component {
321                        component_type: 6,
322                        component_type_uri: None
323                    }
324                ]
325            },
326        );
327    }
328
329    #[test]
330    fn test_cmpd_encode() {
331        let cmpd = Cmpd {
332            components: vec![
333                Component {
334                    component_type: 4,
335                    component_type_uri: None,
336                },
337                Component {
338                    component_type: 5,
339                    component_type_uri: None,
340                },
341                Component {
342                    component_type: 6,
343                    component_type_uri: None,
344                },
345            ],
346        };
347
348        let mut buf = Vec::new();
349        cmpd.encode(&mut buf).unwrap();
350
351        assert_eq!(buf.as_slice(), ENCODED_CMPD);
352    }
353
354    #[test]
355    fn test_uncc_decode() {
356        let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_UNCC);
357
358        let uncc = UncC::decode(buf).expect("failed to decode uncC");
359
360        assert_eq!(
361            uncc,
362            UncC::V0 {
363                profile: FourCC::new(b"\0\0\0\0"),
364                components: vec![
365                    UncompressedComponent {
366                        component_index: 0,
367                        component_bit_depth_minus_one: 7,
368                        component_format: 0,
369                        component_align_size: 0
370                    },
371                    UncompressedComponent {
372                        component_index: 1,
373                        component_bit_depth_minus_one: 7,
374                        component_format: 0,
375                        component_align_size: 0
376                    },
377                    UncompressedComponent {
378                        component_index: 2,
379                        component_bit_depth_minus_one: 7,
380                        component_format: 0,
381                        component_align_size: 0
382                    },
383                ],
384                sampling_type: 0,
385                interleave_type: 1,
386                block_size: 0,
387                components_little_endian: false,
388                block_pad_lsb: false,
389                block_little_endian: false,
390                block_reversed: false,
391                pad_unknown: false,
392                pixel_size: 0,
393                row_align_size: 0,
394                tile_align_size: 0,
395                num_tile_cols_minus_one: 0,
396                num_tile_rows_minus_one: 0
397            }
398        );
399    }
400
401    #[test]
402    fn test_uncc_encode() {
403        let uncc = UncC::V0 {
404            profile: FourCC::new(b"\0\0\0\0"),
405            components: vec![
406                UncompressedComponent {
407                    component_index: 0,
408                    component_bit_depth_minus_one: 7,
409                    component_format: 0,
410                    component_align_size: 0,
411                },
412                UncompressedComponent {
413                    component_index: 1,
414                    component_bit_depth_minus_one: 7,
415                    component_format: 0,
416                    component_align_size: 0,
417                },
418                UncompressedComponent {
419                    component_index: 2,
420                    component_bit_depth_minus_one: 7,
421                    component_format: 0,
422                    component_align_size: 0,
423                },
424            ],
425            sampling_type: 0,
426            interleave_type: 1,
427            block_size: 0,
428            components_little_endian: false,
429            block_pad_lsb: false,
430            block_little_endian: false,
431            block_reversed: false,
432            pad_unknown: false,
433            pixel_size: 0,
434            row_align_size: 0,
435            tile_align_size: 0,
436            num_tile_cols_minus_one: 0,
437            num_tile_rows_minus_one: 0,
438        };
439
440        let mut buf = Vec::new();
441        uncc.encode(&mut buf).unwrap();
442
443        assert_eq!(buf.as_slice(), ENCODED_UNCC);
444    }
445}