forked from alfg/mp4-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request alfg#27 from alfg/fragmented-boxes
Add support for reading/writing fragmented mp4 (fMP4) boxes.
- Loading branch information
Showing
10 changed files
with
402 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; | ||
use std::io::{Read, Seek, Write}; | ||
|
||
use crate::mp4box::*; | ||
|
||
#[derive(Debug, Clone, PartialEq)] | ||
pub struct MfhdBox { | ||
pub version: u8, | ||
pub flags: u32, | ||
pub sequence_number: u32, | ||
} | ||
|
||
impl Default for MfhdBox { | ||
fn default() -> Self { | ||
MfhdBox { | ||
version: 0, | ||
flags: 0, | ||
sequence_number: 1, | ||
} | ||
} | ||
} | ||
|
||
impl MfhdBox { | ||
pub fn get_type(&self) -> BoxType { | ||
BoxType::MfhdBox | ||
} | ||
|
||
pub fn get_size(&self) -> u64 { | ||
HEADER_SIZE + HEADER_EXT_SIZE + 4 | ||
} | ||
} | ||
|
||
impl Mp4Box for MfhdBox { | ||
fn box_type(&self) -> BoxType { | ||
return self.get_type(); | ||
} | ||
|
||
fn box_size(&self) -> u64 { | ||
return self.get_size(); | ||
} | ||
} | ||
|
||
impl<R: Read + Seek> ReadBox<&mut R> for MfhdBox { | ||
fn read_box(reader: &mut R, size: u64) -> Result<Self> { | ||
let start = box_start(reader)?; | ||
|
||
let (version, flags) = read_box_header_ext(reader)?; | ||
let sequence_number = reader.read_u32::<BigEndian>()?; | ||
|
||
skip_bytes_to(reader, start + size)?; | ||
|
||
Ok(MfhdBox { | ||
version, | ||
flags, | ||
sequence_number, | ||
}) | ||
} | ||
} | ||
|
||
impl<W: Write> WriteBox<&mut W> for MfhdBox { | ||
fn write_box(&self, writer: &mut W) -> Result<u64> { | ||
let size = self.box_size(); | ||
BoxHeader::new(self.box_type(), size).write(writer)?; | ||
|
||
write_box_header_ext(writer, self.version, self.flags)?; | ||
writer.write_u32::<BigEndian>(self.sequence_number)?; | ||
|
||
Ok(size) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::mp4box::BoxHeader; | ||
use std::io::Cursor; | ||
|
||
#[test] | ||
fn test_mfhd() { | ||
let src_box = MfhdBox { | ||
version: 0, | ||
flags: 0, | ||
sequence_number: 1, | ||
}; | ||
let mut buf = Vec::new(); | ||
src_box.write_box(&mut buf).unwrap(); | ||
assert_eq!(buf.len(), src_box.box_size() as usize); | ||
|
||
let mut reader = Cursor::new(&buf); | ||
let header = BoxHeader::read(&mut reader).unwrap(); | ||
assert_eq!(header.name, BoxType::MfhdBox); | ||
assert_eq!(src_box.box_size(), header.size); | ||
|
||
let dst_box = MfhdBox::read_box(&mut reader, header.size).unwrap(); | ||
assert_eq!(src_box, dst_box); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use std::io::{Read, Seek, SeekFrom, Write}; | ||
|
||
use crate::mp4box::*; | ||
use crate::mp4box::{mfhd::MfhdBox, traf::TrafBox}; | ||
|
||
#[derive(Debug, Clone, PartialEq, Default)] | ||
pub struct MoofBox { | ||
pub mfhd: MfhdBox, | ||
pub trafs: Vec<TrafBox>, | ||
} | ||
|
||
impl MoofBox { | ||
pub fn get_type(&self) -> BoxType { | ||
BoxType::MoofBox | ||
} | ||
|
||
pub fn get_size(&self) -> u64 { | ||
let mut size = HEADER_SIZE + self.mfhd.box_size(); | ||
for traf in self.trafs.iter() { | ||
size += traf.box_size(); | ||
} | ||
size | ||
} | ||
} | ||
|
||
impl Mp4Box for MoofBox { | ||
fn box_type(&self) -> BoxType { | ||
return self.get_type(); | ||
} | ||
|
||
fn box_size(&self) -> u64 { | ||
return self.get_size(); | ||
} | ||
} | ||
|
||
impl<R: Read + Seek> ReadBox<&mut R> for MoofBox { | ||
fn read_box(reader: &mut R, size: u64) -> Result<Self> { | ||
let start = box_start(reader)?; | ||
|
||
let mut mfhd = None; | ||
let mut trafs = Vec::new(); | ||
|
||
let mut current = reader.seek(SeekFrom::Current(0))?; | ||
let end = start + size; | ||
while current < end { | ||
// Get box header. | ||
let header = BoxHeader::read(reader)?; | ||
let BoxHeader { name, size: s } = header; | ||
|
||
match name { | ||
BoxType::MfhdBox => { | ||
mfhd = Some(MfhdBox::read_box(reader, s)?); | ||
} | ||
BoxType::TrafBox => { | ||
let traf = TrafBox::read_box(reader, s)?; | ||
trafs.push(traf); | ||
} | ||
_ => { | ||
// XXX warn!() | ||
skip_box(reader, s)?; | ||
} | ||
} | ||
current = reader.seek(SeekFrom::Current(0))?; | ||
} | ||
|
||
if mfhd.is_none() { | ||
return Err(Error::BoxNotFound(BoxType::MfhdBox)); | ||
} | ||
|
||
skip_bytes_to(reader, start + size)?; | ||
|
||
Ok(MoofBox { | ||
mfhd: mfhd.unwrap(), | ||
trafs, | ||
}) | ||
} | ||
} | ||
|
||
impl<W: Write> WriteBox<&mut W> for MoofBox { | ||
fn write_box(&self, writer: &mut W) -> Result<u64> { | ||
let size = self.box_size(); | ||
BoxHeader::new(self.box_type(), size).write(writer)?; | ||
|
||
self.mfhd.write_box(writer)?; | ||
for traf in self.trafs.iter() { | ||
traf.write_box(writer)?; | ||
} | ||
Ok(0) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; | ||
use std::io::{Read, Seek, Write}; | ||
|
||
use crate::mp4box::*; | ||
|
||
#[derive(Debug, Clone, PartialEq)] | ||
pub struct TfhdBox { | ||
pub version: u8, | ||
pub flags: u32, | ||
pub track_id: u32, | ||
} | ||
|
||
impl Default for TfhdBox { | ||
fn default() -> Self { | ||
TfhdBox { | ||
version: 0, | ||
flags: 0, | ||
track_id: 0, | ||
} | ||
} | ||
} | ||
|
||
impl TfhdBox { | ||
pub fn get_type(&self) -> BoxType { | ||
BoxType::TfhdBox | ||
} | ||
|
||
pub fn get_size(&self) -> u64 { | ||
HEADER_SIZE + HEADER_EXT_SIZE + 4 | ||
} | ||
} | ||
|
||
impl Mp4Box for TfhdBox { | ||
fn box_type(&self) -> BoxType { | ||
return self.get_type(); | ||
} | ||
|
||
fn box_size(&self) -> u64 { | ||
return self.get_size(); | ||
} | ||
} | ||
|
||
impl<R: Read + Seek> ReadBox<&mut R> for TfhdBox { | ||
fn read_box(reader: &mut R, size: u64) -> Result<Self> { | ||
let start = box_start(reader)?; | ||
|
||
let (version, flags) = read_box_header_ext(reader)?; | ||
let track_id = reader.read_u32::<BigEndian>()?; | ||
|
||
skip_bytes_to(reader, start + size)?; | ||
|
||
Ok(TfhdBox { | ||
version, | ||
flags, | ||
track_id, | ||
}) | ||
} | ||
} | ||
|
||
impl<W: Write> WriteBox<&mut W> for TfhdBox { | ||
fn write_box(&self, writer: &mut W) -> Result<u64> { | ||
let size = self.box_size(); | ||
BoxHeader::new(self.box_type(), size).write(writer)?; | ||
|
||
write_box_header_ext(writer, self.version, self.flags)?; | ||
writer.write_u32::<BigEndian>(self.track_id)?; | ||
|
||
Ok(size) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::mp4box::BoxHeader; | ||
use std::io::Cursor; | ||
|
||
#[test] | ||
fn test_tfhd() { | ||
let src_box = TfhdBox { | ||
version: 0, | ||
flags: 0, | ||
track_id: 1, | ||
}; | ||
let mut buf = Vec::new(); | ||
src_box.write_box(&mut buf).unwrap(); | ||
assert_eq!(buf.len(), src_box.box_size() as usize); | ||
|
||
let mut reader = Cursor::new(&buf); | ||
let header = BoxHeader::read(&mut reader).unwrap(); | ||
assert_eq!(header.name, BoxType::TfhdBox); | ||
assert_eq!(src_box.box_size(), header.size); | ||
|
||
let dst_box = TfhdBox::read_box(&mut reader, header.size).unwrap(); | ||
assert_eq!(src_box, dst_box); | ||
} | ||
} |
Oops, something went wrong.