flowly_mp4/mp4box/
hdlr.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 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(); 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)?; writer.write_u32::<BigEndian>((&self.handler_type).into())?;
74
75 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}