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