flowly_mp4/mp4box/
hdlr.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 HdlrBox {
9    pub version: u8,
10    pub flags: u32,
11    pub handler_type: FourCC,
12    pub name: String,
13}
14
15impl HdlrBox {
16    pub fn get_type(&self) -> BoxType {
17        BoxType::HdlrBox
18    }
19
20    pub fn get_size(&self) -> u64 {
21        HEADER_SIZE + HEADER_EXT_SIZE + 20 + self.name.len() as u64 + 1
22    }
23}
24
25impl Mp4Box for HdlrBox {
26    const TYPE: BoxType = BoxType::HdlrBox;
27
28    fn box_size(&self) -> u64 {
29        self.get_size()
30    }
31
32    fn to_json(&self) -> Result<String, Error> {
33        Ok(serde_json::to_string(&self).unwrap())
34    }
35
36    fn summary(&self) -> Result<String, Error> {
37        let s = format!("handler_type={} name={}", self.handler_type, self.name);
38        Ok(s)
39    }
40}
41
42impl BlockReader for HdlrBox {
43    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
44        let (version, flags) = read_box_header_ext(reader);
45
46        reader.get_u32(); // pre-defined
47
48        let handler = reader.get_u32();
49
50        reader.skip(12);
51
52        Ok(HdlrBox {
53            version,
54            flags,
55            handler_type: From::from(handler),
56            name: reader.get_null_terminated_string(),
57        })
58    }
59
60    fn size_hint() -> usize {
61        24
62    }
63}
64
65impl<W: Write> WriteBox<&mut W> for HdlrBox {
66    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
67        let size = self.box_size();
68        BoxHeader::new(Self::TYPE, size).write(writer)?;
69
70        write_box_header_ext(writer, self.version, self.flags)?;
71
72        writer.write_u32::<BigEndian>(0)?; // pre-defined
73        writer.write_u32::<BigEndian>((&self.handler_type).into())?;
74
75        // 12 bytes reserved
76        for _ in 0..3 {
77            writer.write_u32::<BigEndian>(0)?;
78        }
79
80        writer.write_all(self.name.as_bytes())?;
81        writer.write_u8(0)?;
82
83        Ok(size)
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::mp4box::BoxHeader;
91
92    #[tokio::test]
93    async fn test_hdlr() {
94        let src_box = HdlrBox {
95            version: 0,
96            flags: 0,
97            handler_type: str::parse::<FourCC>("vide").unwrap(),
98            name: String::from("VideoHandler"),
99        };
100        let mut buf = Vec::new();
101        src_box.write_box(&mut buf).unwrap();
102        assert_eq!(buf.len(), src_box.box_size() as usize);
103
104        let mut reader = buf.as_slice();
105        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
106        assert_eq!(header.kind, BoxType::HdlrBox);
107        assert_eq!(src_box.box_size(), header.size);
108
109        let dst_box = HdlrBox::read_block(&mut reader).unwrap();
110        assert_eq!(src_box, dst_box);
111    }
112
113    #[tokio::test]
114    async fn test_hdlr_empty() {
115        let src_box = HdlrBox {
116            version: 0,
117            flags: 0,
118            handler_type: str::parse::<FourCC>("vide").unwrap(),
119            name: String::new(),
120        };
121        let mut buf = Vec::new();
122        src_box.write_box(&mut buf).unwrap();
123        assert_eq!(buf.len(), src_box.box_size() as usize);
124
125        let mut reader = buf.as_slice();
126        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
127        assert_eq!(header.kind, BoxType::HdlrBox);
128        assert_eq!(src_box.box_size(), header.size);
129
130        let dst_box = HdlrBox::read_block(&mut reader).unwrap();
131        assert_eq!(src_box, dst_box);
132    }
133
134    #[tokio::test]
135    async fn test_hdlr_extra() {
136        let real_src_box = HdlrBox {
137            version: 0,
138            flags: 0,
139            handler_type: str::parse::<FourCC>("vide").unwrap(),
140            name: String::from("Good"),
141        };
142        let src_box = HdlrBox {
143            version: 0,
144            flags: 0,
145            handler_type: str::parse::<FourCC>("vide").unwrap(),
146            name: String::from_utf8(b"Good\0Bad".to_vec()).unwrap(),
147        };
148        let mut buf = Vec::new();
149        src_box.write_box(&mut buf).unwrap();
150        assert_eq!(buf.len(), src_box.box_size() as usize);
151
152        let mut reader = buf.as_slice();
153        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
154        assert_eq!(header.kind, BoxType::HdlrBox);
155        assert_eq!(src_box.box_size(), header.size);
156
157        let dst_box = HdlrBox::read_block(&mut reader).unwrap();
158        assert_eq!(real_src_box, dst_box);
159    }
160}