flowly_mp4/mp4box/
moov.rs

1use serde::Serialize;
2use std::io::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    const TYPE: BoxType = BoxType::MoovBox;
47
48    fn box_size(&self) -> u64 {
49        self.get_size()
50    }
51
52    fn to_json(&self) -> Result<String, Error> {
53        Ok(serde_json::to_string(&self).unwrap())
54    }
55
56    fn summary(&self) -> Result<String, Error> {
57        let s = format!("traks={}", self.traks.len());
58        Ok(s)
59    }
60}
61
62impl BlockReader for MoovBox {
63    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
64        let mut mvhd = None;
65        let mut meta = None;
66        let mut udta = None;
67        let mut mvex = None;
68        let mut traks = Vec::new();
69
70        while let Some(mut bx) = reader.get_box()? {
71            match bx.kind {
72                BoxType::MvhdBox => {
73                    mvhd = Some(bx.read()?);
74                }
75
76                BoxType::MetaBox => {
77                    meta = Some(bx.read()?);
78                }
79
80                BoxType::MvexBox => {
81                    mvex = Some(bx.read()?);
82                }
83
84                BoxType::TrakBox => {
85                    traks.push(bx.read()?);
86                }
87
88                BoxType::UdtaBox => {
89                    udta = Some(bx.read()?);
90                }
91
92                _ => continue,
93            }
94        }
95
96        if mvhd.is_none() {
97            return Err(Error::BoxNotFound(BoxType::MvhdBox));
98        }
99
100        Ok(MoovBox {
101            mvhd: mvhd.unwrap(),
102            meta,
103            udta,
104            mvex,
105            traks,
106        })
107    }
108
109    fn size_hint() -> usize {
110        MvhdBox::size_hint()
111    }
112}
113
114impl<W: Write> WriteBox<&mut W> for MoovBox {
115    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
116        let size = self.box_size();
117        BoxHeader::new(Self::TYPE, size).write(writer)?;
118
119        self.mvhd.write_box(writer)?;
120        for trak in self.traks.iter() {
121            trak.write_box(writer)?;
122        }
123        if let Some(meta) = &self.meta {
124            meta.write_box(writer)?;
125        }
126        if let Some(udta) = &self.udta {
127            udta.write_box(writer)?;
128        }
129        Ok(0)
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use crate::mp4box::BoxHeader;
137
138    #[tokio::test]
139    async fn test_moov() {
140        let src_box = MoovBox {
141            mvhd: MvhdBox::default(),
142            mvex: None, // XXX mvex is not written currently
143            traks: vec![],
144            meta: Some(MetaBox::default()),
145            udta: Some(UdtaBox::default()),
146        };
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::MoovBox);
155        assert_eq!(header.size, src_box.box_size());
156
157        let dst_box = MoovBox::read_block(&mut reader).unwrap();
158        assert_eq!(dst_box, src_box);
159    }
160
161    #[tokio::test]
162    async fn test_moov_empty() {
163        let src_box = MoovBox::default();
164
165        let mut buf = Vec::new();
166        src_box.write_box(&mut buf).unwrap();
167        assert_eq!(buf.len(), src_box.box_size() as usize);
168
169        let mut reader = buf.as_slice();
170        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
171        assert_eq!(header.kind, BoxType::MoovBox);
172        assert_eq!(header.size, src_box.box_size());
173
174        let dst_box = MoovBox::read_block(&mut reader).unwrap();
175        assert_eq!(dst_box, src_box);
176    }
177}