flowly_mp4/mp4box/
ftyp.rs

1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
8pub struct FtypBox {
9    pub major_brand: FourCC,
10    pub minor_version: u32,
11    pub compatible_brands: Vec<FourCC>,
12}
13
14impl FtypBox {
15    pub fn get_type(&self) -> BoxType {
16        BoxType::FtypBox
17    }
18
19    pub fn get_size(&self) -> u64 {
20        HEADER_SIZE + 8 + (4 * self.compatible_brands.len() as u64)
21    }
22}
23
24impl Mp4Box for FtypBox {
25    const TYPE: BoxType = BoxType::FtypBox;
26
27    fn box_size(&self) -> u64 {
28        self.get_size()
29    }
30
31    fn to_json(&self) -> Result<String, Error> {
32        Ok(serde_json::to_string(&self).unwrap())
33    }
34
35    fn summary(&self) -> Result<String, Error> {
36        let mut compatible_brands = Vec::new();
37        for brand in self.compatible_brands.iter() {
38            compatible_brands.push(brand.to_string());
39        }
40        let s = format!(
41            "major_brand={} minor_version={} compatible_brands={}",
42            self.major_brand,
43            self.minor_version,
44            compatible_brands.join("-")
45        );
46        Ok(s)
47    }
48}
49
50impl BlockReader for FtypBox {
51    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
52        let brand_count = (reader.remaining() - 8) / 4; // major + minor
53
54        let major = reader.get_u32();
55        let minor = reader.get_u32();
56
57        let mut brands = Vec::new();
58        for _ in 0..brand_count {
59            let b = reader.get_u32();
60            brands.push(From::from(b));
61        }
62
63        Ok(FtypBox {
64            major_brand: From::from(major),
65            minor_version: minor,
66            compatible_brands: brands,
67        })
68    }
69
70    fn size_hint() -> usize {
71        8
72    }
73}
74
75impl<W: Write> WriteBox<&mut W> for FtypBox {
76    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
77        let size = self.box_size();
78        BoxHeader::new(Self::TYPE, size).write(writer)?;
79
80        writer.write_u32::<BigEndian>((&self.major_brand).into())?;
81        writer.write_u32::<BigEndian>(self.minor_version)?;
82        for b in self.compatible_brands.iter() {
83            writer.write_u32::<BigEndian>(b.into())?;
84        }
85        Ok(size)
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::mp4box::BoxHeader;
93
94    #[tokio::test]
95    async fn test_ftyp() {
96        let src_box = FtypBox {
97            major_brand: str::parse("isom").unwrap(),
98            minor_version: 0,
99            compatible_brands: vec![
100                str::parse("isom").unwrap(),
101                str::parse("iso2").unwrap(),
102                str::parse("avc1").unwrap(),
103                str::parse("mp41").unwrap(),
104            ],
105        };
106        let mut buf = Vec::new();
107        src_box.write_box(&mut buf).unwrap();
108        assert_eq!(buf.len(), src_box.box_size() as usize);
109
110        let mut reader = buf.as_slice();
111        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
112        assert_eq!(header.kind, BoxType::FtypBox);
113        assert_eq!(src_box.box_size(), header.size);
114
115        let dst_box = FtypBox::read_block(&mut reader).unwrap();
116        assert_eq!(src_box, dst_box);
117    }
118}