diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index fc8ec69..d654cbc 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -53,11 +53,11 @@ impl Mp4aBox { impl Mp4Box for Mp4aBox { fn box_type(&self) -> BoxType { - return self.get_type(); + self.get_type() } fn box_size(&self) -> u64 { - return self.get_size(); + self.get_size() } fn to_json(&self) -> Result { @@ -159,8 +159,7 @@ impl Mp4Box for EsdsBox { } fn summary(&self) -> Result { - let s = format!(""); - Ok(s) + Ok(String::new()) } } @@ -471,13 +470,45 @@ impl Descriptor for DecoderSpecificDescriptor { } } +fn get_audio_object_type(byte_a: u8, byte_b: u8) -> u8 { + let mut profile = byte_a >> 3; + if profile == 31 { + profile = 32 + ((byte_a & 7) | (byte_b >> 5)); + } + + profile +} + +fn get_chan_conf(reader: &mut R, byte_b: u8, freq_index: u8, extended_profile: bool) -> Result { + let chan_conf; + if freq_index == 15 { + // Skip the 24 bit sample rate + let sample_rate = reader.read_u24::()?; + chan_conf = ((sample_rate >> 4) & 0x0F) as u8; + } else if extended_profile { + let byte_c = reader.read_u8()?; + chan_conf = (byte_b & 1) | (byte_c & 0xE0); + } else { + chan_conf = (byte_b >> 3) & 0x0F; + } + + Ok(chan_conf) +} + impl ReadDesc<&mut R> for DecoderSpecificDescriptor { fn read_desc(reader: &mut R, _size: u32) -> Result { let byte_a = reader.read_u8()?; let byte_b = reader.read_u8()?; - let profile = byte_a >> 3; - let freq_index = ((byte_a & 0x07) << 1) + (byte_b >> 7); - let chan_conf = (byte_b >> 3) & 0x0F; + let profile = get_audio_object_type(byte_a, byte_b); + let freq_index; + let chan_conf; + if profile > 31 { + freq_index = (byte_b >> 1) & 0x0F; + chan_conf = get_chan_conf(reader, byte_b, freq_index, true)?; + } else { + freq_index = ((byte_a & 0x07) << 1) + (byte_b >> 7); + chan_conf = get_chan_conf(reader, byte_b, freq_index, false)?; + } Ok(DecoderSpecificDescriptor { profile, diff --git a/tests/lib.rs b/tests/lib.rs index 0fa0b25..e40fe2b 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,16 +1,11 @@ -use mp4::{AudioObjectType, AvcProfile, ChannelConfig, MediaType, SampleFreqIndex, TrackType}; +use mp4::{AudioObjectType, AvcProfile, ChannelConfig, MediaType, Mp4Reader, SampleFreqIndex, TrackType}; use std::fs::File; use std::io::BufReader; use std::time::Duration; #[test] fn test_read_mp4() { - let filename = "tests/samples/minimal.mp4"; - let f = File::open(filename).unwrap(); - let size = f.metadata().unwrap().len(); - let reader = BufReader::new(f); - - let mut mp4 = mp4::Mp4Reader::read_header(reader, size).unwrap(); + let mut mp4 = get_reader("tests/samples/minimal.mp4"); assert_eq!(2591, mp4.size()); @@ -119,3 +114,31 @@ fn test_read_mp4() { assert_eq!(track2.channel_config().unwrap(), ChannelConfig::Mono); assert_eq!(track2.bitrate(), 67695); } + +#[test] +fn test_read_extended_audio_object_type() { + // Extended audio object type and sample rate index of 15 + let mp4 = get_reader("tests/samples/extended_audio_object_type.mp4"); + + let track = mp4.tracks().get(&1).unwrap(); + assert_eq!(track.track_type().unwrap(), TrackType::Audio); + assert_eq!(track.media_type().unwrap(), MediaType::AAC); + assert_eq!( + track.audio_profile().unwrap(), + AudioObjectType::AudioLosslessCoding + ); + assert_eq!( + track.trak.mdia.minf.stbl.stsd.mp4a.as_ref().unwrap().esds.as_ref().unwrap().es_desc.dec_config.dec_specific.freq_index, + 15 + ); + assert_eq!(track.channel_config().unwrap(), ChannelConfig::Stereo); + assert_eq!(track.bitrate(), 839250); +} + +fn get_reader(path: &str) -> Mp4Reader> { + let f = File::open(path).unwrap(); + let f_size = f.metadata().unwrap().len(); + let reader = BufReader::new(f); + + mp4::Mp4Reader::read_header(reader, f_size).unwrap() +} \ No newline at end of file diff --git a/tests/samples/extended_audio_object_type.mp4 b/tests/samples/extended_audio_object_type.mp4 new file mode 100644 index 0000000..3d1a711 Binary files /dev/null and b/tests/samples/extended_audio_object_type.mp4 differ