X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-mpeg%2Fsrc%2Fcodecs%2Fmpegaudio%2Fmod.rs;fp=nihav-mpeg%2Fsrc%2Fcodecs%2Fmpegaudio%2Fmod.rs;h=f61b0a18314bab10610637703be6a7b03c5c94eb;hp=0000000000000000000000000000000000000000;hb=16cca4d3a7a7505ae31a7469b3547c52650fd194;hpb=576cd7d337fc80ec25bb1fc07fa2d25c5373f7b0 diff --git a/nihav-mpeg/src/codecs/mpegaudio/mod.rs b/nihav-mpeg/src/codecs/mpegaudio/mod.rs new file mode 100644 index 0000000..f61b0a1 --- /dev/null +++ b/nihav-mpeg/src/codecs/mpegaudio/mod.rs @@ -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, + 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 { + 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 { + 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 { None } +} + +pub fn get_decoder_mp3() -> Box { + 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 ];