scuffle_mp4/boxes/types/
ftyp.rs

1use std::io;
2
3use byteorder::{ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5
6use crate::boxes::header::BoxHeader;
7use crate::boxes::traits::BoxType;
8
9#[derive(Debug, Clone, PartialEq)]
10/// File Type Box
11/// ISO/IEC 14496-12:2022(E) - 4.2.3
12pub struct Ftyp {
13    pub header: BoxHeader,
14    pub major_brand: FourCC,
15    pub minor_version: u32,
16    pub compatible_brands: Vec<FourCC>,
17}
18
19impl Ftyp {
20    pub fn new(major_brand: FourCC, minor_version: u32, compatible_brands: Vec<FourCC>) -> Self {
21        Self {
22            header: BoxHeader::new(Self::NAME),
23            major_brand,
24            minor_version,
25            compatible_brands,
26        }
27    }
28}
29
30impl BoxType for Ftyp {
31    const NAME: [u8; 4] = *b"ftyp";
32
33    fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
34        let major_brand =
35            FourCC::from(TryInto::<[u8; 4]>::try_into(data.slice(0..4).as_ref()).expect("slice is 4 bytes long"));
36        let minor_version = data.slice(4..8).as_ref().read_u32::<byteorder::BigEndian>()?;
37        let compatible_brands = {
38            let mut compatible_brands = Vec::new();
39            let mut data = data.slice(8..);
40            while data.len() >= 4 {
41                compatible_brands.push(FourCC::from(
42                    TryInto::<[u8; 4]>::try_into(data.slice(0..4).as_ref()).expect("slice is 4 bytes long"),
43                ));
44                data = data.slice(4..);
45            }
46            compatible_brands
47        };
48
49        Ok(Self {
50            header,
51            major_brand,
52            minor_version,
53            compatible_brands,
54        })
55    }
56
57    fn primitive_size(&self) -> u64 {
58        4 + 4 + (self.compatible_brands.len() * 4) as u64
59    }
60
61    fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
62        writer.write_all(&self.major_brand.to_bytes())?;
63        writer.write_u32::<byteorder::BigEndian>(self.minor_version)?;
64        for compatible_brand in &self.compatible_brands {
65            writer.write_all(&compatible_brand.to_bytes())?;
66        }
67        Ok(())
68    }
69}
70
71#[derive(Debug, Clone, PartialEq)]
72/// FourCC (Four Character Code)
73pub enum FourCC {
74    Iso5,
75    Iso6,
76    Mp41,
77    Avc1,
78    Av01,
79    Hev1,
80    Unknown([u8; 4]),
81}
82
83impl FourCC {
84    pub fn to_bytes(&self) -> [u8; 4] {
85        match self {
86            Self::Iso5 => *b"iso5",
87            Self::Iso6 => *b"iso6",
88            Self::Mp41 => *b"mp41",
89            Self::Avc1 => *b"avc1",
90            Self::Av01 => *b"av01",
91            Self::Hev1 => *b"hev1",
92            Self::Unknown(bytes) => *bytes,
93        }
94    }
95}
96
97impl From<[u8; 4]> for FourCC {
98    fn from(bytes: [u8; 4]) -> Self {
99        match &bytes {
100            b"iso5" => Self::Iso5,
101            b"iso6" => Self::Iso6,
102            b"mp41" => Self::Mp41,
103            b"avc1" => Self::Avc1,
104            b"av01" => Self::Av01,
105            b"hev1" => Self::Hev1,
106            _ => Self::Unknown(bytes),
107        }
108    }
109}