flowly_mp4/mp4box/
moov.rs1use 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, 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}