Skip to main content

mp4_atom/
types.rs

1use std::fmt;
2
3use crate::*;
4
5// Re-export this common types.
6pub use num::rational::Ratio;
7pub use num::traits::ToBytes;
8
9/// A four-character code used to identify atoms.
10#[derive(Clone, Copy, PartialEq, Eq, Hash)]
11// TODO serialize as a string
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct FourCC([u8; 4]);
14
15impl FourCC {
16    // Helper function to create a FourCC from a string literal
17    // ex. FourCC::new(b"abcd")
18    pub const fn new(value: &[u8; 4]) -> Self {
19        FourCC(*value)
20    }
21}
22
23impl From<u32> for FourCC {
24    fn from(value: u32) -> Self {
25        FourCC(value.to_be_bytes())
26    }
27}
28
29impl From<FourCC> for u32 {
30    fn from(cc: FourCC) -> Self {
31        u32::from_be_bytes(cc.0)
32    }
33}
34
35impl From<[u8; 4]> for FourCC {
36    fn from(value: [u8; 4]) -> Self {
37        FourCC(value)
38    }
39}
40
41impl From<FourCC> for [u8; 4] {
42    fn from(cc: FourCC) -> Self {
43        cc.0
44    }
45}
46
47impl From<&[u8; 4]> for FourCC {
48    fn from(value: &[u8; 4]) -> Self {
49        FourCC(*value)
50    }
51}
52
53impl fmt::Display for FourCC {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        let s = String::from_utf8_lossy(&self.0);
56        write!(f, "{s}")
57    }
58}
59
60impl fmt::Debug for FourCC {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        let s = String::from_utf8_lossy(&self.0);
63        write!(f, "{s}")
64    }
65}
66
67impl Encode for FourCC {
68    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
69        self.0.encode(buf)
70    }
71}
72
73impl Decode for FourCC {
74    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
75        Ok(FourCC(<[u8; 4]>::decode(buf)?))
76    }
77}
78
79impl AsRef<[u8; 4]> for FourCC {
80    fn as_ref(&self) -> &[u8; 4] {
81        &self.0
82    }
83}
84
85#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
86#[allow(non_camel_case_types)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88pub struct u24([u8; 3]);
89
90impl u24 {
91    pub const MAX: u32 = 0x00FF_FFFF;
92}
93
94impl From<[u8; 3]> for u24 {
95    fn from(value: [u8; 3]) -> Self {
96        Self(value)
97    }
98}
99
100impl Decode for u24 {
101    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
102        Ok(Self(<[u8; 3]>::decode(buf)?))
103    }
104}
105
106impl Encode for u24 {
107    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
108        self.0.encode(buf)
109    }
110}
111
112impl From<u24> for u32 {
113    fn from(value: u24) -> Self {
114        u32::from_be_bytes([0, value.0[0], value.0[1], value.0[2]])
115    }
116}
117
118impl TryFrom<u32> for u24 {
119    type Error = std::array::TryFromSliceError;
120
121    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
122        Ok(Self(value.to_be_bytes()[1..].try_into()?))
123    }
124}
125
126impl ToBytes for u24 {
127    type Bytes = [u8; 3];
128
129    fn to_be_bytes(&self) -> Self::Bytes {
130        self.0
131    }
132
133    fn to_le_bytes(&self) -> Self::Bytes {
134        [self.0[2], self.0[1], self.0[0]]
135    }
136}
137
138#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
139#[allow(non_camel_case_types)]
140#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
141pub struct u48([u8; 6]);
142
143impl Decode for u48 {
144    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
145        Ok(Self(<[u8; 6]>::decode(buf)?))
146    }
147}
148
149impl Encode for u48 {
150    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
151        self.0.encode(buf)
152    }
153}
154
155impl TryFrom<u64> for u48 {
156    type Error = std::array::TryFromSliceError;
157
158    fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
159        Ok(Self(value.to_be_bytes()[2..].try_into()?))
160    }
161}
162
163impl From<u48> for u64 {
164    fn from(value: u48) -> Self {
165        u64::from_be_bytes([
166            0, 0, value.0[0], value.0[1], value.0[2], value.0[3], value.0[4], value.0[5],
167        ])
168    }
169}
170
171impl From<[u8; 6]> for u48 {
172    fn from(value: [u8; 6]) -> Self {
173        u48(value)
174    }
175}
176
177impl AsRef<[u8; 6]> for u48 {
178    fn as_ref(&self) -> &[u8; 6] {
179        &self.0
180    }
181}
182
183// The top N bits are the integer part, the bottom N bits are the fractional part.
184// Somebody who cares should implement some math stuff.
185#[derive(Copy, Clone, Default, PartialEq, Eq)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
187pub struct FixedPoint<T> {
188    int: T,
189    dec: T,
190}
191
192impl<T: Copy> FixedPoint<T> {
193    pub fn new(int: T, dec: T) -> Self {
194        Self { int, dec }
195    }
196
197    pub fn integer(&self) -> T {
198        self.int
199    }
200
201    pub fn decimal(&self) -> T {
202        self.dec
203    }
204}
205
206impl<T: Decode> Decode for FixedPoint<T> {
207    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
208        Ok(Self {
209            int: T::decode(buf)?,
210            dec: T::decode(buf)?,
211        })
212    }
213}
214
215impl<T: Encode> Encode for FixedPoint<T> {
216    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
217        self.int.encode(buf)?;
218        self.dec.encode(buf)
219    }
220}
221
222impl<T: num::Zero> From<T> for FixedPoint<T> {
223    fn from(value: T) -> Self {
224        Self {
225            int: value,
226            dec: T::zero(),
227        }
228    }
229}
230
231impl<T> fmt::Debug for FixedPoint<T>
232where
233    T: num::Zero + fmt::Debug + PartialEq + Copy,
234    f64: From<T>,
235{
236    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237        if self.dec.is_zero() {
238            write!(f, "{:?}", self.int)
239        } else {
240            // The fractional half counts units of 1/2^N, N being its bit width.
241            let scale = 2f64.powi(8 * size_of::<T>() as i32);
242            let mut dec = f64::from(self.dec);
243            if dec < 0.0 {
244                // A signed type: the bits are still an unsigned fraction.
245                dec += scale;
246            }
247            write!(f, "{:?}", f64::from(self.int) + dec / scale)
248        }
249    }
250}
251
252// 32 bytes max
253#[derive(Debug, Clone, PartialEq, Eq, Default)]
254#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
255pub struct Compressor(String);
256
257impl From<&str> for Compressor {
258    fn from(value: &str) -> Self {
259        Self(value.to_string())
260    }
261}
262
263impl From<String> for Compressor {
264    fn from(value: String) -> Self {
265        Self(value)
266    }
267}
268
269impl From<Compressor> for String {
270    fn from(value: Compressor) -> Self {
271        value.0
272    }
273}
274
275impl AsRef<str> for Compressor {
276    fn as_ref(&self) -> &str {
277        &self.0
278    }
279}
280
281impl Encode for Compressor {
282    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
283        let name = self.0.as_bytes();
284        let len = name.len();
285        if len > 31 {
286            return Err(Error::InvalidSize);
287        }
288        (len as u8).encode(buf)?;
289        (&name[..len]).encode(buf)?;
290
291        let zero = [0u8; 31];
292        (&zero[..31 - len]).encode(buf)
293    }
294}
295
296impl Decode for Compressor {
297    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
298        let compressor_name_bytes = <[u8; 32]>::decode(buf)?;
299        match compressor_name_bytes[0] {
300            0 => Ok(Self(String::new())),
301            1..=31 => {
302                let start_bytes = 1;
303                let end_bytes = start_bytes + compressor_name_bytes[0] as usize;
304                let name = String::from_utf8_lossy(&compressor_name_bytes[start_bytes..end_bytes])
305                    .trim_end_matches('\0')
306                    .to_string();
307                Ok(Self(name))
308            }
309            _ => {
310                // try reading as a string
311                let name = String::from_utf8_lossy(&compressor_name_bytes)
312                    .trim_end_matches('\0')
313                    .to_string();
314                Ok(Self(name))
315            }
316        }
317    }
318}
319
320#[derive(Debug, Clone, PartialEq, Eq, Default)]
321#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
322pub struct Zeroed {
323    pub size: usize,
324}
325
326impl Zeroed {
327    pub fn new(size: usize) -> Self {
328        Self { size }
329    }
330}
331
332impl Encode for Zeroed {
333    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
334        let zero = [0u8; 32];
335        let mut size = self.size;
336
337        while size > 0 {
338            let len = zero.len().min(size);
339            (&zero[..len]).encode(buf)?;
340            size -= len;
341        }
342
343        Ok(())
344    }
345}
346
347impl Decode for Zeroed {
348    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
349        let size = buf.remaining();
350        buf.advance(size);
351        Ok(Self { size })
352    }
353}
354
355impl From<usize> for Zeroed {
356    fn from(size: usize) -> Self {
357        Self { size }
358    }
359}
360
361/// A 16-byte code used to identify UUID boxes.
362#[derive(Copy, Clone, Default, PartialEq, Eq)]
363#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
364pub struct ExtendedType([u8; 16]);
365
366impl ExtendedType {
367    pub const fn new(value: &[u8; 16]) -> Self {
368        ExtendedType(*value)
369    }
370}
371
372impl From<&[u8; 16]> for ExtendedType {
373    fn from(val: &[u8; 16]) -> ExtendedType {
374        ExtendedType(*val)
375    }
376}
377
378impl From<[u8; 16]> for ExtendedType {
379    fn from(val: [u8; 16]) -> ExtendedType {
380        ExtendedType(val)
381    }
382}
383
384impl From<ExtendedType> for [u8; 16] {
385    fn from(et: ExtendedType) -> [u8; 16] {
386        et.0
387    }
388}
389
390impl Encode for ExtendedType {
391    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
392        self.0.encode(buf)
393    }
394}
395impl Decode for ExtendedType {
396    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
397        Ok(ExtendedType(<[u8; 16]>::decode(buf)?))
398    }
399}
400
401impl fmt::Display for ExtendedType {
402    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403        write!(f, "{:02x?}", self.0)
404    }
405}
406
407impl fmt::Debug for ExtendedType {
408    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409        write!(f, "{:02x?}", self.0)
410    }
411}
412
413impl AsRef<[u8; 16]> for ExtendedType {
414    fn as_ref(&self) -> &[u8; 16] {
415        &self.0
416    }
417}
418
419#[cfg(test)]
420mod tests {
421    use crate::{Compressor, Decode as _, Encode as _, ExtendedType, FixedPoint};
422
423    #[test]
424    fn check_compressor_encode_minimal() {
425        let compressor = Compressor::from("A");
426        let mut buf = Vec::new();
427        compressor.encode(&mut buf).unwrap();
428        assert_eq!(buf.len(), 32);
429        assert_eq!(
430            buf,
431            vec![
432                0x01, b'A', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
434                0x00, 0x00, 0x00, 0x00,
435            ]
436        );
437        let decode = Compressor::decode(&mut buf.as_ref()).unwrap();
438        assert_eq!(decode, compressor);
439    }
440
441    #[test]
442    fn check_compressor_encode_empty() {
443        let compressor = Compressor::from("");
444        let mut buf = Vec::new();
445        compressor.encode(&mut buf).unwrap();
446        assert_eq!(buf.len(), 32);
447        assert_eq!(
448            buf,
449            vec![
450                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
452                0x00, 0x00, 0x00, 0x00,
453            ]
454        );
455        let decode = Compressor::decode(&mut buf.as_ref()).unwrap();
456        assert_eq!(decode, compressor);
457    }
458
459    #[test]
460    fn check_compressor_encode_maximal() {
461        let compressor = Compressor::from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde");
462        let mut buf = Vec::new();
463        compressor.encode(&mut buf).unwrap();
464        assert_eq!(buf.len(), 32);
465        assert_eq!(
466            buf,
467            vec![
468                0x1F, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M',
469                b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a',
470                b'b', b'c', b'd', b'e'
471            ]
472        );
473        let decode = Compressor::decode(&mut buf.as_ref()).unwrap();
474        assert_eq!(decode, compressor);
475    }
476
477    #[test]
478    fn check_compressor_encode_too_long() {
479        let compressor = Compressor::from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef");
480        let mut buf = Vec::new();
481        let result = compressor.encode(&mut buf);
482        assert!(result.is_err());
483    }
484
485    #[test]
486    fn fixed_point_debug_prints_the_value() {
487        // 16.16
488        assert_eq!(format!("{:?}", FixedPoint::new(1u16, 0)), "1");
489        assert_eq!(format!("{:?}", FixedPoint::new(1u16, 0x8000)), "1.5");
490        assert_eq!(format!("{:?}", FixedPoint::new(0u16, 0x4000)), "0.25");
491        // 8.8
492        assert_eq!(format!("{:?}", FixedPoint::new(0u8, 0x80)), "0.5");
493        // Signed: the integer half is two's complement, the fraction unsigned.
494        assert_eq!(format!("{:?}", FixedPoint::new(-2i8, 0x40)), "-1.75");
495        assert_eq!(format!("{:?}", FixedPoint::new(-2i16, 0x4000)), "-1.75");
496    }
497
498    #[test]
499    fn test_extended_type_creation_and_conversion() {
500        let bytes: [u8; 16] = [
501            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
502            0x0e, 0x0f,
503        ];
504
505        let et_new = ExtendedType::new(&bytes);
506        let et_from = ExtendedType::from(bytes);
507        let et_ref_from = ExtendedType::from(&bytes);
508
509        assert_eq!(et_new, et_from);
510        assert_eq!(et_from, et_ref_from);
511
512        let output = <[u8; 16]>::from(et_new);
513
514        assert_eq!(bytes, output);
515    }
516}