]> git.nihav.org Git - nihav.git/blame_incremental - nihav-ms/src/codecs/msadpcm.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-ms / src / codecs / msadpcm.rs
... / ...
CommitLineData
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3use std::str::FromStr;
4
5const ADAPT_TABLE: [i32; 16] = [
6 230, 230, 230, 230, 307, 409, 512, 614,
7 768, 614, 512, 409, 307, 230, 230, 230
8];
9const ADAPT_COEFFS: [[i32; 2]; 7] = [
10 [ 256, 0 ], [ 512, -256 ], [ 0, 0 ], [ 192, 64 ],
11 [ 240, 0 ], [ 460, -208 ], [ 392, -232 ]
12];
13
14#[derive(Default)]
15struct Predictor {
16 sample1: i32,
17 sample2: i32,
18 delta: i32,
19 coef1: i32,
20 coef2: i32,
21}
22
23impl Predictor {
24 fn expand_nibble(&mut self, nibble: u8) -> i16 {
25 let mul = if (nibble & 8) == 0 { i32::from(nibble) } else { i32::from(nibble) - 16 };
26 let pred = self.calc_pred() + self.delta.wrapping_mul(mul);
27 self.update(pred.max(-0x8000).min(0x7FFF));
28 self.delta = (ADAPT_TABLE[nibble as usize].wrapping_mul(self.delta) >> 8).max(16);
29 self.sample1 as i16
30 }
31 fn calc_pred(&self) -> i32 {
32 self.sample1.wrapping_mul(self.coef1).wrapping_add(self.sample2.wrapping_mul(self.coef2)) >> 8
33 }
34 fn update(&mut self, new_samp: i32) {
35 self.sample2 = self.sample1;
36 self.sample1 = new_samp;
37 }
38}
39
40#[cfg(feature="decoder_ms_adpcm")]
41struct MSADPCMDecoder {
42 ainfo: NAAudioInfo,
43 chmap: NAChannelMap,
44 adapt_coeffs: Vec<[i32; 2]>,
45 block_len: usize,
46 block_samps: usize,
47}
48
49#[cfg(feature="decoder_ms_adpcm")]
50impl MSADPCMDecoder {
51 fn new() -> Self {
52 Self {
53 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
54 chmap: NAChannelMap::new(),
55 adapt_coeffs: Vec::with_capacity(7),
56 block_len: 0,
57 block_samps: 0,
58 }
59 }
60}
61
62#[cfg(feature="decoder_ms_adpcm")]
63impl NADecoder for MSADPCMDecoder {
64 #[allow(clippy::int_plus_one)]
65 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
66 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
67 self.block_len = ainfo.get_block_len();
68 let channels = ainfo.get_channels() as usize;
69 validate!(channels == 2 || channels == 1);
70 validate!(self.block_len >= 7 * channels + 1);
71 self.block_samps = (self.block_len / channels - 7) * 2 + 2;
72 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, self.block_samps);
73 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
74 self.adapt_coeffs.clear();
75 if let Some(ref buf) = info.get_extradata() {
76 validate!(buf.len() >= 6);
77 validate!((buf.len() & 3) == 0);
78 let mut mr = MemoryReader::new_read(buf.as_slice());
79 let mut br = ByteReader::new(&mut mr);
80 let _smth = br.read_u16le()?;
81 let ncoeffs = br.read_u16le()? as usize;
82 validate!(buf.len() == ncoeffs * 4 + 4);
83
84 for _ in 0..ncoeffs {
85 let pair = [
86 i32::from(br.read_u16le()? as i16),
87 i32::from(br.read_u16le()? as i16)];
88 self.adapt_coeffs.push(pair);
89 }
90 } else {
91 self.adapt_coeffs.extend_from_slice(&ADAPT_COEFFS);
92 }
93 Ok(())
94 } else {
95 Err(DecoderError::InvalidData)
96 }
97 }
98 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
99 let info = pkt.get_stream().get_info();
100 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
101 let pktbuf = pkt.get_buffer();
102 let channels = self.chmap.num_channels();
103 validate!(!pktbuf.is_empty() && (pktbuf.len() % self.block_len) == 0);
104 let nblocks = pktbuf.len() / self.block_len;
105 let nsamples = nblocks * self.block_samps;
106 let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?;
107 let mut adata = abuf.get_abuf_i16().unwrap();
108 let mut off = [adata.get_offset(0), adata.get_offset(1)];
109 let dst = adata.get_data_mut().unwrap();
110
111 let mut pred = [Predictor::default(), Predictor::default()];
112
113 for blk in pktbuf.chunks(self.block_len) {
114 let mut mr = MemoryReader::new_read(blk);
115 let mut br = ByteReader::new(&mut mr);
116 for p in pred[..channels].iter_mut() {
117 let coef_idx = br.read_byte()? as usize;
118 validate!(coef_idx < self.adapt_coeffs.len());
119 p.coef1 = self.adapt_coeffs[coef_idx][0];
120 p.coef2 = self.adapt_coeffs[coef_idx][1];
121 }
122 for p in pred[..channels].iter_mut() {
123 p.delta = i32::from(br.read_u16le()?);
124 }
125 for p in pred[..channels].iter_mut() {
126 let samp = br.read_u16le()? as i16;
127 p.sample1 = i32::from(samp);
128 }
129 for p in pred[..channels].iter_mut() {
130 let samp = br.read_u16le()? as i16;
131 p.sample2 = i32::from(samp);
132 }
133 for ch in 0..channels {
134 dst[off[ch]] = pred[ch].sample2 as i16;
135 dst[off[ch] + 1] = pred[ch].sample1 as i16;
136 off[ch] += 2;
137 }
138 if channels == 1 {
139 while br.left() > 0 {
140 let idx = br.read_byte()?;
141 dst[off[0]] = pred[0].expand_nibble(idx >> 4);
142 off[0] += 1;
143 dst[off[0]] = pred[0].expand_nibble(idx & 0xF);
144 off[0] += 1;
145 }
146 } else {
147 while br.left() > 0 {
148 let idx = br.read_byte()?;
149 dst[off[0]] = pred[0].expand_nibble(idx >> 4);
150 off[0] += 1;
151 dst[off[1]] = pred[1].expand_nibble(idx & 0xF);
152 off[1] += 1;
153 }
154 }
155 }
156 let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
157 frm.set_duration(Some(nsamples as u64));
158 frm.set_keyframe(false);
159 Ok(frm.into_ref())
160 } else {
161 Err(DecoderError::InvalidData)
162 }
163 }
164 fn flush(&mut self) {
165 }
166}
167
168#[cfg(feature="decoder_ms_adpcm")]
169impl NAOptionHandler for MSADPCMDecoder {
170 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
171 fn set_options(&mut self, _options: &[NAOption]) { }
172 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
173}
174
175#[cfg(feature="decoder_ms_adpcm")]
176pub fn get_decoder() -> Box<dyn NADecoder + Send> {
177 Box::new(MSADPCMDecoder::new())
178}
179
180#[derive(Default)]
181#[cfg(feature="encoder_ms_adpcm")]
182struct MSADPCMEncoder {
183 stream: Option<NAStreamRef>,
184 samples: Vec<i16>,
185 block_len: usize,
186 channels: usize,
187 flush: bool,
188 srate: u32,
189}
190
191#[cfg(feature="encoder_ms_adpcm")]
192const DEFAULT_BLOCK_LEN: usize = 256;
193
194#[cfg(feature="encoder_ms_adpcm")]
195impl MSADPCMEncoder {
196 fn new() -> Self { Self::default() }
197 fn encode_packet(&mut self) -> EncoderResult<NAPacket> {
198 if self.samples.is_empty() {
199 return Err(EncoderError::TryAgain);
200 }
201 let len = (self.samples.len() / self.channels).min(self.block_len);
202 if len < self.block_len && !self.flush {
203 return Err(EncoderError::TryAgain);
204 }
205 if len < 2 {
206 self.flush = false;
207 return Err(EncoderError::TryAgain);
208 }
209
210 let mut dbuf = vec![0u8; Self::calc_block_size(len, self.channels)];
211 let mut mw = MemoryWriter::new_write(dbuf.as_mut_slice());
212 let mut bw = ByteWriter::new(&mut mw);
213
214 let mut best_idx = [0usize; 2];
215 for (ch, best_idx) in best_idx[..self.channels].iter_mut().enumerate() {
216 let mut best_dist = i64::MAX;
217 for i in 0..ADAPT_COEFFS.len() {
218 let dist = self.calc_dist(ch, i, len);
219 if dist < best_dist {
220 best_dist = dist;
221 *best_idx = i;
222 }
223 }
224 bw.write_byte(*best_idx as u8)?;
225 }
226 let mut dec = [Predictor::default(), Predictor::default()];
227 for ch in 0..self.channels {
228 dec[ch].sample1 = i32::from(self.samples[ch + self.channels]);
229 dec[ch].sample2 = i32::from(self.samples[ch]);
230 dec[ch].coef1 = ADAPT_COEFFS[best_idx[ch]][0];
231 dec[ch].coef2 = ADAPT_COEFFS[best_idx[ch]][1];
232 if len > 2 {
233 let pred = dec[ch].calc_pred();
234 dec[ch].delta = ((i32::from(self.samples[ch + self.channels * 2]) - pred).abs() / 4).max(16);
235 } else {
236 dec[ch].delta = 16;
237 }
238 }
239 for d in dec[..self.channels].iter() {
240 bw.write_u16le(d.delta as u16)?;
241 }
242 for d in dec[..self.channels].iter() {
243 bw.write_u16le(d.sample1 as u16)?;
244 }
245 for d in dec[..self.channels].iter() {
246 bw.write_u16le(d.sample2 as u16)?;
247 }
248 if self.channels == 1 {
249 for samps in self.samples.chunks(2).skip(1).take(len/2 - 1) {
250 let diff = i32::from(samps[0]) - dec[0].calc_pred();
251 let nib0 = Self::calculate_mul(dec[0].delta, diff);
252 dec[0].expand_nibble(nib0);
253 let diff = i32::from(samps[1]) - dec[0].calc_pred();
254 let nib1 = Self::calculate_mul(dec[0].delta, diff);
255 dec[0].expand_nibble(nib1);
256 bw.write_byte(nib0 * 16 + nib1)?;
257 }
258 } else {
259 for samps in self.samples.chunks(2).skip(2).take(len - 2) {
260 let diff = i32::from(samps[0]) - dec[0].calc_pred();
261 let nib0 = Self::calculate_mul(dec[0].delta, diff);
262 dec[0].expand_nibble(nib0);
263 let diff = i32::from(samps[1]) - dec[1].calc_pred();
264 let nib1 = Self::calculate_mul(dec[1].delta, diff);
265 dec[1].expand_nibble(nib1);
266 bw.write_byte(nib0 * 16 + nib1)?;
267 }
268 }
269 self.samples.drain(..len * self.channels);
270 let ts = NATimeInfo::new(None, None, Some(1), 1, self.srate);
271 Ok(NAPacket::new(self.stream.clone().unwrap(), ts, true, dbuf))
272 }
273 fn calc_dist(&self, ch: usize, idx: usize, len: usize) -> i64 {
274 let mut dist = 0;
275 let mut dec = Predictor {
276 sample2: i32::from(self.samples[ch]),
277 sample1: i32::from(self.samples[ch + self.channels]),
278 coef1: ADAPT_COEFFS[idx][0],
279 coef2: ADAPT_COEFFS[idx][1],
280 delta: 16,
281 };
282 if self.channels == 1 {
283 for samp in self.samples.iter().skip(2).take(len - 2) {
284 let pred = dec.calc_pred();
285 dec.update(pred);
286 let diff = i64::from(*samp) - i64::from(pred);
287 dist += diff * diff;
288 }
289 } else {
290 for samp in self.samples.chunks(2).skip(2).take(len - 2) {
291 let pred = dec.calc_pred();
292 dec.update(pred);
293 let diff = i64::from(samp[ch]) - i64::from(pred);
294 dist += diff * diff;
295 }
296 }
297 dist
298 }
299 fn calculate_mul(delta: i32, diff: i32) -> u8 {
300 ((diff / delta).max(-8).min(7) & 0xF) as u8
301 }
302 fn calc_block_size(nsamps: usize, channels: usize) -> usize {
303 (nsamps - 2) * channels / 2 + 7 * channels
304 }
305}
306
307#[cfg(feature="encoder_ms_adpcm")]
308impl NAEncoder for MSADPCMEncoder {
309 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
310 match encinfo.format {
311 NACodecTypeInfo::None => {
312 Ok(EncodeParameters {
313 format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 1, SND_S16_FORMAT, DEFAULT_BLOCK_LEN)),
314 ..Default::default() })
315 },
316 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
317 NACodecTypeInfo::Audio(ainfo) => {
318 let mut outinfo = ainfo;
319 outinfo.channels = outinfo.channels.min(2);
320 if outinfo.format != SND_S16P_FORMAT && outinfo.format != SND_S16_FORMAT {
321 outinfo.format = SND_S16_FORMAT;
322 }
323 if outinfo.block_len == 0 {
324 outinfo.block_len = DEFAULT_BLOCK_LEN;
325 }
326 if outinfo.block_len == 1 && encinfo.tb_den != outinfo.sample_rate {
327 outinfo.block_len = ((u64::from(outinfo.sample_rate) * u64::from(encinfo.tb_num) / u64::from(encinfo.tb_den) + 3) & !3) as usize;
328 }
329 if outinfo.block_len < 2 {
330 outinfo.block_len = 2;
331 }
332 if (outinfo.channels == 1) && ((outinfo.block_len & 1) == 1) {
333 outinfo.block_len += 1;
334 }
335 let mut ofmt = *encinfo;
336 ofmt.format = NACodecTypeInfo::Audio(outinfo);
337 Ok(ofmt)
338 }
339 }
340 }
341 fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
342 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
343 match encinfo.format {
344 NACodecTypeInfo::None => Err(EncoderError::FormatError),
345 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
346 NACodecTypeInfo::Audio(ainfo) => {
347 if ainfo.format != SND_S16P_FORMAT && ainfo.format != SND_S16_FORMAT {
348 return Err(EncoderError::FormatError);
349 }
350 if ainfo.channels != 1 && ainfo.channels != 2 {
351 return Err(EncoderError::FormatError);
352 }
353 if ainfo.block_len < 2 || ((ainfo.block_len * (ainfo.channels as usize)) & 1) != 0 {
354 return Err(EncoderError::FormatError);
355 }
356 self.channels = ainfo.channels as usize;
357 self.block_len = ainfo.block_len;
358
359 let soniton = NASoniton::new(4, 0);
360 let out_ainfo = NAAudioInfo::new(ainfo.sample_rate, ainfo.channels, soniton, Self::calc_block_size(self.block_len, self.channels));
361 let info = NACodecInfo::new("ms-adpcm", NACodecTypeInfo::Audio(out_ainfo), None);
362 let mut stream = NAStream::new(StreamType::Audio, stream_id, info, self.block_len as u32, ainfo.sample_rate, 0);
363 stream.set_num(stream_id as usize);
364 let stream = stream.into_ref();
365
366 self.stream = Some(stream.clone());
367 self.samples = Vec::with_capacity(self.block_len * self.channels);
368 self.srate = ainfo.sample_rate;
369 self.flush = false;
370
371 Ok(stream)
372 },
373 }
374 }
375 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
376 let buf = frm.get_buffer();
377 if let Some(ref abuf) = buf.get_abuf_i16() {
378 let src = abuf.get_data();
379 let len = abuf.get_length();
380 let ch = abuf.get_chmap().num_channels();
381 if abuf.get_step() > 1 || ch == 1 {
382 self.samples.extend(src.iter().take(len * ch));
383 } else {
384 let (src0, src1) = src.split_at(abuf.get_stride());
385 self.samples.reserve(len * 2);
386 for (s0, s1) in src0.iter().take(len).zip(src1.iter()) {
387 self.samples.push(*s0);
388 self.samples.push(*s1);
389 }
390 }
391 Ok(())
392 } else {
393 Err(EncoderError::InvalidParameters)
394 }
395 }
396 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
397 if let Ok(pkt) = self.encode_packet() {
398 Ok(Some(pkt))
399 } else {
400 Ok(None)
401 }
402 }
403 fn flush(&mut self) -> EncoderResult<()> {
404 self.flush = true;
405 Ok(())
406 }
407}
408
409#[cfg(feature="encoder_ms_adpcm")]
410impl NAOptionHandler for MSADPCMEncoder {
411 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
412 fn set_options(&mut self, _options: &[NAOption]) { }
413 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
414}
415
416#[cfg(feature="encoder_ms_adpcm")]
417pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
418 Box::new(MSADPCMEncoder::new())
419}
420
421#[cfg(test)]
422mod test {
423 use nihav_core::codecs::*;
424 use nihav_core::demuxers::*;
425 use nihav_core::muxers::*;
426 use nihav_codec_support::test::dec_video::*;
427 use nihav_codec_support::test::enc_video::*;
428 use crate::*;
429 use nihav_commonfmt::*;
430 #[cfg(feature="decoder_ms_adpcm")]
431 #[test]
432 fn test_ms_adpcm_decoder() {
433 let mut dmx_reg = RegisteredDemuxers::new();
434 generic_register_all_demuxers(&mut dmx_reg);
435 let mut dec_reg = RegisteredDecoders::new();
436 ms_register_all_decoders(&mut dec_reg);
437
438 test_decoding("avi", "ms-adpcm", "assets/MS/dance.avi", None, &dmx_reg, &dec_reg,
439 ExpectedTestResult::MD5([0xb1d6f12c, 0x86d2821b, 0x395f6827, 0xb6be93bf]));
440 }
441 #[cfg(feature="encoder_ms_adpcm")]
442 #[test]
443 fn test_ms_adpcm_encoder() {
444 let mut dmx_reg = RegisteredDemuxers::new();
445 generic_register_all_demuxers(&mut dmx_reg);
446 let mut dec_reg = RegisteredDecoders::new();
447 generic_register_all_decoders(&mut dec_reg);
448 ms_register_all_decoders(&mut dec_reg);
449 let mut mux_reg = RegisteredMuxers::new();
450 generic_register_all_muxers(&mut mux_reg);
451 let mut enc_reg = RegisteredEncoders::new();
452 ms_register_all_encoders(&mut enc_reg);
453
454 // sample: https://samples.mplayerhq.hu/V-codecs/RT21/320x240/laser05.avi
455 let dec_config = DecoderTestParams {
456 demuxer: "avi",
457 in_name: "assets/Indeo/laser05.avi",
458 stream_type: StreamType::Audio,
459 limit: None,
460 dmx_reg, dec_reg,
461 };
462 let enc_config = EncoderTestParams {
463 muxer: "wav",
464 enc_name: "ms-adpcm",
465 out_name: "msadpcm.wav",
466 mux_reg, enc_reg,
467 };
468 let dst_ainfo = NAAudioInfo {
469 sample_rate: 0,
470 channels: 0,
471 format: SND_S16_FORMAT,
472 block_len: 128,
473 };
474 let enc_params = EncodeParameters {
475 format: NACodecTypeInfo::Audio(dst_ainfo),
476 quality: 0,
477 bitrate: 0,
478 tb_num: 0,
479 tb_den: 0,
480 flags: 0,
481 };
482 test_encoding_md5(&dec_config, &enc_config, enc_params, &[],
483 &[0x82259f45, 0xba7b984a, 0xc03c94e5, 0x00b4312b]);
484 }
485}