1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-05-19 16:58:04 +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 // TODO interleaving
for track_idx in 0..mp4_reader.tracks().len() { for track in mp4_reader.tracks().values() {
if let Some(ref track) = mp4_reader.tracks().get(track_idx) { let media_conf = match track.media_type()? {
let media_conf = match track.media_type()? { MediaType::H264 => MediaConfig::AvcConfig(AvcConfig {
MediaType::H264 => MediaConfig::AvcConfig(AvcConfig { width: track.width(),
width: track.width(), height: track.height(),
height: track.height(), seq_param_set: track.sequence_parameter_set()?.to_vec(),
seq_param_set: track.sequence_parameter_set()?.to_vec(), pic_param_set: track.picture_parameter_set()?.to_vec(),
pic_param_set: track.picture_parameter_set()?.to_vec(), }),
}), MediaType::H265 => MediaConfig::HevcConfig(HevcConfig {
MediaType::H265 => MediaConfig::HevcConfig(HevcConfig { width: track.width(),
width: track.width(), height: track.height(),
height: track.height(), }),
}), MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config {
MediaType::VP9 => MediaConfig::Vp9Config(Vp9Config { width: track.width(),
width: track.width(), height: track.height(),
height: track.height(), }),
}), MediaType::AAC => MediaConfig::AacConfig(AacConfig {
MediaType::AAC => MediaConfig::AacConfig(AacConfig { bitrate: track.bitrate(),
bitrate: track.bitrate(), profile: track.audio_profile()?,
profile: track.audio_profile()?, freq_index: track.sample_freq_index()?,
freq_index: track.sample_freq_index()?, chan_conf: track.channel_config()?,
chan_conf: track.channel_config()?, }),
}), MediaType::TTXT => MediaConfig::TtxtConfig(TtxtConfig {}),
MediaType::TTXT => MediaConfig::TtxtConfig(TtxtConfig {}), };
};
let track_conf = TrackConfig { let track_conf = TrackConfig {
track_type: track.track_type()?, track_type: track.track_type()?,
timescale: track.timescale(), timescale: track.timescale(),
language: track.language().to_string(), language: track.language().to_string(),
media_conf, media_conf,
}; };
mp4_writer.add_track(&track_conf)?; mp4_writer.add_track(&track_conf)?;
} else { }
unreachable!()
}
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)?; let sample_count = mp4_reader.sample_count(track_id)?;
for sample_idx in 0..sample_count { for sample_idx in 0..sample_count {
let sample_id = sample_idx + 1; let sample_id = sample_idx + 1;

View file

@ -61,7 +61,7 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
} }
// trak. // 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));
boxes.push(build_box(&track.trak.tkhd)); boxes.push(build_box(&track.trak.tkhd));
if let Some(ref edts) = track.trak.edts { 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!(" timescale: {:?}\n", mp4.timescale());
println!("Found {} Tracks", mp4.tracks().len()); 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()? { let media_info = match track.track_type()? {
TrackType::Video => video_info(track)?, TrackType::Video => video_info(track)?,
TrackType::Audio => audio_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)?; let mut mp4 = mp4::Mp4Reader::read_header(reader, size)?;
for track_idx in 0..mp4.tracks().len() { for track_id in mp4.tracks().keys().copied().collect::<Vec<u32>>() {
let track_id = track_idx as u32 + 1;
let sample_count = mp4.sample_count(track_id).unwrap(); let sample_count = mp4.sample_count(track_id).unwrap();
for sample_idx in 0..sample_count { for sample_idx in 0..sample_count {

View file

@ -16,7 +16,7 @@ fn main() {
println!("Major Brand: {}", mp4.major_brand()); println!("Major Brand: {}", mp4.major_brand());
for track in mp4.tracks().iter() { for track in mp4.tracks().values() {
println!("Track: #{}({}) {} {}", println!("Track: #{}({}) {} {}",
track.track_id(), track.track_id(),
track.language(), track.language(),

View file

@ -37,7 +37,7 @@
//! println!("duration: {:?}", mp4.duration()); //! println!("duration: {:?}", mp4.duration());
//! //!
//! // Track info. //! // Track info.
//! for track in mp4.tracks().iter() { //! for track in mp4.tracks().values() {
//! println!( //! println!(
//! "track: #{}({}) {} : {}", //! "track: #{}({}) {} : {}",
//! track.track_id(), //! track.track_id(),

View file

@ -1,8 +1,9 @@
use std::collections::HashMap;
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
use std::time::Duration; use std::time::Duration;
use crate::mp4box::*;
use crate::*; use crate::*;
use crate::mp4box::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Mp4Reader<R> { pub struct Mp4Reader<R> {
@ -11,7 +12,7 @@ pub struct Mp4Reader<R> {
pub moov: MoovBox, pub moov: MoovBox,
pub moofs: Vec<MoofBox>, pub moofs: Vec<MoofBox>,
tracks: Vec<Mp4Track>, tracks: HashMap<u32, Mp4Track>,
size: u64, size: u64,
} }
@ -64,16 +65,14 @@ impl<R: Read + Seek> Mp4Reader<R> {
let size = current - start; let size = current - start;
let mut tracks = if let Some(ref moov) = moov { let mut tracks = if let Some(ref moov) = moov {
let mut tracks = Vec::with_capacity(moov.traks.len()); if moov.traks.iter().any(|trak| trak.tkhd.track_id == 0) {
for (i, trak) in moov.traks.iter().enumerate() { return Err(Error::InvalidData("illegal track id 0"));
if trak.tkhd.track_id != i as u32 + 1 {
return Err(Error::InvalidData("tracks out of order"));
}
tracks.push(Mp4Track::from(trak));
} }
tracks moov.traks.iter()
.map(|trak| (trak.tkhd.track_id, Mp4Track::from(trak)))
.collect()
} else { } else {
Vec::new() HashMap::new()
}; };
// Update tracks if any fragmented (moof) boxes are found. // 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 moof in moofs.iter() {
for traf in moof.trafs.iter() { for traf in moof.trafs.iter() {
let track_id = traf.tfhd.track_id as usize - 1; let track_id = traf.tfhd.track_id;
tracks[track_id].default_sample_duration = default_sample_duration; if let Some(track) = tracks.get_mut(&track_id) {
tracks[track_id].trafs.push(traf.clone()); 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 self.moofs.len() != 0
} }
pub fn tracks(&self) -> &[Mp4Track] { pub fn tracks(&self) -> &HashMap<u32, Mp4Track> {
&self.tracks &self.tracks
} }
pub fn sample_count(&self, track_id: u32) -> Result<u32> { pub fn sample_count(&self, track_id: u32) -> Result<u32> {
if track_id == 0 { if let Some(track) = self.tracks.get(&track_id) {
return Err(Error::TrakNotFound(track_id));
}
if let Some(track) = self.tracks.get(track_id as usize - 1) {
Ok(track.sample_count()) Ok(track.sample_count())
} else { } else {
Err(Error::TrakNotFound(track_id)) 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>> { pub fn read_sample(&mut self, track_id: u32, sample_id: u32) -> Result<Option<Mp4Sample>> {
if track_id == 0 { if let Some(track) = self.tracks.get(&track_id) {
return Err(Error::TrakNotFound(track_id));
}
if let Some(ref track) = self.tracks.get(track_id as usize - 1) {
track.read_sample(&mut self.reader, sample_id) track.read_sample(&mut self.reader, sample_id)
} else { } else {
Err(Error::TrakNotFound(track_id)) Err(Error::TrakNotFound(track_id))

View file

@ -94,7 +94,7 @@ fn test_read_mp4() {
assert!(eos.is_none()); assert!(eos.is_none());
// track #1 // 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_id(), 1);
assert_eq!(track1.track_type().unwrap(), TrackType::Video); assert_eq!(track1.track_type().unwrap(), TrackType::Video);
assert_eq!(track1.media_type().unwrap(), MediaType::H264); assert_eq!(track1.media_type().unwrap(), MediaType::H264);
@ -105,7 +105,7 @@ fn test_read_mp4() {
assert_eq!(track1.frame_rate(), 25.00); // XXX assert_eq!(track1.frame_rate(), 25.00); // XXX
// track #2 // 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.track_type().unwrap(), TrackType::Audio);
assert_eq!(track2.media_type().unwrap(), MediaType::AAC); assert_eq!(track2.media_type().unwrap(), MediaType::AAC);
assert_eq!( assert_eq!(