1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_core::io::bitwriter::*;
4 use nihav_codec_support::dsp::fft::*;
5 use super::cookdata::*;
11 const MAX_FRAME_SIZE: usize = 1024;
13 const EPS: f32 = 1.0e-6;
15 fn get_block_size(srate: u32) -> usize {
24 fn clip_cat(&self) -> usize;
27 impl ClipCat for i32 {
28 fn clip_cat(&self) -> usize { ((*self).max(0) as usize).min(NUM_CATEGORIES - 1) }
31 fn bitalloc(samples: usize, bits: usize, vector_bits: u8, total_subbands: usize, qindex: &[i8], category: &mut [u8], cat_index: &mut [u8]) {
32 let avail_bits = (if bits > samples { samples + ((bits - samples) * 5) / 8 } else { bits }) as i32;
34 let mut bias: i32 = -32;
37 for j in 0..total_subbands {
38 let idx = ((32 >> i) + bias - (qindex[j] as i32)) / 2;
39 sum += COOK_EXP_BITS[idx.clip_cat()];
41 if sum >= (avail_bits - 32) {
46 let mut exp_index1: [usize; MAX_SUBBANDS * 2] = [0; MAX_SUBBANDS * 2];
47 let mut exp_index2: [usize; MAX_SUBBANDS * 2] = [0; MAX_SUBBANDS * 2];
49 for i in 0..total_subbands {
50 let idx = ((bias - (qindex[i] as i32)) / 2).clip_cat();
51 sum += COOK_EXP_BITS[idx];
58 let mut tcat: [usize; 128*2] = [0; 128*2];
59 let mut tcat_idx1 = 128;
60 let mut tcat_idx2 = 128;
61 for _ in 1..(1 << vector_bits) {
62 if tbias1 + tbias2 > avail_bits * 2 {
63 let mut max = -999999;
64 let mut idx = total_subbands + 1;
65 for j in 0..total_subbands {
66 if exp_index1[j] >= (NUM_CATEGORIES - 1) { continue; }
67 let t = -2 * (exp_index1[j] as i32) - (qindex[j] as i32) + bias;
73 if idx >= total_subbands { break; }
74 tcat[tcat_idx1] = idx;
76 tbias1 -= COOK_EXP_BITS[exp_index1[idx]] - COOK_EXP_BITS[exp_index1[idx] + 1];
80 let mut idx = total_subbands + 1;
81 for j in 0..total_subbands {
82 if exp_index2[j] == 0 { continue; }
83 let t = -2 * (exp_index2[j] as i32) - (qindex[j] as i32) + bias;
89 if idx >= total_subbands { break; }
91 tcat[tcat_idx2] = idx;
92 tbias2 -= COOK_EXP_BITS[exp_index2[idx]] - COOK_EXP_BITS[exp_index2[idx] - 1];
96 for i in 0..total_subbands {
97 category[i] = exp_index2[i] as u8;
99 for el in cat_index.iter_mut() {
102 for (dst, &src) in cat_index.iter_mut().zip(tcat[tcat_idx2..tcat_idx1].iter()) {
107 fn map_coef(val: f32, centroids: &[f32]) -> usize {
108 if val < centroids[1] * 0.5 {
111 let len = centroids.len();
112 if val < centroids[len - 1] {
113 for (i, pair) in centroids.windows(2).enumerate().skip(1) {
114 if val <= (pair[0] + pair[1]) * 0.5 {
123 fn couple_bands(left: &[f32], right: &[f32], dst: &mut [f32], cpl_scales: &[f32]) -> u8 {
124 let nrg0 = left.iter().fold(0.0f32, |acc, &v| acc + v * v);
125 let nrg1 = right.iter().fold(0.0f32, |acc, &v| acc + v * v);
126 let last_idx = cpl_scales.len() - 3;
127 match (nrg0 > EPS, nrg1 > EPS) {
129 let tgt_scale0 = (nrg0 / (nrg0 + nrg1)).sqrt();
130 let tgt_scale1 = (nrg1 / (nrg0 + nrg1)).sqrt();
132 let mut best_dist = 42.0;
133 let mut best_idx = 0;
134 for i in 0..=last_idx {
135 let scale0 = cpl_scales[i];
136 let scale1 = cpl_scales[cpl_scales.len() - 1 - i];
137 let dist = (scale0 - tgt_scale0).abs() + (scale1 - tgt_scale1).abs();
138 if dist < best_dist {
143 let scale_l = cpl_scales[best_idx];
144 let scale_r = cpl_scales[cpl_scales.len() - 1 - best_idx];
147 dst.copy_from_slice(left);
149 for (dst, (&ll, &rr)) in dst.iter_mut().zip(left.iter().zip(right.iter())) {
150 *dst = (ll / scale_l + rr / scale_r) * 0.5;
156 dst.copy_from_slice(right);
160 dst.copy_from_slice(left);
164 for (dst, (&ll, &rr)) in dst.iter_mut().zip(left.iter().zip(right.iter())) {
165 *dst = (ll + rr) * std::f32::consts::FRAC_1_SQRT_2;
167 (cpl_scales.len() / 2) as u8
172 #[derive(Clone,Copy,Default)]
173 struct PackedCoeffs {
184 fn pack(&mut self, coeffs: &[f32], cat: usize) -> u16 {
188 if cat >= COOK_NUM_VQ_GROUPS.len() {
193 let group_size = COOK_VQ_GROUP_SIZE[cat];
194 let multiplier = COOK_VQ_MULT[cat] as usize + 1;
195 let (code_words, code_bits) = match cat {
196 0 => (&COOK_VQ0_CODES[..], &COOK_VQ0_BITS[..]),
197 1 => (&COOK_VQ1_CODES[..], &COOK_VQ1_BITS[..]),
198 2 => (&COOK_VQ2_CODES[..], &COOK_VQ2_BITS[..]),
199 3 => (&COOK_VQ3_CODES[..], &COOK_VQ3_BITS[..]),
200 4 => (&COOK_VQ4_CODES[..], &COOK_VQ4_BITS[..]),
201 5 => (&COOK_VQ5_CODES[..], &COOK_VQ5_BITS[..]),
202 6 => (&COOK_VQ6_CODES[..], &COOK_VQ6_BITS[..]),
205 let centroids = &COOK_QUANT_CENTROID[cat][..multiplier];
206 self.num = COOK_NUM_VQ_GROUPS[cat];
208 for (group_no, group) in coeffs.chunks(group_size).enumerate() {
210 let mut cvals = [0; 5];
211 let mut sarr = [0; 5];
212 for ((dval, sign), &el) in cvals.iter_mut().zip(sarr.iter_mut()).zip(group.iter()) {
213 let cur_val = map_coef(el.abs(), centroids);
215 *sign = (el < 0.0) as u16;
216 cw = cw * multiplier + cur_val;
218 while cw >= code_bits.len() || code_bits[cw] == 0 {
220 let mut max_val = cvals[0];
221 for (i, &val) in cvals.iter().enumerate().skip(1) {
229 for &dval in cvals.iter().take(group_size) {
230 cw = cw * multiplier + dval;
235 for (&sign, &val) in sarr.iter().zip(cvals.iter()) {
237 signs = (signs << 1) | sign;
242 self.cw [group_no] = code_words[cw];
243 self.bits [group_no] = code_bits[cw];
244 self.signs[group_no] = signs;
245 self.nnz [group_no] = nnz;
246 self.nbits += u16::from(code_bits[cw]) + u16::from(nnz);
250 fn write(&self, bw: &mut BitWriter, mut bits_left: u16) {
251 for ((&cw, &bits), (&signs, &nnz)) in
252 self.cw.iter().zip(self.bits.iter()).zip(
253 self.signs.iter().zip(self.nnz.iter())).take(self.num) {
254 let cur_bits = u16::from(bits + nnz);
255 if cur_bits > bits_left {
258 bits_left -= cur_bits;
259 bw.write(cw.into(), bits);
261 bw.write(signs.into(), nnz);
268 bands: [PackedCoeffs; MAX_SUBBANDS * 2],
271 impl Default for TempData {
272 fn default() -> Self {
274 bands: [PackedCoeffs::default(); MAX_SUBBANDS * 2],
279 struct ChannelDataParams<'a> {
282 hpow_tab: &'a [f32; 128],
289 struct CookChannelPair {
290 br_info: &'static BitrateParams,
291 delay: [[f32; MAX_FRAME_SIZE]; 2],
294 fn calc_qindex(nrg: f32) -> i8 {
295 let mut nrg0 = nrg * 0.05;
297 nrg0 *= std::f32::consts::FRAC_1_SQRT_2;
299 nrg0 *= std::f32::consts::SQRT_2;
301 nrg0.log2().max(-31.0).min(47.0) as i8
304 impl CookChannelPair {
305 fn new(br_info: &'static BitrateParams) -> Self {
308 delay: [[0.0; MAX_FRAME_SIZE]; 2],
311 fn encode_bands(params: ChannelDataParams, dbuf: Vec<u8>, coeffs: &mut [f32], total_bands: usize, tmp: &mut TempData) -> EncoderResult<Vec<u8>> {
312 let output_start = dbuf.len();
313 let mut bw = BitWriter::new(dbuf, BitWriterMode::BE);
314 let data_end = bw.tell() + params.frame_size;
316 let mut qindex = [0i8; MAX_SUBBANDS * 2];
317 for (qscale, band) in qindex.iter_mut().zip(coeffs.chunks(BAND_SIZE)).take(total_bands) {
318 let nrg = band.iter().fold(0.0f32, |acc, &v| acc + v * v);
319 *qscale = calc_qindex(nrg);
321 qindex[0] = qindex[0].max(-6);
323 bw.write0(); // no gains
326 if params.js_bits > 0 {
327 let (cpl_cb_codes, cpl_cb_bits) = match params.js_bits {
328 2 => (&COOK_CPL_2BITS_CODES[..], &COOK_CPL_2BITS_BITS[..]),
329 3 => (&COOK_CPL_3BITS_CODES[..], &COOK_CPL_3BITS_BITS[..]),
330 4 => (&COOK_CPL_4BITS_CODES[..], &COOK_CPL_4BITS_BITS[..]),
331 5 => (&COOK_CPL_5BITS_CODES[..], &COOK_CPL_5BITS_BITS[..]),
332 6 => (&COOK_CPL_6BITS_CODES[..], &COOK_CPL_6BITS_BITS[..]),
335 let mut bit_size = 0;
336 let mut raw_bit_size = 0;
337 for &el in params.coupling.iter() {
338 bit_size += cpl_cb_bits[usize::from(el)];
339 raw_bit_size += params.js_bits;
341 if bit_size < raw_bit_size {
343 for &el in params.coupling.iter() {
344 let idx = usize::from(el);
345 bw.write(cpl_cb_codes[idx].into(), cpl_cb_bits[idx]);
349 for &el in params.coupling.iter() {
350 bw.write(u32::from(el), params.js_bits);
355 let mut last_q = qindex[0];
356 bw.write((qindex[0] + 6) as u32, 6);
357 if params.js_bits == 0 {
358 for (i, qscale) in qindex[..total_bands].iter_mut().enumerate().skip(1) {
359 let cb_idx = (i - 1).min(12);
360 let diff = (*qscale - last_q).max(-12).min(11);
361 *qscale = last_q + diff;
364 let idx2 = (diff + 12) as usize;
365 bw.write(COOK_QUANT_CODES[cb_idx][idx2].into(), COOK_QUANT_BITS[cb_idx][idx2]);
368 for (i, qscale) in qindex[..total_bands].iter_mut().enumerate().skip(1) {
369 let band_no = if i < params.js_start * 2 { i >> 1 } else { i - params.js_start };
370 let cb_idx = band_no.saturating_sub(1).min(12);
371 let diff = (*qscale - last_q).max(-12).min(11);
372 *qscale = last_q + diff;
375 let idx2 = (diff + 12) as usize;
376 bw.write(COOK_QUANT_CODES[cb_idx][idx2].into(), COOK_QUANT_BITS[cb_idx][idx2]);
380 let mut category = [0; MAX_SUBBANDS * 2];
381 let mut cat_index = [0; 127];
382 let bits_avail = data_end - bw.tell() - usize::from(params.vector_bits);
384 bitalloc(params.size, bits_avail, params.vector_bits, total_bands, &qindex, &mut category, &mut cat_index);
386 let mut tot_bits = 0;
387 for ((band, packed), (&qindex, &cat)) in
388 coeffs.chunks_exact_mut(BAND_SIZE).zip(tmp.bands.iter_mut())
389 .zip(qindex.iter().zip(category.iter())).take(total_bands) {
390 for coef in band.iter_mut() {
391 *coef *= params.hpow_tab[(64 - qindex) as usize];
393 tot_bits += packed.pack(band, cat.into());
396 let mut bits_left = bits_avail as u16;
397 let mut bands_corrected = 0;
398 let max_corr_bands = (1 << params.vector_bits) - 1;
399 for &index in cat_index.iter() {
400 if bands_corrected >= max_corr_bands || tot_bits <= bits_left || index == 255 {
403 let index = usize::from(index);
404 let pband = &mut tmp.bands[index];
405 let band_coeffs = &coeffs[index * BAND_SIZE..][..BAND_SIZE];
406 let new_cat = (pband.cat + 1).min(NUM_CATEGORIES - 1);
407 tot_bits -= pband.nbits;
408 pband.pack(band_coeffs, new_cat);
409 tot_bits += pband.nbits;
410 bands_corrected += 1;
413 bw.write(bands_corrected, params.vector_bits);
414 for packed in tmp.bands.iter().take(total_bands) {
415 packed.write(&mut bw, bits_left);
416 bits_left = bits_left.saturating_sub(packed.nbits);
422 pad(&mut bw, data_end);
424 let mut dbuf = bw.end();
425 for (i, el) in dbuf[output_start..].iter_mut().enumerate() {
426 *el ^= COOK_XOR_KEY[i & 3];
431 fn encode_mono(&mut self, dbuf: Vec<u8>, dsp: &mut CookDSP, src: &[f32], ch_no: usize, tmp: &mut TempData) -> EncoderResult<Vec<u8>> {
432 dsp.mdct(&mut self.delay[ch_no], src, true);
433 let coeffs = &mut dsp.coeffs;
435 let frame_size = (self.br_info.frame_bits / u32::from(self.br_info.channels)) as usize;
436 let total_bands: usize = self.br_info.max_subbands.into();
438 let params = ChannelDataParams {
440 hpow_tab: &dsp.hpow_tab,
447 Self::encode_bands(params, dbuf, coeffs, total_bands, tmp)
449 fn encode_jstereo(&mut self, dbuf: Vec<u8>, dsp: &mut CookDSP, l_ch: &[f32], r_ch: &[f32], tmp: &mut TempData) -> EncoderResult<Vec<u8>> {
450 let frame_size = self.br_info.frame_bits as usize;
451 let low_bands = usize::from(self.br_info.js_start);
452 let total_bands = usize::from(self.br_info.max_subbands) + low_bands;
454 dsp.mdct(&mut self.delay[0], l_ch, true);
455 dsp.mdct(&mut self.delay[1], r_ch, false);
457 let mut decouple = [0; 20];
458 let cpl_scales = COOK_CPL_SCALES[usize::from(self.br_info.js_bits - 2)];
459 let cpl_start_band = COOK_CPL_BAND[usize::from(self.br_info.js_start)] as usize;
460 let cpl_end_band = COOK_CPL_BAND[usize::from(self.br_info.max_subbands) - 1] as usize;
462 let coeffs = &mut dsp.coeffs;
463 let coeffs2 = &mut dsp.coeffs2;
464 let coupled = &mut dsp.coupled;
465 for (dst, (src0, src1)) in coupled.chunks_exact_mut(BAND_SIZE * 2).zip(coeffs.chunks(BAND_SIZE).zip(coeffs2.chunks(BAND_SIZE))).take(low_bands) {
466 let (dst0, dst1) = dst.split_at_mut(BAND_SIZE);
467 dst0.copy_from_slice(src0);
468 dst1.copy_from_slice(src1);
470 for el in coupled[total_bands * BAND_SIZE..].iter_mut() {
474 let mut band = low_bands;
475 let mut start_band = band;
476 let mut cpl_band = cpl_start_band;
477 let mut last_cpl_band = cpl_band;
478 let end_band = usize::from(self.br_info.max_subbands);
479 while band < end_band {
480 cpl_band = usize::from(COOK_CPL_BAND[band]);
481 if cpl_band != last_cpl_band {
482 let length = (band - start_band) * BAND_SIZE;
483 decouple[last_cpl_band] = couple_bands(&coeffs[start_band * BAND_SIZE..][..length],
484 &coeffs2[start_band * BAND_SIZE..][..length],
485 &mut coupled[(start_band + low_bands) * BAND_SIZE..][..length],
487 last_cpl_band = cpl_band;
492 if band != start_band {
493 let length = (band - start_band) * BAND_SIZE;
494 decouple[last_cpl_band] = couple_bands(&coeffs[start_band * BAND_SIZE..][..length],
495 &coeffs2[start_band * BAND_SIZE..][..length],
496 &mut coupled[(start_band + low_bands) * BAND_SIZE..][..length],
500 let vector_bits = match dsp.size {
505 let params = ChannelDataParams {
507 hpow_tab: &dsp.hpow_tab,
508 coupling: &decouple[cpl_start_band..=cpl_end_band],
509 js_bits: self.br_info.js_bits,
510 js_start: self.br_info.js_start.into(),
515 Self::encode_bands(params, dbuf, coupled, total_bands, tmp)
519 fn pad(bw: &mut BitWriter, data_end: usize) {
520 while (bw.tell() & 7) != 0 {
523 while bw.tell() + 32 <= data_end {
526 while bw.tell() + 8 <= data_end {
531 table: Vec<FFTComplex>,
532 tmp: Vec<FFTComplex>,
538 pub fn new(size: usize) -> Self {
539 let fft = FFTBuilder::new_fft(size / 4, false);
540 let mut table = Vec::with_capacity(size / 4);
541 let factor = std::f32::consts::PI * 2.0 / (size as f32);
542 for i in 0..(size / 4) {
543 let val = factor * ((i as f32) + 1.0 / 8.0);
544 table.push(FFTComplex::exp(val));
548 tmp: vec![FFTC_ZERO; size / 4],
553 pub fn mdct(&mut self, src: &[f32], dst: &mut [f32]) {
554 let size1_8 = self.size / 8;
555 let size1_4 = self.size / 4;
556 let size1_2 = self.size / 2;
557 let size3_4 = size1_4 * 3;
559 for i in 0..size1_8 {
560 let a0 = FFTComplex{re: -src[2 * i + size3_4] - src[size3_4 - 1 - 2 * i],
561 im: -src[size1_4 + 2 * i] + src[size1_4 - 1 - 2 * i]};
562 let t0 = !self.table[i];
563 let a1 = FFTComplex{re: src[2 * i] - src[size1_2 - 1 - 2 * i],
564 im: -src[size1_2 + 2 * i] - src[self.size - 1 - 2 * i]};
565 let t1 = !self.table[size1_8 + i];
566 self.tmp[i] = a0 * t0;
567 self.tmp[i + size1_8] = a1 * t1;
569 self.fft.do_fft_inplace(&mut self.tmp);
571 for i in 0..size1_8 {
572 let a0 = self.tmp[size1_8 - 1 - i] * !self.table[size1_8 - 1 - i].rotate();
573 let a1 = self.tmp[size1_8 + i] * !self.table[size1_8 + i].rotate();
574 dst[size1_4 - 2 - i * 2] = a0.im;
575 dst[size1_4 - 1 - i * 2] = a1.re;
576 dst[size1_4 + i * 2] = a1.im;
577 dst[size1_4 + 1 + i * 2] = a0.re;
586 tmp: [f32; MAX_FRAME_SIZE * 2],
587 window: [f32; MAX_FRAME_SIZE * 2],
589 hpow_tab: [f32; 128],
592 coeffs: [f32; MAX_FRAME_SIZE],
593 coeffs2: [f32; MAX_FRAME_SIZE],
594 coupled: [f32; MAX_FRAME_SIZE * 2],
598 fn init(&mut self, frame_size: usize) {
599 if self.size == frame_size {
602 self.size = frame_size;
603 self.mdct = MDCT::new(self.size * 2);
605 let fsamples = self.size as f32;
606 let factor = std::f32::consts::PI / (2.0 * fsamples);
607 let scale = fsamples;
608 for (k, dst) in self.window[..self.size * 2].iter_mut().enumerate() {
609 *dst = (factor * ((k as f32) + 0.5)).sin() * scale;
612 for (dst, &pow_val) in self.gain_tab.iter_mut().zip(self.pow_tab[53..].iter()) {
613 *dst = pow_val.powf(8.0 / fsamples);
616 fn mdct(&mut self, delay: &mut [f32], src: &[f32], mono: bool) {
617 let (w0, w1) = self.window[..self.size * 2].split_at(self.size);
618 let (d0, d1) = self.tmp[..self.size * 2].split_at_mut(self.size);
620 for (dst, (&src, &win)) in d1.iter_mut().zip(delay.iter().zip(w0.iter()).rev()) {
623 for (dst, (&src, &win)) in d0.iter_mut().zip(src.iter().zip(w1.iter()).rev()) {
626 self.mdct.mdct(&self.tmp, if mono { &mut self.coeffs } else { &mut self.coeffs2 });
628 delay[..self.size].copy_from_slice(&src[..self.size]);
632 impl Default for CookDSP {
633 fn default() -> Self {
634 let mut pow_tab: [f32; 128] = [0.0; 128];
635 let mut hpow_tab: [f32; 128] = [0.0; 128];
637 pow_tab[i] = 2.0f32.powf((i as f32) - 64.0);
638 hpow_tab[i] = 2.0f32.powf(((i as f32) - 64.0) * 0.5);
643 tmp: [0.0; MAX_FRAME_SIZE * 2],
644 window: [0.0; MAX_FRAME_SIZE * 2],
648 coeffs: [0.0; MAX_FRAME_SIZE],
649 coeffs2: [0.0; MAX_FRAME_SIZE],
650 coupled: [0.0; MAX_FRAME_SIZE * 2],
657 stream: Option<NAStreamRef>,
662 samples: Vec<Vec<f32>>,
673 pairs: Vec<CookChannelPair>,
678 fn new() -> Self { Self::default() }
679 fn encode_packet(&mut self) -> EncoderResult<NAPacket> {
680 if self.rd_pos == self.nframes {
681 let mut start = self.wr_pos * self.frm_size;
682 let mut dbuf = Vec::with_capacity(self.tgt_size * self.frm_per_blk);
683 for _ in 0..self.frm_per_blk {
684 let mut channels = self.samples.iter();
686 for ch_pair in self.pairs.iter_mut() {
687 if ch_pair.br_info.channels == 1 {
688 let ch = channels.next().unwrap();
689 dbuf = ch_pair.encode_mono(dbuf, &mut self.dsp, &ch[start..][..self.frm_size], 0, &mut self.tmp)?;
691 let l_ch = channels.next().unwrap();
692 let r_ch = channels.next().unwrap();
693 if ch_pair.br_info.js_bits == 0 {
694 dbuf = ch_pair.encode_mono(dbuf, &mut self.dsp, &l_ch[start..][..self.frm_size], 0, &mut self.tmp)?;
695 dbuf = ch_pair.encode_mono(dbuf, &mut self.dsp, &r_ch[start..][..self.frm_size], 1, &mut self.tmp)?;
697 dbuf = ch_pair.encode_jstereo(dbuf, &mut self.dsp, &l_ch[start..][..self.frm_size], &r_ch[start..][..self.frm_size], &mut self.tmp)?;
702 start += self.frm_size;
705 let first = self.wr_pos == 0;
707 self.wr_pos += self.frm_per_blk;
708 if self.wr_pos == self.nframes {
713 let stream = self.stream.clone().unwrap();
714 let (tb_num, tb_den) = stream.get_timebase();
715 let ts = NATimeInfo::new(Some(self.apts), None, Some(1), tb_num, tb_den);
716 self.apts += self.frm_per_blk as u64;
717 Ok(NAPacket::new(self.stream.clone().unwrap(), ts, first, dbuf))
719 Err(EncoderError::TryAgain)
724 impl NAEncoder for CookEncoder {
725 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
726 match encinfo.format {
727 NACodecTypeInfo::None => {
728 Ok(EncodeParameters {
729 format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 1, SND_F32P_FORMAT, 512)),
730 ..Default::default() })
732 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
733 NACodecTypeInfo::Audio(ainfo) => {
735 let mut outinfo = ainfo;
736 outinfo.format = SND_F32P_FORMAT;
737 outinfo.sample_rate = match ainfo.sample_rate {
739 8001..=11025 => 11025,
740 11026..=22050 => 22050,
743 if !matches!(outinfo.channels, 1 | 2) && (outinfo.sample_rate != 44100 || !matches!(outinfo.channels, 4 | 5)) {
744 outinfo.channels = 2;
746 outinfo.block_len = get_block_size(outinfo.sample_rate);
747 let mut ofmt = *encinfo;
748 ofmt.format = NACodecTypeInfo::Audio(outinfo);
751 let flavour = &COOK_FLAVOURS[self.flavour];
752 let blk_len = match flavour.sample_rate {
757 let newinfo = NAAudioInfo::new(flavour.sample_rate, flavour.channels, SND_F32P_FORMAT, blk_len);
758 let ofmt = EncodeParameters {
759 format: NACodecTypeInfo::Audio(newinfo),
760 tb_num: blk_len as u32,
761 tb_den: flavour.sample_rate,
762 bitrate: u32::from(flavour.bitrate) * 1000,
771 fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
772 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
773 match encinfo.format {
774 NACodecTypeInfo::None => Err(EncoderError::FormatError),
775 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
776 NACodecTypeInfo::Audio(ainfo) => {
777 if ainfo.format != SND_F32P_FORMAT || !matches!(ainfo.sample_rate, 8000 | 11025 | 22050 | 44100) {
778 return Err(EncoderError::FormatError);
780 let blk_size = get_block_size(ainfo.sample_rate);
781 if ainfo.block_len != blk_size {
782 return Err(EncoderError::FormatError);
785 let bitrate = if encinfo.bitrate > 0 { Some(encinfo.bitrate / 1000) } else { None };
787 let flavours = if self.g8_only { &COOK_FLAVOURS[..RM8_AUDIO] } else { COOK_FLAVOURS };
788 let mut cand_id = None;
789 for (i, flavour) in flavours.iter().enumerate().rev() {
790 if flavour.sample_rate == ainfo.sample_rate && flavour.channels == ainfo.channels {
791 if let Some(target) = bitrate {
792 if target <= flavour.bitrate.into() {
794 if target == flavour.bitrate.into() {
805 if let Some(id) = cand_id {
808 return Err(EncoderError::FormatError);
811 let flavour = &COOK_FLAVOURS[self.flavour];
812 self.nframes = flavour.frames_per_blk * flavour.factor;
813 self.frm_per_blk = flavour.frames_per_blk;
814 self.samples.clear();
815 self.frm_size = blk_size;
816 for _ in 0..flavour.channels {
817 self.samples.push(vec![0.0; self.nframes * self.frm_size]);
819 self.dsp.init(self.frm_size);
822 for br_info in flavour.br_infos() {
823 self.pairs.push(CookChannelPair::new(br_info));
827 for br_info in flavour.br_infos() {
828 self.tgt_size += br_info.frame_bits as usize / 8;
831 let mut edata = Vec::new();
832 let mut gw = GrowableMemoryWriter::new_write(&mut edata);
833 let mut bw = ByteWriter::new(&mut gw);
834 if flavour.channels <= 2 {
835 let br_info = &BITRATE_PARAMS[flavour.br_ids[0]];
836 let ch_mode = if br_info.channels == 1 {
838 } else if br_info.js_bits == 0 {
843 bw.write_u32be((1 << 24) | ch_mode)?;
844 bw.write_u16be((self.frm_size as u16) * u16::from(br_info.channels))?;
845 bw.write_u16be(br_info.max_subbands.into())?;
847 bw.write_u32be(0)?; // delay
848 bw.write_u16be(br_info.js_start.into())?;
849 bw.write_u16be(br_info.js_bits.into())?;
852 let chmap: &[u32] = match flavour.channels {
854 2 => &[ 0x03 ], // L,R
855 5 => &[ 0x03, 0x04, 0x30 ], // L,R C Ls,Rs
856 6 => &[ 0x03, 0x04, 0x08, 0x30 ], // L,R C LFE Ls,Rs
859 for (br_info, &channel_map) in flavour.br_infos().zip(chmap.iter()) {
860 bw.write_u32be(2 << 24)?;
861 bw.write_u16be((self.frm_size as u16) * u16::from(br_info.channels))?;
862 bw.write_u16be(br_info.max_subbands.into())?;
863 bw.write_u32be(0)?; // delay
864 bw.write_u16be(br_info.js_start.into())?;
865 bw.write_u16be(br_info.js_bits.into())?;
866 bw.write_u32be(channel_map)?;
870 let soniton = NASoniton::new(16, 0);
871 let out_ainfo = NAAudioInfo::new(ainfo.sample_rate, ainfo.channels, soniton, self.tgt_size);
872 let info = NACodecInfo::new("cook", NACodecTypeInfo::Audio(out_ainfo), Some(edata));
873 let mut stream = NAStream::new(StreamType::Audio, stream_id, info, blk_size as u32, ainfo.sample_rate, 0);
874 stream.set_num(stream_id as usize);
875 let stream = stream.into_ref();
877 self.stream = Some(stream.clone());
885 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
886 if let Some(ref abuf) = frm.get_buffer().get_abuf_f32() {
887 if self.rd_pos == self.nframes {
888 return Err(EncoderError::TryAgain);
890 let stride = abuf.get_stride();
891 let src = abuf.get_data();
892 let start = self.rd_pos * self.frm_size;
894 for (dst, src) in self.samples.iter_mut().zip(src.chunks(stride)) {
895 dst[start..][..self.frm_size].copy_from_slice(&src[..self.frm_size]);
901 Err(EncoderError::InvalidParameters)
904 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
905 if let Ok(pkt) = self.encode_packet() {
911 fn flush(&mut self) -> EncoderResult<()> {
912 if self.wr_pos != 0 {
913 let start = self.wr_pos * self.frm_size;
914 for channel in self.samples.iter_mut() {
915 for el in channel[start..].iter_mut() {
919 self.wr_pos = self.nframes;
925 const FLAVOUR_OPTION: &str = "flavor";
926 const G8_ONLY_OPTION: &str = "g8_only";
928 const ENCODER_OPTS: &[NAOptionDefinition] = &[
930 name: FLAVOUR_OPTION, description: "Codec-specific profile (0..32, -1 = auto)",
931 opt_type: NAOptionDefinitionType::Int(Some(-1), Some((COOK_FLAVOURS.len() - 1) as i64)) },
933 name: G8_ONLY_OPTION, description: "Force formats present in RealMedia G8",
934 opt_type: NAOptionDefinitionType::Bool },
937 impl NAOptionHandler for CookEncoder {
938 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
939 fn set_options(&mut self, options: &[NAOption]) {
940 for option in options.iter() {
941 for opt_def in ENCODER_OPTS.iter() {
942 if opt_def.check(option).is_ok() {
945 if let NAValue::Int(val) = option.value {
947 self.flavour = val as usize;
948 self.force_flv = true;
950 self.force_flv = false;
955 if let NAValue::Bool(val) = option.value {
965 fn query_option_value(&self, name: &str) -> Option<NAValue> {
967 FLAVOUR_OPTION => Some(NAValue::Int(self.flavour as i64)),
968 G8_ONLY_OPTION => Some(NAValue::Bool(self.g8_only)),
974 pub fn get_encoder() -> Box<dyn NAEncoder + Send> { Box::new(CookEncoder::new()) }
980 frames_per_blk: usize,
986 fn br_infos(&self) -> BitrateParamsIterator {
987 BitrateParamsIterator::new(self.br_ids, self.channels)
991 struct BitrateParamsIterator {
997 impl BitrateParamsIterator {
998 fn new(ids: [usize; 4], chans: u8) -> Self {
1002 len: usize::from((chans + 1) / 2)
1007 impl Iterator for BitrateParamsIterator {
1008 type Item = &'static BitrateParams;
1009 fn next(&mut self) -> Option<Self::Item> {
1010 if self.cur < self.len {
1011 let ret = &BITRATE_PARAMS[self.ids[self.cur]];
1020 macro_rules! flavour_desc {
1021 ($srate:expr, $ch:expr, $br:expr, $fpb:expr, $factor:expr, $br_ids:expr) => {
1023 sample_rate: $srate,
1026 frames_per_blk: $fpb,
1033 const RM8_AUDIO: usize = 17; // newer variants that use joint-stereo coding and support multichannel
1034 const COOK_FLAVOURS: &[FlavourInfo] = &[
1035 flavour_desc!( 8000, 1, 8, 9, 8, [ 0, 0, 0, 0]),
1036 flavour_desc!(11025, 1, 11, 11, 8, [ 1, 0, 0, 0]),
1037 flavour_desc!(22050, 1, 16, 12, 8, [ 2, 0, 0, 0]),
1038 flavour_desc!(22050, 1, 20, 10, 9, [ 3, 0, 0, 0]),
1039 flavour_desc!(44100, 1, 32, 7, 14, [ 4, 0, 0, 0]),
1040 flavour_desc!(44100, 1, 44, 5, 16, [ 5, 0, 0, 0]),
1041 flavour_desc!(44100, 1, 64, 4, 20, [ 6, 0, 0, 0]),
1042 flavour_desc!(22050, 1, 32, 6, 16, [ 7, 0, 0, 0]),
1043 flavour_desc!( 8000, 1, 6, 12, 6, [ 8, 0, 0, 0]),
1044 flavour_desc!(11025, 2, 19, 10, 10, [ 9, 0, 0, 0]),
1045 flavour_desc!(22050, 2, 32, 6, 14, [10, 0, 0, 0]),
1046 flavour_desc!(22050, 2, 44, 5, 16, [11, 0, 0, 0]),
1047 flavour_desc!(44100, 2, 64, 4, 20, [12, 0, 0, 0]),
1048 flavour_desc!(44100, 2, 95, 3, 30, [13, 0, 0, 0]),
1049 flavour_desc!(44100, 1, 64, 4, 20, [14, 0, 0, 0]),
1050 flavour_desc!(44100, 1, 20, 10, 9, [15, 0, 0, 0]),
1051 flavour_desc!(44100, 1, 32, 7, 14, [16, 0, 0, 0]),
1052 flavour_desc!(22050, 2, 16, 10, 10, [17, 0, 0, 0]),
1053 flavour_desc!(22050, 2, 20, 10, 10, [18, 0, 0, 0]),
1054 flavour_desc!(22050, 2, 20, 10, 10, [19, 0, 0, 0]),
1055 flavour_desc!(22050, 2, 32, 5, 16, [20, 0, 0, 0]),
1056 flavour_desc!(44100, 2, 32, 5, 16, [21, 0, 0, 0]),
1057 flavour_desc!(44100, 2, 44, 5, 16, [22, 0, 0, 0]),
1058 flavour_desc!(44100, 2, 44, 5, 16, [23, 0, 0, 0]),
1059 flavour_desc!(44100, 2, 64, 5, 16, [24, 0, 0, 0]),
1060 flavour_desc!(44100, 2, 96, 5, 16, [25, 0, 0, 0]),
1061 flavour_desc!(11025, 2, 12, 11, 8, [26, 0, 0, 0]),
1062 flavour_desc!(44100, 2, 64, 5, 16, [27, 0, 0, 0]),
1063 flavour_desc!(44100, 2, 96, 5, 16, [28, 0, 0, 0]),
1064 flavour_desc!(22050, 2, 44, 5, 16, [29, 0, 0, 0]),
1065 flavour_desc!(44100, 5, 96, 5, 16, [21, 16, 21, 0]),
1066 flavour_desc!(44100, 6, 131, 3, 10, [23, 5, 30, 21]),
1067 flavour_desc!(44100, 6, 183, 2, 10, [24, 6, 30, 23]),
1068 flavour_desc!(44100, 6, 268, 1, 1, [25, 6, 30, 25])
1071 struct BitrateParams {
1079 macro_rules! br_desc {
1080 ($ch:expr, $bits:expr, $subbands:expr, $js_start:expr, $js_bits:expr) => {
1083 max_subbands: $subbands,
1085 js_start: $js_start,
1091 const BITRATE_PARAMS: &[BitrateParams] = &[
1092 br_desc!(1, 256, 12, 0, 0),
1093 br_desc!(1, 256, 12, 0, 0),
1094 br_desc!(1, 376, 18, 0, 0),
1095 br_desc!(1, 480, 23, 0, 0),
1096 br_desc!(1, 744, 37, 0, 0),
1097 br_desc!(1, 1024, 47, 0, 0),
1098 br_desc!(1, 1488, 47, 0, 0),
1099 br_desc!(1, 744, 24, 0, 0),
1101 br_desc!(1, 192, 9, 0, 0),
1102 br_desc!(2, 464, 11, 0, 0),
1103 br_desc!(2, 752, 18, 0, 0),
1104 br_desc!(2, 1024, 24, 0, 0),
1105 br_desc!(2, 1488, 37, 0, 0),
1106 br_desc!(2, 2224, 47, 0, 0),
1107 br_desc!(1, 1488, 47, 0, 0),
1108 br_desc!(1, 480, 47, 0, 0),
1110 br_desc!(1, 744, 47, 0, 0),
1111 br_desc!(2, 384, 16, 1, 3),
1112 br_desc!(2, 480, 20, 1, 3),
1113 br_desc!(2, 480, 23, 1, 3),
1114 br_desc!(2, 744, 24, 2, 4),
1115 br_desc!(2, 744, 32, 2, 4),
1116 br_desc!(2, 1024, 32, 5, 5),
1117 br_desc!(2, 1024, 37, 2, 4),
1119 br_desc!(2, 1488, 37, 6, 5),
1120 br_desc!(2, 2240, 37, 8, 5),
1121 br_desc!(2, 288, 9, 1, 2),
1122 br_desc!(2, 1488, 30, 17, 5),
1123 br_desc!(2, 2240, 34, 19, 5),
1124 br_desc!(2, 1024, 23, 17, 5),
1125 br_desc!(1, 256, 1, 0, 0)
1130 use nihav_core::codecs::*;
1131 use nihav_core::demuxers::*;
1132 use nihav_core::muxers::*;
1133 use nihav_codec_support::test::enc_video::*;
1136 fn test_encoder(name: &'static str, enc_options: &[NAOption], bitrate: u32, channels: u8, hash: &[u32; 4]) {
1137 let mut dmx_reg = RegisteredDemuxers::new();
1138 realmedia_register_all_demuxers(&mut dmx_reg);
1139 let mut dec_reg = RegisteredDecoders::new();
1140 realmedia_register_all_decoders(&mut dec_reg);
1141 let mut mux_reg = RegisteredMuxers::new();
1142 realmedia_register_all_muxers(&mut mux_reg);
1143 let mut enc_reg = RegisteredEncoders::new();
1144 realmedia_register_all_encoders(&mut enc_reg);
1146 // sample from a private collection
1147 let dec_config = DecoderTestParams {
1148 demuxer: "realmedia",
1149 in_name: "assets/RV/rv30_weighted_mc.rm",
1150 stream_type: StreamType::Audio,
1154 let enc_config = EncoderTestParams {
1160 let dst_ainfo = NAAudioInfo {
1163 format: SND_F32P_FORMAT,
1166 let enc_params = EncodeParameters {
1167 format: NACodecTypeInfo::Audio(dst_ainfo),
1174 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
1176 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options, hash);
1179 fn test_cook_encoder_mono() {
1180 let enc_options = &[
1182 test_encoder("cook-mono.rma", enc_options, 0, 1,
1183 &[0xa07cffaa, 0x257e8ca1, 0x27f58960, 0xb48f64f4]);
1186 fn test_cook_encoder_stereo() {
1187 let enc_options = &[
1188 NAOption { name: super::G8_ONLY_OPTION, value: NAValue::Bool(true) },
1190 test_encoder("cook-stereo.rma", enc_options, 0, 2,
1191 &[0xbc407879, 0x18c7b334, 0xc0299482, 0x89c6b953]);
1194 fn test_cook_encoder_jstereo_32kbps() {
1195 let enc_options = &[
1197 test_encoder("cook-jstereo32.rma", enc_options, 32000, 2,
1198 &[0xe7526c4e, 0xda095156, 0x840a74f7, 0x0e9a1603]);
1201 fn test_cook_encoder_jstereo_64kbps() {
1202 let enc_options = &[
1204 test_encoder("cook-jstereo64.rma", enc_options, 64000, 2,
1205 &[0x09688175, 0x9abe1aac, 0x3c3f15fb, 0x066b99f0]);
1208 fn test_cook_encoder_jstereo_96kbps() {
1209 let enc_options = &[
1211 test_encoder("cook-jstereo96.rma", enc_options, 96000, 2,
1212 &[0x51829ff8, 0x00017191, 0x5bc95490, 0xd1d03faf]);