From 12ba304023f8a85f9f07997fb26c09216b51b4a4 Mon Sep 17 00:00:00 2001 From: Alex <69764315+Serial-ATA@users.noreply.github.com> Date: Fri, 25 Mar 2022 23:02:50 -0400 Subject: [PATCH] Support profiles > 31 in `DecoderSpecificDescriptor` (#69) --- src/mp4box/mp4a.rs | 45 ++++++++++++++++--- tests/lib.rs | 37 ++++++++++++--- tests/samples/extended_audio_object_type.mp4 | Bin 0 -> 5230 bytes 3 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 tests/samples/extended_audio_object_type.mp4 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 0000000000000000000000000000000000000000..3d1a711a30fc4aedc6684e2f55711113a86e386b GIT binary patch literal 5230 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 W+2{1z^}o4)*8t>vC!c?d!T$$!pw>_T literal 0 HcmV?d00001