Skip to content

Commit f8f767d

Browse files
authored
Fragmented boxes (#30)
* Add trun box. * Adding Movie Extends Box and subboxes (mvex, mehd, trex).
1 parent a1f7902 commit f8f767d

File tree

9 files changed

+547
-3
lines changed

9 files changed

+547
-3
lines changed

src/mp4box/mehd.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2+
use std::io::{Read, Seek, Write};
3+
use serde::{Serialize};
4+
5+
use crate::mp4box::*;
6+
7+
#[derive(Debug, Clone, PartialEq, Serialize)]
8+
pub struct MehdBox {
9+
pub version: u8,
10+
pub flags: u32,
11+
pub fragment_duration: u64,
12+
}
13+
14+
impl MehdBox {
15+
pub fn get_type(&self) -> BoxType {
16+
BoxType::MehdBox
17+
}
18+
19+
pub fn get_size(&self) -> u64 {
20+
let mut size = HEADER_SIZE + HEADER_EXT_SIZE;
21+
22+
if self.version == 1 {
23+
size += 8;
24+
} else {
25+
assert_eq!(self.version, 0);
26+
size += 4;
27+
}
28+
size
29+
}
30+
}
31+
32+
impl Default for MehdBox {
33+
fn default() -> Self {
34+
MehdBox {
35+
version: 0,
36+
flags: 0,
37+
fragment_duration: 0,
38+
}
39+
}
40+
}
41+
42+
impl Mp4Box for MehdBox {
43+
fn box_type(&self) -> BoxType {
44+
return self.get_type();
45+
}
46+
47+
fn box_size(&self) -> u64 {
48+
return self.get_size();
49+
}
50+
51+
fn to_json(&self) -> Result<String> {
52+
Ok(serde_json::to_string(&self).unwrap())
53+
}
54+
55+
fn summary(&self) -> Result<String> {
56+
let s = format!("fragment_duration={}", self.fragment_duration);
57+
Ok(s)
58+
}
59+
}
60+
61+
impl<R: Read + Seek> ReadBox<&mut R> for MehdBox {
62+
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
63+
let start = box_start(reader)?;
64+
65+
let (version, flags) = read_box_header_ext(reader)?;
66+
67+
let fragment_duration = if version == 1 {
68+
reader.read_u64::<BigEndian>()?
69+
} else {
70+
assert_eq!(version, 0);
71+
reader.read_u32::<BigEndian>()? as u64
72+
};
73+
skip_bytes_to(reader, start + size)?;
74+
75+
Ok(MehdBox {
76+
version,
77+
flags,
78+
fragment_duration,
79+
})
80+
}
81+
}
82+
83+
impl<W: Write> WriteBox<&mut W> for MehdBox {
84+
fn write_box(&self, writer: &mut W) -> Result<u64> {
85+
let size = self.box_size();
86+
BoxHeader::new(self.box_type(), size).write(writer)?;
87+
88+
write_box_header_ext(writer, self.version, self.flags)?;
89+
90+
if self.version == 1 {
91+
writer.write_u64::<BigEndian>(self.fragment_duration)?;
92+
} else {
93+
assert_eq!(self.version, 0);
94+
writer.write_u32::<BigEndian>(self.fragment_duration as u32)?;
95+
}
96+
97+
Ok(size)
98+
}
99+
}
100+
101+
#[cfg(test)]
102+
mod tests {
103+
use super::*;
104+
use crate::mp4box::BoxHeader;
105+
use std::io::Cursor;
106+
107+
108+
#[test]
109+
fn test_mehd32() {
110+
let src_box = MehdBox {
111+
version: 0,
112+
flags: 0,
113+
fragment_duration: 32,
114+
};
115+
let mut buf = Vec::new();
116+
src_box.write_box(&mut buf).unwrap();
117+
assert_eq!(buf.len(), src_box.box_size() as usize);
118+
119+
let mut reader = Cursor::new(&buf);
120+
let header = BoxHeader::read(&mut reader).unwrap();
121+
assert_eq!(header.name, BoxType::MehdBox);
122+
assert_eq!(src_box.box_size(), header.size);
123+
124+
let dst_box = MehdBox::read_box(&mut reader, header.size).unwrap();
125+
assert_eq!(src_box, dst_box);
126+
}
127+
128+
#[test]
129+
fn test_mehd64() {
130+
let src_box = MehdBox {
131+
version: 0,
132+
flags: 0,
133+
fragment_duration: 30439936,
134+
};
135+
let mut buf = Vec::new();
136+
src_box.write_box(&mut buf).unwrap();
137+
assert_eq!(buf.len(), src_box.box_size() as usize);
138+
139+
let mut reader = Cursor::new(&buf);
140+
let header = BoxHeader::read(&mut reader).unwrap();
141+
assert_eq!(header.name, BoxType::MehdBox);
142+
assert_eq!(src_box.box_size(), header.size);
143+
144+
let dst_box = MehdBox::read_box(&mut reader, header.size).unwrap();
145+
assert_eq!(src_box, dst_box);
146+
}
147+
}

src/mp4box/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ pub(crate) mod mdhd;
1616
pub(crate) mod mdia;
1717
pub(crate) mod minf;
1818
pub(crate) mod moov;
19+
pub(crate) mod mvex;
20+
pub(crate) mod mehd;
21+
pub(crate) mod trex;
1922
pub(crate) mod moof;
2023
pub(crate) mod mp4a;
2124
pub(crate) mod mvhd;
@@ -32,6 +35,7 @@ pub(crate) mod tkhd;
3235
pub(crate) mod tfhd;
3336
pub(crate) mod trak;
3437
pub(crate) mod traf;
38+
pub(crate) mod trun;
3539
pub(crate) mod tx3g;
3640
pub(crate) mod vmhd;
3741

@@ -78,6 +82,9 @@ boxtype! {
7882
FreeBox => 0x66726565,
7983
MdatBox => 0x6d646174,
8084
MoovBox => 0x6d6f6f76,
85+
MvexBox => 0x6d766578,
86+
MehdBox => 0x6d656864,
87+
TrexBox => 0x74726578,
8188
MoofBox => 0x6d6f6f66,
8289
TkhdBox => 0x746b6864,
8390
TfhdBox => 0x74666864,
@@ -99,6 +106,7 @@ boxtype! {
99106
Co64Box => 0x636F3634,
100107
TrakBox => 0x7472616b,
101108
TrafBox => 0x74726166,
109+
TrunBox => 0x7472756E,
102110
UdtaBox => 0x75647461,
103111
DinfBox => 0x64696e66,
104112
SmhdBox => 0x736d6864,

src/mp4box/moof.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use crate::mp4box::{mfhd::MfhdBox, traf::TrafBox};
77
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
88
pub struct MoofBox {
99
pub mfhd: MfhdBox,
10+
11+
#[serde(rename = "traf")]
1012
pub trafs: Vec<TrafBox>,
1113
}
1214

src/mp4box/moov.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ use std::io::{Read, Seek, SeekFrom, Write};
22
use serde::{Serialize};
33

44
use crate::mp4box::*;
5-
use crate::mp4box::{mvhd::MvhdBox, trak::TrakBox};
5+
use crate::mp4box::{mvhd::MvhdBox, mvex::MvexBox, trak::TrakBox};
66

77
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
88
pub struct MoovBox {
99
pub mvhd: MvhdBox,
10+
11+
#[serde(skip_serializing_if = "Option::is_none")]
12+
pub mvex: Option<MvexBox>,
13+
14+
#[serde(rename = "trak")]
1015
pub traks: Vec<TrakBox>,
1116
}
1217

@@ -48,6 +53,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
4853
let start = box_start(reader)?;
4954

5055
let mut mvhd = None;
56+
let mut mvex = None;
5157
let mut traks = Vec::new();
5258

5359
let mut current = reader.seek(SeekFrom::Current(0))?;
@@ -61,6 +67,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
6167
BoxType::MvhdBox => {
6268
mvhd = Some(MvhdBox::read_box(reader, s)?);
6369
}
70+
BoxType::MvexBox => {
71+
mvex = Some(MvexBox::read_box(reader, s)?);
72+
}
6473
BoxType::TrakBox => {
6574
let trak = TrakBox::read_box(reader, s)?;
6675
traks.push(trak);
@@ -86,6 +95,7 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
8695

8796
Ok(MoovBox {
8897
mvhd: mvhd.unwrap(),
98+
mvex,
8999
traks,
90100
})
91101
}

src/mp4box/mvex.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use std::io::{Read, Seek, SeekFrom, Write};
2+
use serde::{Serialize};
3+
4+
use crate::mp4box::*;
5+
use crate::mp4box::{mehd::MehdBox, trex::TrexBox};
6+
7+
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
8+
pub struct MvexBox {
9+
pub mehd: MehdBox,
10+
pub trex: TrexBox,
11+
}
12+
13+
impl MvexBox {
14+
pub fn get_type(&self) -> BoxType {
15+
BoxType::MdiaBox
16+
}
17+
18+
pub fn get_size(&self) -> u64 {
19+
HEADER_SIZE + self.mehd.box_size() + self.trex.box_size()
20+
}
21+
}
22+
23+
impl Mp4Box for MvexBox {
24+
fn box_type(&self) -> BoxType {
25+
return self.get_type();
26+
}
27+
28+
fn box_size(&self) -> u64 {
29+
return self.get_size();
30+
}
31+
32+
fn to_json(&self) -> Result<String> {
33+
Ok(serde_json::to_string(&self).unwrap())
34+
}
35+
36+
fn summary(&self) -> Result<String> {
37+
let s = format!("");
38+
Ok(s)
39+
}
40+
}
41+
42+
impl<R: Read + Seek> ReadBox<&mut R> for MvexBox {
43+
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
44+
let start = box_start(reader)?;
45+
46+
let mut mehd = None;
47+
let mut trex = None;
48+
49+
let mut current = reader.seek(SeekFrom::Current(0))?;
50+
let end = start + size;
51+
while current < end {
52+
// Get box header.
53+
let header = BoxHeader::read(reader)?;
54+
let BoxHeader { name, size: s } = header;
55+
56+
match name {
57+
BoxType::MehdBox => {
58+
mehd = Some(MehdBox::read_box(reader, s)?);
59+
}
60+
BoxType::TrexBox => {
61+
trex = Some(TrexBox::read_box(reader, s)?);
62+
}
63+
_ => {
64+
// XXX warn!()
65+
skip_box(reader, s)?;
66+
}
67+
}
68+
69+
current = reader.seek(SeekFrom::Current(0))?;
70+
}
71+
72+
if mehd.is_none() {
73+
return Err(Error::BoxNotFound(BoxType::MehdBox));
74+
}
75+
if trex.is_none() {
76+
return Err(Error::BoxNotFound(BoxType::TrexBox));
77+
}
78+
79+
skip_bytes_to(reader, start + size)?;
80+
81+
Ok(MvexBox {
82+
mehd: mehd.unwrap(),
83+
trex: trex.unwrap(),
84+
})
85+
}
86+
}
87+
88+
impl<W: Write> WriteBox<&mut W> for MvexBox {
89+
fn write_box(&self, writer: &mut W) -> Result<u64> {
90+
let size = self.box_size();
91+
BoxHeader::new(self.box_type(), size).write(writer)?;
92+
93+
self.mehd.write_box(writer)?;
94+
self.trex.write_box(writer)?;
95+
96+
Ok(size)
97+
}
98+
}

src/mp4box/tfhd.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub struct TfhdBox {
99
pub version: u8,
1010
pub flags: u32,
1111
pub track_id: u32,
12+
pub base_data_offset: u64,
1213
}
1314

1415
impl Default for TfhdBox {
@@ -17,6 +18,7 @@ impl Default for TfhdBox {
1718
version: 0,
1819
flags: 0,
1920
track_id: 0,
21+
base_data_offset: 0,
2022
}
2123
}
2224
}
@@ -27,7 +29,7 @@ impl TfhdBox {
2729
}
2830

2931
pub fn get_size(&self) -> u64 {
30-
HEADER_SIZE + HEADER_EXT_SIZE + 4
32+
HEADER_SIZE + HEADER_EXT_SIZE + 4 + 8
3133
}
3234
}
3335

@@ -56,13 +58,15 @@ impl<R: Read + Seek> ReadBox<&mut R> for TfhdBox {
5658

5759
let (version, flags) = read_box_header_ext(reader)?;
5860
let track_id = reader.read_u32::<BigEndian>()?;
61+
let base_data_offset = reader.read_u64::<BigEndian>()?;
5962

6063
skip_bytes_to(reader, start + size)?;
6164

6265
Ok(TfhdBox {
6366
version,
6467
flags,
6568
track_id,
69+
base_data_offset,
6670
})
6771
}
6872
}
@@ -74,6 +78,7 @@ impl<W: Write> WriteBox<&mut W> for TfhdBox {
7478

7579
write_box_header_ext(writer, self.version, self.flags)?;
7680
writer.write_u32::<BigEndian>(self.track_id)?;
81+
writer.write_u64::<BigEndian>(self.base_data_offset)?;
7782

7883
Ok(size)
7984
}
@@ -91,6 +96,7 @@ mod tests {
9196
version: 0,
9297
flags: 0,
9398
track_id: 1,
99+
base_data_offset: 0,
94100
};
95101
let mut buf = Vec::new();
96102
src_box.write_box(&mut buf).unwrap();

0 commit comments

Comments
 (0)