add nihav-mpeg crate
[nihav.git] / nihav-mpeg / src / codecs / mpegaudio / mod.rs
diff --git a/nihav-mpeg/src/codecs/mpegaudio/mod.rs b/nihav-mpeg/src/codecs/mpegaudio/mod.rs
new file mode 100644 (file)
index 0000000..f61b0a1
--- /dev/null
@@ -0,0 +1,326 @@
+use nihav_core::codecs::*;
+use nihav_core::io::bitreader::*;
+use nihav_codec_support::dsp::qmf::QMF;
+
+mod mp3data;
+mod mp3code;
+use mp3code::*;
+
+const SAMPLES: usize = 1152;
+const BYTEBUF_SIZE: usize = 1024;
+
+#[allow(clippy::large_enum_variant)]
+enum LayerData {
+    MP1,
+    MP2,
+    MP3(MP3Data),
+}
+
+impl LayerData {
+    fn layer_id(&self) -> u8 {
+        match *self {
+            LayerData::MP1    => 0,
+            LayerData::MP2    => 1,
+            LayerData::MP3(_) => 2,
+        }
+    }
+    fn reset(&mut self) {
+        match self {
+            LayerData::MP1 => {},
+            LayerData::MP2 => {},
+            LayerData::MP3(ref mut data) => data.reset(),
+        };
+    }
+}
+
+struct MPADecoder {
+    info:       NACodecInfoRef,
+    smap:       NAChannelMap,
+    mmap:       NAChannelMap,
+    qmf:        [QMF; 2],
+    srate:      u32,
+    channels:   u8,
+    sf_idx:     usize,
+
+    bytebuf:    Vec<u8>,
+    coeffs:     [[f32; SAMPLES]; 2],
+    out:        [[[f32; 32]; 36]; 2],
+    ctx:        LayerData,
+}
+
+impl MPADecoder {
+    fn new(layer: u8) -> Self {
+        let ctx = match layer {
+                0 => LayerData::MP1,
+                1 => LayerData::MP2,
+                2 => LayerData::MP3(MP3Data::new()),
+                _ => unreachable!(),
+            };
+        Self {
+            info:       NACodecInfo::new_dummy(),
+            smap:       NAChannelMap::from_ms_mapping(3),
+            mmap:       NAChannelMap::from_ms_mapping(4),
+            qmf:        [QMF::new(), QMF::new()],
+            srate:      0,
+            channels:   0,
+            sf_idx:     0,
+            ctx,
+
+            bytebuf:    Vec::with_capacity(BYTEBUF_SIZE),
+            coeffs:     [[0.0; SAMPLES]; 2],
+            out:        [[[0.0; 32]; 36]; 2],
+        }
+    }
+    fn read_mp3_side_data(&mut self, br: &mut BitReader, src: &[u8], mono: bool) -> DecoderResult<()> {
+        if let LayerData::MP3(ref mut ctx) = self.ctx {
+            let channels = if mono { 1 } else { 2 };
+            ctx.mpeg1 = self.sf_idx < 3;
+            ctx.sf_idx = self.sf_idx;
+            ctx.read_mp3_side_data(br, channels)?;
+            let hdr_size = (br.tell() / 8) as usize;
+            let add_len = src.len() - hdr_size;
+            if self.bytebuf.len() + add_len > BYTEBUF_SIZE {
+                self.bytebuf.drain(..self.bytebuf.len() + add_len - BYTEBUF_SIZE);
+            }
+            let underrun = self.bytebuf.len() < ctx.main_data_end;
+            let del_len = if !underrun { self.bytebuf.len() - ctx.main_data_end } else { 0 };
+            self.bytebuf.extend_from_slice(&src[hdr_size..]);
+            self.bytebuf.drain(..del_len);
+            if underrun {
+                return Err(DecoderError::MissingReference);
+            }
+
+            Ok(())
+        } else {
+            Err(DecoderError::Bug)
+        }
+    }
+    fn decode_layer3(&mut self, channels: usize, mode_ext: u8) -> DecoderResult<bool> {
+        if let LayerData::MP3(ref mut ctx) = self.ctx {
+            let mut br = BitReader::new(&self.bytebuf, BitReaderMode::BE);
+            if ctx.mpeg1 {
+                ctx.decode_mpeg1_layer3(&mut br, &mut self.coeffs, channels)?;
+            } else {
+                ctx.decode_mpeg2_layer3(&mut br, &mut self.coeffs, channels, mode_ext)?;
+            }
+            let used_data = (br.tell() + 7) / 8;
+            self.bytebuf.drain(..used_data);
+
+            Ok(true)
+        } else {
+            Err(DecoderError::Bug)
+        }
+    }
+    fn synth_layer3(&mut self, mode: u8, mode_ext: u8) {
+        if let LayerData::MP3(ref mut ctx) = self.ctx {
+            ctx.synth(&mut self.coeffs, &mut self.out, mode, mode_ext);
+        }
+    }
+}
+
+fn apply_ms(ch0: &mut [f32], ch1: &mut [f32]) {
+    for (l, r) in ch0.iter_mut().zip(ch1) {
+        let ll = (*l + *r) * std::f32::consts::FRAC_1_SQRT_2;
+        let rr = (*l - *r) * std::f32::consts::FRAC_1_SQRT_2;
+        *l = ll;
+        *r = rr;
+    }
+}
+
+impl NADecoder for MPADecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+            self.info = info.clone();
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let src = pkt.get_buffer();
+
+            let mut br = BitReader::new(src.as_slice(), BitReaderMode::BE);
+
+            let syncword                = br.read(11)?;
+            validate!(syncword == 0x7FF);
+            let id                      = br.read(2)?;
+            validate!(id != 1);
+            let layer                   = (br.read(2)? ^ 3) as u8;
+            validate!(layer != 3);
+            let protection              = br.read_bool()?;
+            let bitrate_index           = br.read(4)? as usize;
+            validate!(bitrate_index < 15);
+            if bitrate_index == 0 {
+                //todo freeform eventually
+                unimplemented!();
+            }
+            let mut sf_idx              = br.read(2)? as usize;
+            validate!(sf_idx != 3);
+            let padding                 = br.read_bool()?;
+            let _private                = br.read_bool()?;
+            let mode                    = br.read(2)? as u8;
+            let mode_extension          = br.read(2)? as u8;
+            let _copyright              = br.read_bool()?;
+            let _original               = br.read_bool()?;
+            let _emphasis               = br.read(2)?;
+            if !protection {
+                let _crc_check          = br.read(16)?;
+            }
+            validate!(layer == self.ctx.layer_id());
+            match id {
+                0 => sf_idx += 6,
+                2 => sf_idx += 3,
+                _ => {},
+            };
+            let mpeg1 = id == 3;
+            let srate = SAMPLING_RATE[sf_idx];
+            if self.srate == 0 {
+                self.srate = srate;
+            }
+            validate!(srate == self.srate);
+            let channels = if mode == 3 { 1 } else { 2 };
+            if self.channels == 0 {
+                self.channels = channels;
+            }
+            if channels != self.channels {
+                self.flush();
+            }
+            let bitrate = BITRATE[if mpeg1 { 0 } else { 1 }][layer as usize][bitrate_index];
+            let frame_size = match layer {
+                    0 => {
+                        ((SAMPLES / 3 / 8 * 1000 * (bitrate as usize) / (srate as usize)) & !3) + if padding { 4 } else { 0 }
+                    },
+                    2 if !mpeg1 => {
+                        SAMPLES / 2 / 8 * 1000 * (bitrate as usize) / (srate as usize) + if padding { 1 } else { 0 }
+                    },
+                    _ => {
+                        SAMPLES / 8 * 1000 * (bitrate as usize) / (srate as usize) + if padding { 1 } else { 0 }
+                    },
+                };
+            validate!(src.len() >= frame_size);
+            self.sf_idx = sf_idx;
+
+            let nsamples = if mpeg1 { SAMPLES } else { SAMPLES / 2 };
+
+            let ainfo = NAAudioInfo::new(srate, channels, SND_F32P_FORMAT, nsamples);
+            let chmap = if channels == 1 { self.mmap.clone() } else { self.smap.clone() };
+
+            let mut abuf = alloc_audio_buffer(ainfo, nsamples, chmap)?;
+            let mut adata = abuf.get_abuf_f32().unwrap();
+            let off = if channels == 1 { adata.get_length() } else { adata.get_stride() };
+            let buf = adata.get_data_mut().unwrap();
+            let (ch0, ch1) = buf.split_at_mut(off);
+
+            match layer {
+                0 => unimplemented!(),
+                1 => unimplemented!(),
+                _ => {
+                    let ret = self.read_mp3_side_data(&mut br, &src[..frame_size], channels == 1);
+                    match ret {
+                        Err(DecoderError::MissingReference) => {
+                            abuf.truncate_audio(0);
+                            let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
+                            frm.set_duration(Some(0));
+                            return Ok(frm.into_ref());
+                        },
+                        Err(err) => return Err(err),
+                        Ok(()) => {},
+                    };
+                    let has_data = self.decode_layer3(channels as usize, mode_extension)?;
+                    if !has_data {
+                        let frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
+                        return Ok(frm.into_ref());
+                    }
+                    self.synth_layer3(mode, mode_extension);
+                    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 mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
+            frm.set_duration(Some(nsamples as u64));
+            frm.set_keyframe(true);
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::Bug)
+        }
+    }
+    fn flush(&mut self) {
+        for qmf in self.qmf.iter_mut() {
+            *qmf = QMF::new();
+        }
+        self.bytebuf.clear();
+        self.ctx.reset();
+    }
+}
+
+impl NAOptionHandler for MPADecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder_mp3() -> Box<dyn NADecoder + Send> {
+    Box::new(MPADecoder::new(2))
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::test_decode_audio;
+    use crate::mpeg_register_all_decoders;
+    use nihav_flash::flash_register_all_demuxers;
+    #[test]
+    fn test_mpeg1_layer3_mono() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        flash_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        mpeg_register_all_decoders(&mut dec_reg);
+
+        let file = "assets/Flash/i_004.flv";
+        test_decode_audio("flv", file, Some(6000), None/*Some("mp3_1")*/, &dmx_reg, &dec_reg);
+    }
+    #[test]
+    fn test_mpeg1_layer3_stereo() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        flash_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        mpeg_register_all_decoders(&mut dec_reg);
+
+        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);
+    }
+    #[test]
+    fn test_mpeg2_layer3() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        flash_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        mpeg_register_all_decoders(&mut dec_reg);
+
+        let file = "assets/Flash/lection2-2.flv";
+        test_decode_audio("flv", file, Some(6000), None/*Some("mp3_3")*/, &dmx_reg, &dec_reg);
+    }
+}
+
+const BITRATE: [[[u32; 15]; 3]; 2] = [
+  [
+    [ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 ],
+    [ 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384 ],
+    [ 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320 ]
+  ], [
+    [ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 ],
+    [ 0,  8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160 ],
+    [ 0,  8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160 ]
+  ]
+];
+
+const SAMPLING_RATE: [u32; 9] = [ 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000 ];