]>
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; | |
101 | for k in 0..samples { | |
102 | window[k] = (factor * ((k as f32) + 0.5)).sin() * scale; | |
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 { | |
216 | validate!((js_bits >= 2) && (js_bits <= 6)); | |
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; | |
257 | for j in 0..total_subbands { | |
258 | if exp_index1[j] >= (NUM_CATEGORIES - 1) { continue; } | |
259 | let t = -2 * (exp_index1[j] as i32) - (self.qindex[j] as i32) + bias; | |
260 | if t >= max { | |
261 | max = t; | |
262 | idx = j; | |
263 | } | |
264 | } | |
265 | if idx >= total_subbands { break; } | |
266 | tcat[tcat_idx1] = idx; | |
267 | tcat_idx1 += 1; | |
268 | tbias1 -= COOK_EXP_BITS[exp_index1[idx]] - COOK_EXP_BITS[exp_index1[idx] + 1]; | |
269 | exp_index1[idx] += 1; | |
270 | } else { | |
271 | let mut min = 999999; | |
272 | let mut idx = total_subbands + 1; | |
273 | for j in 0..total_subbands { | |
274 | if exp_index2[j] == 0 { continue; } | |
275 | let t = -2 * (exp_index2[j] as i32) - (self.qindex[j] as i32) + bias; | |
276 | if t < min { | |
277 | min = t; | |
278 | idx = j; | |
279 | } | |
280 | } | |
281 | if idx >= total_subbands { break; } | |
282 | tcat_idx2 -= 1; | |
283 | tcat[tcat_idx2] = idx; | |
284 | tbias2 -= COOK_EXP_BITS[exp_index2[idx]] - COOK_EXP_BITS[exp_index2[idx] - 1]; | |
285 | exp_index2[idx] -= 1; | |
286 | } | |
287 | } | |
288 | for i in 0..total_subbands { | |
289 | self.category[i] = exp_index2[i] as u8; | |
290 | } | |
291 | ||
292 | for _ in 0..num_vectors { | |
293 | let idx = tcat[tcat_idx2]; | |
294 | tcat_idx2 += 1; | |
e6aaad5c | 295 | self.category[idx] = (self.category[idx] + 1).min((NUM_CATEGORIES - 1) as u8); |
594ca5ca KS |
296 | } |
297 | } | |
298 | fn decode_channel_data(&mut self, dsp: &mut CookDSP, rnd: &mut RND, codebooks: &Codebooks, src: &[u8], buf: &mut [u8], channel: usize) -> DecoderResult<()> { | |
299 | // decrypt | |
300 | for (i, b) in src.iter().enumerate() { | |
301 | buf[i] = b ^ COOK_XOR_KEY[i & 3]; | |
302 | } | |
fa90ccfb | 303 | let mut br = BitReader::new(&buf[..src.len()], BitReaderMode::BE); |
594ca5ca KS |
304 | |
305 | let num_gains = br.read_code(UintCodeType::UnaryOnes)? as usize; | |
306 | validate!(num_gains <= 8); | |
307 | ||
308 | swap(&mut self.gains[channel], &mut self.prev_gains[channel]); | |
69f77596 | 309 | self.block[channel] = [0.0; MAX_SAMPLES * 2]; |
594ca5ca KS |
310 | |
311 | // gains | |
312 | let mut ipos = 0; | |
313 | for _ in 0..num_gains { | |
314 | let idx = br.read(3)? as usize; | |
315 | let val; | |
316 | if br.read_bool()? { | |
317 | val = (br.read(4)? as i32) - 7; | |
318 | } else { | |
319 | val = -1; | |
320 | } | |
321 | validate!(idx >= ipos); | |
322 | while ipos <= idx { | |
323 | self.prev_gains[channel][ipos] = val; | |
324 | ipos += 1; | |
325 | } | |
326 | } | |
327 | while ipos <= 8 { | |
328 | self.prev_gains[channel][ipos] = 0; | |
329 | ipos += 1; | |
330 | } | |
331 | ||
332 | // coupling information | |
333 | if self.mode == Mode::JointStereo { | |
334 | let cstart = COOK_CPL_BAND[self.js_start] as usize; | |
335 | let cend = COOK_CPL_BAND[self.subbands - 1] as usize; | |
336 | if br.read_bool()? { | |
337 | let cb = &codebooks.cpl_cb[(self.js_bits - 2) as usize]; | |
e07387c7 | 338 | for i in cstart..=cend { |
594ca5ca KS |
339 | self.decouple[i] = br.read_cb(cb)? as u8; |
340 | } | |
341 | } else { | |
e07387c7 | 342 | for i in cstart..=cend { |
594ca5ca KS |
343 | self.decouple[i] = br.read(self.js_bits)? as u8; |
344 | } | |
345 | } | |
346 | } | |
347 | ||
348 | // envelope | |
349 | let tot_subbands = self.subbands + self.js_start; | |
350 | self.qindex[0] = (br.read(6)? as i8) - 6; | |
351 | for i in 1..tot_subbands { | |
352 | let mut pos = i; | |
353 | if pos >= self.js_start * 2 { | |
354 | pos -= self.js_start; | |
355 | } else { | |
356 | pos >>= 1; | |
357 | } | |
358 | let ipos = ((pos as i8) - 1).max(0).min(12); | |
359 | let cb = &codebooks.quant_cb[ipos as usize]; | |
360 | self.qindex[i] = (br.read_cb(cb)? as i8) + self.qindex[i - 1] - 12; | |
361 | validate!((self.qindex[i] >= -63) && (self.qindex[i] <= 63)); | |
362 | } | |
363 | let num_vectors = br.read(self.vector_bits)? as usize; | |
364 | self.bitalloc(num_vectors, br.left() as usize); | |
365 | ||
366 | // coefficients | |
69f77596 | 367 | self.block[channel] = [0.0; MAX_SAMPLES * 2]; |
594ca5ca KS |
368 | let mut off = 0; |
369 | for sb in 0..tot_subbands { | |
370 | let mut coef_index: [u8; BAND_SIZE] = [0; BAND_SIZE]; | |
371 | let mut coef_sign: [bool; BAND_SIZE] = [false; BAND_SIZE]; | |
372 | let cat = self.category[sb] as usize; | |
373 | if (cat < NUM_CATEGORIES - 1) && br.left() > 0 { | |
374 | unpack_band(&mut br, codebooks, &mut coef_index, &mut coef_sign, cat)?; | |
375 | } | |
376 | for i in 0..BAND_SIZE { | |
377 | let val; | |
378 | if coef_index[i] == 0 { | |
379 | let v = COOK_DITHER_TAB[cat]; | |
380 | val = if !rnd.get_sign() { v } else { -v }; | |
381 | } else { | |
382 | let v = COOK_QUANT_CENTROID[cat][coef_index[i] as usize]; | |
383 | val = if !coef_sign[i] { v } else { -v }; | |
384 | } | |
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 | } | |
392 | fn decode(&mut self, dsp: &mut CookDSP, rnd: &mut RND, codebooks: &Codebooks, src: &[u8], buf: &mut [u8], abuf: &mut NABufferType) -> DecoderResult<()> { | |
393 | if self.mode == Mode::Stereo { | |
394 | let mut schunk = src.chunks(src.len() / 2); | |
395 | self.decode_channel_data(dsp, rnd, codebooks, schunk.next().unwrap(), buf, 0)?; | |
396 | self.decode_channel_data(dsp, rnd, codebooks, schunk.next().unwrap(), buf, 1)?; | |
397 | } else { | |
398 | self.decode_channel_data(dsp, rnd, codebooks, src, buf, 0)?; | |
399 | } | |
400 | // uncouple joint stereo channels | |
401 | if self.mode == Mode::JointStereo { | |
402 | for i in 0..self.js_start { | |
403 | for j in 0..BAND_SIZE { | |
404 | self.block[1][i * BAND_SIZE + j] = self.block[0][(i * 2 + 1) * BAND_SIZE + j]; | |
405 | self.block[0][i * BAND_SIZE + j] = self.block[0][(i * 2) * BAND_SIZE + j]; | |
406 | } | |
407 | } | |
408 | let scale_idx = (self.js_bits as usize) - 2; | |
409 | let scale_off = (1 << self.js_bits) as usize; | |
410 | for i in self.js_start..self.subbands { | |
411 | let idx = self.decouple[COOK_CPL_BAND[i] as usize] as usize; | |
412 | let doff = i * BAND_SIZE; | |
413 | let soff = (i + self.js_start) * BAND_SIZE; | |
414 | let m1 = COOK_CPL_SCALES[scale_idx][ 1 + idx]; | |
415 | let m2 = COOK_CPL_SCALES[scale_idx][scale_off - 1 - idx]; | |
416 | for j in 0..BAND_SIZE { | |
417 | self.block[0][doff + j] = self.block[0][soff + j] * m1; | |
418 | self.block[1][doff + j] = self.block[0][soff + j] * m2; | |
419 | } | |
420 | } | |
421 | for i in (self.subbands * BAND_SIZE)..MAX_SAMPLES { | |
422 | self.block[0][i] = 0.0; | |
423 | self.block[1][i] = 0.0; | |
424 | } | |
425 | self.gains[1] = self.gains[0]; | |
426 | self.prev_gains[1] = self.prev_gains[0]; | |
427 | } | |
428 | for ch in 0..self.mode.get_channels() { | |
429 | let off = abuf.get_offset(ch + self.start_ch); | |
430 | let mut adata = abuf.get_abuf_f32().unwrap(); | |
1a967e6b | 431 | let output = adata.get_data_mut().unwrap(); |
594ca5ca KS |
432 | let dst = &mut output[off..]; |
433 | ||
434 | dsp.imdct.imdct(&self.block[ch], &mut dsp.out); | |
435 | ||
436 | let prev_gain = dsp.pow_tab[(self.prev_gains[ch][0] + 64) as usize]; | |
437 | let mut cur_gain = 0.0; | |
438 | let mut cur_gain2 = 0.0; | |
439 | let mut gain_idx = 0; | |
440 | let eighthmask = (self.samples >> 3) - 1; | |
441 | for (i, out) in dst.iter_mut().take(self.samples).enumerate() { | |
442 | *out = dsp.out[i + self.samples] * prev_gain * dsp.window[i] | |
443 | - self.delay[ch][i] * dsp.window[self.samples - i - 1]; | |
444 | if (i & eighthmask) == 0 { | |
445 | if (self.gains[ch][gain_idx] == 0) && (self.gains[ch][gain_idx + 1] == 0) { | |
446 | cur_gain = 1.0; | |
447 | cur_gain2 = 1.0; | |
448 | } else { | |
449 | cur_gain = dsp.pow_tab[(self.gains[ch][gain_idx] + 64) as usize]; | |
450 | cur_gain2 = dsp.gain_tab[(self.gains[ch][gain_idx + 1] - self.gains[ch][gain_idx] + 11) as usize]; | |
451 | } | |
452 | gain_idx += 1; | |
453 | } | |
454 | *out *= cur_gain; | |
455 | cur_gain *= cur_gain2; | |
456 | } | |
fa57381e | 457 | self.delay[ch][..self.samples].copy_from_slice(&dsp.out[..self.samples]); |
594ca5ca KS |
458 | } |
459 | Ok(()) | |
460 | } | |
461 | } | |
462 | ||
594ca5ca KS |
463 | fn unpack_band(br: &mut BitReader, codebooks: &Codebooks, coef_index: &mut [u8; BAND_SIZE], coef_sign: &mut [bool; BAND_SIZE], cat: usize) -> DecoderResult<()> { |
464 | let cb = &codebooks.vq_cb[cat]; | |
465 | let group_size = COOK_VQ_GROUP_SIZE[cat]; | |
466 | let mult = COOK_VQ_MULT[cat] + 1; | |
467 | for i in 0..COOK_NUM_VQ_GROUPS[cat] { | |
468 | let ret = br.read_cb(cb); | |
469 | let mut val; | |
470 | if let Ok(v) = ret { | |
471 | val = v as u32; | |
472 | } else { | |
473 | let left = br.left() as u32; | |
474 | br.skip(left)?; | |
475 | break; | |
476 | } | |
477 | let mut nnz = 0; | |
478 | for j in (0..group_size).rev() { | |
479 | let t = (val * COOK_VQ_INV_RADIX[cat]) >> 20; | |
480 | coef_index[i * group_size + j] = (val - t * mult) as u8; | |
481 | if coef_index[i * group_size + j] != 0 { | |
482 | nnz += 1; | |
483 | } | |
484 | val = t; | |
485 | } | |
486 | if (br.left() as usize) < nnz { | |
487 | let left = br.left() as u32; | |
488 | br.skip(left)?; | |
489 | break; | |
490 | } | |
491 | for j in 0..group_size { | |
492 | if coef_index[i * group_size + j] != 0 { | |
493 | coef_sign[i * group_size + j] = br.read_bool()?; | |
494 | } else { | |
495 | coef_sign[i * group_size + j] = false; | |
496 | } | |
497 | } | |
498 | } | |
499 | Ok(()) | |
500 | } | |
501 | ||
502 | struct RND { | |
503 | state: u32, | |
504 | } | |
505 | ||
506 | impl RND { | |
507 | fn new() -> Self { | |
508 | Self { state: 0xC0DECC00 } | |
509 | } | |
510 | fn get_sign(&mut self) -> bool { | |
511 | self.state = (self.state & 0xFFFF).wrapping_mul(36969).wrapping_add(self.state >> 16); | |
512 | (self.state & 0x10000) != 0 | |
513 | } | |
514 | } | |
515 | ||
516 | struct CookDecoder { | |
2422d969 | 517 | info: NACodecInfoRef, |
594ca5ca KS |
518 | chmap: NAChannelMap, |
519 | src: [u8; 65536], | |
520 | num_pairs: usize, | |
521 | pairs: [CookChannelPair; MAX_PAIRS], | |
522 | channels: usize, | |
523 | samples: usize, | |
524 | codebooks: Codebooks, | |
525 | rnd: RND, | |
526 | dsp: CookDSP, | |
527 | } | |
528 | ||
529 | impl CookDecoder { | |
530 | fn new() -> Self { | |
531 | CookDecoder { | |
532 | info: NACodecInfo::new_dummy(), | |
533 | chmap: NAChannelMap::new(), | |
534 | src: [0; 65536], | |
535 | num_pairs: 0, | |
536 | channels: 0, | |
537 | samples: 0, | |
538 | pairs: [CookChannelPair::new(); MAX_PAIRS], | |
539 | codebooks: Codebooks::new(), | |
540 | rnd: RND::new(), | |
541 | dsp: CookDSP::new(1024), | |
542 | } | |
543 | } | |
544 | } | |
545 | ||
546 | impl NADecoder for CookDecoder { | |
01613464 | 547 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
594ca5ca KS |
548 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
549 | let edata = info.get_extradata().unwrap(); | |
550 | validate!(edata.len() >= 4); | |
551 | ||
552 | let mut mr = MemoryReader::new_read(&edata); | |
553 | let mut br = ByteReader::new(&mut mr); | |
554 | let ver = br.peek_u32be()?; | |
555 | ||
556 | let maj_ver = ver >> 24; | |
557 | let mut chmap: u32 = 0; | |
558 | match maj_ver { | |
559 | 1 => { | |
560 | self.num_pairs = 1; | |
561 | self.pairs[0].read_hdr_v1(&mut br)?; | |
562 | self.channels = self.pairs[0].mode.get_channels(); | |
563 | if ainfo.get_channels() == 1 { // forced mono | |
b7eda71d | 564 | self.pairs[0].mode = Mode::Mono; |
594ca5ca KS |
565 | self.channels = 1; |
566 | chmap = 0x4; | |
567 | } else { | |
568 | chmap = 0x3; | |
569 | } | |
570 | }, | |
571 | 2 => { | |
572 | self.num_pairs = (edata.len() - (br.tell() as usize)) / 20; | |
573 | validate!(self.num_pairs <= MAX_PAIRS); | |
574 | let mut start_ch = 0; | |
575 | for i in 0..self.num_pairs { | |
576 | let pair_chmap = self.pairs[i].read_hdr_v2(&mut br)?; | |
577 | self.pairs[i].start_ch = start_ch; | |
578 | validate!((chmap & pair_chmap) == 0); | |
1ef35f7d | 579 | chmap |= pair_chmap; |
594ca5ca KS |
580 | start_ch += self.pairs[i].mode.get_channels(); |
581 | } | |
582 | self.channels = start_ch; | |
583 | }, | |
584 | _ => { return Err(DecoderError::InvalidData); } | |
585 | }; | |
586 | ||
587 | self.samples = self.pairs[0].samples / self.pairs[0].mode.get_channels(); | |
588 | validate!((self.samples >= 16) && (self.samples <= 1024)); | |
589 | if self.samples != self.dsp.size { | |
590 | self.dsp = CookDSP::new(self.samples); | |
591 | } | |
592 | self.chmap = NAChannelMap::from_ms_mapping(chmap); | |
593 | ||
594 | for i in 1..self.num_pairs { | |
595 | validate!((self.pairs[i].samples / self.pairs[i].mode.get_channels()) == self.samples); | |
596 | } | |
597 | ||
598 | let vector_bits = match self.samples { | |
599 | 16 | 32 | 64 | 128 | 256 => 5, | |
600 | 512 => 6, | |
601 | 1024 => 7, | |
602 | _ => unreachable!(), | |
603 | }; | |
604 | for pair in self.pairs.iter_mut() { | |
605 | match pair.mode { | |
606 | Mode::Mono => { | |
607 | pair.vector_bits = 5; | |
608 | }, | |
609 | Mode::Stereo => { | |
610 | pair.vector_bits = 5; | |
611 | pair.samples >>= 1; | |
612 | }, | |
613 | Mode::JointStereo => { | |
614 | pair.vector_bits = vector_bits; | |
615 | pair.samples >>= 1; | |
616 | }, | |
617 | }; | |
618 | } | |
619 | ||
620 | let ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), self.channels as u8, | |
621 | SND_F32P_FORMAT, self.samples); | |
622 | self.info = info.replace_info(NACodecTypeInfo::Audio(ainfo)); | |
623 | ||
624 | Ok(()) | |
625 | } else { | |
626 | Err(DecoderError::InvalidData) | |
627 | } | |
628 | } | |
01613464 | 629 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
594ca5ca KS |
630 | let info = pkt.get_stream().get_info(); |
631 | validate!(info.get_properties().is_audio()); | |
632 | let pktbuf = pkt.get_buffer(); | |
633 | validate!(pktbuf.len() > self.num_pairs * 2); | |
634 | ||
635 | let mut seg_size: [usize; MAX_PAIRS] = [0; MAX_PAIRS]; | |
636 | let mut seg_start: [usize; MAX_PAIRS+1] = [0; MAX_PAIRS+1]; | |
637 | ||
638 | let ainfo = self.info.get_properties().get_audio_info().unwrap(); | |
639 | ||
640 | seg_size[0] = pktbuf.len() - (self.num_pairs - 1); | |
641 | for i in 1..self.num_pairs { | |
642 | seg_size[i] = (pktbuf[pktbuf.len() - self.num_pairs + i] as usize) * 2; | |
643 | validate!(seg_size[i] != 0); | |
644 | let ret = seg_size[0].checked_sub(seg_size[i]); | |
645 | if let Some(val) = ret { | |
646 | seg_size[0] = val; | |
647 | } else { | |
648 | return Err(DecoderError::InvalidData); | |
649 | } | |
650 | } | |
651 | validate!(seg_size[0] != 0); | |
652 | seg_start[0] = 0; | |
653 | for i in 0..self.num_pairs { | |
654 | seg_start[i + 1] = seg_start[i] + seg_size[i]; | |
655 | } | |
656 | ||
657 | let mut abuf = alloc_audio_buffer(ainfo, self.samples, self.chmap.clone())?; | |
658 | ||
659 | for pair in 0..self.num_pairs { | |
660 | 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)?; | |
661 | } | |
662 | ||
663 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.replace_info(NACodecTypeInfo::Audio(ainfo)), abuf); | |
664 | frm.set_keyframe(true); | |
171860fc | 665 | Ok(frm.into_ref()) |
594ca5ca | 666 | } |
f9be4e75 KS |
667 | fn flush(&mut self) { |
668 | for pair in self.pairs.iter_mut() { | |
669 | pair.delay = [[0.0; MAX_SAMPLES]; 2]; | |
670 | } | |
671 | } | |
594ca5ca KS |
672 | } |
673 | ||
7d57ae2f KS |
674 | impl NAOptionHandler for CookDecoder { |
675 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
676 | fn set_options(&mut self, _options: &[NAOption]) { } | |
677 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
678 | } | |
679 | ||
08a1fab7 | 680 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
594ca5ca KS |
681 | Box::new(CookDecoder::new()) |
682 | } | |
683 | ||
684 | #[cfg(test)] | |
685 | mod test { | |
3167c45c KS |
686 | use nihav_core::codecs::RegisteredDecoders; |
687 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 688 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 689 | use crate::realmedia_register_all_decoders; |
e64739f8 | 690 | use crate::realmedia_register_all_demuxers; |
594ca5ca KS |
691 | #[test] |
692 | fn test_cook() { | |
3167c45c KS |
693 | let mut dmx_reg = RegisteredDemuxers::new(); |
694 | realmedia_register_all_demuxers(&mut dmx_reg); | |
695 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 696 | realmedia_register_all_decoders(&mut dec_reg); |
3167c45c | 697 | |
594ca5ca | 698 | // let file = "assets/RV/rv30_weighted_mc.rm"; |
886cde48 | 699 | // sample: https://samples.mplayerhq.hu/real/AC-cook/cook_5.1/multichannel.rma |
594ca5ca | 700 | let file = "assets/RV/multichannel.rma"; |
5580b11b | 701 | test_decode_audio("realmedia", file, Some(2000), None/*Some("cook")*/, &dmx_reg, &dec_reg); |
594ca5ca KS |
702 | } |
703 | } |