Skip to content

Commit

Permalink
Feature/mp4reader (alfg#13)
Browse files Browse the repository at this point in the history
* Add ReadBox trait

* Add boxtype macro

* Remove offset in BoxHeader

* Fix parsing error when box has largesize

* Remove duplicated codes reading version and flags

* Add avc1 box

* Add mp4a box

* Add mp4a box

* Add DecoderSpecificDescriptor in esds box

* Add necessary sub-boxes to stbl box

* Improve ReadBox::read_box()

* Add smhd box

* Refactor BoxHeader

* Refactor BMFF

* Refactor

* Add some functions to get offset and size of sample

* Add Mp4Reader::read_sample() that read media samples

Co-authored-by: Byungwan Jun <unipro.kr@gmail.com>
  • Loading branch information
ian-spoonradio and unipro authored Jul 31, 2020
1 parent 6fc03d5 commit 2af9131
Show file tree
Hide file tree
Showing 31 changed files with 2,489 additions and 624 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ license = "MIT"
[dependencies]
thiserror = "^1.0"
byteorder = "1"
bytes = "0.5"
num-rational = "0.3"
41 changes: 41 additions & 0 deletions examples/mp4copy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::Path;

use mp4::Result;

fn main() {
let args: Vec<String> = env::args().collect();

if args.len() < 3 {
println!("Usage: mp4copy <source file> <target file>");
std::process::exit(1);
}

if let Err(err) = copy(&args[1], &args[2]) {
let _ = writeln!(io::stderr(), "{}", err);
}
}

fn copy<P: AsRef<Path>>(src_filename: &P, _dst_filename: &P) -> Result<()> {
let src_file = File::open(src_filename)?;
let size = src_file.metadata()?.len();
let reader = BufReader::new(src_file);

let mut mp4 = mp4::Mp4Reader::new(reader);
mp4.read(size)?;

for tix in 0..mp4.track_count()? {
let track_id = tix + 1;
let sample_count = mp4.sample_count(track_id)?;
for six in 0..sample_count {
let sample_id = six + 1;
let sample = mp4.read_sample(track_id, sample_id)?.unwrap();
println!("sample_id: {}, {}", sample_id, sample);
}
}

Ok(())
}
157 changes: 79 additions & 78 deletions examples/mp4info.rs
Original file line number Diff line number Diff line change
@@ -1,97 +1,98 @@
use mp4;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::Path;

use mp4::{Result, Mp4Reader, TrackType};

fn main() {
let args: Vec<String> = env::args().collect();

match args.len() {
2 => {
let filename = &args[1];
let f = File::open(filename).unwrap();

let bmff = mp4::read_mp4(f).unwrap();
let moov = bmff.moov.unwrap();

// Print results.
println!("File:");
println!(" file size: {}", bmff.size);
println!(
" brands: {:?} {:?}\n",
bmff.ftyp.major_brand, bmff.ftyp.compatible_brands
);

println!("Movie:");
println!(" version: {:?}", moov.mvhd.version);
println!(
" creation time: {}",
creation_time(moov.mvhd.creation_time)
);
println!(" duration: {:?}", moov.mvhd.duration);
println!(" timescale: {:?}\n", moov.mvhd.timescale);

println!("Found {} Tracks", moov.traks.len());
for trak in moov.traks.iter() {
let tkhd = trak.tkhd.as_ref().unwrap();
println!("Track: {:?}", tkhd.track_id);
println!(" flags: {:?}", tkhd.flags);
println!(" id: {:?}", tkhd.track_id);
println!(" duration: {:?}", tkhd.duration);
if tkhd.width != 0 && tkhd.height != 0 {
println!(" width: {:?}", tkhd.width);
println!(" height: {:?}", tkhd.height);
if args.len() < 2 {
println!("Usage: mp4info <filename>");
std::process::exit(1);
}

if let Err(err) = info(&args[1]) {
let _ = writeln!(io::stderr(), "{}", err);
}
}

fn info<P: AsRef<Path>>(filename: &P) -> Result<()> {
let f = File::open(filename)?;
let size = f.metadata()?.len();
let reader = BufReader::new(f);

let mut mp4 = Mp4Reader::new(reader);
mp4.read(size)?;

println!("File:");
println!(" size: {}", mp4.size());
println!(" brands: {:?} {:?}\n",
mp4.ftyp.major_brand, mp4.ftyp.compatible_brands);

if let Some(ref moov) = mp4.moov {
println!("Movie:");
println!(" version: {:?}", moov.mvhd.version);
println!(" creation time: {}",
creation_time(moov.mvhd.creation_time));
println!(" duration: {:?}", moov.mvhd.duration);
println!(" timescale: {:?}\n", moov.mvhd.timescale);

println!("Found {} Tracks", moov.traks.len());
for trak in moov.traks.iter() {
let tkhd = trak.tkhd.as_ref().unwrap();
println!("Track: {:?}", tkhd.track_id);
println!(" flags: {:?}", tkhd.flags);
println!(" id: {:?}", tkhd.track_id);
println!(" duration: {:?}", tkhd.duration);
if tkhd.width != 0 && tkhd.height != 0 {
println!(" width: {:?}", tkhd.width);
println!(" height: {:?}", tkhd.height);
}
if let Some(ref mdia) = trak.mdia {
let hdlr = mdia.hdlr.as_ref().unwrap();
let mdhd = mdia.mdhd.as_ref().unwrap();
let stts = mdia
.minf
.as_ref()
.map(|m| m.stbl.as_ref().map(|s| s.stts.as_ref()).flatten())
.flatten();

println!(" type: {:?}",
get_handler_type(hdlr.handler_type.value.as_ref()));
println!(" language: {:?}", mdhd.language);

println!(" media:");
if let Some(ref s) = stts {
println!(" sample count: {:?}", s.entries[0].sample_count);
}
if let Some(ref mdia) = trak.mdia {
let hdlr = mdia.hdlr.as_ref().unwrap();
let mdhd = mdia.mdhd.as_ref().unwrap();
let stts = mdia
.minf
.as_ref()
.map(|m| m.stbl.as_ref().map(|s| s.stts.as_ref()).flatten())
.flatten();

println!(
" type: {:?}",
get_handler_type(hdlr.handler_type.value.as_ref())
);
println!(" language: {:?}", mdhd.language);

println!(" media:");
println!(" timescale: {:?}", mdhd.timescale);
println!(" duration: {:?} (media timescale units)",
mdhd.duration);
println!(" duration: {:?} (ms)",
get_duration_ms(mdhd.duration, mdhd.timescale));
if get_handler_type(hdlr.handler_type.value.as_ref()) == TrackType::Video {
if let Some(ref s) = stts {
println!(" sample count: {:?}", s.entries[0].sample_count);
}
println!(" timescale: {:?}", mdhd.timescale);
println!(
" duration: {:?} (media timescale units)",
mdhd.duration
);
println!(
" duration: {:?} (ms)",
get_duration_ms(mdhd.duration, mdhd.timescale)
);
if get_handler_type(hdlr.handler_type.value.as_ref()) == mp4::TrackType::Video {
if let Some(ref s) = stts {
println!(
" frame rate: (computed): {:?}",
get_framerate(s.entries[0].sample_count, mdhd.duration, mdhd.timescale)
);
}
println!(" frame rate: (computed): {:?}",
get_framerate(s.entries[0].sample_count,
mdhd.duration, mdhd.timescale));
}
}
}
}
_ => {
println!("Usage: mp4info <filename>");
}
}

Ok(())
}

fn get_handler_type(handler: &str) -> mp4::TrackType {
let mut typ: mp4::TrackType = mp4::TrackType::Unknown;
fn get_handler_type(handler: &str) -> TrackType {
let mut typ: TrackType = TrackType::Unknown;
match handler {
"vide" => typ = mp4::TrackType::Video,
"soun" => typ = mp4::TrackType::Audio,
"meta" => typ = mp4::TrackType::Unknown,
"vide" => typ = TrackType::Video,
"soun" => typ = TrackType::Audio,
"meta" => typ = TrackType::Unknown,
_ => (),
}
return typ;
Expand Down
Loading

0 comments on commit 2af9131

Please sign in to comment.