]> git.nihav.org Git - nihav.git/commitdiff
aac: improve ADTS handling
authorKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 15 Aug 2025 15:29:55 +0000 (17:29 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 15 Aug 2025 15:29:55 +0000 (17:29 +0200)
This should help with ADTS inside MP4

nihav-mpeg/src/codecs/aac/mod.rs
nihav-mpeg/src/codecs/aac/packetiser.rs

index 192b4e333b77a901d4fdafad757a0a5e179cea9d..d0588e378ea20c7a946906d5708f0db0c5aae6cb 100644 (file)
@@ -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)?;
index daecb2d5689cf3f06b41b17ea86f121af6ba944a..16c123af7f99ec9ba09df4611f711fa34795bc57 100644 (file)
@@ -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<u8>,
-    hdr:        Option<ADTSHeader>,
-}
+impl ADTSHeader {
+    pub fn parse(src: &[u8]) -> DecoderResult<ADTSHeader> {
+        if src.len() < 7 { return Err(DecoderError::ShortData); }
 
-impl PacketiserADTS {
-    fn new() -> Self { Self::default() }
-    fn skip_id3(buf: &[u8]) -> DecoderResult<usize> {
-        // 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<ADTSHeader> {
-        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<u8>,
+    hdr:        Option<ADTSHeader>,
+}
+
+impl PacketiserADTS {
+    fn new() -> Self { Self::default() }
+    fn skip_id3(buf: &[u8]) -> DecoderResult<usize> {
+        // 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);
         }