]>
Commit | Line | Data |
---|---|---|
029d2552 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
e781ccc3 | 3 | use nihav_codec_support::codecs::imaadpcm::*; |
029d2552 KS |
4 | use std::str::FromStr; |
5 | ||
029d2552 KS |
6 | struct DuckADPCMDecoder { |
7 | ainfo: NAAudioInfo, | |
8 | chmap: NAChannelMap, | |
9 | is_dk3: bool, | |
10 | ch_state: [IMAState; 2], | |
11 | block_len: usize, | |
12 | } | |
13 | ||
14 | impl DuckADPCMDecoder { | |
15 | fn new(is_dk3: bool) -> Self { | |
16 | Self { | |
17 | ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0), | |
18 | chmap: NAChannelMap::new(), | |
19 | is_dk3, | |
20 | ch_state: [IMAState::new(), IMAState::new()], | |
21 | block_len: 0, | |
22 | } | |
23 | } | |
24 | } | |
25 | ||
26 | impl NADecoder for DuckADPCMDecoder { | |
01613464 | 27 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
029d2552 KS |
28 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
29 | validate!(ainfo.get_block_len() > 16); | |
30 | self.block_len = ainfo.get_block_len(); | |
31 | let channels = ainfo.get_channels(); | |
32 | validate!(channels == 2 || (!self.is_dk3 && channels == 1)); | |
33 | let len = if self.is_dk3 { | |
34 | ((self.block_len - 16) * 2 / 3) * 2 | |
35 | } else { | |
36 | (self.block_len - 4 * (channels as usize)) * 2 / (channels as usize) | |
37 | }; | |
38 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels, SND_S16P_FORMAT, len); | |
39 | self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap(); | |
40 | Ok(()) | |
41 | } else { | |
42 | Err(DecoderError::InvalidData) | |
43 | } | |
44 | } | |
01613464 | 45 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
029d2552 KS |
46 | let info = pkt.get_stream().get_info(); |
47 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
48 | let pktbuf = pkt.get_buffer(); | |
49 | validate!(pktbuf.len() > (if self.is_dk3 { 16 } else { 4 * self.chmap.num_channels() })); | |
50 | let nblocks = pktbuf.len() / self.block_len; | |
51 | let out_block_len = self.ainfo.get_block_len(); | |
52 | let duration = out_block_len * nblocks; | |
b70cc006 | 53 | let abuf = alloc_audio_buffer(self.ainfo, duration, self.chmap.clone())?; |
029d2552 KS |
54 | let mut adata = abuf.get_abuf_i16().unwrap(); |
55 | let mut off0 = adata.get_offset(0); | |
56 | let mut off1 = adata.get_offset(1); | |
1a967e6b | 57 | let dst = adata.get_data_mut().unwrap(); |
029d2552 KS |
58 | |
59 | for blk in pktbuf.chunks_exact(self.block_len) { | |
60 | let mut mr = MemoryReader::new_read(blk); | |
61 | let mut br = ByteReader::new(&mut mr); | |
62 | if self.is_dk3 { | |
63 | let _typeid = br.read_byte()?; | |
64 | let _version = br.read_byte()?; | |
65 | let _srate = br.read_u32le()?; | |
66 | let samples = br.read_u32le()? as usize; | |
67 | let sumpred = br.read_u16le()? as i16; | |
68 | let diffpred = br.read_u16le()? as i16; | |
69 | let sumstep = br.read_byte()?; | |
70 | let diffstep = br.read_byte()?; | |
71 | validate!(sumstep <= IMA_MAX_STEP && diffstep <= IMA_MAX_STEP); | |
72 | validate!(samples <= out_block_len); | |
73 | self.ch_state[0].reset(sumpred, sumstep); | |
74 | self.ch_state[1].reset(diffpred, diffstep); | |
75 | let mut last_nib = 0; | |
8a7352c0 | 76 | let mut diff_val: i32 = i32::from(diffpred); |
029d2552 KS |
77 | for x in (0..out_block_len).step_by(2) { |
78 | let nib0; | |
79 | let nib1; | |
80 | let nib2; | |
81 | if (x & 2) == 0 { | |
82 | let b0 = br.read_byte()?; | |
83 | let b1 = br.read_byte()?; | |
84 | nib0 = b0 & 0xF; | |
85 | nib1 = b0 >> 4; | |
86 | nib2 = b1 & 0xF; | |
87 | last_nib = b1 >> 4; | |
88 | } else { | |
89 | let b0 = br.read_byte()?; | |
90 | nib0 = last_nib; | |
91 | nib1 = b0 & 0xF; | |
92 | nib2 = b0 >> 4; | |
93 | } | |
8a7352c0 KS |
94 | let sum0 = i32::from(self.ch_state[0].expand_sample(nib0)); |
95 | let diff = i32::from(self.ch_state[1].expand_sample(nib1)); | |
96 | let sum1 = i32::from(self.ch_state[0].expand_sample(nib2)); | |
029d2552 KS |
97 | diff_val = (diff_val + diff) >> 1; |
98 | dst[off0 + x + 0] = (sum0 + diff_val) as i16; | |
99 | dst[off1 + x + 0] = (sum0 - diff_val) as i16; | |
100 | diff_val = (diff_val + diff) >> 1; | |
101 | dst[off0 + x + 1] = (sum1 + diff_val) as i16; | |
102 | dst[off1 + x + 1] = (sum1 - diff_val) as i16; | |
103 | diff_val = diff; | |
104 | } | |
105 | } else { | |
106 | let nchannels = self.chmap.num_channels(); | |
107 | for ch in 0..nchannels { | |
108 | let pred = br.read_u16le()? as i16; | |
109 | let step = br.read_byte()?; | |
110 | br.read_skip(1)?; | |
111 | validate!(step <= IMA_MAX_STEP); | |
112 | self.ch_state[ch].reset(pred, step); | |
113 | } | |
114 | if nchannels == 2 { | |
115 | for x in 0..out_block_len { | |
116 | let b = br.read_byte()?; | |
117 | dst[off0 + x] = self.ch_state[0].expand_sample(b >> 4); | |
118 | dst[off1 + x] = self.ch_state[1].expand_sample(b & 0xF); | |
119 | } | |
120 | } else { | |
121 | for x in (0..out_block_len).step_by(2) { | |
122 | let b = br.read_byte()?; | |
123 | dst[off0 + x + 0] = self.ch_state[0].expand_sample(b >> 4); | |
124 | dst[off0 + x + 1] = self.ch_state[0].expand_sample(b & 0xF); | |
125 | } | |
126 | } | |
127 | } | |
128 | off0 += out_block_len; | |
129 | off1 += out_block_len; | |
130 | } | |
131 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); | |
132 | frm.set_duration(Some(duration as u64)); | |
133 | frm.set_keyframe(false); | |
171860fc | 134 | Ok(frm.into_ref()) |
029d2552 KS |
135 | } else { |
136 | Err(DecoderError::InvalidData) | |
137 | } | |
138 | } | |
f9be4e75 KS |
139 | fn flush(&mut self) { |
140 | } | |
029d2552 KS |
141 | } |
142 | ||
7d57ae2f KS |
143 | impl NAOptionHandler for DuckADPCMDecoder { |
144 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
145 | fn set_options(&mut self, _options: &[NAOption]) { } | |
146 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
147 | } | |
148 | ||
08a1fab7 | 149 | pub fn get_decoder_dk3() -> Box<dyn NADecoder + Send> { |
029d2552 KS |
150 | Box::new(DuckADPCMDecoder::new(true)) |
151 | } | |
152 | ||
08a1fab7 | 153 | pub fn get_decoder_dk4() -> Box<dyn NADecoder + Send> { |
029d2552 KS |
154 | Box::new(DuckADPCMDecoder::new(false)) |
155 | } | |
156 | ||
157 | #[cfg(test)] | |
158 | mod test { | |
159 | use nihav_core::codecs::RegisteredDecoders; | |
160 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 161 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 162 | use crate::duck_register_all_decoders; |
e64739f8 | 163 | use nihav_commonfmt::generic_register_all_demuxers; |
029d2552 KS |
164 | #[test] |
165 | fn test_dk3() { | |
166 | let mut dmx_reg = RegisteredDemuxers::new(); | |
167 | generic_register_all_demuxers(&mut dmx_reg); | |
168 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 169 | duck_register_all_decoders(&mut dec_reg); |
029d2552 | 170 | |
16b13997 KS |
171 | //let file = "assets/Duck/AVI-DUCK-dk3.duk"; |
172 | //test_decode_audio("avi", file, Some(100), None/*Some("dk3")*/, &dmx_reg, &dec_reg); | |
173 | test_decoding("avi", "adpcm-dk3", "assets/Duck/AVI-DUCK-dk3.duk", None, &dmx_reg, &dec_reg, | |
174 | ExpectedTestResult::MD5([0xa48fae0a, 0xa536b27f, 0x169ecc19, 0x8436fade])); | |
029d2552 KS |
175 | } |
176 | #[test] | |
177 | fn test_dk4() { | |
178 | let mut dmx_reg = RegisteredDemuxers::new(); | |
179 | generic_register_all_demuxers(&mut dmx_reg); | |
180 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 181 | duck_register_all_decoders(&mut dec_reg); |
029d2552 | 182 | |
16b13997 KS |
183 | // let file = "assets/Duck/virtuafighter2-opening1.avi"; |
184 | // test_decode_audio("avi", file, Some(100), None/*Some("dk4")*/, &dmx_reg, &dec_reg); | |
185 | test_decoding("avi", "adpcm-dk4", "assets/Duck/virtuafighter2-opening1.avi", None, &dmx_reg, &dec_reg, | |
186 | ExpectedTestResult::MD5([0x04e40d15, 0xf65b3427, 0x1dd5181f, 0xf321b56f])); | |
029d2552 KS |
187 | } |
188 | } |