mirror of
https://github.com/alfg/mp4-rust.git
synced 2024-11-13 18:51:02 +00:00
Maintain a separate indexing from track_id to index to allow for non continues track ids (#43) (#58)
This commit is contained in:
parent
94f9e88b2d
commit
8fe009e248
8 changed files with 59 additions and 68 deletions
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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> {
|
||||
|
@ -11,7 +12,7 @@ pub struct Mp4Reader<R> {
|
|||
pub moov: MoovBox,
|
||||
pub moofs: Vec<MoofBox>,
|
||||
|
||||
tracks: Vec<Mp4Track>,
|
||||
tracks: HashMap<u32, Mp4Track>,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,16 +135,12 @@ 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))
|
||||
|
@ -149,11 +148,7 @@ impl<R: Read + Seek> Mp4Reader<R> {
|
|||
}
|
||||
|
||||
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))
|
||||
|
|
|
@ -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);
|
||||
|
@ -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!(
|
||||
|
|
Loading…
Reference in a new issue