1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-05-19 16:58:04 +00:00

Set optional EsdsBox in Mp4aBox. (#23)

* Make EsdsBox in Mp4aBox optional, instead of error when parsing. Also update mp4info example with some missing info that was removed.

* Update Mp4aBox test to check for optional EsdsBox.
This commit is contained in:
Alfred Gutierrez 2020-08-23 13:38:25 -07:00 committed by GitHub
parent 0ac9986c7f
commit c4ff8627b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 42 deletions

View file

@ -4,7 +4,7 @@ use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::Path;
use mp4::{Mp4Track, Result, TrackType};
use mp4::{Mp4Track, Result, TrackType, Error};
fn main() {
let args: Vec<String> = env::args().collect();
@ -26,17 +26,23 @@ fn info<P: AsRef<Path>>(filename: &P) -> Result<()> {
let mp4 = mp4::Mp4Reader::read_header(reader, size)?;
println!("Metadata:");
println!(" size : {}", mp4.size());
println!(" major_brand : {}", mp4.major_brand());
println!("File:");
println!(" file 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(",");
compatible_brands.push_str(" ");
}
println!(" compatible_brands: {}", compatible_brands);
println!("Duration: {:?}", mp4.duration());
println!(" compatible_brands: {}\n", compatible_brands);
println!("Movie:");
println!(" version: {}", mp4.moov.mvhd.version);
println!(" creation time: {}", creation_time(mp4.moov.mvhd.creation_time));
println!(" duration: {:?}", mp4.duration());
println!(" timescale: {:?}\n", mp4.timescale());
println!("Found {} Tracks", mp4.tracks().len());
for track in mp4.tracks().iter() {
let media_info = match track.track_type()? {
TrackType::Video => video_info(track)?,
@ -68,13 +74,35 @@ fn video_info(track: &Mp4Track) -> Result<String> {
}
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
))
if let Some(ref mp4a) = track.trak.mdia.minf.stbl.stsd.mp4a {
if mp4a.esds.is_some() {
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
))
} else {
Ok(format!(
"{} ({:?}), {} kb/s",
track.media_type()?,
track.box_type()?,
track.bitrate() / 1000
))
}
} else {
Err(Error::InvalidData("mp4a box not found"))
}
}
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
}
}

View file

@ -9,7 +9,7 @@ pub struct Mp4aBox {
pub channelcount: u16,
pub samplesize: u16,
pub samplerate: FixedPointU16,
pub esds: EsdsBox,
pub esds: Option<EsdsBox>,
}
impl Default for Mp4aBox {
@ -19,7 +19,7 @@ impl Default for Mp4aBox {
channelcount: 2,
samplesize: 16,
samplerate: FixedPointU16::new(48000),
esds: EsdsBox::default(),
esds: Some(EsdsBox::default()),
}
}
}
@ -31,7 +31,7 @@ impl Mp4aBox {
channelcount: config.chan_conf as u16,
samplesize: 16,
samplerate: FixedPointU16::new(config.freq_index.freq() as u16),
esds: EsdsBox::new(config),
esds: Some(EsdsBox::new(config)),
}
}
}
@ -42,7 +42,11 @@ impl Mp4Box for Mp4aBox {
}
fn box_size(&self) -> u64 {
HEADER_SIZE + 8 + 20 + self.esds.box_size()
let mut size = HEADER_SIZE + 8 + 20;
if let Some(ref esds) = self.esds {
size += esds.box_size();
}
size
}
}
@ -62,21 +66,20 @@ impl<R: Read + Seek> ReadBox<&mut R> for Mp4aBox {
let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
let mut esds = None;
if name == BoxType::EsdsBox {
let esds = EsdsBox::read_box(reader, s)?;
skip_bytes_to(reader, start + size)?;
Ok(Mp4aBox {
data_reference_index,
channelcount,
samplesize,
samplerate,
esds,
})
} else {
Err(Error::InvalidData("esds not found"))
esds = Some(EsdsBox::read_box(reader, s)?);
}
skip_bytes_to(reader, start + size)?;
Ok(Mp4aBox {
data_reference_index,
channelcount,
samplesize,
samplerate,
esds,
})
}
}
@ -95,7 +98,9 @@ impl<W: Write> WriteBox<&mut W> for Mp4aBox {
writer.write_u32::<BigEndian>(0)?; // reserved
writer.write_u32::<BigEndian>(self.samplerate.raw_value())?;
self.esds.write_box(writer)?;
if let Some(ref esds) = self.esds {
esds.write_box(writer)?;
}
Ok(size)
}
@ -524,7 +529,7 @@ mod tests {
channelcount: 2,
samplesize: 16,
samplerate: FixedPointU16::new(48000),
esds: EsdsBox {
esds: Some(EsdsBox {
version: 0,
flags: 0,
es_desc: ESDescriptor {
@ -544,7 +549,29 @@ mod tests {
},
sl_config: SLConfigDescriptor::default(),
},
},
}),
};
let mut buf = Vec::new();
src_box.write_box(&mut buf).unwrap();
assert_eq!(buf.len(), src_box.box_size() as usize);
let mut reader = Cursor::new(&buf);
let header = BoxHeader::read(&mut reader).unwrap();
assert_eq!(header.name, BoxType::Mp4aBox);
assert_eq!(src_box.box_size(), header.size);
let dst_box = Mp4aBox::read_box(&mut reader, header.size).unwrap();
assert_eq!(src_box, dst_box);
}
#[test]
fn test_mp4a_no_esds() {
let src_box = Mp4aBox {
data_reference_index: 1,
channelcount: 2,
samplesize: 16,
samplerate: FixedPointU16::new(48000),
esds: None,
};
let mut buf = Vec::new();
src_box.write_box(&mut buf).unwrap();

View file

@ -53,7 +53,7 @@ impl From<AacConfig> for TrackConfig {
#[derive(Debug)]
pub struct Mp4Track {
trak: TrakBox,
pub trak: TrakBox,
}
impl Mp4Track {
@ -126,7 +126,11 @@ impl Mp4Track {
pub fn sample_freq_index(&self) -> Result<SampleFreqIndex> {
if let Some(ref mp4a) = self.trak.mdia.minf.stbl.stsd.mp4a {
SampleFreqIndex::try_from(mp4a.esds.es_desc.dec_config.dec_specific.freq_index)
if let Some(ref esds) = mp4a.esds {
SampleFreqIndex::try_from(esds.es_desc.dec_config.dec_specific.freq_index)
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::EsdsBox))
}
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Mp4aBox))
}
@ -134,7 +138,11 @@ impl Mp4Track {
pub fn channel_config(&self) -> Result<ChannelConfig> {
if let Some(ref mp4a) = self.trak.mdia.minf.stbl.stsd.mp4a {
ChannelConfig::try_from(mp4a.esds.es_desc.dec_config.dec_specific.chan_conf)
if let Some(ref esds) = mp4a.esds {
ChannelConfig::try_from(esds.es_desc.dec_config.dec_specific.chan_conf)
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::EsdsBox))
}
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Mp4aBox))
}
@ -156,7 +164,12 @@ impl Mp4Track {
pub fn bitrate(&self) -> u32 {
if let Some(ref mp4a) = self.trak.mdia.minf.stbl.stsd.mp4a {
mp4a.esds.es_desc.dec_config.avg_bitrate
if let Some(ref esds) = mp4a.esds {
esds.es_desc.dec_config.avg_bitrate
} else {
0
}
// mp4a.esds.es_desc.dec_config.avg_bitrate
} else {
let dur_sec = self.duration().as_secs();
if dur_sec > 0 {
@ -215,7 +228,11 @@ impl Mp4Track {
pub fn audio_profile(&self) -> Result<AudioObjectType> {
if let Some(ref mp4a) = self.trak.mdia.minf.stbl.stsd.mp4a {
AudioObjectType::try_from(mp4a.esds.es_desc.dec_config.dec_specific.profile)
if let Some(ref esds) = mp4a.esds {
AudioObjectType::try_from(esds.es_desc.dec_config.dec_specific.profile)
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::EsdsBox))
}
} else {
Err(Error::BoxInStblNotFound(self.track_id(), BoxType::Mp4aBox))
}
@ -660,7 +677,9 @@ impl Mp4TrackWriter {
let max_sample_size = self.max_sample_size();
if let Some(ref mut mp4a) = self.trak.mdia.minf.stbl.stsd.mp4a {
mp4a.esds.es_desc.dec_config.buffer_size_db = max_sample_size;
if let Some(ref mut esds) = mp4a.esds {
esds.es_desc.dec_config.buffer_size_db = max_sample_size;
}
// TODO
// mp4a.esds.es_desc.dec_config.max_bitrate
// mp4a.esds.es_desc.dec_config.avg_bitrate