mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-06-11 01:19:21 +00:00
refactoring: split off Mp4Header from Mp4Reader
This commit is contained in:
parent
35560e94f5
commit
045677e56e
|
@ -46,12 +46,12 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
|
||||||
|
|
||||||
// collect known boxes
|
// collect known boxes
|
||||||
let mut boxes = vec![
|
let mut boxes = vec![
|
||||||
build_box(&mp4.ftyp),
|
build_box(&mp4.header.ftyp),
|
||||||
build_box(&mp4.moov),
|
build_box(&mp4.header.moov),
|
||||||
build_box(&mp4.moov.mvhd),
|
build_box(&mp4.header.moov.mvhd),
|
||||||
];
|
];
|
||||||
|
|
||||||
if let Some(ref mvex) = &mp4.moov.mvex {
|
if let Some(ref mvex) = &mp4.header.moov.mvex {
|
||||||
boxes.push(build_box(mvex));
|
boxes.push(build_box(mvex));
|
||||||
if let Some(mehd) = &mvex.mehd {
|
if let Some(mehd) = &mvex.mehd {
|
||||||
boxes.push(build_box(mehd));
|
boxes.push(build_box(mehd));
|
||||||
|
@ -117,7 +117,7 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If fragmented, add moof boxes.
|
// If fragmented, add moof boxes.
|
||||||
for moof in mp4.moofs.iter() {
|
for moof in mp4.header.moofs.iter() {
|
||||||
boxes.push(build_box(moof));
|
boxes.push(build_box(moof));
|
||||||
boxes.push(build_box(&moof.mfhd));
|
boxes.push(build_box(&moof.mfhd));
|
||||||
for traf in moof.trafs.iter() {
|
for traf in moof.trafs.iter() {
|
||||||
|
|
|
@ -37,10 +37,10 @@ fn info<P: AsRef<Path>>(filename: &P) -> Result<()> {
|
||||||
println!(" compatible_brands: {}\n", compatible_brands);
|
println!(" compatible_brands: {}\n", compatible_brands);
|
||||||
|
|
||||||
println!("Movie:");
|
println!("Movie:");
|
||||||
println!(" version: {}", mp4.moov.mvhd.version);
|
println!(" version: {}", mp4.header.moov.mvhd.version);
|
||||||
println!(
|
println!(
|
||||||
" creation time: {}",
|
" creation time: {}",
|
||||||
creation_time(mp4.moov.mvhd.creation_time)
|
creation_time(mp4.header.moov.mvhd.creation_time)
|
||||||
);
|
);
|
||||||
println!(" duration: {:?}", mp4.duration());
|
println!(" duration: {:?}", mp4.duration());
|
||||||
println!(" fragments: {:?}", mp4.is_fragmented());
|
println!(" fragments: {:?}", mp4.is_fragmented());
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
//! let mp4 = mp4::Mp4Reader::read_header(reader, size)?;
|
//! let mp4 = mp4::Mp4Reader::read_header(reader, size)?;
|
||||||
//!
|
//!
|
||||||
//! // Print boxes.
|
//! // Print boxes.
|
||||||
//! println!("major brand: {}", mp4.ftyp.major_brand);
|
//! println!("major brand: {}", mp4.header.ftyp.major_brand);
|
||||||
//! println!("timescale: {}", mp4.moov.mvhd.timescale);
|
//! println!("timescale: {}", mp4.header.moov.mvhd.timescale);
|
||||||
//!
|
//!
|
||||||
//! // Use available methods.
|
//! // Use available methods.
|
||||||
//! println!("size: {}", mp4.size());
|
//! println!("size: {}", mp4.size());
|
||||||
|
@ -83,7 +83,7 @@ mod track;
|
||||||
pub use track::{Mp4Track, TrackConfig};
|
pub use track::{Mp4Track, TrackConfig};
|
||||||
|
|
||||||
mod reader;
|
mod reader;
|
||||||
pub use reader::Mp4Reader;
|
pub use reader::{Mp4Header, Mp4Reader};
|
||||||
|
|
||||||
mod writer;
|
mod writer;
|
||||||
pub use writer::{Mp4Config, Mp4Writer};
|
pub use writer::{Mp4Config, Mp4Writer};
|
||||||
|
|
137
src/reader.rs
137
src/reader.rs
|
@ -6,8 +6,7 @@ use crate::meta::MetaBox;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Mp4Reader<R> {
|
pub struct Mp4Header {
|
||||||
reader: R,
|
|
||||||
pub ftyp: FtypBox,
|
pub ftyp: FtypBox,
|
||||||
pub moov: MoovBox,
|
pub moov: MoovBox,
|
||||||
pub moofs: Vec<MoofBox>,
|
pub moofs: Vec<MoofBox>,
|
||||||
|
@ -17,8 +16,8 @@ pub struct Mp4Reader<R> {
|
||||||
size: u64,
|
size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read + Seek> Mp4Reader<R> {
|
impl Mp4Header {
|
||||||
pub fn read_header(mut reader: R, size: u64) -> Result<Self> {
|
pub fn read<R: Read + Seek>(reader: &mut R, size: u64) -> Result<Self> {
|
||||||
let start = reader.stream_position()?;
|
let start = reader.stream_position()?;
|
||||||
|
|
||||||
let mut ftyp = None;
|
let mut ftyp = None;
|
||||||
|
@ -30,7 +29,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
let mut current = start;
|
let mut current = start;
|
||||||
while current < size {
|
while current < size {
|
||||||
// Get box header.
|
// Get box header.
|
||||||
let header = BoxHeader::read(&mut reader)?;
|
let header = BoxHeader::read(reader)?;
|
||||||
let BoxHeader { name, size: s } = header;
|
let BoxHeader { name, size: s } = header;
|
||||||
if s > size {
|
if s > size {
|
||||||
return Err(Error::InvalidData(
|
return Err(Error::InvalidData(
|
||||||
|
@ -46,30 +45,30 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
// Match and parse the atom boxes.
|
// Match and parse the atom boxes.
|
||||||
match name {
|
match name {
|
||||||
BoxType::FtypBox => {
|
BoxType::FtypBox => {
|
||||||
ftyp = Some(FtypBox::read_box(&mut reader, s)?);
|
ftyp = Some(FtypBox::read_box(reader, s)?);
|
||||||
}
|
}
|
||||||
BoxType::FreeBox => {
|
BoxType::FreeBox => {
|
||||||
skip_box(&mut reader, s)?;
|
skip_box(reader, s)?;
|
||||||
}
|
}
|
||||||
BoxType::MdatBox => {
|
BoxType::MdatBox => {
|
||||||
skip_box(&mut reader, s)?;
|
skip_box(reader, s)?;
|
||||||
}
|
}
|
||||||
BoxType::MoovBox => {
|
BoxType::MoovBox => {
|
||||||
moov = Some(MoovBox::read_box(&mut reader, s)?);
|
moov = Some(MoovBox::read_box(reader, s)?);
|
||||||
}
|
}
|
||||||
BoxType::MoofBox => {
|
BoxType::MoofBox => {
|
||||||
let moof_offset = reader.stream_position()? - 8;
|
let moof_offset = reader.stream_position()? - 8;
|
||||||
let moof = MoofBox::read_box(&mut reader, s)?;
|
let moof = MoofBox::read_box(reader, s)?;
|
||||||
moofs.push(moof);
|
moofs.push(moof);
|
||||||
moof_offsets.push(moof_offset);
|
moof_offsets.push(moof_offset);
|
||||||
}
|
}
|
||||||
BoxType::EmsgBox => {
|
BoxType::EmsgBox => {
|
||||||
let emsg = EmsgBox::read_box(&mut reader, s)?;
|
let emsg = EmsgBox::read_box(reader, s)?;
|
||||||
emsgs.push(emsg);
|
emsgs.push(emsg);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// XXX warn!()
|
// XXX warn!()
|
||||||
skip_box(&mut reader, s)?;
|
skip_box(reader, s)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current = reader.stream_position()?;
|
current = reader.stream_position()?;
|
||||||
|
@ -118,8 +117,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Mp4Reader {
|
Ok(Mp4Header {
|
||||||
reader,
|
|
||||||
ftyp: ftyp.unwrap(),
|
ftyp: ftyp.unwrap(),
|
||||||
moov: moov.unwrap(),
|
moov: moov.unwrap(),
|
||||||
moofs,
|
moofs,
|
||||||
|
@ -129,11 +127,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_fragment_header<FR: Read + Seek>(
|
pub fn read_fragment<R: Read + Seek>(&self, reader: &mut R, size: u64) -> Result<Self> {
|
||||||
&self,
|
|
||||||
mut reader: FR,
|
|
||||||
size: u64,
|
|
||||||
) -> Result<Mp4Reader<FR>> {
|
|
||||||
let start = reader.stream_position()?;
|
let start = reader.stream_position()?;
|
||||||
|
|
||||||
let mut moofs = Vec::new();
|
let mut moofs = Vec::new();
|
||||||
|
@ -142,7 +136,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
let mut current = start;
|
let mut current = start;
|
||||||
while current < size {
|
while current < size {
|
||||||
// Get box header.
|
// Get box header.
|
||||||
let header = BoxHeader::read(&mut reader)?;
|
let header = BoxHeader::read(reader)?;
|
||||||
let BoxHeader { name, size: s } = header;
|
let BoxHeader { name, size: s } = header;
|
||||||
if s > size {
|
if s > size {
|
||||||
return Err(Error::InvalidData(
|
return Err(Error::InvalidData(
|
||||||
|
@ -158,17 +152,17 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
// Match and parse the atom boxes.
|
// Match and parse the atom boxes.
|
||||||
match name {
|
match name {
|
||||||
BoxType::MdatBox => {
|
BoxType::MdatBox => {
|
||||||
skip_box(&mut reader, s)?;
|
skip_box(reader, s)?;
|
||||||
}
|
}
|
||||||
BoxType::MoofBox => {
|
BoxType::MoofBox => {
|
||||||
let moof_offset = reader.stream_position()? - 8;
|
let moof_offset = reader.stream_position()? - 8;
|
||||||
let moof = MoofBox::read_box(&mut reader, s)?;
|
let moof = MoofBox::read_box(reader, s)?;
|
||||||
moofs.push(moof);
|
moofs.push(moof);
|
||||||
moof_offsets.push(moof_offset);
|
moof_offsets.push(moof_offset);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// XXX warn!()
|
// XXX warn!()
|
||||||
skip_box(&mut reader, s)?;
|
skip_box(reader, s)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current = reader.stream_position()?;
|
current = reader.stream_position()?;
|
||||||
|
@ -204,8 +198,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Mp4Reader {
|
Ok(Mp4Header {
|
||||||
reader,
|
|
||||||
ftyp: self.ftyp.clone(),
|
ftyp: self.ftyp.clone(),
|
||||||
moov: self.moov.clone(),
|
moov: self.moov.clone(),
|
||||||
moofs,
|
moofs,
|
||||||
|
@ -215,10 +208,12 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn size(&self) -> u64 {
|
pub fn size(&self) -> u64 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn major_brand(&self) -> &FourCC {
|
pub fn major_brand(&self) -> &FourCC {
|
||||||
&self.ftyp.major_brand
|
&self.ftyp.major_brand
|
||||||
}
|
}
|
||||||
|
@ -255,9 +250,14 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_sample(&mut self, track_id: u32, sample_id: u32) -> Result<Option<Mp4Sample>> {
|
pub fn read_sample<R: Read + Seek>(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut R,
|
||||||
|
track_id: u32,
|
||||||
|
sample_id: u32,
|
||||||
|
) -> Result<Option<Mp4Sample>> {
|
||||||
if let Some(track) = self.tracks.get(&track_id) {
|
if let Some(track) = self.tracks.get(&track_id) {
|
||||||
track.read_sample(&mut self.reader, sample_id)
|
track.read_sample(reader, sample_id)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::TrakNotFound(track_id))
|
Err(Error::TrakNotFound(track_id))
|
||||||
}
|
}
|
||||||
|
@ -270,9 +270,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
Err(Error::TrakNotFound(track_id))
|
Err(Error::TrakNotFound(track_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> Mp4Reader<R> {
|
|
||||||
pub fn metadata(&self) -> impl Metadata<'_> {
|
pub fn metadata(&self) -> impl Metadata<'_> {
|
||||||
self.moov.udta.as_ref().and_then(|udta| {
|
self.moov.udta.as_ref().and_then(|udta| {
|
||||||
udta.meta.as_ref().and_then(|meta| match meta {
|
udta.meta.as_ref().and_then(|meta| match meta {
|
||||||
|
@ -282,3 +280,84 @@ impl<R> Mp4Reader<R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Mp4Reader<R> {
|
||||||
|
reader: R,
|
||||||
|
pub header: Mp4Header,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Read + Seek> Mp4Reader<R> {
|
||||||
|
pub fn from_reader(reader: R, header: Mp4Header) -> Self {
|
||||||
|
Self { reader, header }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_header(mut reader: R, size: u64) -> Result<Self> {
|
||||||
|
Ok(Mp4Reader {
|
||||||
|
header: Mp4Header::read(&mut reader, size)?,
|
||||||
|
reader,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_fragment_header<FR: Read + Seek>(
|
||||||
|
&self,
|
||||||
|
mut reader: FR,
|
||||||
|
size: u64,
|
||||||
|
) -> Result<Mp4Reader<FR>> {
|
||||||
|
Ok(Mp4Reader {
|
||||||
|
header: self.header.read_fragment(&mut reader, size)?,
|
||||||
|
reader,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> u64 {
|
||||||
|
self.header.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn major_brand(&self) -> &FourCC {
|
||||||
|
self.header.major_brand()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minor_version(&self) -> u32 {
|
||||||
|
self.header.minor_version()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compatible_brands(&self) -> &[FourCC] {
|
||||||
|
self.header.compatible_brands()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duration(&self) -> Duration {
|
||||||
|
self.header.duration()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timescale(&self) -> u32 {
|
||||||
|
self.header.timescale()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_fragmented(&self) -> bool {
|
||||||
|
self.header.is_fragmented()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tracks(&self) -> &HashMap<u32, Mp4Track> {
|
||||||
|
self.header.tracks()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_count(&self, track_id: u32) -> Result<u32> {
|
||||||
|
self.header.sample_count(track_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_sample(&mut self, track_id: u32, sample_id: u32) -> Result<Option<Mp4Sample>> {
|
||||||
|
self.header
|
||||||
|
.read_sample(&mut self.reader, track_id, sample_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_offset(&mut self, track_id: u32, sample_id: u32) -> Result<u64> {
|
||||||
|
self.header.sample_offset(track_id, sample_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Mp4Reader<R> {
|
||||||
|
pub fn metadata(&self) -> impl Metadata<'_> {
|
||||||
|
self.header.metadata()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue