Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/mp4copy #14

Merged
merged 36 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7df8c33
Add ReadBox trait
ian-spoonradio Jul 23, 2020
acc0566
Add boxtype macro
ian-spoonradio Jul 24, 2020
ab1ee18
Remove offset in BoxHeader
ian-spoonradio Jul 24, 2020
db80686
Fix parsing error when box has largesize
ian-spoonradio Jul 24, 2020
3b18642
Remove duplicated codes reading version and flags
ian-spoonradio Jul 24, 2020
592232c
Merge 'master'
unipro Jul 26, 2020
e684d69
Merge remote-tracking branch 'alfg/master'
ian-spoonradio Jul 27, 2020
d565963
Merge remote-tracking branch 'alfg/master'
ian-spoonradio Jul 29, 2020
c6a4dd8
Merge remote-tracking branch 'alfg/master'
ian-spoonradio Jul 29, 2020
4cb92fe
Add avc1 box
ian-spoonradio Jul 29, 2020
7cc433b
Add mp4a box
ian-spoonradio Jul 29, 2020
08fac96
Add mp4a box
ian-spoonradio Jul 29, 2020
34da7f9
Add DecoderSpecificDescriptor in esds box
ian-spoonradio Jul 30, 2020
f09085f
Add necessary sub-boxes to stbl box
ian-spoonradio Jul 30, 2020
948dc01
Improve ReadBox::read_box()
ian-spoonradio Jul 30, 2020
4ce2399
Add smhd box
ian-spoonradio Jul 30, 2020
928fa66
Refactor BoxHeader
ian-spoonradio Jul 30, 2020
75d5599
Refactor BMFF
ian-spoonradio Jul 30, 2020
27bdcbb
Refactor
ian-spoonradio Jul 30, 2020
5e8d7d6
Add some functions to get offset and size of sample
ian-spoonradio Jul 30, 2020
e824f11
Add Mp4Reader::read_sample() that read media samples
ian-spoonradio Jul 31, 2020
db3defd
Merge remote-tracking branch 'alfg/master' into feature/mp4reader
ian-spoonradio Jul 31, 2020
c0fdbcf
Move Mp4Reader to reader.rs
ian-spoonradio Jul 31, 2020
4b82165
Add mandatory check when reading boxes
ian-spoonradio Jul 31, 2020
18bc289
Update mp4info
ian-spoonradio Aug 3, 2020
c83a81f
Refactor common types
ian-spoonradio Aug 4, 2020
cf41654
Add FixedPointX types
ian-spoonradio Aug 4, 2020
9a311f3
Add media configuration, profile, ...
ian-spoonradio Aug 4, 2020
8a7d2ae
Add initial Mp4Writer
ian-spoonradio Aug 4, 2020
82f9e25
Run cargo fmt
ian-spoonradio Aug 4, 2020
72e8861
Add Mp4Writer and examples/mp4copy
ian-spoonradio Aug 4, 2020
e21980c
Add test codes for Avc1Box and Mp4aBox
ian-spoonradio Aug 4, 2020
f5f031c
Remove prefix "get_" from method names
ian-spoonradio Aug 4, 2020
51252c1
Rename atoms to mp4box
ian-spoonradio Aug 4, 2020
6152caa
Fix some bugs
ian-spoonradio Aug 4, 2020
2a54b8d
Merge remote-tracking branch 'alfg/master' into feature/mp4copy
ian-spoonradio Aug 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 53 additions & 10 deletions examples/mp4copy.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::io::{self, BufReader, BufWriter};
use std::path::Path;

use mp4::Result;
use mp4::{AacConfig, AvcConfig, MediaConfig, MediaType, Mp4Config, Result, TrackConfig};

fn main() {
let args: Vec<String> = env::args().collect();
Expand All @@ -19,23 +19,66 @@ fn main() {
}
}

fn copy<P: AsRef<Path>>(src_filename: &P, _dst_filename: &P) -> Result<()> {
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)?;
let dst_file = File::create(dst_filename)?;
let writer = BufWriter::new(dst_file);

for tix in 0..mp4.track_count()? {
let track_id = tix + 1;
let sample_count = mp4.sample_count(track_id)?;
let mut mp4_reader = mp4::Mp4Reader::read_header(reader, size)?;
let mut mp4_writer = mp4::Mp4Writer::write_start(
writer,
&Mp4Config {
major_brand: mp4_reader.major_brand().clone(),
minor_version: mp4_reader.minor_version(),
compatible_brands: mp4_reader.compatible_brands().to_vec(),
timescale: mp4_reader.timescale(),
},
)?;

// TODO interleaving
for track_idx in 0..mp4_reader.tracks().len() {
if let Some(ref track) = mp4_reader.tracks().get(track_idx) {
let media_conf = match track.media_type()? {
MediaType::H264 => MediaConfig::AvcConfig(AvcConfig {
width: track.width(),
height: track.height(),
seq_param_set: track.sequence_parameter_set()?.to_vec(),
pic_param_set: track.picture_parameter_set()?.to_vec(),
}),
MediaType::AAC => MediaConfig::AacConfig(AacConfig {
bitrate: track.bitrate(),
profile: track.audio_profile()?,
freq_index: track.sample_freq_index()?,
chan_conf: track.channel_config()?,
}),
};

let track_conf = TrackConfig {
track_type: track.track_type()?,
timescale: track.timescale(),
language: track.language().to_string(),
media_conf,
};

mp4_writer.add_track(&track_conf)?;
} else {
unreachable!()
}

let track_id = track_idx as u32 + 1;
let sample_count = mp4_reader.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);
let sample = mp4_reader.read_sample(track_id, sample_id)?.unwrap();
mp4_writer.write_sample(track_id, &sample)?;
// println!("copy {}:({})", sample_id, sample);
}
}

mp4_writer.write_end()?;

Ok(())
}
135 changes: 50 additions & 85 deletions examples/mp4info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::Path;

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

fn main() {
let args: Vec<String> = env::args().collect();
Expand All @@ -24,96 +24,61 @@ fn info<P: AsRef<Path>>(filename: &P) -> Result<()> {
let size = f.metadata()?.len();
let reader = BufReader::new(f);

let mut mp4 = Mp4Reader::new(reader);
mp4.read(size)?;
let mp4 = mp4::Mp4Reader::read_header(reader, 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);
}
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!(" frame rate: (computed): {:?}",
get_framerate(s.entries[0].sample_count,
mdhd.duration, mdhd.timescale));
}
}
}
}
println!("Metadata:");
println!(" size : {}", mp4.size());
println!(" major_brand : {}", mp4.major_brand());
let mut compatible_brands = String::new();
for brand in mp4.compatible_brands().iter() {
compatible_brands.push_str(&brand.to_string());
compatible_brands.push_str(",");
}

Ok(())
}

fn get_handler_type(handler: &str) -> TrackType {
let mut typ: TrackType = TrackType::Unknown;
match handler {
"vide" => typ = TrackType::Video,
"soun" => typ = TrackType::Audio,
"meta" => typ = TrackType::Unknown,
_ => (),
println!(" compatible_brands: {}", compatible_brands);
println!(
"Duration: {}, timescale: {}",
mp4.duration(),
mp4.timescale()
);

for track in mp4.tracks().iter() {
let media_info = match track.track_type()? {
TrackType::Video => video_info(track)?,
TrackType::Audio => audio_info(track)?,
};
println!(
" Track: #{}({}) {}: {}",
track.track_id(),
track.language(),
track.track_type()?,
media_info
);
}
return typ;
}

fn get_duration_ms(duration: u64, timescale: u32) -> String {
let ms = (duration as f64 / timescale as f64) * 1000.0;
return format!("{:.2}", ms.floor());
Ok(())
}

fn get_framerate(sample_count: u32, duration: u64, timescale: u32) -> String {
let sc = (sample_count as f64) * 1000.0;
let ms = (duration as f64 / timescale as f64) * 1000.0;
return format!("{:.2}", sc / ms.floor());
fn video_info(track: &Mp4Track) -> Result<String> {
Ok(format!(
"{} ({}) ({:?}), {}x{}, {} kb/s, {:.2} fps",
track.media_type()?,
track.video_profile()?,
track.box_type()?,
track.width(),
track.height(),
track.bitrate() / 1000,
track.frame_rate_f64()
))
}

fn creation_time(creation_time: u64) -> u64 {
// convert from MP4 epoch (1904-01-01) to Unix epoch (1970-01-01)
if creation_time >= 2082844800 {
creation_time - 2082844800
} else {
creation_time
}
fn audio_info(track: &Mp4Track) -> Result<String> {
Ok(format!(
"{} ({}) ({:?}), {} Hz, {}, {} kb/s",
track.media_type()?,
track.audio_profile()?,
track.box_type()?,
track.sample_freq_index()?.freq(),
track.channel_config()?,
track.bitrate() / 1000
))
}
99 changes: 0 additions & 99 deletions src/atoms/mdia.rs

This file was deleted.

Loading