]>
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]; | |
90 | for i in 0..self.num_bands { | |
91 | let idx = br.read(8)? as usize; | |
92 | quants[i] = self.quants[idx.min(self.quants.len() - 1)] * self.scale; | |
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 | |
100 | } else { | |
101 | if br.read_bool()? { | |
102 | let idx = br.read(4)? as usize; | |
103 | RUN_TAB[idx] * 8 | |
104 | } else { | |
105 | 8 | |
106 | } | |
107 | }; | |
108 | let end = (idx + width).min(self.len); | |
109 | let bits = br.read(4)? as u8; | |
110 | if bits != 0 { | |
111 | for i in idx..end { | |
112 | while self.bands[band_idx] <= i { band_idx += 1; } | |
113 | let q = quants[band_idx - 1]; | |
114 | let coeff = br.read(bits)?; | |
115 | if coeff != 0 { | |
116 | if br.read_bool()? { | |
117 | self.coeffs[i] = -(coeff as f32) * q; | |
118 | } else { | |
119 | self.coeffs[i] = (coeff as f32) * q; | |
120 | } | |
121 | } | |
122 | } | |
123 | } | |
124 | idx = end; | |
125 | } | |
126 | Ok(()) | |
127 | } | |
bf109afe | 128 | #[allow(clippy::transmute_ptr_to_ptr)] |
e5ea6525 KS |
129 | fn output(&mut self, dst: &mut [f32], off0: usize, off1: usize, chno: usize) { |
130 | match self.transform { | |
131 | Transform::DCT(ref mut dct) => { | |
132 | dct.do_dct_inplace(&mut self.coeffs[0..]); | |
133 | }, | |
134 | Transform::RDFT(ref mut rdft) => { | |
135 | unsafe { | |
136 | let buf = &mut self.coeffs[0..]; | |
137 | rdft.do_rdft_inplace(std::mem::transmute::<&mut [f32], &mut [FFTComplex]>(buf)); | |
138 | } | |
139 | }, | |
140 | _ => unreachable!(), | |
141 | }; | |
142 | if self.use_dct || self.chmap.num_channels() == 1 { | |
143 | let overlap_len = if self.first_frm { 0 } else { self.len >> 4 }; | |
144 | let out = if chno == 0 { &mut dst[off0..] } else { &mut dst[off1..] }; | |
145 | overlap(&self.delay[chno], &self.coeffs, out, overlap_len, 1); | |
146 | let out2 = &mut out[overlap_len..self.duration]; | |
147 | out2.copy_from_slice(&self.coeffs[overlap_len..self.duration]); | |
148 | for i in 0..(self.len >> 4) { | |
149 | self.delay[chno][i] = self.coeffs[self.duration + i]; | |
150 | } | |
b3799375 | 151 | } else { |
e5ea6525 KS |
152 | let overlap_len = if self.first_frm { 0 } else { self.len >> 8 }; |
153 | overlap(&self.delay[0], &self.coeffs[0..], &mut dst[off0..], overlap_len, 2); | |
154 | overlap(&self.delay[1], &self.coeffs[1..], &mut dst[off1..], overlap_len, 2); | |
155 | for i in overlap_len..self.duration { | |
156 | dst[i + off0] = self.coeffs[i * 2 + 0]; | |
157 | dst[i + off1] = self.coeffs[i * 2 + 1]; | |
158 | } | |
159 | for i in 0..(self.len >> 8) { | |
160 | self.delay[0][i] = self.coeffs[self.duration * 2 + i * 2 + 0]; | |
161 | self.delay[1][i] = self.coeffs[self.duration * 2 + i * 2 + 1]; | |
162 | } | |
163 | } | |
164 | } | |
165 | } | |
166 | ||
e5ea6525 | 167 | impl NADecoder for BinkAudioDecoder { |
01613464 | 168 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
e5ea6525 KS |
169 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
170 | let srate = ainfo.get_sample_rate(); | |
171 | let channels = ainfo.get_channels(); | |
172 | validate!(channels <= 2); | |
173 | self.ainfo = NAAudioInfo::new(srate, channels, SND_F32P_FORMAT, 2); | |
ef1d2014 | 174 | self.chmap = NAChannelMap::from_str(if channels == 2 {"L,R"} else {"C"}).unwrap(); |
e5ea6525 KS |
175 | if let Some(ref edata) = info.get_extradata() { |
176 | if edata.as_slice() == b"BIKb" { | |
177 | self.version_b = true; | |
178 | } | |
179 | } else { | |
180 | self.version_b = false; | |
181 | } | |
182 | let mut frame_bits = if srate < 22050 { 9 } else if srate < 44100 { 10 } else { 11 }; | |
183 | if !self.use_dct && !self.version_b { | |
184 | frame_bits += 1; | |
185 | } | |
186 | self.len = 1 << frame_bits; | |
187 | self.duration = self.len - (self.len >> 4); | |
188 | let single = !self.use_dct && channels == 2; // RDFT codes samples interleaved as single buffer | |
189 | if single { | |
190 | self.duration >>= 1; | |
191 | } | |
192 | self.transform = if !self.use_dct { | |
9e78289c | 193 | Transform::RDFT(RDFTBuilder::new_rdft(self.len >> 1, false, false)) |
e5ea6525 KS |
194 | } else { |
195 | Transform::DCT(DCT::new(DCTMode::DCT_III, self.len)) | |
196 | }; | |
197 | self.scale = if !self.use_dct { | |
198 | 1.0 / (32768.0 * (self.len as f32).sqrt()) | |
199 | } else { | |
200 | (2.0 / (self.len as f32)).sqrt() / 1024.0 | |
201 | }; | |
202 | let s_srate = if single { srate } else { srate >> 1 } as usize; | |
e9f61dd2 | 203 | init_bands(s_srate, self.len, &mut self.num_bands, &mut self.bands); |
e5ea6525 KS |
204 | self.first_frm = true; |
205 | ||
206 | Ok(()) | |
207 | } else { | |
208 | Err(DecoderError::InvalidData) | |
209 | } | |
210 | } | |
01613464 | 211 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
e5ea6525 KS |
212 | let info = pkt.get_stream().get_info(); |
213 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
214 | let pktbuf = pkt.get_buffer(); | |
215 | validate!(pktbuf.len() > 1); | |
fa90ccfb | 216 | let mut br = BitReader::new(&pktbuf, BitReaderMode::LE); |
e5ea6525 KS |
217 | let nsamples = br.read(32)? as usize; |
218 | // validate!(nsamples % self.duration == 0); | |
219 | ||
b70cc006 | 220 | let abuf = alloc_audio_buffer(self.ainfo, nsamples / self.chmap.num_channels() / 2, self.chmap.clone())?; |
e5ea6525 KS |
221 | let mut adata = abuf.get_abuf_f32().unwrap(); |
222 | let mut off0 = adata.get_offset(0); | |
223 | let mut off1 = adata.get_offset(1); | |
1a967e6b | 224 | let dst = adata.get_data_mut().unwrap(); |
e5ea6525 KS |
225 | |
226 | let num_subframes = nsamples / self.duration / self.chmap.num_channels() / 2; | |
227 | ||
228 | for _subfrm in 0..num_subframes { | |
229 | if self.use_dct { | |
230 | br.skip(2)?; | |
231 | } | |
232 | self.decode_block(&mut br)?; | |
233 | self.output(&mut dst[0..], off0, off1, 0); | |
234 | if self.chmap.num_channels() > 1 && self.use_dct { | |
235 | self.decode_block(&mut br)?; | |
236 | self.output(&mut dst[0..], off0, off1, 1); | |
237 | } | |
238 | self.first_frm = false; | |
239 | let left = br.left() & 31; | |
240 | if left != 0 { | |
241 | br.skip(left as u32)?; | |
242 | } | |
243 | off0 += self.duration; | |
244 | off1 += self.duration; | |
245 | } | |
246 | ||
247 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); | |
248 | frm.set_duration(Some(self.duration as u64)); | |
249 | frm.set_keyframe(false); | |
171860fc | 250 | Ok(frm.into_ref()) |
e5ea6525 KS |
251 | } else { |
252 | Err(DecoderError::InvalidData) | |
253 | } | |
254 | } | |
f9be4e75 KS |
255 | fn flush(&mut self) { |
256 | self.delay = [[0.0; 256]; 2]; | |
257 | } | |
e5ea6525 | 258 | } |
606c448e | 259 | |
7d57ae2f KS |
260 | impl NAOptionHandler for BinkAudioDecoder { |
261 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
262 | fn set_options(&mut self, _options: &[NAOption]) { } | |
263 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
264 | } | |
265 | ||
08a1fab7 | 266 | pub fn get_decoder_dct() -> Box<dyn NADecoder + Send> { |
e5ea6525 | 267 | Box::new(BinkAudioDecoder::new(true)) |
606c448e KS |
268 | } |
269 | ||
08a1fab7 | 270 | pub fn get_decoder_rdft() -> Box<dyn NADecoder + Send> { |
e5ea6525 KS |
271 | Box::new(BinkAudioDecoder::new(false)) |
272 | } | |
273 | ||
274 | #[cfg(test)] | |
275 | mod test { | |
276 | use nihav_core::codecs::RegisteredDecoders; | |
277 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 278 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 279 | use crate::rad_register_all_decoders; |
e64739f8 | 280 | use crate::rad_register_all_demuxers; |
e5ea6525 KS |
281 | |
282 | #[test] | |
3b981842 | 283 | fn test_bink_audio_dct() { |
e5ea6525 KS |
284 | let mut dmx_reg = RegisteredDemuxers::new(); |
285 | rad_register_all_demuxers(&mut dmx_reg); | |
286 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 287 | rad_register_all_decoders(&mut dec_reg); |
e5ea6525 | 288 | |
886cde48 | 289 | // sample: https://samples.mplayerhq.hu/game-formats/bink/ActivisionLogo.bik |
3b981842 KS |
290 | let file = "assets/RAD/ActivisionLogo.bik"; |
291 | test_decode_audio("bink", file, None, None/*Some("bink")*/, &dmx_reg, &dec_reg); | |
292 | } | |
293 | #[test] | |
294 | fn test_bink_audio_rdft() { | |
295 | let mut dmx_reg = RegisteredDemuxers::new(); | |
296 | rad_register_all_demuxers(&mut dmx_reg); | |
297 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 298 | rad_register_all_decoders(&mut dec_reg); |
3b981842 | 299 | |
886cde48 | 300 | // sample from Heroes of Might and Magic 3 |
3b981842 | 301 | let file = "assets/RAD/NWCLOGO.BIK"; |
5580b11b | 302 | test_decode_audio("bink", file, None, None/*Some("bink")*/, &dmx_reg, &dec_reg); |
e5ea6525 | 303 | } |
606c448e | 304 | } |