]> git.nihav.org Git - nihav.git/commitdiff
Bink audio decoder (semi-working)
authorKostya Shishkov <kostya.shishkov@gmail.com>
Wed, 30 Jan 2019 13:58:44 +0000 (14:58 +0100)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Wed, 30 Jan 2019 13:58:44 +0000 (14:58 +0100)
nihav-rad/Cargo.toml
nihav-rad/src/codecs/binkaud.rs

index e32dcd89c50e382b7ac3fb8518af0ee0d7f4ed78..0fe09935759dc224b1549adee1c6da93291d9300 100644 (file)
@@ -6,7 +6,7 @@ edition = "2018"
 
 [dependencies.nihav_core]
 path = "../nihav-core"
-features = ["fft"]
+features = ["dct", "fft"]
 
 [features]
 default = ["all_decoders", "all_demuxers"]
index ba8f707e795c83fdfd81d03df3c6b58d9a320921..a85a07ed00fd5ee2a3986dcb421d3b1863d9f5bc 100644 (file)
@@ -1,9 +1,316 @@
 use nihav_core::codecs::*;
+use nihav_core::dsp::dct::*;
+use nihav_core::dsp::fft::*;
+use nihav_core::io::bitreader::*;
+use std::f32::consts;
+use std::str::FromStr;
+
+enum Transform {
+    None,
+    DCT(DCT),
+    RDFT(RDFT),
+}
+
+const MAX_BANDS: usize = 25;
+
+struct BinkAudioDecoder {
+    ainfo:      NAAudioInfo,
+    chmap:      NAChannelMap,
+    use_dct:    bool,
+    version_b:  bool,
+    transform:  Transform,
+    len:        usize,
+    quants:     [f32; 96],
+    bands:      [usize; MAX_BANDS + 1],
+    num_bands:  usize,
+    duration:   usize,
+    coeffs:     [f32; 4096],
+    delay:      [[f32; 256]; 2],
+    first_frm:  bool,
+    scale:      f32,
+}
+
+fn read_bink_float(br: &mut BitReader) -> DecoderResult<f32> {
+    /*let exp                                     = (br.read(5)? as i8) - 23;
+    let mant                                    = br.read(23)? as u32;
+    let sign                                    = br.read_bool()?;
+    let v = if exp >= 0 {
+            (mant as f32) * ((1 << exp) as f32)
+        } else {
+            (mant as f32) / ((1 << -exp) as f32)
+        };
+    if sign {
+        Ok(-v)
+    } else {
+        Ok(v)
+    }*/
+    let exp                                     = br.read(5)? as u8;
+    let mant                                    = br.read(23)? as u32;
+    let sign                                    = br.read(1)? as u32;
+    let nexp = exp.wrapping_add(0x7E) as u32;
+    let nmant = (mant << 1) & ((1 << 23) - 1);
+    Ok(f32::from_bits((sign << 31) | (nexp << 23) | nmant))
+}
+
+fn overlap(a: &[f32], b: &[f32], dst: &mut [f32], len: usize, step: usize) {
+    for i in 0..len {
+        dst[i] = (a[i] * ((len - i) as f32) + b[i * step] * (i as f32)) / (len as f32);
+    }
+}
+
+impl BinkAudioDecoder {
+    fn new(use_dct: bool) -> Self {
+        let mut quants: [f32; 96] = [0.0; 96];
+        for i in 0..quants.len() {
+            quants[i] = ((i as f32) * 0.0664 / consts::LOG10_E).exp();
+        }
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_F32P_FORMAT, 0),
+            chmap:      NAChannelMap::new(),
+            use_dct,
+            transform:  Transform::None,
+            version_b:  false,
+            len:        0,
+            quants:     quants,
+            bands:      [MAX_BANDS + 1; 26],
+            num_bands:  0,
+            duration:   0,
+            coeffs:     [0.0; 4096],
+            delay:      [[0.0; 256]; 2],
+            first_frm:  true,
+            scale:      1.0,
+        }
+    }
+    fn decode_block(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+        if self.version_b {
+            let flt                             = br.read(32)?;
+            self.coeffs[0] = f32::from_bits(flt) * self.scale;
+            let flt                             = br.read(32)?;
+            self.coeffs[1] = f32::from_bits(flt) * self.scale;
+        } else {
+            self.coeffs[0] = read_bink_float(br)? * self.scale;
+            self.coeffs[1] = read_bink_float(br)? * self.scale;
+        }
+        let mut quants: [f32; MAX_BANDS] = [0.0; MAX_BANDS];
+        for i in 0..self.num_bands {
+            let idx                             = br.read(8)? as usize;
+            quants[i] = self.quants[idx.min(self.quants.len() - 1)] * self.scale;
+        }
+        let mut idx = 2;
+        let mut band_idx = 0;
+        self.coeffs = [0.0; 4096];
+        while idx < self.len {
+            let width = if self.version_b {
+                    16
+                } else {
+                    if br.read_bool()? {
+                        let idx                 = br.read(4)? as usize;
+                        RUN_TAB[idx] * 8
+                    } else {
+                        8
+                    }
+                };
+            let end = (idx + width).min(self.len);
+            let bits                            = br.read(4)? as u8;
+            if bits != 0 {
+                for i in idx..end {
+                    while self.bands[band_idx] <= i { band_idx += 1; }
+                    let q = quants[band_idx - 1];
+                    let coeff                   = br.read(bits)?;
+                    if coeff != 0 {
+                        if br.read_bool()? {
+                            self.coeffs[i] = -(coeff as f32) * q;
+                        } else {
+                            self.coeffs[i] =  (coeff as f32) * q;
+                        }
+                    }
+                }
+            }
+            idx = end;
+        }
+        Ok(())
+    }
+    fn output(&mut self, dst: &mut [f32], off0: usize, off1: usize, chno: usize) {
+        match self.transform {
+            Transform::DCT(ref mut dct) => {
+                    dct.do_dct_inplace(&mut self.coeffs[0..]);
+                },
+            Transform::RDFT(ref mut rdft) => {
+                    unsafe {
+                        let buf = &mut self.coeffs[0..];
+                        rdft.do_rdft_inplace(std::mem::transmute::<&mut [f32], &mut [FFTComplex]>(buf));
+                    }
+                },
+            _ => unreachable!(),
+        };
+        if self.use_dct || self.chmap.num_channels() == 1 {
+            let overlap_len = if self.first_frm { 0 } else { self.len >> 4 };
+            let out = if chno == 0 { &mut dst[off0..] } else { &mut dst[off1..] };
+            overlap(&self.delay[chno], &self.coeffs, out, overlap_len, 1);
+            let out2 = &mut out[overlap_len..self.duration];
+            out2.copy_from_slice(&self.coeffs[overlap_len..self.duration]);
+            for i in 0..(self.len >> 4) {
+                self.delay[chno][i] = self.coeffs[self.duration + i];
+            }
+        } else { // somehow it ends here in reverse order
+            for i in 0..self.len >> 2 {
+                let t0 = self.coeffs[self.len - 2 - i * 2];
+                let t1 = self.coeffs[self.len - 1 - i * 2];
+                self.coeffs[self.len - 2 - i * 2] = self.coeffs[i * 2];
+                self.coeffs[self.len - 1 - i * 2] = self.coeffs[i * 2 + 1];
+                self.coeffs[i * 2] = t0;
+                self.coeffs[i * 2 + 1] = t1;
+            }
+            let overlap_len = if self.first_frm { 0 } else { self.len >> 8 };
+            overlap(&self.delay[0], &self.coeffs[0..], &mut dst[off0..], overlap_len, 2);
+            overlap(&self.delay[1], &self.coeffs[1..], &mut dst[off1..], overlap_len, 2);
+            for i in overlap_len..self.duration {
+                dst[i + off0] = self.coeffs[i * 2 + 0];
+                dst[i + off1] = self.coeffs[i * 2 + 1];
+            }
+            for i in 0..(self.len >> 8) {
+                self.delay[0][i] = self.coeffs[self.duration * 2 + i * 2 + 0];
+                self.delay[1][i] = self.coeffs[self.duration * 2 + i * 2 + 1];
+            }
+        }
+    }
+}
+
+const CRITICAL_FREQS: [usize; MAX_BANDS] = [
+      100,   200,  300,  400,  510,  630,   770,   920,
+     1080,  1270, 1480, 1720, 2000, 2320,  2700,  3150,
+     3700,  4400, 5300, 6400, 7700, 9500, 12000, 15500,
+    24500
+];
+
+const RUN_TAB: [usize; 16] = [ 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32, 64 ];
+
+impl NADecoder for BinkAudioDecoder {
+    fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+            let srate    = ainfo.get_sample_rate();
+            let channels = ainfo.get_channels();
+            validate!(channels <= 2);
+            self.ainfo = NAAudioInfo::new(srate, channels, SND_F32P_FORMAT, 2);
+            self.chmap = NAChannelMap::from_str("L,R").unwrap();
+            if let Some(ref edata) = info.get_extradata() {
+                if edata.as_slice() == b"BIKb" {
+                    self.version_b = true;
+                }
+            } else {
+                self.version_b = false;
+            }
+            let mut frame_bits = if srate < 22050 { 9 } else if srate < 44100 { 10 } else { 11 };
+            if !self.use_dct && !self.version_b {
+                frame_bits += 1;
+            }
+            self.len = 1 << frame_bits;
+            self.duration = self.len - (self.len >> 4);
+            let single = !self.use_dct && channels == 2; // RDFT codes samples interleaved as single buffer
+            if single {
+                self.duration >>= 1;
+            }
+            self.transform = if !self.use_dct {
+                    Transform::RDFT(RDFTBuilder::new_rdft(FFTMode::SplitRadix, self.len >> 1, false))
+                } else {
+                    Transform::DCT(DCT::new(DCTMode::DCT_III, self.len))
+                };
+            self.scale = if !self.use_dct {
+                    1.0 / (32768.0 * (self.len as f32).sqrt())
+                } else {
+                    (2.0 / (self.len as f32)).sqrt() / 1024.0
+                };
+            let s_srate = if single { srate } else { srate >> 1 } as usize;
+            self.num_bands = 1;
+            while self.num_bands < CRITICAL_FREQS.len() && CRITICAL_FREQS[self.num_bands - 1] < s_srate {
+                self.num_bands += 1;
+            }
+            self.bands[0] = 2;
+            for i in 1..self.num_bands {
+                self.bands[i] = (CRITICAL_FREQS[i - 1] * self.len / s_srate) & !1;
+            }
+            self.bands[self.num_bands] = self.len;
+            self.first_frm = true;
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() > 1);
+            let mut br = BitReader::new(&pktbuf, pktbuf.len(), BitReaderMode::LE);
+            let nsamples = br.read(32)? as usize;
+//            validate!(nsamples % self.duration == 0);
+
+            let mut abuf = alloc_audio_buffer(self.ainfo, nsamples / self.chmap.num_channels() / 2, self.chmap.clone())?;
+            let mut adata = abuf.get_abuf_f32().unwrap();
+            let mut off0 = adata.get_offset(0);
+            let mut off1 = adata.get_offset(1);
+            let mut dst = adata.get_data_mut();
+
+            let num_subframes = nsamples / self.duration / self.chmap.num_channels() / 2;
+
+            for _subfrm in 0..num_subframes {
+                if self.use_dct {
+                                                    br.skip(2)?;
+                }
+                self.decode_block(&mut br)?;
+                self.output(&mut dst[0..], off0, off1, 0);
+                if self.chmap.num_channels() > 1 && self.use_dct {
+                    self.decode_block(&mut br)?;
+                    self.output(&mut dst[0..], off0, off1, 1);
+                }
+                self.first_frm = false;
+                let left = br.left() & 31;
+                if left != 0 {
+                    br.skip(left as u32)?;
+                }
+                off0 += self.duration;
+                off1 += self.duration;
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+            frm.set_duration(Some(self.duration as u64));
+            frm.set_keyframe(false);
+            Ok(Rc::new(RefCell::new(frm)))
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+}
 
 pub fn get_decoder_dct() -> Box<NADecoder> {
-unimplemented!("");
+    Box::new(BinkAudioDecoder::new(true))
 }
 
 pub fn get_decoder_rdft() -> Box<NADecoder> {
-unimplemented!("");
+    Box::new(BinkAudioDecoder::new(false))
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_core::test::dec_video::*;
+    use crate::codecs::rad_register_all_codecs;
+    use crate::demuxers::rad_register_all_demuxers;
+
+    #[test]
+    fn test_bink_audio() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        rad_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        rad_register_all_codecs(&mut dec_reg);
+
+//        let file = "assets/RAD/ActivisionLogo.bik";
+        let file = "assets/RAD/original.bik";
+//        let file = "assets/RAD/Snd0a110c51.dee";
+//        let file = "assets/RAD/NEW.BIK";
+//        let file = "assets/RAD/ge_video_86l.bk2";
+        test_decode_audio("bink", file, None, "bink", &dmx_reg, &dec_reg);
+    }
 }