flowly_mp4/mp4box/
ftyp.rs1use 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; 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}