Skip to main content

mp4/mp4box/
udta.rs

1use std::io::{Read, Seek};
2
3use serde::Serialize;
4
5use crate::mp4box::meta::MetaBox;
6use crate::mp4box::*;
7
8#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
9pub struct UdtaBox {
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub meta: Option<MetaBox>,
12}
13
14impl UdtaBox {
15    pub fn get_type(&self) -> BoxType {
16        BoxType::UdtaBox
17    }
18
19    pub fn get_size(&self) -> u64 {
20        let mut size = HEADER_SIZE;
21        if let Some(meta) = &self.meta {
22            size += meta.box_size();
23        }
24        size
25    }
26}
27
28impl Mp4Box for UdtaBox {
29    fn box_type(&self) -> BoxType {
30        self.get_type()
31    }
32
33    fn box_size(&self) -> u64 {
34        self.get_size()
35    }
36
37    fn to_json(&self) -> Result<String> {
38        Ok(serde_json::to_string(&self).unwrap())
39    }
40
41    fn summary(&self) -> Result<String> {
42        Ok(String::new())
43    }
44}
45
46impl<R: Read + Seek> ReadBox<&mut R> for UdtaBox {
47    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
48        let start = box_start(reader)?;
49
50        let mut meta = None;
51
52        let mut current = reader.stream_position()?;
53        let end = start + size;
54        while current < end {
55            // Get box header.
56            let header = BoxHeader::read(reader)?;
57            let BoxHeader { name, size: s } = header;
58            if s > size {
59                return Err(Error::InvalidData(
60                    "udta box contains a box with a larger size than it",
61                ));
62            }
63
64            match name {
65                BoxType::MetaBox => {
66                    meta = Some(MetaBox::read_box(reader, s)?);
67                }
68                _ => {
69                    // XXX warn!()
70                    skip_box(reader, s)?;
71                }
72            }
73
74            current = reader.stream_position()?;
75        }
76
77        skip_bytes_to(reader, start + size)?;
78
79        Ok(UdtaBox { meta })
80    }
81}
82
83impl<W: Write> WriteBox<&mut W> for UdtaBox {
84    fn write_box(&self, writer: &mut W) -> Result<u64> {
85        let size = self.box_size();
86        BoxHeader::new(self.box_type(), size).write(writer)?;
87
88        if let Some(meta) = &self.meta {
89            meta.write_box(writer)?;
90        }
91        Ok(size)
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use crate::mp4box::BoxHeader;
99    use std::io::Cursor;
100
101    #[test]
102    fn test_udta_empty() {
103        let src_box = UdtaBox { meta: None };
104
105        let mut buf = Vec::new();
106        src_box.write_box(&mut buf).unwrap();
107        assert_eq!(buf.len(), src_box.box_size() as usize);
108
109        let mut reader = Cursor::new(&buf);
110        let header = BoxHeader::read(&mut reader).unwrap();
111        assert_eq!(header.name, BoxType::UdtaBox);
112        assert_eq!(header.size, src_box.box_size());
113
114        let dst_box = UdtaBox::read_box(&mut reader, header.size).unwrap();
115        assert_eq!(dst_box, src_box);
116    }
117
118    #[test]
119    fn test_udta() {
120        let src_box = UdtaBox {
121            meta: Some(MetaBox::default()),
122        };
123
124        let mut buf = Vec::new();
125        src_box.write_box(&mut buf).unwrap();
126        assert_eq!(buf.len(), src_box.box_size() as usize);
127
128        let mut reader = Cursor::new(&buf);
129        let header = BoxHeader::read(&mut reader).unwrap();
130        assert_eq!(header.name, BoxType::UdtaBox);
131        assert_eq!(header.size, src_box.box_size());
132
133        let dst_box = UdtaBox::read_box(&mut reader, header.size).unwrap();
134        assert_eq!(dst_box, src_box);
135    }
136}