]>
Commit | Line | Data |
---|---|---|
5641dccf KS |
1 | use nihav_core::formats::*; |
2 | use nihav_core::frame::*; | |
3 | use nihav_core::codecs::*; | |
b4d5b851 | 4 | use nihav_codec_support::dsp::mdct::IMDCT; |
5641dccf KS |
5 | use nihav_core::io::bitreader::*; |
6 | use nihav_core::io::byteio::{ByteReader, MemoryReader}; | |
7 | use nihav_core::io::codebook::*; | |
8 | use nihav_core::io::intcode::*; | |
594ca5ca KS |
9 | use std::f32::consts; |
10 | use std::mem::swap; | |
38c78f36 | 11 | use super::cookdata::*; |
594ca5ca KS |
12 | |
13 | #[derive(Debug,Clone,Copy,PartialEq)] | |
14 | enum Mode { | |
15 | Mono, | |
16 | Stereo, | |
17 | JointStereo, | |
18 | } | |
19 | ||
20 | impl Mode { | |
e07387c7 KS |
21 | fn get_channels(self) -> usize { |
22 | match self { | |
594ca5ca KS |
23 | Mode::Mono => 1, |
24 | _ => 2, | |
25 | } | |
26 | } | |
27 | } | |
28 | ||
29 | struct CookBookReader { | |
30 | bits: &'static [u8], | |
31 | codes: &'static [u16], | |
32 | } | |
33 | impl CodebookDescReader<u16> for CookBookReader { | |
34 | fn bits(&mut self, idx: usize) -> u8 { self.bits[idx] } | |
35 | fn code(&mut self, idx: usize) -> u32 { self.codes[idx] as u32 } | |
36 | fn sym (&mut self, idx: usize) -> u16 { idx as u16 } | |
37 | fn len(&mut self) -> usize { self.bits.len() } | |
38 | } | |
39 | ||
40 | struct Codebooks { | |
41 | cpl_cb: [Codebook<u16>; 5], | |
42 | quant_cb: Vec<Codebook<u16>>, | |
43 | vq_cb: [Codebook<u16>; 7], | |
44 | } | |
45 | ||
46 | impl Codebooks { | |
47 | fn new() -> Self { | |
48 | let mut cpl0 = CookBookReader { codes: COOK_CPL_2BITS_CODES, bits: COOK_CPL_2BITS_BITS }; | |
49 | let mut cpl1 = CookBookReader { codes: COOK_CPL_3BITS_CODES, bits: COOK_CPL_3BITS_BITS }; | |
50 | let mut cpl2 = CookBookReader { codes: COOK_CPL_4BITS_CODES, bits: COOK_CPL_4BITS_BITS }; | |
51 | let mut cpl3 = CookBookReader { codes: COOK_CPL_5BITS_CODES, bits: COOK_CPL_5BITS_BITS }; | |
52 | let mut cpl4 = CookBookReader { codes: COOK_CPL_6BITS_CODES, bits: COOK_CPL_6BITS_BITS }; | |
53 | let cpl_cb = [Codebook::new(&mut cpl0, CodebookMode::MSB).unwrap(), | |
54 | Codebook::new(&mut cpl1, CodebookMode::MSB).unwrap(), | |
55 | Codebook::new(&mut cpl2, CodebookMode::MSB).unwrap(), | |
56 | Codebook::new(&mut cpl3, CodebookMode::MSB).unwrap(), | |
57 | Codebook::new(&mut cpl4, CodebookMode::MSB).unwrap()]; | |
58 | let mut quant_cb: Vec<Codebook<u16>> = Vec::with_capacity(COOK_QUANT_CODES.len()); | |
59 | for i in 0..COOK_QUANT_CODES.len() { | |
60 | let mut quant = CookBookReader { codes: COOK_QUANT_CODES[i], bits: COOK_QUANT_BITS[i] }; | |
61 | quant_cb.push(Codebook::new(&mut quant, CodebookMode::MSB).unwrap()); | |
62 | } | |
63 | let mut vq0 = CookBookReader { codes: COOK_VQ0_CODES, bits: COOK_VQ0_BITS }; | |
64 | let mut vq1 = CookBookReader { codes: COOK_VQ1_CODES, bits: COOK_VQ1_BITS }; | |
65 | let mut vq2 = CookBookReader { codes: COOK_VQ2_CODES, bits: COOK_VQ2_BITS }; | |
66 | let mut vq3 = CookBookReader { codes: COOK_VQ3_CODES, bits: COOK_VQ3_BITS }; | |
67 | let mut vq4 = CookBookReader { codes: COOK_VQ4_CODES, bits: COOK_VQ4_BITS }; | |
68 | let mut vq5 = CookBookReader { codes: COOK_VQ5_CODES, bits: COOK_VQ5_BITS }; | |
69 | let mut vq6 = CookBookReader { codes: COOK_VQ6_CODES, bits: COOK_VQ6_BITS }; | |
70 | let vq_cb = [Codebook::new(&mut vq0, CodebookMode::MSB).unwrap(), | |
71 | Codebook::new(&mut vq1, CodebookMode::MSB).unwrap(), | |
72 | Codebook::new(&mut vq2, CodebookMode::MSB).unwrap(), | |
73 | Codebook::new(&mut vq3, CodebookMode::MSB).unwrap(), | |
74 | Codebook::new(&mut vq4, CodebookMode::MSB).unwrap(), | |
75 | Codebook::new(&mut vq5, CodebookMode::MSB).unwrap(), | |
76 | Codebook::new(&mut vq6, CodebookMode::MSB).unwrap()]; | |
77 | Codebooks { | |
e07387c7 KS |
78 | cpl_cb, |
79 | quant_cb, | |
80 | vq_cb, | |
594ca5ca KS |
81 | } |
82 | } | |
83 | } | |
84 | ||
85 | struct CookDSP { | |
86 | imdct: IMDCT, | |
87 | window: [f32; 1024], | |
88 | out: [f32; 2048], | |
89 | size: usize, | |
90 | pow_tab: [f32; 128], | |
91 | hpow_tab: [f32; 128], | |
92 | gain_tab: [f32; 23], | |
93 | } | |
94 | ||
95 | impl CookDSP { | |
96 | fn new(samples: usize) -> Self { | |
97 | let fsamples = samples as f32; | |
98 | let mut window: [f32; 1024] = [0.0; 1024]; | |
99 | let factor = consts::PI / (2.0 * fsamples); | |
100 | let scale = (2.0 / fsamples).sqrt() / 32768.0; | |
d92111a8 KS |
101 | for (k, el) in window[..samples].iter_mut().enumerate() { |
102 | *el = (factor * ((k as f32) + 0.5)).sin() * scale; | |
594ca5ca KS |
103 | } |
104 | let mut pow_tab: [f32; 128] = [0.0; 128]; | |
105 | let mut hpow_tab: [f32; 128] = [0.0; 128]; | |
106 | for i in 0..128 { | |
107 | pow_tab[i] = 2.0f32.powf((i as f32) - 64.0); | |
108 | hpow_tab[i] = 2.0f32.powf(((i as f32) - 64.0) * 0.5); | |
109 | } | |
110 | let mut gain_tab: [f32; 23] = [0.0; 23]; | |
111 | for i in 0..23 { | |
112 | gain_tab[i] = pow_tab[i + 53].powf(8.0 / fsamples); | |
113 | } | |
114 | let size = samples; | |
e07387c7 | 115 | CookDSP { imdct: IMDCT::new(samples*2, false), window, out: [0.0; 2048], size, pow_tab, hpow_tab, gain_tab } |
594ca5ca KS |
116 | } |
117 | } | |
118 | ||
119 | trait ClipCat { | |
120 | fn clip_cat(&self) -> usize; | |
121 | } | |
122 | ||
123 | impl ClipCat for i32 { | |
124 | fn clip_cat(&self) -> usize { ((*self).max(0) as usize).min(NUM_CATEGORIES - 1) } | |
125 | } | |
126 | ||
594ca5ca KS |
127 | const MAX_SAMPLES: usize = MAX_SUBBANDS * BAND_SIZE; |
128 | const MAX_PAIRS: usize = 5; | |
594ca5ca KS |
129 | |
130 | #[derive(Clone,Copy)] | |
131 | struct CookChannelPair { | |
132 | start_ch: usize, | |
133 | mode: Mode, | |
134 | samples: usize, | |
135 | subbands: usize, | |
136 | js_start: usize, | |
137 | js_bits: u8, | |
138 | vector_bits: u8, | |
139 | ||
140 | decouple: [u8; BAND_SIZE], | |
141 | category: [u8; MAX_SUBBANDS * 2], | |
142 | ||
69f77596 | 143 | block: [[f32; MAX_SAMPLES * 2]; 2], |
594ca5ca KS |
144 | delay: [[f32; MAX_SAMPLES]; 2], |
145 | gains: [[i32; 9]; 2], | |
146 | prev_gains: [[i32; 9]; 2], | |
147 | qindex: [i8; MAX_SUBBANDS * 2], | |
148 | } | |
149 | ||
150 | impl CookChannelPair { | |
151 | fn new() -> Self { | |
152 | CookChannelPair { | |
153 | start_ch: 0, | |
154 | mode: Mode::Mono, | |
155 | samples: 0, | |
156 | subbands: 0, | |
157 | js_start: 0, | |
158 | js_bits: 0, | |
159 | vector_bits: 0, | |
160 | ||
161 | decouple: [0; BAND_SIZE], | |
162 | category: [0; MAX_SUBBANDS * 2], | |
163 | ||
69f77596 | 164 | block: [[0.0; MAX_SAMPLES * 2]; 2], |
594ca5ca KS |
165 | delay: [[0.0; MAX_SAMPLES]; 2], |
166 | gains: [[0; 9]; 2], | |
167 | prev_gains: [[0; 9]; 2], | |
168 | qindex: [0; MAX_SUBBANDS * 2], | |
169 | } | |
170 | } | |
171 | fn read_hdr_v1(&mut self, br: &mut ByteReader) -> DecoderResult<()> { | |
172 | let ver = br.read_u32be()?; | |
173 | let micro_ver = ver & 0xFF; | |
174 | self.samples = br.read_u16be()? as usize; | |
175 | validate!(self.samples > 0 && ((self.samples & (self.samples - 1)) == 0)); | |
176 | self.subbands = br.read_u16be()? as usize; | |
177 | validate!(self.subbands <= MAX_SUBBANDS); | |
178 | match micro_ver { | |
179 | 1 => { | |
180 | self.mode = Mode::Mono; | |
181 | self.js_start = 0; | |
182 | self.js_bits = 0; | |
183 | }, | |
184 | 2 => { | |
185 | self.mode = Mode::Stereo; | |
186 | self.js_start = 0; | |
187 | self.js_bits = 0; | |
188 | }, | |
189 | 3 => { | |
190 | self.mode = Mode::JointStereo; | |
191 | let _delay = br.read_u32be()?; | |
192 | self.js_start = br.read_u16be()? as usize; | |
193 | self.js_bits = br.read_u16be()? as u8; | |
194 | validate!(self.js_start < MAX_SUBBANDS); | |
195 | validate!((self.js_bits >= 2) && (self.js_bits <= 6)); | |
196 | }, | |
197 | _ => { return Err(DecoderError::InvalidData);} | |
198 | } | |
199 | Ok(()) | |
200 | } | |
201 | fn read_hdr_v2(&mut self, br: &mut ByteReader) -> DecoderResult<u32> { | |
202 | let ver = br.read_u32be()?; | |
203 | validate!((ver >> 24) == 2); | |
204 | self.samples = br.read_u16be()? as usize; | |
205 | self.subbands = br.read_u16be()? as usize; | |
206 | validate!(self.subbands <= MAX_SUBBANDS); | |
207 | let _delay = br.read_u32be()?; | |
208 | self.js_start = br.read_u16be()? as usize; | |
209 | validate!(self.js_start < MAX_SUBBANDS); | |
210 | let js_bits = br.read_u16be()?; | |
211 | let chmap = br.read_u32be()?; | |
212 | if chmap.count_ones() == 1 { | |
213 | self.js_bits = 0; | |
214 | self.mode = Mode::Mono; | |
215 | } else { | |
d92111a8 | 216 | validate!((2..=6).contains(&js_bits)); |
594ca5ca KS |
217 | self.js_bits = js_bits as u8; |
218 | self.mode = Mode::JointStereo; | |
219 | } | |
220 | Ok(chmap) | |
221 | } | |
222 | fn bitalloc(&mut self, num_vectors: usize, bits: usize) { | |
223 | let avail_bits = (if bits > self.samples { self.samples + ((bits - self.samples) * 5) / 8 } else { bits }) as i32; | |
224 | let total_subbands = self.subbands + self.js_start; | |
225 | ||
226 | let mut bias: i32 = -32; | |
227 | for i in 0..6 { | |
228 | let mut sum = 0; | |
229 | for j in 0..total_subbands { | |
230 | let idx = ((32 >> i) + bias - (self.qindex[j] as i32)) / 2; | |
231 | sum += COOK_EXP_BITS[idx.clip_cat()]; | |
232 | } | |
233 | if sum >= (avail_bits - 32) { | |
234 | bias += 32 >> i; | |
235 | } | |
236 | } | |
237 | ||
238 | let mut exp_index1: [usize; MAX_SUBBANDS * 2] = [0; MAX_SUBBANDS * 2]; | |
239 | let mut exp_index2: [usize; MAX_SUBBANDS * 2] = [0; MAX_SUBBANDS * 2]; | |
240 | let mut sum = 0; | |
241 | for i in 0..total_subbands { | |
242 | let idx = ((bias - (self.qindex[i] as i32)) / 2).clip_cat(); | |
243 | sum += COOK_EXP_BITS[idx]; | |
244 | exp_index1[i] = idx; | |
245 | exp_index2[i] = idx; | |
246 | } | |
247 | ||
248 | let mut tbias1 = sum; | |
249 | let mut tbias2 = sum; | |
250 | let mut tcat: [usize; 128*2] = [0; 128*2]; | |
251 | let mut tcat_idx1 = 128; | |
252 | let mut tcat_idx2 = 128; | |
253 | for _ in 1..(1 << self.vector_bits) { | |
254 | if tbias1 + tbias2 > avail_bits * 2 { | |
255 | let mut max = -999999; | |
256 | let mut idx = total_subbands + 1; | |
d92111a8 KS |
257 | for (j, (&exp_idx, &q_idx)) in exp_index1.iter() |
258 | .zip(self.qindex.iter()).enumerate().take(total_subbands) { | |
259 | if exp_idx >= (NUM_CATEGORIES - 1) { continue; } | |
260 | let t = -2 * (exp_idx as i32) - (q_idx as i32) + bias; | |
594ca5ca KS |
261 | if t >= max { |
262 | max = t; | |
263 | idx = j; | |
264 | } | |
265 | } | |
266 | if idx >= total_subbands { break; } | |
267 | tcat[tcat_idx1] = idx; | |
268 | tcat_idx1 += 1; | |
269 | tbias1 -= COOK_EXP_BITS[exp_index1[idx]] - COOK_EXP_BITS[exp_index1[idx] + 1]; | |
270 | exp_index1[idx] += 1; | |
271 | } else { | |
272 | let mut min = 999999; | |
273 | let mut idx = total_subbands + 1; | |
d92111a8 KS |
274 | for (j, (&exp_idx, &q_idx)) in exp_index2.iter() |
275 | .zip(self.qindex.iter()).enumerate().take(total_subbands) { | |
276 | if exp_idx == 0 { continue; } | |
277 | let t = -2 * (exp_idx as i32) - (q_idx as i32) + bias; | |
594ca5ca KS |
278 | if t < min { |
279 | min = t; | |
280 | idx = j; | |
281 | } | |
282 | } | |
283 | if idx >= total_subbands { break; } | |
284 | tcat_idx2 -= 1; | |
285 | tcat[tcat_idx2] = idx; | |
286 | tbias2 -= COOK_EXP_BITS[exp_index2[idx]] - COOK_EXP_BITS[exp_index2[idx] - 1]; | |
287 | exp_index2[idx] -= 1; | |
288 | } | |
289 | } | |
d92111a8 KS |
290 | for (cat, &exp_idx) in self.category.iter_mut().zip(exp_index2.iter()).take(total_subbands) { |
291 | *cat = exp_idx as u8; | |
594ca5ca KS |
292 | } |
293 | ||
294 | for _ in 0..num_vectors { | |
295 | let idx = tcat[tcat_idx2]; | |
296 | tcat_idx2 += 1; | |
e6aaad5c | 297 | self.category[idx] = (self.category[idx] + 1).min((NUM_CATEGORIES - 1) as u8); |
594ca5ca KS |
298 | } |
299 | } | |
300 | fn decode_channel_data(&mut self, dsp: &mut CookDSP, rnd: &mut RND, codebooks: &Codebooks, src: &[u8], buf: &mut [u8], channel: usize) -> DecoderResult<()> { | |
301 | // decrypt | |
302 | for (i, b) in src.iter().enumerate() { | |
303 | buf[i] = b ^ COOK_XOR_KEY[i & 3]; | |
304 | } | |
fa90ccfb | 305 | let mut br = BitReader::new(&buf[..src.len()], BitReaderMode::BE); |
594ca5ca KS |
306 | |
307 | let num_gains = br.read_code(UintCodeType::UnaryOnes)? as usize; | |
308 | validate!(num_gains <= 8); | |
309 | ||
310 | swap(&mut self.gains[channel], &mut self.prev_gains[channel]); | |
69f77596 | 311 | self.block[channel] = [0.0; MAX_SAMPLES * 2]; |
594ca5ca KS |
312 | |
313 | // gains | |
314 | let mut ipos = 0; | |
315 | for _ in 0..num_gains { | |
316 | let idx = br.read(3)? as usize; | |
d92111a8 KS |
317 | let val = if br.read_bool()? { |
318 | (br.read(4)? as i32) - 7 | |
319 | } else { | |
320 | -1 | |
321 | }; | |
594ca5ca KS |
322 | validate!(idx >= ipos); |
323 | while ipos <= idx { | |
324 | self.prev_gains[channel][ipos] = val; | |
325 | ipos += 1; | |
326 | } | |
327 | } | |
328 | while ipos <= 8 { | |
329 | self.prev_gains[channel][ipos] = 0; | |
330 | ipos += 1; | |
331 | } | |
332 | ||
333 | // coupling information | |
334 | if self.mode == Mode::JointStereo { | |
335 | let cstart = COOK_CPL_BAND[self.js_start] as usize; | |
336 | let cend = COOK_CPL_BAND[self.subbands - 1] as usize; | |
337 | if br.read_bool()? { | |
338 | let cb = &codebooks.cpl_cb[(self.js_bits - 2) as usize]; | |
e07387c7 | 339 | for i in cstart..=cend { |
594ca5ca KS |
340 | self.decouple[i] = br.read_cb(cb)? as u8; |
341 | } | |
342 | } else { | |
e07387c7 | 343 | for i in cstart..=cend { |
594ca5ca KS |
344 | self.decouple[i] = br.read(self.js_bits)? as u8; |
345 | } | |
346 | } | |
347 | } | |
348 | ||
349 | // envelope | |
350 | let tot_subbands = self.subbands + self.js_start; | |
351 | self.qindex[0] = (br.read(6)? as i8) - 6; | |
352 | for i in 1..tot_subbands { | |
353 | let mut pos = i; | |
354 | if pos >= self.js_start * 2 { | |
355 | pos -= self.js_start; | |
356 | } else { | |
357 | pos >>= 1; | |
358 | } | |
359 | let ipos = ((pos as i8) - 1).max(0).min(12); | |
360 | let cb = &codebooks.quant_cb[ipos as usize]; | |
361 | self.qindex[i] = (br.read_cb(cb)? as i8) + self.qindex[i - 1] - 12; | |
362 | validate!((self.qindex[i] >= -63) && (self.qindex[i] <= 63)); | |
363 | } | |
364 | let num_vectors = br.read(self.vector_bits)? as usize; | |
365 | self.bitalloc(num_vectors, br.left() as usize); | |
366 | ||
367 | // coefficients | |
69f77596 | 368 | self.block[channel] = [0.0; MAX_SAMPLES * 2]; |
594ca5ca KS |
369 | let mut off = 0; |
370 | for sb in 0..tot_subbands { | |
371 | let mut coef_index: [u8; BAND_SIZE] = [0; BAND_SIZE]; | |
372 | let mut coef_sign: [bool; BAND_SIZE] = [false; BAND_SIZE]; | |
373 | let cat = self.category[sb] as usize; | |
374 | if (cat < NUM_CATEGORIES - 1) && br.left() > 0 { | |
375 | unpack_band(&mut br, codebooks, &mut coef_index, &mut coef_sign, cat)?; | |
376 | } | |
377 | for i in 0..BAND_SIZE { | |
d92111a8 KS |
378 | let val = if coef_index[i] == 0 { |
379 | let v = COOK_DITHER_TAB[cat]; | |
380 | if !rnd.get_sign() { v } else { -v } | |
381 | } else { | |
382 | let v = COOK_QUANT_CENTROID[cat][coef_index[i] as usize]; | |
383 | if !coef_sign[i] { v } else { -v } | |
384 | }; | |
594ca5ca KS |
385 | self.block[channel][off + i] = val * dsp.hpow_tab[(self.qindex[sb] + 64) as usize]; |
386 | } | |
387 | off += BAND_SIZE; | |
388 | } | |
389 | ||
390 | Ok(()) | |
391 | } | |
d92111a8 | 392 | #[allow(clippy::needless_range_loop)] |
594ca5ca KS |
393 | fn decode(&mut self, dsp: &mut CookDSP, rnd: &mut RND, codebooks: &Codebooks, src: &[u8], buf: &mut [u8], abuf: &mut NABufferType) -> DecoderResult<()> { |
394 | if self.mode == Mode::Stereo { | |
395 | let mut schunk = src.chunks(src.len() / 2); | |
396 | self.decode_channel_data(dsp, rnd, codebooks, schunk.next().unwrap(), buf, 0)?; | |
397 | self.decode_channel_data(dsp, rnd, codebooks, schunk.next().unwrap(), buf, 1)?; | |
398 | } else { | |
399 | self.decode_channel_data(dsp, rnd, codebooks, src, buf, 0)?; | |
400 | } | |
401 | // uncouple joint stereo channels | |
402 | if self.mode == Mode::JointStereo { | |
403 | for i in 0..self.js_start { | |
404 | for j in 0..BAND_SIZE { | |
405 | self.block[1][i * BAND_SIZE + j] = self.block[0][(i * 2 + 1) * BAND_SIZE + j]; | |
406 | self.block[0][i * BAND_SIZE + j] = self.block[0][(i * 2) * BAND_SIZE + j]; | |
407 | } | |
408 | } | |
409 | let scale_idx = (self.js_bits as usize) - 2; | |
410 | let scale_off = (1 << self.js_bits) as usize; | |
411 | for i in self.js_start..self.subbands { | |
412 | let idx = self.decouple[COOK_CPL_BAND[i] as usize] as usize; | |
413 | let doff = i * BAND_SIZE; | |
414 | let soff = (i + self.js_start) * BAND_SIZE; | |
415 | let m1 = COOK_CPL_SCALES[scale_idx][ 1 + idx]; | |
416 | let m2 = COOK_CPL_SCALES[scale_idx][scale_off - 1 - idx]; | |
417 | for j in 0..BAND_SIZE { | |
418 | self.block[0][doff + j] = self.block[0][soff + j] * m1; | |
419 | self.block[1][doff + j] = self.block[0][soff + j] * m2; | |
420 | } | |
421 | } | |
422 | for i in (self.subbands * BAND_SIZE)..MAX_SAMPLES { | |
423 | self.block[0][i] = 0.0; | |
424 | self.block[1][i] = 0.0; | |
425 | } | |
426 | self.gains[1] = self.gains[0]; | |
427 | self.prev_gains[1] = self.prev_gains[0]; | |
428 | } | |
429 | for ch in 0..self.mode.get_channels() { | |
430 | let off = abuf.get_offset(ch + self.start_ch); | |
431 | let mut adata = abuf.get_abuf_f32().unwrap(); | |
1a967e6b | 432 | let output = adata.get_data_mut().unwrap(); |
594ca5ca KS |
433 | let dst = &mut output[off..]; |
434 | ||
435 | dsp.imdct.imdct(&self.block[ch], &mut dsp.out); | |
436 | ||
437 | let prev_gain = dsp.pow_tab[(self.prev_gains[ch][0] + 64) as usize]; | |
438 | let mut cur_gain = 0.0; | |
439 | let mut cur_gain2 = 0.0; | |
440 | let mut gain_idx = 0; | |
441 | let eighthmask = (self.samples >> 3) - 1; | |
442 | for (i, out) in dst.iter_mut().take(self.samples).enumerate() { | |
443 | *out = dsp.out[i + self.samples] * prev_gain * dsp.window[i] | |
444 | - self.delay[ch][i] * dsp.window[self.samples - i - 1]; | |
445 | if (i & eighthmask) == 0 { | |
446 | if (self.gains[ch][gain_idx] == 0) && (self.gains[ch][gain_idx + 1] == 0) { | |
447 | cur_gain = 1.0; | |
448 | cur_gain2 = 1.0; | |
449 | } else { | |
450 | cur_gain = dsp.pow_tab[(self.gains[ch][gain_idx] + 64) as usize]; | |
451 | cur_gain2 = dsp.gain_tab[(self.gains[ch][gain_idx + 1] - self.gains[ch][gain_idx] + 11) as usize]; | |
452 | } | |
453 | gain_idx += 1; | |
454 | } | |
455 | *out *= cur_gain; | |
456 | cur_gain *= cur_gain2; | |
457 | } | |
fa57381e | 458 | self.delay[ch][..self.samples].copy_from_slice(&dsp.out[..self.samples]); |
594ca5ca KS |
459 | } |
460 | Ok(()) | |
461 | } | |
462 | } | |
463 | ||
594ca5ca KS |
464 | fn unpack_band(br: &mut BitReader, codebooks: &Codebooks, coef_index: &mut [u8; BAND_SIZE], coef_sign: &mut [bool; BAND_SIZE], cat: usize) -> DecoderResult<()> { |
465 | let cb = &codebooks.vq_cb[cat]; | |
466 | let group_size = COOK_VQ_GROUP_SIZE[cat]; | |
467 | let mult = COOK_VQ_MULT[cat] + 1; | |
468 | for i in 0..COOK_NUM_VQ_GROUPS[cat] { | |
469 | let ret = br.read_cb(cb); | |
470 | let mut val; | |
471 | if let Ok(v) = ret { | |
472 | val = v as u32; | |
473 | } else { | |
474 | let left = br.left() as u32; | |
475 | br.skip(left)?; | |
476 | break; | |
477 | } | |
478 | let mut nnz = 0; | |
479 | for j in (0..group_size).rev() { | |
480 | let t = (val * COOK_VQ_INV_RADIX[cat]) >> 20; | |
481 | coef_index[i * group_size + j] = (val - t * mult) as u8; | |
482 | if coef_index[i * group_size + j] != 0 { | |
483 | nnz += 1; | |
484 | } | |
485 | val = t; | |
486 | } | |
487 | if (br.left() as usize) < nnz { | |
488 | let left = br.left() as u32; | |
489 | br.skip(left)?; | |
490 | break; | |
491 | } | |
492 | for j in 0..group_size { | |
493 | if coef_index[i * group_size + j] != 0 { | |
494 | coef_sign[i * group_size + j] = br.read_bool()?; | |
495 | } else { | |
496 | coef_sign[i * group_size + j] = false; | |
497 | } | |
498 | } | |
499 | } | |
500 | Ok(()) | |
501 | } | |
502 | ||
503 | struct RND { | |
504 | state: u32, | |
505 | } | |
506 | ||
507 | impl RND { | |
508 | fn new() -> Self { | |
509 | Self { state: 0xC0DECC00 } | |
510 | } | |
511 | fn get_sign(&mut self) -> bool { | |
512 | self.state = (self.state & 0xFFFF).wrapping_mul(36969).wrapping_add(self.state >> 16); | |
513 | (self.state & 0x10000) != 0 | |
514 | } | |
515 | } | |
516 | ||
517 | struct CookDecoder { | |
2422d969 | 518 | info: NACodecInfoRef, |
594ca5ca KS |
519 | chmap: NAChannelMap, |
520 | src: [u8; 65536], | |
521 | num_pairs: usize, | |
522 | pairs: [CookChannelPair; MAX_PAIRS], | |
523 | channels: usize, | |
524 | samples: usize, | |
525 | codebooks: Codebooks, | |
526 | rnd: RND, | |
527 | dsp: CookDSP, | |
528 | } | |
529 | ||
530 | impl CookDecoder { | |
531 | fn new() -> Self { | |
532 | CookDecoder { | |
533 | info: NACodecInfo::new_dummy(), | |
534 | chmap: NAChannelMap::new(), | |
535 | src: [0; 65536], | |
536 | num_pairs: 0, | |
537 | channels: 0, | |
538 | samples: 0, | |
539 | pairs: [CookChannelPair::new(); MAX_PAIRS], | |
540 | codebooks: Codebooks::new(), | |
541 | rnd: RND::new(), | |
542 | dsp: CookDSP::new(1024), | |
543 | } | |
544 | } | |
545 | } | |
546 | ||
547 | impl NADecoder for CookDecoder { | |
01613464 | 548 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
594ca5ca KS |
549 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
550 | let edata = info.get_extradata().unwrap(); | |
551 | validate!(edata.len() >= 4); | |
552 | ||
553 | let mut mr = MemoryReader::new_read(&edata); | |
554 | let mut br = ByteReader::new(&mut mr); | |
555 | let ver = br.peek_u32be()?; | |
556 | ||
557 | let maj_ver = ver >> 24; | |
558 | let mut chmap: u32 = 0; | |
559 | match maj_ver { | |
560 | 1 => { | |
561 | self.num_pairs = 1; | |
562 | self.pairs[0].read_hdr_v1(&mut br)?; | |
563 | self.channels = self.pairs[0].mode.get_channels(); | |
564 | if ainfo.get_channels() == 1 { // forced mono | |
b7eda71d | 565 | self.pairs[0].mode = Mode::Mono; |
594ca5ca KS |
566 | self.channels = 1; |
567 | chmap = 0x4; | |
568 | } else { | |
569 | chmap = 0x3; | |
570 | } | |
571 | }, | |
572 | 2 => { | |
573 | self.num_pairs = (edata.len() - (br.tell() as usize)) / 20; | |
574 | validate!(self.num_pairs <= MAX_PAIRS); | |
575 | let mut start_ch = 0; | |
576 | for i in 0..self.num_pairs { | |
577 | let pair_chmap = self.pairs[i].read_hdr_v2(&mut br)?; | |
578 | self.pairs[i].start_ch = start_ch; | |
579 | validate!((chmap & pair_chmap) == 0); | |
1ef35f7d | 580 | chmap |= pair_chmap; |
594ca5ca KS |
581 | start_ch += self.pairs[i].mode.get_channels(); |
582 | } | |
583 | self.channels = start_ch; | |
584 | }, | |
585 | _ => { return Err(DecoderError::InvalidData); } | |
586 | }; | |
587 | ||
588 | self.samples = self.pairs[0].samples / self.pairs[0].mode.get_channels(); | |
589 | validate!((self.samples >= 16) && (self.samples <= 1024)); | |
590 | if self.samples != self.dsp.size { | |
591 | self.dsp = CookDSP::new(self.samples); | |
592 | } | |
593 | self.chmap = NAChannelMap::from_ms_mapping(chmap); | |
594 | ||
595 | for i in 1..self.num_pairs { | |
596 | validate!((self.pairs[i].samples / self.pairs[i].mode.get_channels()) == self.samples); | |
597 | } | |
598 | ||
599 | let vector_bits = match self.samples { | |
600 | 16 | 32 | 64 | 128 | 256 => 5, | |
601 | 512 => 6, | |
602 | 1024 => 7, | |
603 | _ => unreachable!(), | |
604 | }; | |
605 | for pair in self.pairs.iter_mut() { | |
606 | match pair.mode { | |
607 | Mode::Mono => { | |
608 | pair.vector_bits = 5; | |
609 | }, | |
610 | Mode::Stereo => { | |
611 | pair.vector_bits = 5; | |
612 | pair.samples >>= 1; | |
613 | }, | |
614 | Mode::JointStereo => { | |
615 | pair.vector_bits = vector_bits; | |
616 | pair.samples >>= 1; | |
617 | }, | |
618 | }; | |
619 | } | |
620 | ||
621 | let ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), self.channels as u8, | |
622 | SND_F32P_FORMAT, self.samples); | |
623 | self.info = info.replace_info(NACodecTypeInfo::Audio(ainfo)); | |
624 | ||
625 | Ok(()) | |
626 | } else { | |
627 | Err(DecoderError::InvalidData) | |
628 | } | |
629 | } | |
01613464 | 630 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
594ca5ca KS |
631 | let info = pkt.get_stream().get_info(); |
632 | validate!(info.get_properties().is_audio()); | |
633 | let pktbuf = pkt.get_buffer(); | |
634 | validate!(pktbuf.len() > self.num_pairs * 2); | |
635 | ||
636 | let mut seg_size: [usize; MAX_PAIRS] = [0; MAX_PAIRS]; | |
637 | let mut seg_start: [usize; MAX_PAIRS+1] = [0; MAX_PAIRS+1]; | |
638 | ||
639 | let ainfo = self.info.get_properties().get_audio_info().unwrap(); | |
640 | ||
641 | seg_size[0] = pktbuf.len() - (self.num_pairs - 1); | |
642 | for i in 1..self.num_pairs { | |
643 | seg_size[i] = (pktbuf[pktbuf.len() - self.num_pairs + i] as usize) * 2; | |
644 | validate!(seg_size[i] != 0); | |
645 | let ret = seg_size[0].checked_sub(seg_size[i]); | |
646 | if let Some(val) = ret { | |
647 | seg_size[0] = val; | |
648 | } else { | |
649 | return Err(DecoderError::InvalidData); | |
650 | } | |
651 | } | |
652 | validate!(seg_size[0] != 0); | |
653 | seg_start[0] = 0; | |
654 | for i in 0..self.num_pairs { | |
655 | seg_start[i + 1] = seg_start[i] + seg_size[i]; | |
656 | } | |
657 | ||
658 | let mut abuf = alloc_audio_buffer(ainfo, self.samples, self.chmap.clone())?; | |
659 | ||
660 | for pair in 0..self.num_pairs { | |
661 | self.pairs[pair].decode(&mut self.dsp, &mut self.rnd, &self.codebooks, &pktbuf[seg_start[pair]..seg_start[pair + 1]], &mut self.src, &mut abuf)?; | |
662 | } | |
663 | ||
664 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.replace_info(NACodecTypeInfo::Audio(ainfo)), abuf); | |
665 | frm.set_keyframe(true); | |
171860fc | 666 | Ok(frm.into_ref()) |
594ca5ca | 667 | } |
f9be4e75 KS |
668 | fn flush(&mut self) { |
669 | for pair in self.pairs.iter_mut() { | |
670 | pair.delay = [[0.0; MAX_SAMPLES]; 2]; | |
671 | } | |
672 | } | |
594ca5ca KS |
673 | } |
674 | ||
7d57ae2f KS |
675 | impl NAOptionHandler for CookDecoder { |
676 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
677 | fn set_options(&mut self, _options: &[NAOption]) { } | |
678 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
679 | } | |
680 | ||
08a1fab7 | 681 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
594ca5ca KS |
682 | Box::new(CookDecoder::new()) |
683 | } | |
684 | ||
685 | #[cfg(test)] | |
686 | mod test { | |
3167c45c KS |
687 | use nihav_core::codecs::RegisteredDecoders; |
688 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 689 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 690 | use crate::realmedia_register_all_decoders; |
e64739f8 | 691 | use crate::realmedia_register_all_demuxers; |
594ca5ca KS |
692 | #[test] |
693 | fn test_cook() { | |
3167c45c KS |
694 | let mut dmx_reg = RegisteredDemuxers::new(); |
695 | realmedia_register_all_demuxers(&mut dmx_reg); | |
696 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 697 | realmedia_register_all_decoders(&mut dec_reg); |
3167c45c | 698 | |
594ca5ca | 699 | // let file = "assets/RV/rv30_weighted_mc.rm"; |
886cde48 | 700 | // sample: https://samples.mplayerhq.hu/real/AC-cook/cook_5.1/multichannel.rma |
594ca5ca | 701 | let file = "assets/RV/multichannel.rma"; |
5580b11b | 702 | test_decode_audio("realmedia", file, Some(2000), None/*Some("cook")*/, &dmx_reg, &dec_reg); |
594ca5ca KS |
703 | } |
704 | } |