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 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 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, 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}