Skip to content

Commit

Permalink
Maintain a separate indexing from track_id to index to allow for non …
Browse files Browse the repository at this point in the history
…continues track ids (alfg#43) (alfg#58)
  • Loading branch information
cTopher authored Jul 30, 2021
1 parent 5b1dfb2 commit 3711e91
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 68 deletions.
69 changes: 33 additions & 36 deletions examples/mp4copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,45 +49,42 @@ fn copy<P: AsRef<Path>>(src_filename: &P, dst_filename: &P) -> Result<()> {
)?;

// 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::H265 => MediaConfig::HevcConfig(HevcConfig {
width: track.width(),
height: track.height(),
}),
MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config {
width: track.width(),
height: track.height(),
}),
MediaType::AAC => MediaConfig::AacConfig(AacConfig {
bitrate: track.bitrate(),
profile: track.audio_profile()?,
freq_index: track.sample_freq_index()?,
chan_conf: track.channel_config()?,
}),
MediaType::TTXT => MediaConfig::TtxtConfig(TtxtConfig {}),
};
for track in mp4_reader.tracks().values() {
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::H265 => MediaConfig::HevcConfig(HevcConfig {
width: track.width(),
height: track.height(),
}),
MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config {
width: track.width(),
height: track.height(),
}),
MediaType::AAC => MediaConfig::AacConfig(AacConfig {
bitrate: track.bitrate(),
profile: track.audio_profile()?,
freq_index: track.sample_freq_index()?,
chan_conf: track.channel_config()?,
}),
MediaType::TTXT => MediaConfig::TtxtConfig(TtxtConfig {}),
};

let track_conf = TrackConfig {
track_type: track.track_type()?,
timescale: track.timescale(),
language: track.language().to_string(),
media_conf,
};
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!()
}
mp4_writer.add_track(&track_conf)?;
}

let track_id = track_idx as u32 + 1;
for track_id in mp4_reader.tracks().keys().copied().collect::<Vec<u32>>() {
let sample_count = mp4_reader.sample_count(track_id)?;
for sample_idx in 0..sample_count {
let sample_id = sample_idx + 1;
Expand Down
2 changes: 1 addition & 1 deletion examples/mp4dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
}

// trak.
for track in mp4.tracks().iter() {
for track in mp4.tracks().values() {
boxes.push(build_box(&track.trak));
boxes.push(build_box(&track.trak.tkhd));
if let Some(ref edts) = track.trak.edts {
Expand Down
2 changes: 1 addition & 1 deletion examples/mp4info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn info<P: AsRef<Path>>(filename: &P) -> Result<()> {
println!(" timescale: {:?}\n", mp4.timescale());

println!("Found {} Tracks", mp4.tracks().len());
for track in mp4.tracks().iter() {
for track in mp4.tracks().values() {
let media_info = match track.track_type()? {
TrackType::Video => video_info(track)?,
TrackType::Audio => audio_info(track)?,
Expand Down
3 changes: 1 addition & 2 deletions examples/mp4sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ fn samples<P: AsRef<Path>>(filename: &P) -> Result<()> {

let mut mp4 = mp4::Mp4Reader::read_header(reader, size)?;

for track_idx in 0..mp4.tracks().len() {
let track_id = track_idx as u32 + 1;
for track_id in mp4.tracks().keys().copied().collect::<Vec<u32>>() {
let sample_count = mp4.sample_count(track_id).unwrap();

for sample_idx in 0..sample_count {
Expand Down
2 changes: 1 addition & 1 deletion examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() {

println!("Major Brand: {}", mp4.major_brand());

for track in mp4.tracks().iter() {
for track in mp4.tracks().values() {
println!("Track: #{}({}) {} {}",
track.track_id(),
track.language(),
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
//! println!("duration: {:?}", mp4.duration());
//!
//! // Track info.
//! for track in mp4.tracks().iter() {
//! for track in mp4.tracks().values() {
//! println!(
//! "track: #{}({}) {} : {}",
//! track.track_id(),
Expand Down
43 changes: 19 additions & 24 deletions src/reader.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::collections::HashMap;
use std::io::{Read, Seek, SeekFrom};
use std::time::Duration;

use crate::mp4box::*;
use crate::*;
use crate::mp4box::*;

#[derive(Debug)]
pub struct Mp4Reader<R> {
Expand All @@ -11,7 +12,7 @@ pub struct Mp4Reader<R> {
pub moov: MoovBox,
pub moofs: Vec<MoofBox>,

tracks: Vec<Mp4Track>,
tracks: HashMap<u32, Mp4Track>,
size: u64,
}

Expand Down Expand Up @@ -64,16 +65,14 @@ impl<R: Read + Seek> Mp4Reader<R> {

let size = current - start;
let mut tracks = if let Some(ref moov) = moov {
let mut tracks = Vec::with_capacity(moov.traks.len());
for (i, trak) in moov.traks.iter().enumerate() {
if trak.tkhd.track_id != i as u32 + 1 {
return Err(Error::InvalidData("tracks out of order"));
}
tracks.push(Mp4Track::from(trak));
if moov.traks.iter().any(|trak| trak.tkhd.track_id == 0) {
return Err(Error::InvalidData("illegal track id 0"));
}
tracks
moov.traks.iter()
.map(|trak| (trak.tkhd.track_id, Mp4Track::from(trak)))
.collect()
} else {
Vec::new()
HashMap::new()
};

// Update tracks if any fragmented (moof) boxes are found.
Expand All @@ -87,9 +86,13 @@ impl<R: Read + Seek> Mp4Reader<R> {

for moof in moofs.iter() {
for traf in moof.trafs.iter() {
let track_id = traf.tfhd.track_id as usize - 1;
tracks[track_id].default_sample_duration = default_sample_duration;
tracks[track_id].trafs.push(traf.clone());
let track_id = traf.tfhd.track_id;
if let Some(track) = tracks.get_mut(&track_id) {
track.default_sample_duration = default_sample_duration;
track.trafs.push(traf.clone())
} else {
return Err(Error::TrakNotFound(track_id));
}
}
}
}
Expand Down Expand Up @@ -132,28 +135,20 @@ impl<R: Read + Seek> Mp4Reader<R> {
self.moofs.len() != 0
}

pub fn tracks(&self) -> &[Mp4Track] {
pub fn tracks(&self) -> &HashMap<u32, Mp4Track> {
&self.tracks
}

pub fn sample_count(&self, track_id: u32) -> Result<u32> {
if track_id == 0 {
return Err(Error::TrakNotFound(track_id));
}

if let Some(track) = self.tracks.get(track_id as usize - 1) {
if let Some(track) = self.tracks.get(&track_id) {
Ok(track.sample_count())
} else {
Err(Error::TrakNotFound(track_id))
}
}

pub fn read_sample(&mut self, track_id: u32, sample_id: u32) -> Result<Option<Mp4Sample>> {
if track_id == 0 {
return Err(Error::TrakNotFound(track_id));
}

if let Some(ref track) = self.tracks.get(track_id as usize - 1) {
if let Some(track) = self.tracks.get(&track_id) {
track.read_sample(&mut self.reader, sample_id)
} else {
Err(Error::TrakNotFound(track_id))
Expand Down
4 changes: 2 additions & 2 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fn test_read_mp4() {
assert!(eos.is_none());

// track #1
let track1 = mp4.tracks().get(0).unwrap();
let track1 = mp4.tracks().get(&1).unwrap();
assert_eq!(track1.track_id(), 1);
assert_eq!(track1.track_type().unwrap(), TrackType::Video);
assert_eq!(track1.media_type().unwrap(), MediaType::H264);
Expand All @@ -105,7 +105,7 @@ fn test_read_mp4() {
assert_eq!(track1.frame_rate(), 25.00); // XXX

// track #2
let track2 = mp4.tracks().get(1).unwrap();
let track2 = mp4.tracks().get(&2).unwrap();
assert_eq!(track2.track_type().unwrap(), TrackType::Audio);
assert_eq!(track2.media_type().unwrap(), MediaType::AAC);
assert_eq!(
Expand Down

0 comments on commit 3711e91

Please sign in to comment.