X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-mpeg%2Fsrc%2Fcodecs%2Fmpegaudio%2Fmod.rs;h=99b57720127296ca210430b86146581b3952e538;hp=f61b0a18314bab10610637703be6a7b03c5c94eb;hb=7f7356a02d44ed553643502806d4342394419637;hpb=16cca4d3a7a7505ae31a7469b3547c52650fd194 diff --git a/nihav-mpeg/src/codecs/mpegaudio/mod.rs b/nihav-mpeg/src/codecs/mpegaudio/mod.rs index f61b0a1..99b5772 100644 --- a/nihav-mpeg/src/codecs/mpegaudio/mod.rs +++ b/nihav-mpeg/src/codecs/mpegaudio/mod.rs @@ -1,18 +1,22 @@ 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::*; const SAMPLES: usize = 1152; -const BYTEBUF_SIZE: usize = 1024; +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,10 +289,198 @@ impl NAOptionHandler for MPADecoder { fn query_option_value(&self, _name: &str) -> Option { None } } +pub fn get_decoder_mp2() -> Box { + Box::new(MPADecoder::new(1)) +} + pub fn get_decoder_mp3() -> Box { Box::new(MPADecoder::new(2)) } +#[derive(Clone,Copy,Debug)] +struct MPAHeader { + layer: u8, + srate: u32, + channels: u8, + frame_size: usize, + nsamples: usize, +} + +impl PartialEq for MPAHeader { + fn eq(&self, other: &Self) -> bool { + self.layer == other.layer && + self.srate == other.srate && + self.channels == other.channels + } +} + +#[derive(Default)] +struct MPAPacketiser { + buf: Vec, + hdr: Option, +} + +impl MPAPacketiser { + fn new() -> Self { Self::default() } + fn parse_header(&self, off: usize) -> DecoderResult { + if self.buf.len() < off + 4 { return Err(DecoderError::ShortData); } + + let mut br = BitReader::new(&self.buf[off..], BitReaderMode::BE); + + let syncword = br.read(11)?; + if syncword != 0x7FF { return Err(DecoderError::InvalidData); } + let id = br.read(2)?; + if id == 1 { return Err(DecoderError::InvalidData); } + let layer = (br.read(2)? ^ 3) as u8; + if layer == 3 { return Err(DecoderError::InvalidData); } + let _protection = br.read_bool()?; + let bitrate_index = br.read(4)? as usize; + 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; + 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; + + match id { + 0 => sf_idx += 6, + 2 => sf_idx += 3, + _ => {}, + }; + let mpeg1 = id == 3; + let srate = SAMPLING_RATE[sf_idx]; + let channels = if mode == 3 { 1 } else { 2 }; + 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 } + }, + }; + let nsamples = if mpeg1 { SAMPLES } else { SAMPLES / 2 }; + + Ok(MPAHeader{ layer, srate, channels, frame_size, nsamples }) + } +} + +impl NAPacketiser for MPAPacketiser { + fn add_data(&mut self, src: &[u8]) -> bool { + self.buf.extend_from_slice(src); + self.buf.len() < 4096 + } + fn parse_stream(&mut self, id: u32) -> DecoderResult { + if self.hdr.is_none() { + if self.buf.len() < 4 { + return Err(DecoderError::ShortData); + } + let hdr = self.parse_header(0)?; + 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 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 { + if self.buf.len() <= 2 { + return Ok(0); + } + let mut off = 0; + let mut hdr = u16::from(self.buf[0]) * 256 + u16::from(self.buf[1]); + let mut iter = self.buf[2..].iter(); + loop { + if (hdr & 0xFFE0) != 0xFFE0 { + let ret = self.parse_header(off); + match ret { + Ok(hdr) => { + if self.hdr.is_none() { + self.hdr = Some(hdr); + } + if self.hdr.unwrap() != hdr { // header is valid but mismatches + self.buf.drain(..off + 1); + return Err(DecoderError::InvalidData); + } + break; + }, + Err(err) => { + self.buf.drain(..off + 1); + return Err(err); + }, + }; + } + off += 1; + if let Some(&b) = iter.next() { + hdr = (hdr << 8) | u16::from(b); + } else { + break; + } + } + self.buf.drain(..off); + Ok(off) + } + fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult> { + if self.buf.len() < 4 { + return Err(DecoderError::ShortData); + } + let hdr = self.parse_header(0)?; + if self.hdr.is_none() { + self.hdr = Some(hdr); + } + if self.hdr.unwrap() != hdr { + return Err(DecoderError::InvalidData); + } + if hdr.frame_size <= self.buf.len() { + let mut data = Vec::with_capacity(hdr.frame_size); + data.extend_from_slice(&self.buf[..hdr.frame_size]); + self.buf.drain(..hdr.frame_size); + let ts = NATimeInfo::new(None, None, Some(1), hdr.nsamples as u32, hdr.srate); + Ok(Some(NAPacket::new(stream, ts, true, data))) + } else { + Ok(None) + } + } + fn reset(&mut self) { + self.buf.clear(); + } + fn bytes_left(&self) -> usize { self.buf.len() } +} + +pub fn get_packetiser() -> Box { + Box::new(MPAPacketiser::new()) +} + #[cfg(test)] mod test { use nihav_core::codecs::RegisteredDecoders; @@ -279,6 +488,9 @@ mod test { use nihav_codec_support::test::dec_video::test_decode_audio; use crate::mpeg_register_all_decoders; use nihav_flash::flash_register_all_demuxers; + use std::io::Read; + use nihav_core::codecs::NAPacketiser; + #[test] fn test_mpeg1_layer3_mono() { let mut dmx_reg = RegisteredDemuxers::new(); @@ -286,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); } @@ -296,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); } @@ -306,9 +520,28 @@ 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(); + file.read_exact(&mut buf).unwrap(); + pkts.add_data(&buf); + let stream = pkts.parse_stream(0).unwrap(); + let mut frame_sizes = Vec::with_capacity(15); + while let Some(pkt) = pkts.get_packet(stream.clone()).unwrap() { + let frame_size = pkt.get_buffer().len(); + println!("pkt size {}", frame_size); + frame_sizes.push(frame_size); + } + assert_eq!(&frame_sizes, &[1044, 1044, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1044, 1045, 1045, 1045]); + } } const BITRATE: [[[u32; 15]; 3]; 2] = [