1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_codec_support::codecs::imaadpcm::*;
5 struct NibbleWriter<'a> {
11 impl<'a> NibbleWriter<'a> {
12 fn new(bw: ByteWriter<'a>) -> Self {
13 Self { bw, val: 0, first: true }
15 fn write(&mut self, nib: u8) -> EncoderResult<()> {
21 self.bw.write_byte(self.val)?;
35 impl Default for TrellisNode {
36 fn default() -> Self {
38 state: IMAState::new(),
46 struct IMAADPCMEncoder {
47 stream: Option<NAStreamRef>,
55 nodes: Vec<[TrellisNode; 16]>,
60 const DEFAULT_BLOCK_LEN: usize = 256;
62 impl IMAADPCMEncoder {
63 fn new() -> Self { Self::default() }
64 fn encode_packet(&mut self) -> EncoderResult<NAPacket> {
65 if self.samples.is_empty() {
66 return Err(EncoderError::TryAgain);
68 let cur_len = (self.samples.len() / self.channels).min(self.block_len);
69 if cur_len < self.block_len && !self.flush {
70 return Err(EncoderError::TryAgain);
72 if cur_len < self.block_len {
73 self.samples.resize(self.block_len * self.channels, 0);
76 let mut dbuf = vec![0u8; self.block_size];
77 let mut mw = MemoryWriter::new_write(dbuf.as_mut_slice());
78 let mut bw = ByteWriter::new(&mut mw);
80 for ch in 0..self.channels {
81 self.first[ch].predictor = i32::from(self.samples[ch]);
82 self.first[ch].step = Self::calc_step(self.samples[ch], self.samples[ch + self.channels]) as usize;
86 for ch in 0..self.channels {
87 bw.write_u16le(self.first[ch].predictor as u16)?;
88 bw.write_byte(self.first[ch].step as u8)?;
91 let mut nw = NibbleWriter::new(bw);
92 for samples in self.samples.chunks(self.channels).take(self.block_len).skip(1) {
93 for (state, &samp) in self.first.iter_mut().zip(samples.iter()) {
94 let nib = state.compress_sample(samp);
95 state.expand_sample(nib);
101 self.nodes.reserve(self.block_len);
102 self.nibs.resize(self.channels, Vec::new());
103 for nibs in self.nibs.iter_mut() {
104 nibs.resize(self.block_len, 0);
106 let step = self.channels;
107 let mut state = [TrellisNode::default(); 16];
108 for ch in 0..self.channels {
111 let step = (((self.first[ch].step + i) as isize) - 8).max(0).min(IMA_MAX_STEP as isize) as usize;
112 state[i].state.predictor = self.first[ch].predictor;
113 state[i].state.step = step;
115 state[i].nib = step as u8;
117 self.nodes.push(state);
118 let mut sidx = ch + step;
119 for _i in 1..self.block_len {
120 let sample = self.samples[sidx];
122 for (nnib, cstate) in state.iter_mut().enumerate() {
124 let pnode = &self.nodes[self.nodes.len() - 1][nib];
125 let mut ima = pnode.state;
126 let nsamp = ima.expand_sample(nnib as u8);
127 let diff = i64::from(i32::from(sample) - i32::from(nsamp));
128 let error = pnode.error + diff * diff;
129 if (nib == 0) || error < cstate.error {
131 cstate.nib = nib as u8;
132 cstate.error = error;
136 self.nodes.push(state);
142 let mut best_err = self.nodes[self.nodes.len() - 1][0].error;
143 for (i, node) in self.nodes[self.nodes.len() - 1].iter().enumerate() {
144 if node.error < best_err {
145 best_err = node.error;
149 let mut dst = self.nibs[ch].iter_mut().rev();
150 while let Some(nodes) = self.nodes.pop() {
151 *dst.next().unwrap() = idx as u8;
152 idx = nodes[idx].nib as usize;
154 self.nibs[ch][0] = idx as u8;
156 for ch in 0..self.channels {
157 bw.write_u16le(self.first[ch].predictor as u16)?;
158 bw.write_byte(self.nibs[ch][0])?;
161 let mut nw = NibbleWriter::new(bw);
162 for i in 1..self.block_len {
163 for ch in 0..self.channels {
164 nw.write(self.nibs[ch][i])?;
170 self.samples.drain(..self.block_len * self.channels);
171 let ts = NATimeInfo::new(None, None, Some(1), 1, self.srate);
172 Ok(NAPacket::new(self.stream.clone().unwrap(), ts, true, dbuf))
174 fn calc_block_size(nsamps: usize, channels: usize) -> usize {
175 ((nsamps - 1) * channels + 1) / 2 + 4 * channels
177 fn calc_step(samp1: i16, samp2: i16) -> u8 {
178 let diff = (i32::from(samp1) - i32::from(samp2)).abs();
179 for (i, &step) in IMA_STEP_TABLE.iter().enumerate() {
188 impl NAEncoder for IMAADPCMEncoder {
189 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
190 match encinfo.format {
191 NACodecTypeInfo::None => {
192 Ok(EncodeParameters {
193 format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 1, SND_S16_FORMAT, DEFAULT_BLOCK_LEN)),
194 ..Default::default() })
196 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
197 NACodecTypeInfo::Audio(ainfo) => {
198 let mut outinfo = ainfo;
199 outinfo.channels = outinfo.channels.max(1);
200 if outinfo.format != SND_S16P_FORMAT && outinfo.format != SND_S16_FORMAT {
201 outinfo.format = SND_S16_FORMAT;
203 if outinfo.block_len == 0 {
204 outinfo.block_len = DEFAULT_BLOCK_LEN;
206 if outinfo.block_len < 2 {
207 outinfo.block_len = 2;
209 if (outinfo.block_len & 7) != 0 {
210 outinfo.block_len = (outinfo.block_len & 7) + 7;
212 let mut ofmt = *encinfo;
213 ofmt.format = NACodecTypeInfo::Audio(outinfo);
218 fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
219 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
220 match encinfo.format {
221 NACodecTypeInfo::None => Err(EncoderError::FormatError),
222 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
223 NACodecTypeInfo::Audio(ainfo) => {
224 if ainfo.format != SND_S16P_FORMAT && ainfo.format != SND_S16_FORMAT {
225 return Err(EncoderError::FormatError);
227 if ainfo.block_len < 2 || ((ainfo.block_len * (ainfo.channels as usize)) & 7) != 0 {
228 return Err(EncoderError::FormatError);
230 self.channels = ainfo.channels as usize;
231 self.block_len = ainfo.block_len;
232 self.block_size = Self::calc_block_size(self.block_len, ainfo.channels as usize);
233 self.first = Vec::with_capacity(self.channels);
234 for _ in 0..self.channels {
235 self.first.push(IMAState::new());
238 let soniton = NASoniton::new(4, 0);
239 let out_ainfo = NAAudioInfo::new(ainfo.sample_rate, ainfo.channels, soniton, Self::calc_block_size(self.block_len, self.channels));
240 let info = NACodecInfo::new("ima-adpcm-ms", NACodecTypeInfo::Audio(out_ainfo), None);
241 let mut stream = NAStream::new(StreamType::Audio, stream_id, info, self.block_len as u32, ainfo.sample_rate, 0);
242 stream.set_num(stream_id as usize);
243 let stream = stream.into_ref();
245 self.stream = Some(stream.clone());
246 self.samples = Vec::with_capacity(self.block_len * self.channels);
247 self.srate = ainfo.sample_rate;
254 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
255 let buf = frm.get_buffer();
256 if let Some(ref abuf) = buf.get_abuf_i16() {
257 let src = abuf.get_data();
258 let len = abuf.get_length();
259 let ch = abuf.get_chmap().num_channels();
260 if abuf.get_step() > 1 || ch == 1 {
261 self.samples.extend_from_slice(&src[..len * ch]);
263 let astride = abuf.get_stride();
264 self.samples.reserve(len * ch);
266 for ch in 0..self.channels {
267 self.samples.push(src[ch * astride + i]);
273 Err(EncoderError::InvalidParameters)
276 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
277 if let Ok(pkt) = self.encode_packet() {
283 fn flush(&mut self) -> EncoderResult<()> {
289 const ENCODER_OPTS: &[NAOptionDefinition] = &[
291 name: "trellis", description: "Use trellis search",
292 opt_type: NAOptionDefinitionType::Bool },
295 impl NAOptionHandler for IMAADPCMEncoder {
296 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
297 fn set_options(&mut self, options: &[NAOption]) {
298 for option in options.iter() {
299 for opt_def in ENCODER_OPTS.iter() {
300 if opt_def.check(option).is_ok() {
303 if let NAValue::Bool(val) = option.value {
313 fn query_option_value(&self, name: &str) -> Option<NAValue> {
315 "trellis" => Some(NAValue::Bool(self.trellis)),
321 pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
322 Box::new(IMAADPCMEncoder::new())
327 use nihav_core::codecs::*;
328 use nihav_core::demuxers::*;
329 use nihav_core::muxers::*;
330 use nihav_codec_support::test::enc_video::*;
332 use nihav_commonfmt::*;
334 fn test_ima_adpcm_ms_encoder(name: &'static str, trellis: bool, hash: &[u32; 4]) {
335 let mut dmx_reg = RegisteredDemuxers::new();
336 generic_register_all_demuxers(&mut dmx_reg);
337 let mut dec_reg = RegisteredDecoders::new();
338 generic_register_all_decoders(&mut dec_reg);
339 ms_register_all_decoders(&mut dec_reg);
340 let mut mux_reg = RegisteredMuxers::new();
341 generic_register_all_muxers(&mut mux_reg);
342 let mut enc_reg = RegisteredEncoders::new();
343 ms_register_all_encoders(&mut enc_reg);
345 // sample: https://samples.mplayerhq.hu/V-codecs/VP4/ot171_vp40.avi
346 let dec_config = DecoderTestParams {
348 in_name: "assets/Duck/ot171_vp40.avi",
349 stream_type: StreamType::Audio,
353 let enc_config = EncoderTestParams {
355 enc_name: "ima-adpcm-ms",
359 let dst_ainfo = NAAudioInfo {
362 format: SND_S16_FORMAT,
365 let enc_params = EncodeParameters {
366 format: NACodecTypeInfo::Audio(dst_ainfo),
374 NAOption{name: "trellis", value: NAValue::Bool(trellis)},
376 // test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
378 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
382 fn test_ima_adpcm_ms_encoder_notrellis() {
383 test_ima_adpcm_ms_encoder("msimaadpcm-notr.wav", false,
384 &[0x59909f10, 0xf0420dd2, 0xcfee7ef5, 0x7623caa3]);
387 fn test_ima_adpcm_ms_encoder_trellis() {
388 test_ima_adpcm_ms_encoder("msimaadpcm-tr.wav", true,
389 &[0x99e373e2, 0x80439b4b, 0xcb4f0b78, 0xeb1e9a51]);