Skip to main content

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

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