From f5c54c1053ae1665907d4a356da721c552ce0595 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sat, 6 Jun 2020 12:46:41 +0200 Subject: [PATCH] PCM encoder --- nihav-commonfmt/Cargo.toml | 5 +- nihav-commonfmt/src/codecs/mod.rs | 5 +- nihav-commonfmt/src/codecs/pcm.rs | 130 ++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/nihav-commonfmt/Cargo.toml b/nihav-commonfmt/Cargo.toml index 6e572d3..3edd03a 100644 --- a/nihav-commonfmt/Cargo.toml +++ b/nihav-commonfmt/Cargo.toml @@ -44,7 +44,10 @@ decoder_sipro = ["decoders"] decoder_atrac3 = ["decoders"] decoder_aac = ["decoders"] -all_encoders = ["all_video_encoders"] +all_encoders = ["all_video_encoders", "all_audio_encoders"] all_video_encoders = ["encoder_cinepak"] encoder_cinepak = ["encoders"] + +all_audio_encoders = ["encoder_pcm"] +encoder_pcm = ["encoders"] diff --git a/nihav-commonfmt/src/codecs/mod.rs b/nihav-commonfmt/src/codecs/mod.rs index 32fbc7f..e2f5ed0 100644 --- a/nihav-commonfmt/src/codecs/mod.rs +++ b/nihav-commonfmt/src/codecs/mod.rs @@ -13,7 +13,7 @@ mod clearvideo; mod aac; #[cfg(feature="decoder_atrac3")] mod atrac3; -#[cfg(feature="decoder_pcm")] +#[cfg(any(feature="decoder_pcm",feature="encoder_pcm"))] mod pcm; #[cfg(feature="decoder_sipro")] mod sipro; @@ -53,6 +53,9 @@ mod cinepakenc; const ENCODERS: &[EncoderInfo] = &[ #[cfg(feature="encoder_cinepak")] EncoderInfo { name: "cinepak", get_encoder: cinepakenc::get_encoder }, + +#[cfg(feature="encoder_pcm")] + EncoderInfo { name: "pcm", get_encoder: pcm::get_encoder }, ]; /// Registers all available encoders provided by this crate. diff --git a/nihav-commonfmt/src/codecs/pcm.rs b/nihav-commonfmt/src/codecs/pcm.rs index b4ded87..0cd3715 100644 --- a/nihav-commonfmt/src/codecs/pcm.rs +++ b/nihav-commonfmt/src/codecs/pcm.rs @@ -1,5 +1,6 @@ use nihav_core::formats::*; use nihav_core::codecs::*; +use nihav_core::io::byteio::*; struct PCMDecoder { chmap: NAChannelMap } @@ -69,3 +70,132 @@ impl NAOptionHandler for PCMDecoder { pub fn get_decoder() -> Box { Box::new(PCMDecoder::new()) } + +struct PCMEncoder { + stream: Option, + pkt: Option, +} + +impl PCMEncoder { + fn new() -> Self { + PCMEncoder { + stream: None, + pkt: None, + } + } +} + +macro_rules! write_buffer { + ($abuf: expr, $dvec: expr, $write_be: ident, $write_le: ident, $dtype: tt) => { + let info = $abuf.get_info(); + let len = $abuf.get_length(); + let data = $abuf.get_data(); + let channels = $abuf.get_chmap().num_channels(); + let stride = $abuf.get_stride(); + let step = $abuf.get_step(); + let is_be = info.format.be; + + $dvec = vec![0u8; len * channels * std::mem::size_of::<$dtype>()]; + let mut mw = MemoryWriter::new_write($dvec.as_mut_slice()); + let mut bw = ByteWriter::new(&mut mw); + for off in 0..len { + for j in 0..channels { + if is_be { + bw.$write_be(data[off * step + j * stride] as $dtype).unwrap(); + } else { + bw.$write_le(data[off * step + j * stride] as $dtype).unwrap(); + } + } + } + } +} + +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) + }, + NACodecTypeInfo::Video(_) => return Err(EncoderError::FormatError), + NACodecTypeInfo::Audio(_) => { + Ok(*encinfo) + } + } + } + fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult { + match encinfo.format { + NACodecTypeInfo::None => Err(EncoderError::FormatError), + 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); + stream.set_num(stream_id as usize); + let stream = stream.into_ref(); + self.stream = Some(stream.clone()); + Ok(stream) + } + } + } + fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> { + let buf = frm.get_buffer(); + let mut dbuf; + match buf { + NABufferType::AudioU8(ref abuf) => { + let stride = abuf.get_stride(); + if stride == 1 { // packed already + self.pkt = Some(NAPacket::new_from_refbuf(self.stream.clone().unwrap(), frm.ts, true, abuf.get_data_ref())); + return Ok(()); + } + let len = abuf.get_length(); + let data = abuf.get_data(); + let channels = abuf.get_chmap().num_channels(); + dbuf = Vec::with_capacity(len * channels); + for off in 0..len { + for j in 0..channels { + dbuf.push(data[off + j * stride]); + } + } + }, + NABufferType::AudioI16(ref abuf) => { + write_buffer!(abuf, dbuf, write_u16be, write_u16le, u16); + }, + NABufferType::AudioI32(ref abuf) => { + write_buffer!(abuf, dbuf, write_u32be, write_u32le, u32); + }, + NABufferType::AudioF32(ref abuf) => { + write_buffer!(abuf, dbuf, write_f32be, write_f32le, f32); + }, + NABufferType::AudioPacked(ref abuf) => { + self.pkt = Some(NAPacket::new_from_refbuf(self.stream.clone().unwrap(), frm.ts, true, abuf.get_data_ref())); + return Ok(()); + }, + NABufferType::None => { + self.pkt = None; + return Ok(()); + }, + _ => return Err(EncoderError::FormatError), + }; + self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, true, dbuf)); + Ok(()) + } + fn get_packet(&mut self) -> EncoderResult> { + let mut npkt = None; + std::mem::swap(&mut self.pkt, &mut npkt); + Ok(npkt) + } + fn flush(&mut self) -> EncoderResult<()> { + Ok(()) + } +} + +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 } +} + +pub fn get_encoder() -> Box { + Box::new(PCMEncoder::new()) +} -- 2.30.2