mpegaudio: make packetiser checks less verbose
[nihav.git] / nihav-mpeg / src / codecs / mpegaudio / mod.rs
index 6c908d825e35609cc262c9ec621421a47428a72a..99b57720127296ca210430b86146581b3952e538 100644 (file)
@@ -1,7 +1,11 @@
 use nihav_core::codecs::*;
+use nihav_core::io::byteio::read_u32be;
 use nihav_core::io::bitreader::*;
 use nihav_codec_support::dsp::qmf::QMF;
 
+mod mp2data;
+mod mp2code;
+use mp2code::*;
 mod mp3data;
 mod mp3code;
 use mp3code::*;
@@ -12,7 +16,7 @@ const BYTEBUF_SIZE: usize = 2048;
 #[allow(clippy::large_enum_variant)]
 enum LayerData {
     MP1,
-    MP2,
+    MP2(MP2Data),
     MP3(MP3Data),
 }
 
@@ -20,14 +24,14 @@ impl LayerData {
     fn layer_id(&self) -> u8 {
         match *self {
             LayerData::MP1    => 0,
-            LayerData::MP2    => 1,
+            LayerData::MP2(_) => 1,
             LayerData::MP3(_) => 2,
         }
     }
     fn reset(&mut self) {
         match self {
             LayerData::MP1 => {},
-            LayerData::MP2 => {},
+            LayerData::MP2(ref mut data) => data.reset(),
             LayerData::MP3(ref mut data) => data.reset(),
         };
     }
@@ -52,7 +56,7 @@ impl MPADecoder {
     fn new(layer: u8) -> Self {
         let ctx = match layer {
                 0 => LayerData::MP1,
-                1 => LayerData::MP2,
+                1 => LayerData::MP2(MP2Data::new()),
                 2 => LayerData::MP3(MP3Data::new()),
                 _ => unreachable!(),
             };
@@ -215,7 +219,24 @@ impl NADecoder for MPADecoder {
 
             match layer {
                 0 => unimplemented!(),
-                1 => unimplemented!(),
+                1 => {
+                    if let LayerData::MP2(ref mut ctx) = self.ctx {
+                        ctx.mpeg1 = self.sf_idx < 3;
+                        ctx.sf_idx = self.sf_idx;
+                        ctx.br_idx = bitrate_index;
+                        ctx.read_layer2(&mut br, channels as usize, &mut self.out, mode, mode_extension)?;
+                    } else {
+                        return Err(DecoderError::Bug);
+                    }
+                    for (dst, src) in ch0.chunks_exact_mut(32).zip(self.out[0].iter_mut()) {
+                        self.qmf[0].synth(src, dst);
+                    }
+                    if channels == 2 {
+                        for (dst, src) in ch1.chunks_mut(32).zip(self.out[1].iter_mut()) {
+                            self.qmf[1].synth(src, dst);
+                        }
+                    }
+                },
                 _ => {
                     let ret = self.read_mp3_side_data(&mut br, &src[..frame_size], channels == 1);
                     match ret {
@@ -268,6 +289,10 @@ impl NAOptionHandler for MPADecoder {
     fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
 }
 
+pub fn get_decoder_mp2() -> Box<dyn NADecoder + Send> {
+    Box::new(MPADecoder::new(1))
+}
+
 pub fn get_decoder_mp3() -> Box<dyn NADecoder + Send> {
     Box::new(MPADecoder::new(2))
 }
@@ -303,20 +328,20 @@ impl MPAPacketiser {
         let mut br = BitReader::new(&self.buf[off..], BitReaderMode::BE);
 
         let syncword                = br.read(11)?;
-        validate!(syncword == 0x7FF);
+        if syncword != 0x7FF { return Err(DecoderError::InvalidData); }
         let id                      = br.read(2)?;
-        validate!(id != 1);
+        if id == 1 { return Err(DecoderError::InvalidData); }
         let layer                   = (br.read(2)? ^ 3) as u8;
-        validate!(layer != 3);
+        if layer == 3 { return Err(DecoderError::InvalidData); }
         let _protection             = br.read_bool()?;
         let bitrate_index           = br.read(4)? as usize;
-        validate!(bitrate_index < 15);
+        if bitrate_index == 15 { return Err(DecoderError::InvalidData); }
         if bitrate_index == 0 {
             //todo freeform eventually
             unimplemented!();
         }
         let mut sf_idx              = br.read(2)? as usize;
-        validate!(sf_idx != 3);
+        if sf_idx == 3 { return Err(DecoderError::InvalidData); }
         let padding                 = br.read_bool()?;
         let _private                = br.read_bool()?;
         let mode                    = br.read(2)? as u8;
@@ -361,9 +386,32 @@ impl NAPacketiser for MPAPacketiser {
             self.hdr = Some(hdr);
         }
         let hdr = self.hdr.unwrap();
+        let mut duration = 0;
+        if hdr.layer == 2 { // check for Xing/LAME info
+            let mpeg1 = hdr.srate >= 32000;
+            let offset = match (mpeg1, hdr.channels) {
+                    (true, 1)  => 24,
+                    (true, _)  => 36,
+                    (false, 1) => 13,
+                    (false, _) => 21,
+                };
+            if self.buf.len() >= offset + 12 && (&self.buf[offset..][..4] == b"Xing" || &self.buf[offset..][..4] == b"Info") {
+                let flags   = read_u32be(&self.buf[offset + 4..]).unwrap_or(0);
+                if (flags & 1) != 0 {
+                    duration = u64::from(read_u32be(&self.buf[offset + 8..]).unwrap_or(0));
+                }
+            } else if self.buf.len() >= offset + 18 && &self.buf[offset..][..6] == b"VBRI\x00\x01" {
+                duration = u64::from(read_u32be(&self.buf[offset + 14..]).unwrap_or(0));
+            }
+        }
         let ainfo = NAAudioInfo::new(hdr.srate, hdr.channels, SND_F32P_FORMAT, hdr.nsamples);
-        let info = NACodecInfo::new("mp3", NACodecTypeInfo::Audio(ainfo), None);
-        Ok(NAStream::new(StreamType::Audio, id, info, hdr.nsamples as u32, hdr.srate, 0).into_ref())
+        let cname = match hdr.layer {
+                0 => "mp1",
+                1 => "mp2",
+                _ => "mp3",
+            };
+        let info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ainfo), None);
+        Ok(NAStream::new(StreamType::Audio, id, info, hdr.nsamples as u32, hdr.srate, duration).into_ref())
     }
     fn skip_junk(&mut self) -> DecoderResult<usize> {
         if self.buf.len() <= 2 {
@@ -426,6 +474,7 @@ impl NAPacketiser for MPAPacketiser {
     fn reset(&mut self) {
         self.buf.clear();
     }
+    fn bytes_left(&self) -> usize { self.buf.len() }
 }
 
 pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
@@ -449,6 +498,7 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         mpeg_register_all_decoders(&mut dec_reg);
 
+        // sample: https://samples.mplayerhq.hu/FLV/flash_video_5/i_004.flv
         let file = "assets/Flash/i_004.flv";
         test_decode_audio("flv", file, Some(6000), None/*Some("mp3_1")*/, &dmx_reg, &dec_reg);
     }
@@ -459,6 +509,7 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         mpeg_register_all_decoders(&mut dec_reg);
 
+        // sample: https://samples.mplayerhq.hu/FLV/venture_030_ivcp_001_8bit.flv
         let file = "assets/Flash/venture_030_ivcp_001_8bit.flv";
         test_decode_audio("flv", file, Some(7200), None/*Some("mp3_2")*/, &dmx_reg, &dec_reg);
     }
@@ -469,12 +520,14 @@ mod test {
         let mut dec_reg = RegisteredDecoders::new();
         mpeg_register_all_decoders(&mut dec_reg);
 
+        // sample: https://samples.mplayerhq.hu/FLV/flash_with_alpha/lection2-2.flv
         let file = "assets/Flash/lection2-2.flv";
         test_decode_audio("flv", file, Some(6000), None/*Some("mp3_3")*/, &dmx_reg, &dec_reg);
     }
     #[test]
     fn test_mpa_packetiser() {
         let mut buf = [0; 16384];
+        // sample from a private collection
         let mut file = std::fs::File::open("assets/MPEG/1.mp3").unwrap();
 
         let mut pkts = super::MPAPacketiser::new();