1
0
Fork 0
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:
cTopher 2021-07-30 04:57:15 +02:00 committed by GitHub
parent 94f9e88b2d
commit 8fe009e248
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 68 deletions

View file

@ -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;

View file

@ -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 {

View file

@ -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)?,

View file

@ -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 {

View file

@ -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(),

View file

@ -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(),

View file

@ -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))

View file

@ -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!(