X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fcodecs%2Fpcm.rs;h=3bc67c007f04461ac2262c6504ba949d661d49fc;hb=6f2630992fe340ad1a122ec10c649f756e478185;hp=0cd37156b185d1a864dc39296185e196baa32c25;hpb=f5c54c1053ae1665907d4a356da721c552ce0595;p=nihav.git diff --git a/nihav-commonfmt/src/codecs/pcm.rs b/nihav-commonfmt/src/codecs/pcm.rs index 0cd3715..3bc67c0 100644 --- a/nihav-commonfmt/src/codecs/pcm.rs +++ b/nihav-commonfmt/src/codecs/pcm.rs @@ -1,18 +1,72 @@ use nihav_core::formats::*; use nihav_core::codecs::*; +#[cfg(feature="encoder_pcm")] use nihav_core::io::byteio::*; -struct PCMDecoder { chmap: NAChannelMap } +#[derive(Clone,Copy,Debug,PartialEq)] +#[cfg(feature="decoder_pcm")] +enum PCMMode { + Infinity, + ALaw, + MuLaw, +} + +#[cfg(feature="decoder_pcm")] +struct PCMDecoder { + chmap: NAChannelMap, + mode: PCMMode, +} + +#[cfg(feature="decoder_pcm")] +fn cvt_alaw(val: u8) -> i16 { + let val = val ^ 0x55; + let sign = (val & 0x80) != 0; + let exp = ((val >> 4) & 7) + 4; + let mant = (val & 0xF) + if exp != 0 { 16 } else { 0 }; + let aval = i16::from(mant) << exp; + if sign { aval } else { -aval } +} +#[cfg(feature="decoder_pcm")] +fn cvt_mulaw(val: u8) -> i16 { + let val = !val; + let sign = (val & 0x80) != 0; + let exp = ((val >> 4) & 7) + 3; + let mant = (val & 0xF) | 0x10; + let aval = (i16::from(mant) << exp) - 128 - 4; + if !sign { aval } else { -aval } +} + +#[cfg(feature="decoder_pcm")] impl PCMDecoder { - fn new() -> Self { - PCMDecoder { chmap: NAChannelMap::new() } + fn new(mode: PCMMode) -> Self { + PCMDecoder { chmap: NAChannelMap::new(), mode } + } + fn decode_xlaw(&self, pkt: &NAPacket, duration: u64, srate: u32) -> DecoderResult { + let pktbuf = pkt.get_buffer(); + let channels = self.chmap.num_channels(); + let abuf = alloc_audio_buffer(NAAudioInfo::new(srate, channels as u8, SND_S16_FORMAT, 1), duration as usize, self.chmap.clone())?; + let mut buf = abuf.get_abuf_i16().unwrap(); + let dst = buf.get_data_mut().unwrap(); + for (src, dst) in pktbuf.chunks(channels).zip(dst.chunks_mut(channels)) { + for (isamp, dsamp) in src.iter().zip(dst.iter_mut()) { + *dsamp = if self.mode == PCMMode::ALaw { cvt_alaw(*isamp) } else { cvt_mulaw(*isamp) }; + } + } + let info = pkt.get_stream().get_info(); + let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); + frm.set_duration(Some(duration)); + frm.set_keyframe(true); + Ok(frm.into_ref()) } } +#[cfg(feature="decoder_pcm")] const CHMAP_MONO: [NAChannelType; 1] = [NAChannelType::C]; +#[cfg(feature="decoder_pcm")] const CHMAP_STEREO: [NAChannelType; 2] = [NAChannelType::L, NAChannelType::R]; +#[cfg(feature="decoder_pcm")] fn get_default_chmap(nch: u8) -> NAChannelMap { let mut chmap = NAChannelMap::new(); match nch { @@ -23,6 +77,7 @@ fn get_default_chmap(nch: u8) -> NAChannelMap { chmap } +#[cfg(feature="decoder_pcm")] fn get_duration(ainfo: &NAAudioInfo, duration: Option, data_size: usize) -> u64 { if duration == None { let size_bits = (data_size as u64) * 8; @@ -33,6 +88,7 @@ fn get_duration(ainfo: &NAAudioInfo, duration: Option, data_size: usize) -> } } +#[cfg(feature="decoder_pcm")] impl NADecoder for PCMDecoder { fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { @@ -47,6 +103,9 @@ impl NADecoder for PCMDecoder { let info = pkt.get_stream().get_info(); if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { let duration = get_duration(&ainfo, pkt.get_duration(), pkt.get_buffer().len()); + if self.mode != PCMMode::Infinity { + return self.decode_xlaw(pkt, duration, ainfo.sample_rate); + } let pktbuf = pkt.get_buffer(); let abuf = NAAudioBuffer::new_from_buf(ainfo, pktbuf, self.chmap.clone()); let mut frm = NAFrame::new_from_pkt(pkt, info, NABufferType::AudioPacked(abuf)); @@ -61,21 +120,35 @@ impl NADecoder for PCMDecoder { } } +#[cfg(feature="decoder_pcm")] impl NAOptionHandler for PCMDecoder { fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } fn set_options(&mut self, _options: &[NAOption]) { } fn query_option_value(&self, _name: &str) -> Option { None } } +#[cfg(feature="decoder_pcm")] pub fn get_decoder() -> Box { - Box::new(PCMDecoder::new()) + Box::new(PCMDecoder::new(PCMMode::Infinity)) } +#[cfg(feature="decoder_pcm")] +pub fn get_a_law_decoder() -> Box { + Box::new(PCMDecoder::new(PCMMode::ALaw)) +} + +#[cfg(feature="decoder_pcm")] +pub fn get_mu_law_decoder() -> Box { + Box::new(PCMDecoder::new(PCMMode::MuLaw)) +} + +#[cfg(feature="encoder_pcm")] struct PCMEncoder { stream: Option, pkt: Option, } +#[cfg(feature="encoder_pcm")] impl PCMEncoder { fn new() -> Self { PCMEncoder { @@ -85,6 +158,7 @@ impl PCMEncoder { } } +#[allow(unused_macros)] macro_rules! write_buffer { ($abuf: expr, $dvec: expr, $write_be: ident, $write_le: ident, $dtype: tt) => { let info = $abuf.get_info(); @@ -110,15 +184,17 @@ macro_rules! write_buffer { } } +#[cfg(feature="encoder_pcm")] impl NAEncoder for PCMEncoder { fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult { match encinfo.format { NACodecTypeInfo::None => { - let mut ofmt = EncodeParameters::default(); - ofmt.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16P_FORMAT, 0)); - Ok(ofmt) + Ok(EncodeParameters { + format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16P_FORMAT, 0)), + ..Default::default() + }) }, - NACodecTypeInfo::Video(_) => return Err(EncoderError::FormatError), + NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError), NACodecTypeInfo::Audio(_) => { Ok(*encinfo) } @@ -130,7 +206,7 @@ impl NAEncoder for PCMEncoder { NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError), NACodecTypeInfo::Audio(_) => { let info = NACodecInfo::new("pcm", encinfo.format, None); - let mut stream = NAStream::new(StreamType::Audio, stream_id, info, encinfo.tb_num, encinfo.tb_den); + let mut stream = NAStream::new(StreamType::Audio, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0); stream.set_num(stream_id as usize); let stream = stream.into_ref(); self.stream = Some(stream.clone()); @@ -190,12 +266,14 @@ impl NAEncoder for PCMEncoder { } } +#[cfg(feature="encoder_pcm")] impl NAOptionHandler for PCMEncoder { fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } fn set_options(&mut self, _options: &[NAOption]) { } fn query_option_value(&self, _name: &str) -> Option { None } } +#[cfg(feature="encoder_pcm")] pub fn get_encoder() -> Box { Box::new(PCMEncoder::new()) }