]> git.nihav.org Git - nihav.git/blame - nihav-rad/src/codecs/binkaudenc.rs
Bink Audio encoder (version b for now)
[nihav.git] / nihav-rad / src / codecs / binkaudenc.rs
CommitLineData
ed91af4b
KS
1use std::collections::VecDeque;
2
3use nihav_core::codecs::*;
4use nihav_core::io::bitwriter::*;
5use nihav_codec_support::dsp::dct::*;
6use nihav_codec_support::dsp::fft::*;
7use super::binkauddata::*;
8
9trait WriteBinkFloat {
10 fn write_float(&mut self, val: f32);
11}
12
13impl 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);
19 self.write(nexp, 5);
20 self.write(mant, 23);
21 self.write(sign, 1);
22 }
23}
24
25#[derive(Default)]
26struct RateControl {
27 quality: u8,
28 bitrate: u32,
29 bitpool: u32,
30 spos: u32,
31 srate: u32,
32 blk_size: u32,
33 lambda: f32,
34}
35
36impl RateControl {
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;
41 self.srate = srate;
42 self.spos = 0;
43 self.blk_size = blk_size;
44 self.lambda = if self.quality != 0 {
45 ((100 - self.quality) as f32) / 20.0
46 } else {
47 1.0
48 };
49 }
50 fn get_tgt_size(&self) -> usize {
51 if self.bitrate > 0 {
52 (self.bitpool * self.blk_size / (self.srate - self.spos)) as usize
53 } else {
54 0
55 }
56 }
57 fn update(&mut self, real_size: usize) {
58 if self.bitrate == 0 {
59 return;
60 }
61
62 let tgt_size = self.get_tgt_size();
63
64 if real_size < tgt_size - tgt_size / 8 {
65 self.lambda -= 0.2;
66 if self.lambda < 0.0 {
67 self.lambda = 0.0;
68 }
69 }
70 if real_size > tgt_size + tgt_size / 8 {
71 self.lambda += 0.5;
72 }
73
74 self.spos += self.blk_size;
75 while self.spos >= self.srate {
76 self.spos -= self.srate;
77 self.bitpool += self.bitrate;
78 }
79 self.bitpool = self.bitpool.saturating_sub(real_size as u32);
80 }
81}
82
83#[derive(Default)]
84struct SampleBuffer {
85 samples: Vec<f32>,
86 read_pos: usize,
87 frame_len: usize,
88 step_size: usize,
89}
90
91impl SampleBuffer {
92 fn reset(&mut self) {
93 self.samples.clear();
94 self.read_pos = 0;
95 }
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);
99 }
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);
104 }
105 }
106 fn norm(&mut self) {
107 if self.read_pos == self.samples.len() {
108 self.read_pos = 0;
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);
114 self.read_pos = 0;
115 self.samples.truncate(len);
116 }
117 }
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);
125 }
126 for (i, sample) in dst[self.step_size..][..ovl_len].iter_mut().rev().enumerate() {
127 *sample *= (i as f32) / (ovl_len as f32);
128 }
129 }
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();
134 }
135 self.norm();
136 }
137}
138
139fn find_quant(src: &[f32], quants: &[f32; 96], lambda: f32) -> usize {
140 let maxval = src.iter().fold(0.0f32, |acc, &a| acc.max(a.abs()));
141
142 let mut best = 0;
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; }
147 let mut dist = 0.0;
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);
155 if qval > 0.0 {
156 signs += 1;
157 }
158 }
159 let bits = if maxqv > 0.0 {
160 maxqv.log2().ceil() * (src.len() as f32) + (signs as f32)
161 } else { 0.0 };
162 let metric = (dist + 1.0).log2() * 10.0 + bits * lambda;
163 if metric < best_dist {
164 best_dist = metric;
165 best = i;
166 }
167 }
168 best
169}
170
171enum Transform {
172 None,
173 DCT(DCT),
174 RDFT(RDFT),
175}
176
177struct BinkAudioEncoder {
178 stream: Option<NAStreamRef>,
179 version: char,
180 stereo: bool,
181
182 frm_size: usize,
183 frame_bits: u8,
184 overlap_size: usize,
185
186 apts: u64,
187 use_dct: bool,
188 preload: usize,
189
190 samples: SampleBuffer,
191 transform: Transform,
192 scale: f32,
193 quants: [f32; 96],
194 num_bands: usize,
195 bands: [usize; MAX_BANDS + 1],
196 first_frame: bool,
197 sample_step: usize,
198 leftover: usize,
199
200 tmp: Vec<f32>,
201
202 packets: VecDeque<NAPacket>,
203 rc: RateControl,
204
205 print_stats: bool,
206 blk_bits: usize,
207 nblks: usize,
208 nsamples: usize,
209 nframes: usize,
210 qstats: [usize; 96],
211 bstats: [usize; 16],
212}
213
214impl BinkAudioEncoder {
215 fn new(use_dct: bool) -> Self {
216 Self {
217 stream: None,
218 version: 'b',
219 stereo: false,
220
221 frm_size: 0,
222 frame_bits: 0,
223 overlap_size: 0,
224
225 apts: 0,
226 use_dct,
227 preload: 16,
228
229 samples: SampleBuffer::default(),
230 transform: Transform::None,
231 scale: 0.0,
232 quants: get_quants_table(),
233 num_bands: 0,
234 bands: [0; MAX_BANDS + 1],
235 first_frame: true,
236 sample_step: 0,
237 leftover: 0,
238
239 tmp: Vec::new(),
240
241 packets: VecDeque::new(),
242 rc: RateControl::default(),
243
244 print_stats: false,
245 blk_bits: 0,
246 nblks: 0,
247 nsamples: 0,
248 nframes: 0,
249 qstats: [0; 96],
250 bstats: [0; 16],
251 }
252 }
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) => {
259 unsafe {
260 let buf = std::mem::transmute::<&mut [f32], &mut [FFTComplex]>(self.tmp.as_mut_slice());
261 rdft.do_rdft_inplace(buf);
262 }
263 },
264 };
265 for el in self.tmp.iter_mut() {
266 *el *= self.samples.frame_len as f32;
267 }
268 if self.version == 'b' {
269 bw.write(self.tmp[0].to_bits(), 32);
270 bw.write(self.tmp[1].to_bits(), 32);
271 } else {
272 bw.write_float(self.tmp[0]);
273 bw.write_float(self.tmp[1]);
274 }
275
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];
282 }
283 }
284
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 };
289 }
290
291 for &quant in quants[..self.num_bands].iter() {
292 self.qstats[quant] += 1;
293 }
294
295 for &quant in quants[..self.num_bands].iter() {
296 bw.write(quant as u32, 8);
297 }
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();
303 if max_bits != 0 {
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);
307 if bval != 0 {
308 bw.write_bit(coef < 0.0);
309 }
310 }
311 }
312 }
313 } else {
314 unimplemented!();
315 }
316 }
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 }
322 } else {
323 (self.leftover + self.sample_step) * if self.stereo { 2 } else { 1 }
324 };
325
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 {
329 return Ok(false);
330 }
331 self.leftover = (self.leftover + self.sample_step) % self.frm_size;
332 nblk
333 } else {
334 (nsamples + self.frm_size - 1) / self.frm_size
335 };
336 let nsamples = if !last { nblocks * self.frm_size } else { nsamples };
337
338 self.nsamples += nsamples >> (self.stereo as u8);
339 self.nframes += 1;
340
341 let mut bw = BitWriter::new(Vec::new(), BitWriterMode::LE);
342 bw.write((nsamples * 2) as u32, 32); // number of raw audio bytes
343
344 for _nblk in 0..nblocks {
345 let start = bw.tell();
346
347 if last {
348 for el in self.tmp.iter_mut() {
349 *el = 0.0;
350 }
351 }
352 self.samples.read_frame(&mut self.tmp);
353 self.encode_block(&mut bw);
354 while (bw.tell() & 0x1F) != 0 {
355 bw.write0();
356 }
357 self.samples.consume_frame();
358
359 let blk_bits = bw.tell() - start;
360 self.rc.update(blk_bits);
361 self.blk_bits += blk_bits;
362 self.nblks += 1;
363 }
364
365 if self.first_frame {
366 self.first_frame = false;
367 }
368
369 let dbuf = bw.end();
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));
375
376 Ok(true)
377 }
378}
379
380impl 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() })
387 },
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);
395 Ok(ofmt)
396 }
397 }
398 }
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);
407 }
408
409 let srate = ainfo.get_sample_rate();
410 let mut frame_bits = if srate < 22050 { 9 } else if srate < 44100 { 10 } else { 11 };
411
412 if self.version < 'i' && self.use_dct {
413 println!("DCT is supported starting from version 'i'");
414 return Err(EncoderError::FormatError);
415 }
416
417 if !self.use_dct && self.version != 'b' {
418 frame_bits += 1;
419 }
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
424 if single {
425 duration >>= 1;
426 }
427
428 self.transform = if !self.use_dct {
429 Transform::RDFT(RDFTBuilder::new_rdft(1 << (frame_bits - 1), true, false))
430 } else {
431 Transform::DCT(DCT::new(DCTMode::DCT_II, 1 << frame_bits))
432 };
433 self.scale = if !self.use_dct {
434 1.0 / (32768.0 * ((1 << frame_bits) as f32).sqrt())
435 } else {
436 (2.0 / ((1 << frame_bits) as f32)).sqrt() / 1024.0
437 };
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;
441
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];
448
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);
451
452 let edata = vec![b'B', b'I', b'K', self.version as u8];
453
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();
460
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);
463
464 Ok(stream)
465 },
466 }
467 }
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();
472
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]);
476 } else {
477 self.samples.add_mono(&src[..length]);
478 }
479
480 while self.encode_packet(false)? {
481 }
482
483 Ok(())
484 } else {
485 Err(EncoderError::InvalidParameters)
486 }
487 }
488 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
489 Ok(self.packets.pop_front())
490 }
491 fn flush(&mut self) -> EncoderResult<()> {
492 if self.samples.num_avail() > 0 {
493 self.encode_packet(true)?;
494 }
495 Ok(())
496 }
497}
498
499impl Drop for BinkAudioEncoder {
500 fn drop(&mut self) {
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));
505
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)
511 } else {
512 format!("{}bps", bitrate)
513 };
514 println!("average bitrate {}", br_fmt);
515
516 let mut end = self.qstats.len();
517 for (i, &cnt) in self.qstats.iter().enumerate().rev() {
518 if cnt != 0 {
519 break;
520 }
521 end = i;
522 }
523 print!("quants used:");
524 for &cnt in self.qstats.iter().take(end) {
525 print!(" {}", cnt);
526 }
527 println!();
528
529 let mut end = self.bstats.len();
530 for (i, &cnt) in self.bstats.iter().enumerate().rev() {
531 if cnt != 0 {
532 break;
533 }
534 end = i;
535 }
536 print!("coefficient bits:");
537 for &cnt in self.bstats.iter().take(end) {
538 print!(" {}", cnt);
539 }
540 println!();
541 }
542 }
543}
544
545const ENCODER_OPTS: &[NAOptionDefinition] = &[
546 NAOptionDefinition {
547 name: "version", description: "codec version",
548 opt_type: NAOptionDefinitionType::String(Some(&["b", "f", "g", "h", "i", "k"])) },
549 NAOptionDefinition {
550 name: "preload", description: "number of audio frames to preload",
551 opt_type: NAOptionDefinitionType::Int(Some(1), Some(256)) },
552 NAOptionDefinition {
553 name: "print_stats", description: "print encoder statistics",
554 opt_type: NAOptionDefinitionType::Bool },
555];
556
557impl 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() {
563 match option.name {
564 "version" => {
565 if let NAValue::String(ref strval) = option.value {
566 match strval.as_str() {
567 "b" => self.version = 'b',
568 _ => {
569 println!("versions beside 'b' are not supported");
570 },
571 };
572 }
573 },
574 "preload" => {
575 if let NAValue::Int(ival) = option.value {
576 self.preload = ival as usize;
577 }
578 },
579 "print_stats" => {
580 if let NAValue::Bool(bval) = option.value {
581 self.print_stats = bval;
582 }
583 },
584 _ => {},
585 };
586 }
587 }
588 }
589 }
590 fn query_option_value(&self, name: &str) -> Option<NAValue> {
591 match name {
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)),
595 _ => None,
596 }
597 }
598}
599
600pub fn get_encoder_rdft() -> Box<dyn NAEncoder + Send> { Box::new(BinkAudioEncoder::new(false)) }
601#[allow(dead_code)]
602pub fn get_encoder_dct() -> Box<dyn NAEncoder + Send> { Box::new(BinkAudioEncoder::new(true)) }
603
604#[cfg(test)]
605mod test {
606 use nihav_core::codecs::*;
607 use nihav_core::demuxers::*;
608 use nihav_core::muxers::*;
609 use nihav_codec_support::test::enc_video::*;
610 use crate::*;
611 use nihav_commonfmt::*;
612
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);
623
624 // sample from a private collection
625 let dec_config = DecoderTestParams {
626 demuxer: "wav",
627 in_name: "assets/test-stereo.wav",
628 stream_type: StreamType::Audio,
629 limit: None,//Some(20),
630 dmx_reg, dec_reg,
631 };
632 let enc_config = EncoderTestParams {
633 muxer: "bink",
634 enc_name: "bink-audio-rdft",
635 out_name: name,
636 mux_reg, enc_reg,
637 };
638 let dst_ainfo = NAAudioInfo {
639 sample_rate: 0,
640 channels,
641 format: SND_F32P_FORMAT,
642 block_len: 1024,
643 };
644 let enc_params = EncodeParameters {
645 format: NACodecTypeInfo::Audio(dst_ainfo),
646 quality,
647 bitrate: bitrate * 1000,
648 tb_num: 0,
649 tb_den: 0,
650 flags: 0,
651 };
652 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
653
654 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options, hash);
655 }
656 #[test]
657 fn test_binkaud_encoder_b_q100() {
658 let enc_options = &[
659 NAOption{name: "version", value: NAValue::String("b".to_owned())},
660 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
661 ];
662 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 100, 2,
663 &[0x45c13e44, 0x36ab1efb, 0x84c93f1a, 0x4aa49831]);
664 }
665 #[test]
666 fn test_binkaud_encoder_b_q80() {
667 let enc_options = &[
668 NAOption{name: "version", value: NAValue::String("b".to_owned())},
669 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
670 ];
671 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 80, 2,
672 &[0x3835b6ff, 0xd2da247b, 0xae8ff168, 0x464b4c31]);
673 }
674 #[test]
675 fn test_binkaud_encoder_b_q40() {
676 let enc_options = &[
677 NAOption{name: "version", value: NAValue::String("b".to_owned())},
678 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
679 ];
680 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 40, 2,
681 &[0xe99882b0, 0x12f9be7c, 0xc634c1a7, 0xd88e1c9b]);
682 }
683 #[test]
684 fn test_binkaud_encoder_b_q1() {
685 let enc_options = &[
686 NAOption{name: "version", value: NAValue::String("b".to_owned())},
687 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
688 ];
689 test_encoder("bink-aud-b-q80.bik", enc_options, 0, 1, 2,
690 &[0x783d68e1, 0x9db89348, 0x5348e677, 0x337133fa]);
691 }
692 #[test]
693 fn test_binkaud_encoder_b_br240() {
694 let enc_options = &[
695 NAOption{name: "version", value: NAValue::String("b".to_owned())},
696 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
697 ];
698 test_encoder("bink-aud-b-180k.bik", enc_options, 240, 0, 2,
699 &[0xad33939e, 0x945413f1, 0xf5edc6be, 0xcf8eebd3]);
700 }
701 #[test]
702 fn test_binkaud_encoder_b_br180() {
703 let enc_options = &[
704 NAOption{name: "version", value: NAValue::String("b".to_owned())},
705 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
706 ];
707 test_encoder("bink-aud-b-180k.bik", enc_options, 180, 0, 2,
708 &[0x4d33f1be, 0xb1e662ad, 0x71bd0486, 0x327e053a]);
709 }
710 #[test]
711 fn test_binkaud_encoder_b_br120() {
712 let enc_options = &[
713 NAOption{name: "version", value: NAValue::String("b".to_owned())},
714 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
715 ];
716 test_encoder("bink-aud-b-120k.bik", enc_options, 120, 0, 2,
717 &[0xa1e17945, 0xd837677a, 0x48cd0b3a, 0x3e7c1a03]);
718 }
719 #[test]
720 fn test_binkaud_encoder_b_br60() {
721 let enc_options = &[
722 NAOption{name: "version", value: NAValue::String("b".to_owned())},
723 //NAOption{name: "print_stats", value: NAValue::Bool(true)},
724 ];
725 test_encoder("bink-aud-b-60k.bik", enc_options, 60, 0, 2,
726 &[0xf48cae2e, 0x038ec363, 0x17cb1606, 0x4756f854]);
727 }
728}