Skip to main content

mp4/mp4box/
moov.rs

1use serde::Serialize;
2use std::io::{Read, Seek, Write};
3
4use crate::meta::MetaBox;
5use crate::mp4box::*;
6use crate::mp4box::{mvex::MvexBox, mvhd::MvhdBox, trak::TrakBox, udta::UdtaBox};
7
8#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
9pub struct MoovBox {
10    pub mvhd: MvhdBox,
11
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub meta: Option<MetaBox>,
14
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub mvex: Option<MvexBox>,
17
18    #[serde(rename = "trak")]
19    pub traks: Vec<TrakBox>,
20
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub udta: Option<UdtaBox>,
23}
24
25impl MoovBox {
26    pub fn get_type(&self) -> BoxType {
27        BoxType::MoovBox
28    }
29
30    pub fn get_size(&self) -> u64 {
31        let mut size = HEADER_SIZE + self.mvhd.box_size();
32        for trak in self.traks.iter() {
33            size += trak.box_size();
34        }
35        if let Some(meta) = &self.meta {
36            size += meta.box_size();
37        }
38        if let Some(udta) = &self.udta {
39            size += udta.box_size();
40        }
41        size
42    }
43}
44
45impl Mp4Box for MoovBox {
46    fn box_type(&self) -> BoxType {
47        self.get_type()
48    }
49
50    fn box_size(&self) -> u64 {
51        self.get_size()
52    }
53
54    fn to_json(&self) -> Result<String> {
55        Ok(serde_json::to_string(&self).unwrap())
56    }
57
58    fn summary(&self) -> Result<String> {
59        let s = format!("traks={}", self.traks.len());
60        Ok(s)
61    }
62}
63
64impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
65    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
66        let start = box_start(reader)?;
67
68        let mut mvhd = None;
69        let mut meta = None;
70        let mut udta = None;
71        let mut mvex = None;
72        let mut traks = Vec::new();
73
74        let mut current = reader.stream_position()?;
75        let end = start + size;
76        while current < end {
77            // Get box header.
78            let header = BoxHeader::read(reader)?;
79            let BoxHeader { name, size: s } = header;
80            if s > size {
81                return Err(Error::InvalidData(
82                    "moov box contains a box with a larger size than it",
83                ));
84            }
85
86            match name {
87                BoxType::MvhdBox => {
88                    mvhd = Some(MvhdBox::read_box(reader, s)?);
89                }
90                BoxType::MetaBox => {
91                    meta = Some(MetaBox::read_box(reader, s)?);
92                }
93                BoxType::MvexBox => {
94                    mvex = Some(MvexBox::read_box(reader, s)?);
95                }
96                BoxType::TrakBox => {
97                    let trak = TrakBox::read_box(reader, s)?;
98                    traks.push(trak);
99                }
100                BoxType::UdtaBox => {
101                    udta = Some(UdtaBox::read_box(reader, s)?);
102                }
103                _ => {
104                    // XXX warn!()
105                    skip_box(reader, s)?;
106                }
107            }
108
109            current = reader.stream_position()?;
110        }
111
112        if mvhd.is_none() {
113            return Err(Error::BoxNotFound(BoxType::MvhdBox));
114        }
115
116        skip_bytes_to(reader, start + size)?;
117
118        Ok(MoovBox {
119            mvhd: mvhd.unwrap(),
120            meta,
121            udta,
122            mvex,
123            traks,
124        })
125    }
126}
127
128impl<W: Write> WriteBox<&mut W> for MoovBox {
129    fn write_box(&self, writer: &mut W) -> Result<u64> {
130        let size = self.box_size();
131        BoxHeader::new(self.box_type(), size).write(writer)?;
132
133        self.mvhd.write_box(writer)?;
134        for trak in self.traks.iter() {
135            trak.write_box(writer)?;
136        }
137        if let Some(meta) = &self.meta {
138            meta.write_box(writer)?;
139        }
140        if let Some(udta) = &self.udta {
141            udta.write_box(writer)?;
142        }
143        Ok(0)
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use crate::mp4box::BoxHeader;
151    use std::io::Cursor;
152
153    #[test]
154    fn test_moov() {
155        let src_box = MoovBox {
156            mvhd: MvhdBox::default(),
157            mvex: None, // XXX mvex is not written currently
158            traks: vec![],
159            meta: Some(MetaBox::default()),
160            udta: Some(UdtaBox::default()),
161        };
162
163        let mut buf = Vec::new();
164        src_box.write_box(&mut buf).unwrap();
165        assert_eq!(buf.len(), src_box.box_size() as usize);
166
167        let mut reader = Cursor::new(&buf);
168        let header = BoxHeader::read(&mut reader).unwrap();
169        assert_eq!(header.name, BoxType::MoovBox);
170        assert_eq!(header.size, src_box.box_size());
171
172        let dst_box = MoovBox::read_box(&mut reader, header.size).unwrap();
173        assert_eq!(dst_box, src_box);
174    }
175
176    #[test]
177    fn test_moov_empty() {
178        let src_box = MoovBox::default();
179
180        let mut buf = Vec::new();
181        src_box.write_box(&mut buf).unwrap();
182        assert_eq!(buf.len(), src_box.box_size() as usize);
183
184        let mut reader = Cursor::new(&buf);
185        let header = BoxHeader::read(&mut reader).unwrap();
186        assert_eq!(header.name, BoxType::MoovBox);
187        assert_eq!(header.size, src_box.box_size());
188
189        let dst_box = MoovBox::read_box(&mut reader, header.size).unwrap();
190        assert_eq!(dst_box, src_box);
191    }
192}