]>
Commit | Line | Data |
---|---|---|
606c448e | 1 | use nihav_core::codecs::*; |
b4d5b851 KS |
2 | use nihav_codec_support::dsp::dct::*; |
3 | use nihav_codec_support::dsp::fft::*; | |
e5ea6525 | 4 | use nihav_core::io::bitreader::*; |
e5ea6525 KS |
5 | use std::str::FromStr; |
6 | ||
e9f61dd2 KS |
7 | use super::binkauddata::*; |
8 | ||
e5ea6525 KS |
9 | enum Transform { |
10 | None, | |
11 | DCT(DCT), | |
12 | RDFT(RDFT), | |
13 | } | |
14 | ||
e5ea6525 KS |
15 | struct BinkAudioDecoder { |
16 | ainfo: NAAudioInfo, | |
17 | chmap: NAChannelMap, | |
18 | use_dct: bool, | |
19 | version_b: bool, | |
20 | transform: Transform, | |
21 | len: usize, | |
22 | quants: [f32; 96], | |
23 | bands: [usize; MAX_BANDS + 1], | |
24 | num_bands: usize, | |
25 | duration: usize, | |
26 | coeffs: [f32; 4096], | |
27 | delay: [[f32; 256]; 2], | |
28 | first_frm: bool, | |
29 | scale: f32, | |
30 | } | |
31 | ||
32 | fn read_bink_float(br: &mut BitReader) -> DecoderResult<f32> { | |
33 | /*let exp = (br.read(5)? as i8) - 23; | |
34 | let mant = br.read(23)? as u32; | |
35 | let sign = br.read_bool()?; | |
36 | let v = if exp >= 0 { | |
37 | (mant as f32) * ((1 << exp) as f32) | |
38 | } else { | |
39 | (mant as f32) / ((1 << -exp) as f32) | |
40 | }; | |
41 | if sign { | |
42 | Ok(-v) | |
43 | } else { | |
44 | Ok(v) | |
45 | }*/ | |
46 | let exp = br.read(5)? as u8; | |
e6aaad5c KS |
47 | let mant = br.read(23)?; |
48 | let sign = br.read(1)?; | |
e5ea6525 KS |
49 | let nexp = exp.wrapping_add(0x7E) as u32; |
50 | let nmant = (mant << 1) & ((1 << 23) - 1); | |
51 | Ok(f32::from_bits((sign << 31) | (nexp << 23) | nmant)) | |
52 | } | |
53 | ||
54 | fn overlap(a: &[f32], b: &[f32], dst: &mut [f32], len: usize, step: usize) { | |
55 | for i in 0..len { | |
56 | dst[i] = (a[i] * ((len - i) as f32) + b[i * step] * (i as f32)) / (len as f32); | |
57 | } | |
58 | } | |
59 | ||
60 | impl BinkAudioDecoder { | |
61 | fn new(use_dct: bool) -> Self { | |
e5ea6525 KS |
62 | Self { |
63 | ainfo: NAAudioInfo::new(0, 1, SND_F32P_FORMAT, 0), | |
64 | chmap: NAChannelMap::new(), | |
65 | use_dct, | |
66 | transform: Transform::None, | |
67 | version_b: false, | |
68 | len: 0, | |
e9f61dd2 | 69 | quants: get_quants_table(), |
e5ea6525 KS |
70 | bands: [MAX_BANDS + 1; 26], |
71 | num_bands: 0, | |
72 | duration: 0, | |
73 | coeffs: [0.0; 4096], | |
74 | delay: [[0.0; 256]; 2], | |
75 | first_frm: true, | |
76 | scale: 1.0, | |
77 | } | |
78 | } | |
79 | fn decode_block(&mut self, br: &mut BitReader) -> DecoderResult<()> { | |
80 | if self.version_b { | |
81 | let flt = br.read(32)?; | |
82 | self.coeffs[0] = f32::from_bits(flt) * self.scale; | |
83 | let flt = br.read(32)?; | |
84 | self.coeffs[1] = f32::from_bits(flt) * self.scale; | |
85 | } else { | |
86 | self.coeffs[0] = read_bink_float(br)? * self.scale; | |
87 | self.coeffs[1] = read_bink_float(br)? * self.scale; | |
88 | } | |
89 | let mut quants: [f32; MAX_BANDS] = [0.0; MAX_BANDS]; | |
3687b8b3 | 90 | for quant in quants[..self.num_bands].iter_mut() { |
e5ea6525 | 91 | let idx = br.read(8)? as usize; |
3687b8b3 | 92 | *quant = self.quants[idx.min(self.quants.len() - 1)] * self.scale; |
e5ea6525 KS |
93 | } |
94 | let mut idx = 2; | |
95 | let mut band_idx = 0; | |
96 | self.coeffs = [0.0; 4096]; | |
97 | while idx < self.len { | |
98 | let width = if self.version_b { | |
99 | 16 | |
3687b8b3 KS |
100 | } else if br.read_bool()? { |
101 | let idx = br.read(4)? as usize; | |
102 | RUN_TAB[idx] * 8 | |
e5ea6525 | 103 | } else { |
3687b8b3 | 104 | 8 |
e5ea6525 KS |
105 | }; |
106 | let end = (idx + width).min(self.len); | |
107 | let bits = br.read(4)? as u8; | |
108 | if bits != 0 { | |
109 | for i in idx..end { | |
110 | while self.bands[band_idx] <= i { band_idx += 1; } | |
111 | let q = quants[band_idx - 1]; | |
112 | let coeff = br.read(bits)?; | |
113 | if coeff != 0 { | |
114 | if br.read_bool()? { | |
115 | self.coeffs[i] = -(coeff as f32) * q; | |
116 | } else { | |
117 | self.coeffs[i] = (coeff as f32) * q; | |
118 | } | |
119 | } | |
120 | } | |
121 | } | |
122 | idx = end; | |
123 | } | |
124 | Ok(()) | |
125 | } | |
3687b8b3 | 126 | #[allow(clippy::identity_op)] |
bf109afe | 127 | #[allow(clippy::transmute_ptr_to_ptr)] |
e5ea6525 KS |
128 | fn output(&mut self, dst: &mut [f32], off0: usize, off1: usize, chno: usize) { |
129 | match self.transform { | |
130 | Transform::DCT(ref mut dct) => { | |
131 | dct.do_dct_inplace(&mut self.coeffs[0..]); | |
132 | }, | |
133 | Transform::RDFT(ref mut rdft) => { | |
134 | unsafe { | |
135 | let buf = &mut self.coeffs[0..]; | |
136 | rdft.do_rdft_inplace(std::mem::transmute::<&mut [f32], &mut [FFTComplex]>(buf)); | |
137 | } | |
47da4a32 KS |
138 | for i in (0..self.coeffs.len()).step_by(2) { |
139 | self.coeffs.swap(i, i + 1); | |
140 | } | |
e5ea6525 KS |
141 | }, |
142 | _ => unreachable!(), | |
143 | }; | |
144 | if self.use_dct || self.chmap.num_channels() == 1 { | |
145 | let overlap_len = if self.first_frm { 0 } else { self.len >> 4 }; | |
146 | let out = if chno == 0 { &mut dst[off0..] } else { &mut dst[off1..] }; | |
147 | overlap(&self.delay[chno], &self.coeffs, out, overlap_len, 1); | |
148 | let out2 = &mut out[overlap_len..self.duration]; | |
149 | out2.copy_from_slice(&self.coeffs[overlap_len..self.duration]); | |
150 | for i in 0..(self.len >> 4) { | |
151 | self.delay[chno][i] = self.coeffs[self.duration + i]; | |
152 | } | |
b3799375 | 153 | } else { |
e5ea6525 KS |
154 | let overlap_len = if self.first_frm { 0 } else { self.len >> 8 }; |
155 | overlap(&self.delay[0], &self.coeffs[0..], &mut dst[off0..], overlap_len, 2); | |
156 | overlap(&self.delay[1], &self.coeffs[1..], &mut dst[off1..], overlap_len, 2); | |
157 | for i in overlap_len..self.duration { | |
158 | dst[i + off0] = self.coeffs[i * 2 + 0]; | |
159 | dst[i + off1] = self.coeffs[i * 2 + 1]; | |
160 | } | |
161 | for i in 0..(self.len >> 8) { | |
162 | self.delay[0][i] = self.coeffs[self.duration * 2 + i * 2 + 0]; | |
163 | self.delay[1][i] = self.coeffs[self.duration * 2 + i * 2 + 1]; | |
164 | } | |
165 | } | |
166 | } | |
167 | } | |
168 | ||
e5ea6525 | 169 | impl NADecoder for BinkAudioDecoder { |
01613464 | 170 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
e5ea6525 KS |
171 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
172 | let srate = ainfo.get_sample_rate(); | |
173 | let channels = ainfo.get_channels(); | |
174 | validate!(channels <= 2); | |
175 | self.ainfo = NAAudioInfo::new(srate, channels, SND_F32P_FORMAT, 2); | |
ef1d2014 | 176 | self.chmap = NAChannelMap::from_str(if channels == 2 {"L,R"} else {"C"}).unwrap(); |
e5ea6525 KS |
177 | if let Some(ref edata) = info.get_extradata() { |
178 | if edata.as_slice() == b"BIKb" { | |
179 | self.version_b = true; | |
180 | } | |
181 | } else { | |
182 | self.version_b = false; | |
183 | } | |
184 | let mut frame_bits = if srate < 22050 { 9 } else if srate < 44100 { 10 } else { 11 }; | |
d3ebda9b | 185 | if !self.use_dct && !self.version_b && channels > 1 { |
e5ea6525 KS |
186 | frame_bits += 1; |
187 | } | |
188 | self.len = 1 << frame_bits; | |
189 | self.duration = self.len - (self.len >> 4); | |
190 | let single = !self.use_dct && channels == 2; // RDFT codes samples interleaved as single buffer | |
191 | if single { | |
192 | self.duration >>= 1; | |
193 | } | |
194 | self.transform = if !self.use_dct { | |
9e78289c | 195 | Transform::RDFT(RDFTBuilder::new_rdft(self.len >> 1, false, false)) |
e5ea6525 KS |
196 | } else { |
197 | Transform::DCT(DCT::new(DCTMode::DCT_III, self.len)) | |
198 | }; | |
199 | self.scale = if !self.use_dct { | |
200 | 1.0 / (32768.0 * (self.len as f32).sqrt()) | |
201 | } else { | |
202 | (2.0 / (self.len as f32)).sqrt() / 1024.0 | |
203 | }; | |
204 | let s_srate = if single { srate } else { srate >> 1 } as usize; | |
e9f61dd2 | 205 | init_bands(s_srate, self.len, &mut self.num_bands, &mut self.bands); |
e5ea6525 KS |
206 | self.first_frm = true; |
207 | ||
208 | Ok(()) | |
209 | } else { | |
210 | Err(DecoderError::InvalidData) | |
211 | } | |
212 | } | |
01613464 | 213 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
e5ea6525 KS |
214 | let info = pkt.get_stream().get_info(); |
215 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
216 | let pktbuf = pkt.get_buffer(); | |
217 | validate!(pktbuf.len() > 1); | |
fa90ccfb | 218 | let mut br = BitReader::new(&pktbuf, BitReaderMode::LE); |
e5ea6525 KS |
219 | let nsamples = br.read(32)? as usize; |
220 | // validate!(nsamples % self.duration == 0); | |
221 | ||
b70cc006 | 222 | let abuf = alloc_audio_buffer(self.ainfo, nsamples / self.chmap.num_channels() / 2, self.chmap.clone())?; |
e5ea6525 KS |
223 | let mut adata = abuf.get_abuf_f32().unwrap(); |
224 | let mut off0 = adata.get_offset(0); | |
225 | let mut off1 = adata.get_offset(1); | |
1a967e6b | 226 | let dst = adata.get_data_mut().unwrap(); |
e5ea6525 KS |
227 | |
228 | let num_subframes = nsamples / self.duration / self.chmap.num_channels() / 2; | |
229 | ||
230 | for _subfrm in 0..num_subframes { | |
231 | if self.use_dct { | |
232 | br.skip(2)?; | |
233 | } | |
234 | self.decode_block(&mut br)?; | |
235 | self.output(&mut dst[0..], off0, off1, 0); | |
236 | if self.chmap.num_channels() > 1 && self.use_dct { | |
237 | self.decode_block(&mut br)?; | |
238 | self.output(&mut dst[0..], off0, off1, 1); | |
239 | } | |
240 | self.first_frm = false; | |
241 | let left = br.left() & 31; | |
242 | if left != 0 { | |
243 | br.skip(left as u32)?; | |
244 | } | |
245 | off0 += self.duration; | |
246 | off1 += self.duration; | |
247 | } | |
248 | ||
249 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); | |
250 | frm.set_duration(Some(self.duration as u64)); | |
251 | frm.set_keyframe(false); | |
171860fc | 252 | Ok(frm.into_ref()) |
e5ea6525 KS |
253 | } else { |
254 | Err(DecoderError::InvalidData) | |
255 | } | |
256 | } | |
f9be4e75 KS |
257 | fn flush(&mut self) { |
258 | self.delay = [[0.0; 256]; 2]; | |
259 | } | |
e5ea6525 | 260 | } |
606c448e | 261 | |
7d57ae2f KS |
262 | impl NAOptionHandler for BinkAudioDecoder { |
263 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
264 | fn set_options(&mut self, _options: &[NAOption]) { } | |
265 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
266 | } | |
267 | ||
08a1fab7 | 268 | pub fn get_decoder_dct() -> Box<dyn NADecoder + Send> { |
e5ea6525 | 269 | Box::new(BinkAudioDecoder::new(true)) |
606c448e KS |
270 | } |
271 | ||
08a1fab7 | 272 | pub fn get_decoder_rdft() -> Box<dyn NADecoder + Send> { |
e5ea6525 KS |
273 | Box::new(BinkAudioDecoder::new(false)) |
274 | } | |
275 | ||
276 | #[cfg(test)] | |
277 | mod test { | |
278 | use nihav_core::codecs::RegisteredDecoders; | |
279 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 280 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 281 | use crate::rad_register_all_decoders; |
e64739f8 | 282 | use crate::rad_register_all_demuxers; |
e5ea6525 KS |
283 | |
284 | #[test] | |
3b981842 | 285 | fn test_bink_audio_dct() { |
e5ea6525 KS |
286 | let mut dmx_reg = RegisteredDemuxers::new(); |
287 | rad_register_all_demuxers(&mut dmx_reg); | |
288 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 289 | rad_register_all_decoders(&mut dec_reg); |
e5ea6525 | 290 | |
886cde48 | 291 | // sample: https://samples.mplayerhq.hu/game-formats/bink/ActivisionLogo.bik |
3b981842 KS |
292 | let file = "assets/RAD/ActivisionLogo.bik"; |
293 | test_decode_audio("bink", file, None, None/*Some("bink")*/, &dmx_reg, &dec_reg); | |
294 | } | |
295 | #[test] | |
d3ebda9b KS |
296 | fn test_bink_audio_rdft_mono() { |
297 | let mut dmx_reg = RegisteredDemuxers::new(); | |
298 | rad_register_all_demuxers(&mut dmx_reg); | |
299 | let mut dec_reg = RegisteredDecoders::new(); | |
300 | rad_register_all_decoders(&mut dec_reg); | |
301 | ||
302 | // sample from Star Trek: Armada demo | |
303 | let file = "assets/RAD/F1DEM1.bik"; | |
304 | test_decode_audio("bink", file, None, None/*Some("bink")*/, &dmx_reg, &dec_reg); | |
305 | } | |
306 | #[test] | |
307 | fn test_bink_audio_rdft_stereo() { | |
3b981842 KS |
308 | let mut dmx_reg = RegisteredDemuxers::new(); |
309 | rad_register_all_demuxers(&mut dmx_reg); | |
310 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 311 | rad_register_all_decoders(&mut dec_reg); |
3b981842 | 312 | |
886cde48 | 313 | // sample from Heroes of Might and Magic 3 |
3b981842 | 314 | let file = "assets/RAD/NWCLOGO.BIK"; |
5580b11b | 315 | test_decode_audio("bink", file, None, None/*Some("bink")*/, &dmx_reg, &dec_reg); |
e5ea6525 | 316 | } |
606c448e | 317 | } |