add a crate for common MS formats
[nihav.git] / nihav-ms / src / codecs / msadpcm.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use std::str::FromStr;
4
5 const ADAPT_TABLE: [i32; 16] = [
6 230, 230, 230, 230, 307, 409, 512, 614,
7 768, 614, 512, 409, 307, 230, 230, 230
8 ];
9 const 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)]
15 struct Predictor {
16 sample1: i32,
17 sample2: i32,
18 delta: i32,
19 coef1: i32,
20 coef2: i32,
21 }
22
23 impl 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.sample1.wrapping_mul(self.coef1) + self.sample2.wrapping_mul(self.coef2)) >> 8) + self.delta.wrapping_mul(mul);
27 self.sample2 = self.sample1;
28 self.sample1 = pred.max(-0x8000).min(0x7FFF);
29 self.delta = (ADAPT_TABLE[nibble as usize].wrapping_mul(self.delta) >> 8).max(16);
30 self.sample1 as i16
31 }
32 }
33
34 struct MSADPCMDecoder {
35 ainfo: NAAudioInfo,
36 chmap: NAChannelMap,
37 adapt_coeffs: Vec<[i32; 2]>,
38 block_len: usize,
39 block_samps: usize,
40 }
41
42 impl MSADPCMDecoder {
43 fn new() -> Self {
44 Self {
45 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
46 chmap: NAChannelMap::new(),
47 adapt_coeffs: Vec::with_capacity(7),
48 block_len: 0,
49 block_samps: 0,
50 }
51 }
52 }
53
54 impl NADecoder for MSADPCMDecoder {
55 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
56 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
57 self.block_len = ainfo.get_block_len();
58 let channels = ainfo.get_channels() as usize;
59 validate!(channels == 2 || channels == 1);
60 validate!(self.block_len >= 7 * channels + 1);
61 self.block_samps = (self.block_len / channels - 7) * 2 + 2;
62 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, self.block_samps);
63 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
64 self.adapt_coeffs.truncate(0);
65 if let Some(ref buf) = info.get_extradata() {
66 validate!(buf.len() >= 6);
67 validate!((buf.len() & 3) == 0);
68 let mut mr = MemoryReader::new_read(buf.as_slice());
69 let mut br = ByteReader::new(&mut mr);
70 let _smth = br.read_u16le()?;
71 let ncoeffs = br.read_u16le()? as usize;
72 validate!(buf.len() == ncoeffs * 4 + 4);
73
74 for _ in 0..ncoeffs {
75 let pair = [
76 i32::from(br.read_u16le()? as i16),
77 i32::from(br.read_u16le()? as i16)];
78 self.adapt_coeffs.push(pair);
79 }
80 } else {
81 self.adapt_coeffs.extend_from_slice(&ADAPT_COEFFS);
82 }
83 Ok(())
84 } else {
85 Err(DecoderError::InvalidData)
86 }
87 }
88 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
89 let info = pkt.get_stream().get_info();
90 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
91 let pktbuf = pkt.get_buffer();
92 let channels = self.chmap.num_channels();
93 validate!(pktbuf.len() > 0 && (pktbuf.len() % self.block_len) == 0);
94 let nblocks = pktbuf.len() / self.block_len;
95 let nsamples = nblocks * self.block_samps;
96 let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?;
97 let mut adata = abuf.get_abuf_i16().unwrap();
98 let mut off = [adata.get_offset(0), adata.get_offset(1)];
99 let dst = adata.get_data_mut().unwrap();
100
101 let mut pred = [Predictor::default(), Predictor::default()];
102
103 for blk in pktbuf.chunks(self.block_len) {
104 let mut mr = MemoryReader::new_read(blk);
105 let mut br = ByteReader::new(&mut mr);
106 for ch in 0..channels {
107 let coef_idx = br.read_byte()? as usize;
108 validate!(coef_idx < self.adapt_coeffs.len());
109 pred[ch].coef1 = self.adapt_coeffs[coef_idx][0];
110 pred[ch].coef2 = self.adapt_coeffs[coef_idx][1];
111 }
112 for ch in 0..channels {
113 pred[ch].delta = i32::from(br.read_u16le()?);
114 }
115 for ch in 0..channels {
116 let samp = br.read_u16le()? as i16;
117 pred[ch].sample1 = i32::from(samp);
118 dst[off[ch]] = samp;
119 off[ch] += 1;
120 }
121 for ch in 0..channels {
122 let samp = br.read_u16le()? as i16;
123 pred[ch].sample2 = i32::from(samp);
124 dst[off[ch]] = samp;
125 off[ch] += 1;
126 }
127 if channels == 1 {
128 while br.left() > 0 {
129 let idx = br.read_byte()?;
130 dst[off[0]] = pred[0].expand_nibble(idx >> 4);
131 off[0] += 1;
132 dst[off[0]] = pred[0].expand_nibble(idx & 0xF);
133 off[0] += 1;
134 }
135 } else {
136 while br.left() > 0 {
137 let idx = br.read_byte()?;
138 dst[off[0]] = pred[0].expand_nibble(idx >> 4);
139 off[0] += 1;
140 dst[off[1]] = pred[1].expand_nibble(idx & 0xF);
141 off[1] += 1;
142 }
143 }
144 }
145 let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
146 frm.set_duration(Some(nsamples as u64));
147 frm.set_keyframe(false);
148 Ok(frm.into_ref())
149 } else {
150 Err(DecoderError::InvalidData)
151 }
152 }
153 fn flush(&mut self) {
154 }
155 }
156
157 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
158 Box::new(MSADPCMDecoder::new())
159 }
160
161 #[cfg(test)]
162 mod test {
163 use nihav_core::codecs::RegisteredDecoders;
164 use nihav_core::demuxers::RegisteredDemuxers;
165 use nihav_codec_support::test::dec_video::*;
166 use crate::ms_register_all_codecs;
167 use nihav_commonfmt::generic_register_all_demuxers;
168 #[test]
169 fn test_ms_adpcm() {
170 let mut dmx_reg = RegisteredDemuxers::new();
171 generic_register_all_demuxers(&mut dmx_reg);
172 let mut dec_reg = RegisteredDecoders::new();
173 ms_register_all_codecs(&mut dec_reg);
174
175 test_decoding("avi", "ms-adpcm", "assets/MS/dance.avi", None, &dmx_reg, &dec_reg,
176 ExpectedTestResult::MD5([0x9d6619e1, 0x60d83560, 0xfe5c1fb7, 0xad5d130d]));
177 }
178 }