From 5a05facc593ceba526ad042e7a5b765e7d33f192 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Fri, 15 Aug 2025 17:29:55 +0200 Subject: [PATCH] aac: improve ADTS handling This should help with ADTS inside MP4 --- nihav-mpeg/src/codecs/aac/mod.rs | 39 ++++++++++-- nihav-mpeg/src/codecs/aac/packetiser.rs | 81 +++++++++++++------------ 2 files changed, 77 insertions(+), 43 deletions(-) diff --git a/nihav-mpeg/src/codecs/aac/mod.rs b/nihav-mpeg/src/codecs/aac/mod.rs index 192b4e3..d0588e3 100644 --- a/nihav-mpeg/src/codecs/aac/mod.rs +++ b/nihav-mpeg/src/codecs/aac/mod.rs @@ -676,7 +676,7 @@ impl AACDecoder { impl NADecoder for AACDecoder { fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { - if let NACodecTypeInfo::Audio(_) = info.get_properties() { + if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { let edata = info.get_extradata().unwrap(); validate!(edata.len() >= 2); @@ -729,8 +729,15 @@ impl NADecoder for AACDecoder { _ => br.read_skip(size as usize)?, } } - validate!(info_start > 0 && info_size > 0); - self.m4ainfo.read(&edata[info_start..][..info_size])?; + if info_start > 0 && info_size > 0 { + self.m4ainfo.read(&edata[info_start..][..info_size])?; + } else { + println!("info not found, making up"); + self.m4ainfo.otype = M4AType::LC; + self.m4ainfo.srate = ainfo.sample_rate; + self.m4ainfo.channels = usize::from(ainfo.channels); + self.m4ainfo.samples = 1024; + } } else { self.m4ainfo.read(&edata)?; } @@ -769,11 +776,35 @@ impl NADecoder for AACDecoder { validate!(info.get_properties().is_audio()); let pktbuf = pkt.get_buffer(); + if &pktbuf[0..3] == b"ID3" && (1..=4).contains(&pktbuf[3]) && pktbuf[4] == 0 { + println!("ID3!"); + return Err(DecoderError::InvalidData); + } + + let start = if pktbuf.len() > 2 && pktbuf[0] == 0xFF && (pktbuf[1] & 0xF0) == 0xF0 { + if let Ok(hdr) = packetiser::ADTSHeader::parse(&pktbuf) { + if hdr.srate != self.m4ainfo.srate { + if hdr.srate * 2 == self.m4ainfo.srate { + println!("reported ADTS sample rate differs from the container-provided one, patching..."); + self.m4ainfo.srate = hdr.srate; + self.upsample = true; + self.sbinfo = GASubbandInfo::find(self.m4ainfo.srate); + } else { + println!("reported ADTS sample rate differs from the container-provided one"); + return Err(DecoderError::InvalidData); + } + } + hdr.hdr_size + } else { + 0 + } + } else { 0 }; + let ainfo = self.info.get_properties().get_audio_info().unwrap(); let samples = if !self.upsample { self.m4ainfo.samples } else { self.m4ainfo.samples * 2 }; let mut abuf = alloc_audio_buffer(ainfo, samples, self.chmap.clone())?; - let mut br = BitReader::new(&pktbuf, BitReaderMode::BE); + let mut br = BitReader::new(&pktbuf[start..], BitReaderMode::BE); match self.m4ainfo.otype { M4AType::LC => { self.decode_ga(&mut br, &mut abuf)?; diff --git a/nihav-mpeg/src/codecs/aac/packetiser.rs b/nihav-mpeg/src/codecs/aac/packetiser.rs index daecb2d..16c123a 100644 --- a/nihav-mpeg/src/codecs/aac/packetiser.rs +++ b/nihav-mpeg/src/codecs/aac/packetiser.rs @@ -3,13 +3,13 @@ use nihav_core::io::bitreader::*; use super::info::*; #[derive(Default,Clone,Copy)] -struct ADTSHeader { - srate: u32, - channels: u8, - hdr_size: usize, - frame_size: usize, - samples: usize, - hdr: u32, +pub struct ADTSHeader { + pub srate: u32, + pub channels: u8, + pub hdr_size: usize, + pub frame_size: usize, + pub samples: usize, + pub hdr: u32, } impl PartialEq for ADTSHeader { @@ -18,36 +18,11 @@ impl PartialEq for ADTSHeader { } } -#[derive(Default)] -struct PacketiserADTS { - buf: Vec, - hdr: Option, -} +impl ADTSHeader { + pub fn parse(src: &[u8]) -> DecoderResult { + if src.len() < 7 { return Err(DecoderError::ShortData); } -impl PacketiserADTS { - fn new() -> Self { Self::default() } - fn skip_id3(buf: &[u8]) -> DecoderResult { - // check for ID3 tags in concatenated stream fragments - if &buf[0..3] == b"ID3" && (1..=4).contains(&buf[3]) && buf[4] == 0 { - if buf.len() < 10 { - return Err(DecoderError::ShortData); - } - let mut size = 0; - for &b in buf[6..10].iter() { - if (b & 0x80) != 0 { - return Err(DecoderError::InvalidData); - } - size = (size << 7) | usize::from(b); - } - Ok(size + 10) - } else { - Ok(0) - } - } - fn parse_header(&self, off: usize) -> DecoderResult { - if self.buf.len() < off + 7 { return Err(DecoderError::ShortData); } - - let mut br = BitReader::new(&self.buf[off..], BitReaderMode::BE); + let mut br = BitReader::new(src, BitReaderMode::BE); let syncword = br.read(12)?; if syncword != 0xFFF { return Err(DecoderError::InvalidData); } @@ -93,6 +68,34 @@ impl PacketiserADTS { } } +#[derive(Default)] +struct PacketiserADTS { + buf: Vec, + hdr: Option, +} + +impl PacketiserADTS { + fn new() -> Self { Self::default() } + fn skip_id3(buf: &[u8]) -> DecoderResult { + // check for ID3 tags in concatenated stream fragments + if &buf[0..3] == b"ID3" && (1..=4).contains(&buf[3]) && buf[4] == 0 { + if buf.len() < 10 { + return Err(DecoderError::ShortData); + } + let mut size = 0; + for &b in buf[6..10].iter() { + if (b & 0x80) != 0 { + return Err(DecoderError::InvalidData); + } + size = (size << 7) | usize::from(b); + } + Ok(size + 10) + } else { + Ok(0) + } + } +} + impl NAPacketiser for PacketiserADTS { fn attach_stream(&mut self, _stream: NAStreamRef) {} fn add_data(&mut self, src: &[u8]) -> bool { @@ -108,7 +111,7 @@ impl NAPacketiser for PacketiserADTS { if id3_len + 7 > self.buf.len() { return Err(DecoderError::ShortData); } - let hdr = self.parse_header(id3_len)?; + let hdr = ADTSHeader::parse(&self.buf[id3_len..])?; self.hdr = Some(hdr); } let hdr = self.hdr.unwrap(); @@ -126,7 +129,7 @@ impl NAPacketiser for PacketiserADTS { let mut iter = self.buf[2..].iter(); loop { if (hdr & 0xFFF6) == 0xFFF6 { - let ret = self.parse_header(off); + let ret = ADTSHeader::parse(&self.buf[off..]); match ret { Ok(hdr) => { if self.hdr.is_none() { @@ -166,7 +169,7 @@ impl NAPacketiser for PacketiserADTS { return Err(DecoderError::ShortData); } - let hdr = self.parse_header(0)?; + let hdr = ADTSHeader::parse(&self.buf)?; if self.hdr.is_none() { self.hdr = Some(hdr); } -- 2.39.5