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);
100 self.nodes.reserve(self.block_len);
101 self.nibs.resize(self.channels, Vec::new());
102 for nibs in self.nibs.iter_mut() {
103 nibs.resize(self.block_len, 0);
105 let step = self.channels;
106 let mut state = [TrellisNode::default(); 16];
107 for ch in 0..self.channels {
109 for (i, state) in state.iter_mut().enumerate() {
110 let step = (((self.first[ch].step + i) as isize) - 8).max(0).min(IMA_MAX_STEP as isize) as usize;
111 state.state.predictor = self.first[ch].predictor;
112 state.state.step = step;
114 state.nib = step as u8;
116 self.nodes.push(state);
117 let mut sidx = ch + step;
118 for _i in 1..self.block_len {
119 let sample = self.samples[sidx];
121 for (nnib, cstate) in state.iter_mut().enumerate() {
123 let pnode = &self.nodes[self.nodes.len() - 1][nib];
124 let mut ima = pnode.state;
125 let nsamp = ima.expand_sample(nnib as u8);
126 let diff = i64::from(i32::from(sample) - i32::from(nsamp));
127 let error = pnode.error + diff * diff;
128 if (nib == 0) || error < cstate.error {
130 cstate.nib = nib as u8;
131 cstate.error = error;
135 self.nodes.push(state);
141 let mut best_err = self.nodes[self.nodes.len() - 1][0].error;
142 for (i, node) in self.nodes[self.nodes.len() - 1].iter().enumerate() {
143 if node.error < best_err {
144 best_err = node.error;
148 let mut dst = self.nibs[ch].iter_mut().rev();
149 while let Some(nodes) = self.nodes.pop() {
150 *dst.next().unwrap() = idx as u8;
151 idx = nodes[idx].nib as usize;
153 self.nibs[ch][0] = idx as u8;
155 for ch in 0..self.channels {
156 bw.write_u16le(self.first[ch].predictor as u16)?;
157 bw.write_byte(self.nibs[ch][0])?;
160 let mut nw = NibbleWriter::new(bw);
161 for i in 1..self.block_len {
162 for ch in 0..self.channels {
163 nw.write(self.nibs[ch][i])?;
168 self.samples.drain(..self.block_len * self.channels);
169 let ts = NATimeInfo::new(None, None, Some(1), 1, self.srate);
170 Ok(NAPacket::new(self.stream.clone().unwrap(), ts, true, dbuf))
172 fn calc_block_size(nsamps: usize, channels: usize) -> usize {
173 ((nsamps - 1) * channels + 1) / 2 + 4 * channels
175 fn calc_step(samp1: i16, samp2: i16) -> u8 {
176 let diff = (i32::from(samp1) - i32::from(samp2)).abs();
177 for (i, &step) in IMA_STEP_TABLE.iter().enumerate() {
186 impl NAEncoder for IMAADPCMEncoder {
187 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
188 match encinfo.format {
189 NACodecTypeInfo::None => {
190 Ok(EncodeParameters {
191 format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 1, SND_S16_FORMAT, DEFAULT_BLOCK_LEN)),
192 ..Default::default() })
194 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
195 NACodecTypeInfo::Audio(ainfo) => {
196 let mut outinfo = ainfo;
197 outinfo.channels = outinfo.channels.max(1);
198 if outinfo.format != SND_S16P_FORMAT && outinfo.format != SND_S16_FORMAT {
199 outinfo.format = SND_S16_FORMAT;
201 if outinfo.block_len == 0 {
202 outinfo.block_len = DEFAULT_BLOCK_LEN;
204 if outinfo.block_len == 1 && encinfo.tb_den != outinfo.sample_rate {
205 outinfo.block_len = ((u64::from(outinfo.sample_rate) * u64::from(encinfo.tb_num) / u64::from(encinfo.tb_den) + 3) & !3) as usize;
207 if outinfo.block_len < 2 {
208 outinfo.block_len = 2;
210 if (outinfo.block_len & 7) != 0 {
211 outinfo.block_len = (outinfo.block_len & 7) + 7;
213 let mut ofmt = *encinfo;
214 ofmt.format = NACodecTypeInfo::Audio(outinfo);
219 fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
220 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
221 match encinfo.format {
222 NACodecTypeInfo::None => Err(EncoderError::FormatError),
223 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
224 NACodecTypeInfo::Audio(ainfo) => {
225 if ainfo.format != SND_S16P_FORMAT && ainfo.format != SND_S16_FORMAT {
226 return Err(EncoderError::FormatError);
228 if ainfo.block_len < 2 || ((ainfo.block_len * (ainfo.channels as usize)) & 7) != 0 {
229 return Err(EncoderError::FormatError);
231 self.channels = ainfo.channels as usize;
232 self.block_len = ainfo.block_len;
233 self.block_size = Self::calc_block_size(self.block_len, ainfo.channels as usize);
234 self.first = Vec::with_capacity(self.channels);
235 for _ in 0..self.channels {
236 self.first.push(IMAState::new());
239 let soniton = NASoniton::new(4, 0);
240 let out_ainfo = NAAudioInfo::new(ainfo.sample_rate, ainfo.channels, soniton, Self::calc_block_size(self.block_len, self.channels));
241 let info = NACodecInfo::new("ima-adpcm-ms", NACodecTypeInfo::Audio(out_ainfo), None);
242 let mut stream = NAStream::new(StreamType::Audio, stream_id, info, self.block_len as u32, ainfo.sample_rate, 0);
243 stream.set_num(stream_id as usize);
244 let stream = stream.into_ref();
246 self.stream = Some(stream.clone());
247 self.samples = Vec::with_capacity(self.block_len * self.channels);
248 self.srate = ainfo.sample_rate;
255 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
256 let buf = frm.get_buffer();
257 if let Some(ref abuf) = buf.get_abuf_i16() {
258 let src = abuf.get_data();
259 let len = abuf.get_length();
260 let ch = abuf.get_chmap().num_channels();
261 if abuf.get_step() > 1 || ch == 1 {
262 self.samples.extend_from_slice(&src[..len * ch]);
264 let astride = abuf.get_stride();
265 self.samples.reserve(len * ch);
267 for ch in 0..self.channels {
268 self.samples.push(src[ch * astride + i]);
274 Err(EncoderError::InvalidParameters)
277 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
278 if let Ok(pkt) = self.encode_packet() {
284 fn flush(&mut self) -> EncoderResult<()> {
290 const ENCODER_OPTS: &[NAOptionDefinition] = &[
292 name: "trellis", description: "Use trellis search",
293 opt_type: NAOptionDefinitionType::Bool },
296 impl NAOptionHandler for IMAADPCMEncoder {
297 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
298 fn set_options(&mut self, options: &[NAOption]) {
299 for option in options.iter() {
300 for opt_def in ENCODER_OPTS.iter() {
301 if opt_def.check(option).is_ok() {
304 if let NAValue::Bool(val) = option.value {
314 fn query_option_value(&self, name: &str) -> Option<NAValue> {
316 "trellis" => Some(NAValue::Bool(self.trellis)),
322 pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
323 Box::new(IMAADPCMEncoder::new())
328 use nihav_core::codecs::*;
329 use nihav_core::demuxers::*;
330 use nihav_core::muxers::*;
331 use nihav_codec_support::test::enc_video::*;
333 use nihav_commonfmt::*;
335 fn test_ima_adpcm_ms_encoder(name: &'static str, trellis: bool, hash: &[u32; 4]) {
336 let mut dmx_reg = RegisteredDemuxers::new();
337 generic_register_all_demuxers(&mut dmx_reg);
338 let mut dec_reg = RegisteredDecoders::new();
339 generic_register_all_decoders(&mut dec_reg);
340 ms_register_all_decoders(&mut dec_reg);
341 let mut mux_reg = RegisteredMuxers::new();
342 generic_register_all_muxers(&mut mux_reg);
343 let mut enc_reg = RegisteredEncoders::new();
344 ms_register_all_encoders(&mut enc_reg);
346 // sample: https://samples.mplayerhq.hu/V-codecs/VP4/ot171_vp40.avi
347 let dec_config = DecoderTestParams {
349 in_name: "assets/Duck/ot171_vp40.avi",
350 stream_type: StreamType::Audio,
354 let enc_config = EncoderTestParams {
356 enc_name: "ima-adpcm-ms",
360 let dst_ainfo = NAAudioInfo {
363 format: SND_S16_FORMAT,
366 let enc_params = EncodeParameters {
367 format: NACodecTypeInfo::Audio(dst_ainfo),
375 NAOption{name: "trellis", value: NAValue::Bool(trellis)},
377 // test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
379 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
383 fn test_ima_adpcm_ms_encoder_notrellis() {
384 test_ima_adpcm_ms_encoder("msimaadpcm-notr.wav", false,
385 &[0x59909f10, 0xf0420dd2, 0xcfee7ef5, 0x7623caa3]);
388 fn test_ima_adpcm_ms_encoder_trellis() {
389 test_ima_adpcm_ms_encoder("msimaadpcm-tr.wav", true,
390 &[0x99e373e2, 0x80439b4b, 0xcb4f0b78, 0xeb1e9a51]);