core: fix NAStream.get_duration()
[nihav.git] / nihav-mpeg / src / codecs / mpegaudio / mod.rs
index 6c908d825e35609cc262c9ec621421a47428a72a..187a695938de6f62d01485c446f1496820ca96d7 100644 (file)
@@ -1,4 +1,5 @@
 use nihav_core::codecs::*;
+use nihav_core::io::byteio::read_u32be;
 use nihav_core::io::bitreader::*;
 use nihav_codec_support::dsp::qmf::QMF;
 
@@ -361,9 +362,25 @@ 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));
+                }
+            }
+        }
         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())
+        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 +443,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 +467,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 +478,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 +489,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();