1 use std::collections::VecDeque;
3 use nihav_core::codecs::*;
4 use nihav_core::io::bitwriter::*;
5 use nihav_codec_support::dsp::dct::*;
6 use nihav_codec_support::dsp::fft::*;
7 use super::binkauddata::*;
10 fn write_float(&mut self, val: f32);
13 impl WriteBinkFloat for BitWriter {
14 fn write_float(&mut self, val: f32) {
15 let bits = val.to_bits();
16 let sign = bits >> 31;
17 let nexp = ((bits >> 23).wrapping_sub(0x7E)) & 0x1F;
18 let mant = bits & ((1 << 23) - 1);
37 fn init(&mut self, quality: u8, bitrate: u32, srate: u32, blk_size: u32) {
38 self.quality = quality;
39 self.bitrate = bitrate;
40 self.bitpool = bitrate;
43 self.blk_size = blk_size;
44 self.lambda = if self.quality != 0 {
45 ((100 - self.quality) as f32) / 20.0
50 fn get_tgt_size(&self) -> usize {
52 (self.bitpool * self.blk_size / (self.srate - self.spos)) as usize
57 fn update(&mut self, real_size: usize) {
58 if self.bitrate == 0 {
62 let tgt_size = self.get_tgt_size();
64 if real_size < tgt_size - tgt_size / 8 {
66 if self.lambda < 0.0 {
70 if real_size > tgt_size + tgt_size / 8 {
74 self.spos += self.blk_size;
75 while self.spos >= self.srate {
76 self.spos -= self.srate;
77 self.bitpool += self.bitrate;
79 self.bitpool = self.bitpool.saturating_sub(real_size as u32);
96 fn num_avail(&self) -> usize { self.samples.len() - self.read_pos }
97 fn add_mono(&mut self, src: &[f32]) {
98 self.samples.extend_from_slice(src);
100 fn add_stereo(&mut self, left: &[f32], right: &[f32]) {
101 for (&l, &r) in left.iter().zip(right.iter()) {
102 self.samples.push(l);
103 self.samples.push(r);
107 if self.read_pos == self.samples.len() {
109 self.samples.clear();
110 } else if self.read_pos * 2 >= self.samples.len() {
111 let len = self.num_avail();
112 let (head, tail) = self.samples.split_at_mut(self.read_pos);
113 head[..tail.len()].copy_from_slice(tail);
115 self.samples.truncate(len);
118 fn read_frame(&self, dst: &mut [f32]) {
119 let src = &self.samples[self.read_pos..];
120 let len = dst.len().min(src.len()).min(self.frame_len);
121 dst[..len].copy_from_slice(&src[..len]);
122 let ovl_len = self.frame_len - self.step_size;
123 for (i, sample) in dst[..ovl_len].iter_mut().enumerate() {
124 *sample *= (i as f32) / (ovl_len as f32);
126 for (i, sample) in dst[self.step_size..][..ovl_len].iter_mut().rev().enumerate() {
127 *sample *= (i as f32) / (ovl_len as f32);
130 fn consume_frame(&mut self) {
131 self.read_pos += self.step_size;
132 if self.read_pos > self.samples.len() {
133 self.read_pos = self.samples.len();
139 fn find_quant(src: &[f32], quants: &[f32; 96], lambda: f32) -> usize {
140 let maxval = src.iter().fold(0.0f32, |acc, &a| acc.max(a.abs()));
143 let mut best_dist = maxval * maxval * (src.len() as f32);
144 for (i, &q) in quants.iter().enumerate() {
145 if maxval / q > 32767.0 { continue; }
146 if q > maxval * 2.0 { break; }
148 let mut maxqv = 0.0f32;
149 let mut signs = 0u32;
150 for &el in src.iter() {
151 let qval = (el.abs() / q).round();
152 let iqval = qval * q;
153 dist += (el.abs() - iqval) * (el.abs() - iqval);
154 maxqv = maxqv.max(qval);
159 let bits = if maxqv > 0.0 {
160 maxqv.log2().ceil() * (src.len() as f32) + (signs as f32)
162 let metric = (dist + 1.0).log2() * 10.0 + bits * lambda;
163 if metric < best_dist {
177 struct BinkAudioEncoder {
178 stream: Option<NAStreamRef>,
190 samples: SampleBuffer,
191 transform: Transform,
195 bands: [usize; MAX_BANDS + 1],
202 packets: VecDeque<NAPacket>,
214 impl BinkAudioEncoder {
215 fn new(use_dct: bool) -> Self {
229 samples: SampleBuffer::default(),
230 transform: Transform::None,
232 quants: get_quants_table(),
234 bands: [0; MAX_BANDS + 1],
241 packets: VecDeque::new(),
242 rc: RateControl::default(),
253 #[allow(clippy::transmute_ptr_to_ptr)]
254 fn encode_block(&mut self, bw: &mut BitWriter) {
255 match self.transform {
256 Transform::None => unreachable!(),
257 Transform::DCT(ref mut _dct) => unimplemented!(),
258 Transform::RDFT(ref mut rdft) => {
260 let buf = std::mem::transmute::<&mut [f32], &mut [FFTComplex]>(self.tmp.as_mut_slice());
261 rdft.do_rdft_inplace(buf);
265 for el in self.tmp.iter_mut() {
266 *el *= self.samples.frame_len as f32;
268 if self.version == 'b' {
269 bw.write(self.tmp[0].to_bits(), 32);
270 bw.write(self.tmp[1].to_bits(), 32);
272 bw.write_float(self.tmp[0]);
273 bw.write_float(self.tmp[1]);
276 let mut quants = [0; MAX_BANDS];
277 for (range, quant) in self.bands.windows(2).take(self.num_bands).zip(quants.iter_mut()) {
278 let region = &mut self.tmp[range[0]..range[1]];
279 *quant = find_quant(region, &self.quants, self.rc.lambda);
280 for el in region.iter_mut() {
281 *el /= self.quants[*quant];
285 let mut rec_bits = [0u8; 4096];
286 for (bval, &coef) in rec_bits.iter_mut().zip(self.tmp.iter()).skip(2) {
287 let aval = coef.abs().round() as u32;
288 *bval = if aval > 0 { (32 - aval.leading_zeros()) as u8 } else { 0 };
291 for &quant in quants[..self.num_bands].iter() {
292 self.qstats[quant] += 1;
295 for &quant in quants[..self.num_bands].iter() {
296 bw.write(quant as u32, 8);
298 if self.version == 'b' {
299 for (coef_reg, bits_reg) in self.tmp[2..].chunks(16).zip(rec_bits[2..].chunks(16)) {
300 let max_bits = bits_reg.iter().fold(0u8, |acc, &a| acc.max(a)).min(15);
301 bw.write(u32::from(max_bits), 4);
302 self.bstats[usize::from(max_bits)] += coef_reg.len();
304 for &coef in coef_reg.iter() {
305 let bval = (coef.abs().round() as u32).min((1 << max_bits) - 1);
306 bw.write(bval, max_bits);
308 bw.write_bit(coef < 0.0);
317 fn encode_packet(&mut self, last: bool) -> EncoderResult<bool> {
318 let nsamples = if last {
319 self.samples.num_avail()
320 } else if self.first_frame {
321 self.preload.max(1) * self.frm_size * if self.stereo { 2 } else { 1 }
323 (self.leftover + self.sample_step) * if self.stereo { 2 } else { 1 }
326 let nblocks = if !last {
327 let nblk = (nsamples / self.frm_size).max(1);
328 if self.samples.num_avail() < nblk * self.frm_size + self.overlap_size {
331 self.leftover = (self.leftover + self.sample_step) % self.frm_size;
334 (nsamples + self.frm_size - 1) / self.frm_size
336 let nsamples = if !last { nblocks * self.frm_size } else { nsamples };
338 self.nsamples += nsamples >> (self.stereo as u8);
341 let mut bw = BitWriter::new(Vec::new(), BitWriterMode::LE);
342 bw.write((nsamples * 2) as u32, 32); // number of raw audio bytes
344 for _nblk in 0..nblocks {
345 let start = bw.tell();
348 for el in self.tmp.iter_mut() {
352 self.samples.read_frame(&mut self.tmp);
353 self.encode_block(&mut bw);
354 while (bw.tell() & 0x1F) != 0 {
357 self.samples.consume_frame();
359 let blk_bits = bw.tell() - start;
360 self.rc.update(blk_bits);
361 self.blk_bits += blk_bits;
365 if self.first_frame {
366 self.first_frame = false;
370 let stream = self.stream.clone().unwrap();
371 let (tb_num, tb_den) = stream.get_timebase();
372 let ts = NATimeInfo::new(Some(self.apts), None, Some(nsamples as u64), tb_num, tb_den);
373 self.apts += (nsamples / if self.stereo { 2 } else { 1 }) as u64;
374 self.packets.push_back(NAPacket::new(self.stream.clone().unwrap(), ts, true, dbuf));
380 impl NAEncoder for BinkAudioEncoder {
381 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
382 match encinfo.format {
383 NACodecTypeInfo::None => {
384 Ok(EncodeParameters {
385 format: NACodecTypeInfo::Audio(NAAudioInfo::new(0, 1, SND_F32P_FORMAT, 512)),
386 ..Default::default() })
388 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
389 NACodecTypeInfo::Audio(ainfo) => {
390 let mut outinfo = ainfo;
391 outinfo.channels = if !self.use_dct { 2 } else { ainfo.channels.min(2).max(1) };
392 outinfo.format = SND_F32P_FORMAT;
393 let mut ofmt = *encinfo;
394 ofmt.format = NACodecTypeInfo::Audio(outinfo);
399 fn get_capabilities(&self) -> u64 { ENC_CAPS_CBR }
400 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
401 match encinfo.format {
402 NACodecTypeInfo::None => Err(EncoderError::FormatError),
403 NACodecTypeInfo::Video(_) => Err(EncoderError::FormatError),
404 NACodecTypeInfo::Audio(ainfo) => {
405 if ainfo.format != SND_F32P_FORMAT {
406 return Err(EncoderError::FormatError);
409 let srate = ainfo.get_sample_rate();
410 let mut frame_bits = if srate < 22050 { 9 } else if srate < 44100 { 10 } else { 11 };
412 if self.version < 'i' && self.use_dct {
413 println!("DCT is supported starting from version 'i'");
414 return Err(EncoderError::FormatError);
417 if !self.use_dct && self.version != 'b' {
420 self.frame_bits = frame_bits;
421 self.stereo = ainfo.channels == 2;
422 let mut duration = (1 << frame_bits) - (1 << (frame_bits - 4));
423 let single = !self.use_dct && self.stereo; // RDFT codes samples interleaved as single buffer
428 self.transform = if !self.use_dct {
429 Transform::RDFT(RDFTBuilder::new_rdft(1 << (frame_bits - 1), true, false))
431 Transform::DCT(DCT::new(DCTMode::DCT_II, 1 << frame_bits))
433 self.scale = if !self.use_dct {
434 1.0 / (32768.0 * ((1 << frame_bits) as f32).sqrt())
436 (2.0 / ((1 << frame_bits) as f32)).sqrt() / 1024.0
438 let s_srate = if single { srate } else { srate >> 1 } as usize;
439 init_bands(s_srate, 1 << frame_bits, &mut self.num_bands, &mut self.bands);
440 self.first_frame = true;
442 self.samples.reset();
443 self.samples.frame_len = 1 << frame_bits;
444 self.samples.step_size = duration * usize::from(ainfo.channels);
445 self.frm_size = duration * usize::from(ainfo.channels);
446 self.overlap_size = self.frm_size / 15;
447 self.tmp = vec![0.0; 1 << frame_bits];
449 let blk_len = ((1 << frame_bits) - (1 << (frame_bits - 4))) >> if self.stereo { 1 } else { 0 };
450 self.rc.init(encinfo.quality, encinfo.bitrate, srate, blk_len as u32);
452 let edata = vec![b'B', b'I', b'K', self.version as u8];
454 let out_ainfo = NAAudioInfo::new(ainfo.sample_rate, ainfo.channels, SND_F32P_FORMAT, self.frm_size);
455 let name = if !self.use_dct { "bink-audio-rdft" } else { "bink-audio-dct" };
456 let info = NACodecInfo::new(name, NACodecTypeInfo::Audio(out_ainfo), Some(edata));
457 let mut stream = NAStream::new(StreamType::Audio, stream_id, info, self.frm_size as u32, ainfo.sample_rate, 0);
458 stream.set_num(stream_id as usize);
459 let stream = stream.into_ref();
461 self.stream = Some(stream.clone());
462 self.sample_step = (encinfo.tb_num as usize) * (ainfo.sample_rate as usize) / (encinfo.tb_den as usize);
468 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
469 if let Some(ref abuf) = frm.get_buffer().get_abuf_f32() {
470 let src = abuf.get_data();
471 let length = abuf.get_length();
473 if abuf.get_info().get_channels() == 2 {
474 let offset = abuf.get_offset(1);
475 self.samples.add_stereo(&src[..length], &src[offset..][..length]);
477 self.samples.add_mono(&src[..length]);
480 while self.encode_packet(false)? {
485 Err(EncoderError::InvalidParameters)
488 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
489 Ok(self.packets.pop_front())
491 fn flush(&mut self) -> EncoderResult<()> {
492 if self.samples.num_avail() > 0 {
493 self.encode_packet(true)?;
499 impl Drop for BinkAudioEncoder {
501 if self.print_stats && self.nblks > 0 {
502 println!("encoded {} block(s) in {} frame(s), {} samples total ({}s)",
503 self.nblks, self.nframes, self.nsamples,
504 (self.nsamples as f32) / (self.rc.srate as f32));
506 let bitrate = (self.blk_bits as u64) * u64::from(self.rc.srate) / (self.nsamples as u64);
507 let br_fmt = if bitrate >= 10_000_000 {
508 format!("{}mbps", bitrate / 1000000)
509 } else if bitrate >= 10_000 {
510 format!("{}kbps", bitrate / 1000)
512 format!("{}bps", bitrate)
514 println!("average bitrate {}", br_fmt);
516 let mut end = self.qstats.len();
517 for (i, &cnt) in self.qstats.iter().enumerate().rev() {
523 print!("quants used:");
524 for &cnt in self.qstats.iter().take(end) {
529 let mut end = self.bstats.len();
530 for (i, &cnt) in self.bstats.iter().enumerate().rev() {
536 print!("coefficient bits:");
537 for &cnt in self.bstats.iter().take(end) {
545 const ENCODER_OPTS: &[NAOptionDefinition] = &[
547 name: "version", description: "codec version",
548 opt_type: NAOptionDefinitionType::String(Some(&["b", "f", "g", "h", "i", "k"])) },
550 name: "preload", description: "number of audio frames to preload",
551 opt_type: NAOptionDefinitionType::Int(Some(1), Some(256)) },
553 name: "print_stats", description: "print encoder statistics",
554 opt_type: NAOptionDefinitionType::Bool },
557 impl NAOptionHandler for BinkAudioEncoder {
558 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
559 fn set_options(&mut self, options: &[NAOption]) {
560 for option in options.iter() {
561 for opt_def in ENCODER_OPTS.iter() {
562 if opt_def.check(option).is_ok() {
565 if let NAValue::String(ref strval) = option.value {
566 match strval.as_str() {
567 "b" => self.version = 'b',
569 println!("versions beside 'b' are not supported");
575 if let NAValue::Int(ival) = option.value {
576 self.preload = ival as usize;
580 if let NAValue::Bool(bval) = option.value {
581 self.print_stats = bval;
590 fn query_option_value(&self, name: &str) -> Option<NAValue> {
592 "version" => Some(NAValue::String(self.version.to_string())),
593 "preload" => Some(NAValue::Int(self.preload as i64)),
594 "print_stats" => Some(NAValue::Bool(self.print_stats)),
600 pub fn get_encoder_rdft() -> Box<dyn NAEncoder + Send> { Box::new(BinkAudioEncoder::new(false)) }
602 pub fn get_encoder_dct() -> Box<dyn NAEncoder + Send> { Box::new(BinkAudioEncoder::new(true)) }
606 use nihav_core::codecs::*;
607 use nihav_core::demuxers::*;
608 use nihav_core::muxers::*;
609 use nihav_codec_support::test::enc_video::*;
611 use nihav_commonfmt::*;
613 fn test_encoder(name: &'static str, enc_options: &[NAOption],
614 bitrate: u32, quality: u8, channels: u8, hash: &[u32; 4]) {
615 let mut dmx_reg = RegisteredDemuxers::new();
616 generic_register_all_demuxers(&mut dmx_reg);
617 let mut dec_reg = RegisteredDecoders::new();
618 generic_register_all_decoders(&mut dec_reg);
619 let mut mux_reg = RegisteredMuxers::new();
620 rad_register_all_muxers(&mut mux_reg);
621 let mut enc_reg = RegisteredEncoders::new();
622 rad_register_all_encoders(&mut enc_reg);
624 // sample from a private collection
625 let dec_config = DecoderTestParams {
627 in_name: "assets/test-stereo.wav",
628 stream_type: StreamType::Audio,
629 limit: None,//Some(20),
632 let enc_config = EncoderTestParams {
634 enc_name: "bink-audio-rdft",
638 let dst_ainfo = NAAudioInfo {
641 format: SND_F32P_FORMAT,
644 let enc_params = EncodeParameters {
645 format: NACodecTypeInfo::Audio(dst_ainfo),
647 bitrate: bitrate * 1000,
652 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
654 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options, hash);
657 fn test_binkaud_encoder_b_q100() {
659 NAOption{name: "version", value: NAValue::String("b".to_owned())},
660 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
662 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 100, 2,
663 &[0x45c13e44, 0x36ab1efb, 0x84c93f1a, 0x4aa49831]);
666 fn test_binkaud_encoder_b_q80() {
668 NAOption{name: "version", value: NAValue::String("b".to_owned())},
669 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
671 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 80, 2,
672 &[0x3835b6ff, 0xd2da247b, 0xae8ff168, 0x464b4c31]);
675 fn test_binkaud_encoder_b_q40() {
677 NAOption{name: "version", value: NAValue::String("b".to_owned())},
678 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
680 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 40, 2,
681 &[0xe99882b0, 0x12f9be7c, 0xc634c1a7, 0xd88e1c9b]);
684 fn test_binkaud_encoder_b_q1() {
686 NAOption{name: "version", value: NAValue::String("b".to_owned())},
687 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
689 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 1, 2,
690 &[0x783d68e1, 0x9db89348, 0x5348e677, 0x337133fa]);
693 fn test_binkaud_encoder_b_br240() {
695 NAOption{name: "version", value: NAValue::String("b".to_owned())},
696 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
698 test_encoder("bink-aud-b-180k.bik", enc_options, 240, 0, 2,
699 &[0xad33939e, 0x945413f1, 0xf5edc6be, 0xcf8eebd3]);
702 fn test_binkaud_encoder_b_br180() {
704 NAOption{name: "version", value: NAValue::String("b".to_owned())},
705 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
707 test_encoder("bink-aud-b-180k.bik", enc_options, 180, 0, 2,
708 &[0x4d33f1be, 0xb1e662ad, 0x71bd0486, 0x327e053a]);
711 fn test_binkaud_encoder_b_br120() {
713 NAOption{name: "version", value: NAValue::String("b".to_owned())},
714 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
716 test_encoder("bink-aud-b-120k.bik", enc_options, 120, 0, 2,
717 &[0xa1e17945, 0xd837677a, 0x48cd0b3a, 0x3e7c1a03]);
720 fn test_binkaud_encoder_b_br60() {
722 NAOption{name: "version", value: NAValue::String("b".to_owned())},
723 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
725 test_encoder("bink-aud-b-60k.bik", enc_options, 60, 0, 2,
726 &[0xf48cae2e, 0x038ec363, 0x17cb1606, 0x4756f854]);