Skip to content

Commit 2a374c5

Browse files
authored
Parse unknown metadata and write metadata (#91)
* validate meta box handler type, parse meta with unknown handlers * parse meta in moov and trak position * write meta and udta * fix clippy nit
1 parent 9c0f653 commit 2a374c5

File tree

7 files changed

+569
-23
lines changed

7 files changed

+569
-23
lines changed

src/mp4box/data.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,39 @@ pub struct DataBox {
1313
pub data_type: DataType,
1414
}
1515

16+
impl DataBox {
17+
pub fn get_type(&self) -> BoxType {
18+
BoxType::DataBox
19+
}
20+
21+
pub fn get_size(&self) -> u64 {
22+
let mut size = HEADER_SIZE;
23+
size += 4; // data_type
24+
size += 4; // reserved
25+
size += self.data.len() as u64;
26+
size
27+
}
28+
}
29+
30+
impl Mp4Box for DataBox {
31+
fn box_type(&self) -> BoxType {
32+
self.get_type()
33+
}
34+
35+
fn box_size(&self) -> u64 {
36+
self.get_size()
37+
}
38+
39+
fn to_json(&self) -> Result<String> {
40+
Ok(serde_json::to_string(&self).unwrap())
41+
}
42+
43+
fn summary(&self) -> Result<String> {
44+
let s = format!("type={:?} len={}", self.data_type, self.data.len());
45+
Ok(s)
46+
}
47+
}
48+
1649
impl<R: Read + Seek> ReadBox<&mut R> for DataBox {
1750
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
1851
let start = box_start(reader)?;
@@ -28,3 +61,58 @@ impl<R: Read + Seek> ReadBox<&mut R> for DataBox {
2861
Ok(DataBox { data, data_type })
2962
}
3063
}
64+
65+
impl<W: Write> WriteBox<&mut W> for DataBox {
66+
fn write_box(&self, writer: &mut W) -> Result<u64> {
67+
let size = self.box_size();
68+
BoxHeader::new(self.box_type(), size).write(writer)?;
69+
70+
writer.write_u32::<BigEndian>(self.data_type.clone() as u32)?;
71+
writer.write_u32::<BigEndian>(0)?; // reserved = 0
72+
writer.write_all(&self.data)?;
73+
74+
Ok(size)
75+
}
76+
}
77+
78+
#[cfg(test)]
79+
mod tests {
80+
use super::*;
81+
use crate::mp4box::BoxHeader;
82+
use std::io::Cursor;
83+
84+
#[test]
85+
fn test_data() {
86+
let src_box = DataBox {
87+
data_type: DataType::Text,
88+
data: b"test_data".to_vec(),
89+
};
90+
let mut buf = Vec::new();
91+
src_box.write_box(&mut buf).unwrap();
92+
assert_eq!(buf.len(), src_box.box_size() as usize);
93+
94+
let mut reader = Cursor::new(&buf);
95+
let header = BoxHeader::read(&mut reader).unwrap();
96+
assert_eq!(header.name, BoxType::DataBox);
97+
assert_eq!(src_box.box_size(), header.size);
98+
99+
let dst_box = DataBox::read_box(&mut reader, header.size).unwrap();
100+
assert_eq!(src_box, dst_box);
101+
}
102+
103+
#[test]
104+
fn test_data_empty() {
105+
let src_box = DataBox::default();
106+
let mut buf = Vec::new();
107+
src_box.write_box(&mut buf).unwrap();
108+
assert_eq!(buf.len(), src_box.box_size() as usize);
109+
110+
let mut reader = Cursor::new(&buf);
111+
let header = BoxHeader::read(&mut reader).unwrap();
112+
assert_eq!(header.name, BoxType::DataBox);
113+
assert_eq!(src_box.box_size(), header.size);
114+
115+
let dst_box = DataBox::read_box(&mut reader, header.size).unwrap();
116+
assert_eq!(src_box, dst_box);
117+
}
118+
}

src/mp4box/ilst.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,39 @@ pub struct IlstBox {
1313
pub items: HashMap<MetadataKey, IlstItemBox>,
1414
}
1515

16+
impl IlstBox {
17+
pub fn get_type(&self) -> BoxType {
18+
BoxType::IlstBox
19+
}
20+
21+
pub fn get_size(&self) -> u64 {
22+
let mut size = HEADER_SIZE;
23+
for item in self.items.values() {
24+
size += item.get_size();
25+
}
26+
size
27+
}
28+
}
29+
30+
impl Mp4Box for IlstBox {
31+
fn box_type(&self) -> BoxType {
32+
self.get_type()
33+
}
34+
35+
fn box_size(&self) -> u64 {
36+
self.get_size()
37+
}
38+
39+
fn to_json(&self) -> Result<String> {
40+
Ok(serde_json::to_string(&self).unwrap())
41+
}
42+
43+
fn summary(&self) -> Result<String> {
44+
let s = format!("item_count={}", self.items.len());
45+
Ok(s)
46+
}
47+
}
48+
1649
impl<R: Read + Seek> ReadBox<&mut R> for IlstBox {
1750
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
1851
let start = box_start(reader)?;
@@ -54,11 +87,36 @@ impl<R: Read + Seek> ReadBox<&mut R> for IlstBox {
5487
}
5588
}
5689

90+
impl<W: Write> WriteBox<&mut W> for IlstBox {
91+
fn write_box(&self, writer: &mut W) -> Result<u64> {
92+
let size = self.box_size();
93+
BoxHeader::new(self.box_type(), size).write(writer)?;
94+
95+
for (key, value) in &self.items {
96+
let name = match key {
97+
MetadataKey::Title => BoxType::NameBox,
98+
MetadataKey::Year => BoxType::DayBox,
99+
MetadataKey::Poster => BoxType::CovrBox,
100+
MetadataKey::Summary => BoxType::DescBox,
101+
};
102+
BoxHeader::new(name, value.get_size()).write(writer)?;
103+
value.data.write_box(writer)?;
104+
}
105+
Ok(size)
106+
}
107+
}
108+
57109
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
58110
pub struct IlstItemBox {
59111
pub data: DataBox,
60112
}
61113

114+
impl IlstItemBox {
115+
fn get_size(&self) -> u64 {
116+
HEADER_SIZE + self.data.box_size()
117+
}
118+
}
119+
62120
impl<R: Read + Seek> ReadBox<&mut R> for IlstItemBox {
63121
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
64122
let start = box_start(reader)?;
@@ -130,3 +188,56 @@ fn item_to_u32(item: &IlstItemBox) -> Option<u32> {
130188
_ => None,
131189
}
132190
}
191+
192+
#[cfg(test)]
193+
mod tests {
194+
use super::*;
195+
use crate::mp4box::BoxHeader;
196+
use std::io::Cursor;
197+
198+
#[test]
199+
fn test_ilst() {
200+
let src_year = IlstItemBox {
201+
data: DataBox {
202+
data_type: DataType::Text,
203+
data: b"test_year".to_vec(),
204+
},
205+
};
206+
let src_box = IlstBox {
207+
items: [
208+
(MetadataKey::Title, IlstItemBox::default()),
209+
(MetadataKey::Year, src_year),
210+
(MetadataKey::Poster, IlstItemBox::default()),
211+
(MetadataKey::Summary, IlstItemBox::default()),
212+
]
213+
.into(),
214+
};
215+
let mut buf = Vec::new();
216+
src_box.write_box(&mut buf).unwrap();
217+
assert_eq!(buf.len(), src_box.box_size() as usize);
218+
219+
let mut reader = Cursor::new(&buf);
220+
let header = BoxHeader::read(&mut reader).unwrap();
221+
assert_eq!(header.name, BoxType::IlstBox);
222+
assert_eq!(src_box.box_size(), header.size);
223+
224+
let dst_box = IlstBox::read_box(&mut reader, header.size).unwrap();
225+
assert_eq!(src_box, dst_box);
226+
}
227+
228+
#[test]
229+
fn test_ilst_empty() {
230+
let src_box = IlstBox::default();
231+
let mut buf = Vec::new();
232+
src_box.write_box(&mut buf).unwrap();
233+
assert_eq!(buf.len(), src_box.box_size() as usize);
234+
235+
let mut reader = Cursor::new(&buf);
236+
let header = BoxHeader::read(&mut reader).unwrap();
237+
assert_eq!(header.name, BoxType::IlstBox);
238+
assert_eq!(src_box.box_size(), header.size);
239+
240+
let dst_box = IlstBox::read_box(&mut reader, header.size).unwrap();
241+
assert_eq!(src_box, dst_box);
242+
}
243+
}

0 commit comments

Comments
 (0)