]> git.nihav.org Git - nihav.git/blobdiff - nihav-duck/src/codecs/on2avc.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-duck / src / codecs / on2avc.rs
index d3ac75b36540c81264a0fcd7ab540111144c792f..4fabe2b458deb7da24a0f3110ed285155d44df21 100644 (file)
@@ -4,8 +4,8 @@ use nihav_core::io::byteio::read_u16le;
 use nihav_core::io::bitreader::*;
 use nihav_core::io::codebook::*;
 use nihav_core::io::intcode::*;
-use nihav_core::dsp::fft::*;
-use nihav_core::dsp::mdct::IMDCT;
+use nihav_codec_support::dsp::fft::*;
+use nihav_codec_support::dsp::mdct::IMDCT;
 
 use std::str::FromStr;
 
@@ -37,56 +37,39 @@ struct Codebooks {
     spec_cb:        [Codebook<u16>; 15],
 }
 
-fn scale_map(idx: usize) -> i8 { (idx as i8) - 60 }
-fn cb_map1(idx: usize)  -> u16 { AVC_SPEC_CB1_SYMS[idx] }
-fn cb_map2(idx: usize)  -> u16 { AVC_SPEC_CB2_SYMS[idx] }
-fn cb_map3(idx: usize)  -> u16 { AVC_SPEC_CB3_SYMS[idx] }
-fn cb_map4(idx: usize)  -> u16 { AVC_SPEC_CB4_SYMS[idx] }
-fn cb_map5(idx: usize)  -> u16 { AVC_SPEC_CB5_SYMS[idx] }
-fn cb_map6(idx: usize)  -> u16 { AVC_SPEC_CB6_SYMS[idx] }
-fn cb_map7(idx: usize)  -> u16 { AVC_SPEC_CB7_SYMS[idx] }
-fn cb_map8(idx: usize)  -> u16 { AVC_SPEC_CB8_SYMS[idx] }
-fn cb_map9(idx: usize)  -> u16 { AVC_SPEC_CB9_SYMS[idx] }
-fn cb_map10(idx: usize) -> u16 { AVC_SPEC_CB10_SYMS[idx] }
-fn cb_map11(idx: usize) -> u16 { AVC_SPEC_CB11_SYMS[idx] }
-fn cb_map12(idx: usize) -> u16 { AVC_SPEC_CB12_SYMS[idx] }
-fn cb_map13(idx: usize) -> u16 { AVC_SPEC_CB13_SYMS[idx] }
-fn cb_map14(idx: usize) -> u16 { AVC_SPEC_CB14_SYMS[idx] }
-fn cb_map15(idx: usize) -> u16 { AVC_SPEC_CB15_SYMS[idx] }
-
 impl Codebooks {
     fn new() -> Self {
-        let mut coderead = TableCodebookDescReader::new(AVC_SCF_CODEBOOK_CODES, AVC_SCF_CODEBOOK_BITS, scale_map);
+        let mut coderead = TableCodebookDescReader::new(AVC_SCF_CODEBOOK_CODES, AVC_SCF_CODEBOOK_BITS, |idx| (idx as i8) - 60);
         let scale_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB1_CODES, AVC_SPEC_CB1_BITS, cb_map1);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB1_CODES, AVC_SPEC_CB1_BITS, |idx| AVC_SPEC_CB1_SYMS[idx]);
         let cb1 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB2_CODES, AVC_SPEC_CB2_BITS, cb_map2);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB2_CODES, AVC_SPEC_CB2_BITS, |idx| AVC_SPEC_CB2_SYMS[idx]);
         let cb2 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB3_CODES, AVC_SPEC_CB3_BITS, cb_map3);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB3_CODES, AVC_SPEC_CB3_BITS, |idx| AVC_SPEC_CB3_SYMS[idx]);
         let cb3 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB4_CODES, AVC_SPEC_CB4_BITS, cb_map4);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB4_CODES, AVC_SPEC_CB4_BITS, |idx| AVC_SPEC_CB4_SYMS[idx]);
         let cb4 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB5_CODES, AVC_SPEC_CB5_BITS, cb_map5);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB5_CODES, AVC_SPEC_CB5_BITS, |idx| AVC_SPEC_CB5_SYMS[idx]);
         let cb5 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB6_CODES, AVC_SPEC_CB6_BITS, cb_map6);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB6_CODES, AVC_SPEC_CB6_BITS, |idx| AVC_SPEC_CB6_SYMS[idx]);
         let cb6 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB7_CODES, AVC_SPEC_CB7_BITS, cb_map7);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB7_CODES, AVC_SPEC_CB7_BITS, |idx| AVC_SPEC_CB7_SYMS[idx]);
         let cb7 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB8_CODES, AVC_SPEC_CB8_BITS, cb_map8);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB8_CODES, AVC_SPEC_CB8_BITS, |idx| AVC_SPEC_CB8_SYMS[idx]);
         let cb8 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB9_CODES, AVC_SPEC_CB9_BITS, cb_map9);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB9_CODES, AVC_SPEC_CB9_BITS, |idx| AVC_SPEC_CB9_SYMS[idx]);
         let cb9 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB10_CODES, AVC_SPEC_CB10_BITS, cb_map10);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB10_CODES, AVC_SPEC_CB10_BITS, |idx| AVC_SPEC_CB10_SYMS[idx]);
         let cb10 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB11_CODES, AVC_SPEC_CB11_BITS, cb_map11);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB11_CODES, AVC_SPEC_CB11_BITS, |idx| AVC_SPEC_CB11_SYMS[idx]);
         let cb11 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB12_CODES, AVC_SPEC_CB12_BITS, cb_map12);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB12_CODES, AVC_SPEC_CB12_BITS, |idx| AVC_SPEC_CB12_SYMS[idx]);
         let cb12 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB13_CODES, AVC_SPEC_CB13_BITS, cb_map13);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB13_CODES, AVC_SPEC_CB13_BITS, |idx| AVC_SPEC_CB13_SYMS[idx]);
         let cb13 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB14_CODES, AVC_SPEC_CB14_BITS, cb_map14);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB14_CODES, AVC_SPEC_CB14_BITS, |idx| AVC_SPEC_CB14_SYMS[idx]);
         let cb14 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
-        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB15_CODES, AVC_SPEC_CB15_BITS, cb_map15);
+        let mut coderead = TableCodebookDescReader::new(AVC_SPEC_CB15_CODES, AVC_SPEC_CB15_BITS, |idx| AVC_SPEC_CB15_SYMS[idx]);
         let cb15 = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap();
         let spec_cb = [cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9, cb10, cb11, cb12, cb13, cb14, cb15];
         Self { scale_cb, spec_cb }
@@ -144,6 +127,7 @@ struct AVCDecoder {
     delay:          [[f32; COEFFS]; 2],
     tmp:            [f32; COEFFS * 2],
     ew_buf:         [f32; 1152],
+    use_generic:    bool,
 
     qtab:           [f32; QTAB_SIZE],
     scale_tab:      [f32; 128],
@@ -194,6 +178,7 @@ impl AVCDecoder {
             delay:          [[0.0; COEFFS]; 2],
             tmp:            [0.0; COEFFS * 2],
             ew_buf:         [0.0; 1152],
+            use_generic:    true,
 
             qtab,
             scale_tab,
@@ -208,21 +193,36 @@ impl AVCDecoder {
         let mut cur_band = 0;
         let mut scale = 0;
         let mut first = true;
-        for wg in self.win_grp.iter().take(self.windows) {
-            if *wg {
+        for wg in 0..self.windows {
+            if self.win_grp[wg] {
                 for _ in 0..bands {
                     if self.cbs[cur_band] == 0 {
-                        self.scales[cur_band] = 0;
-                    } else {
-                        if first {
-                            scale               = br.read(7)? as i16;
-                            first = false
-                        } else {
-                            scale               += br.read_cb(&self.codebooks.scale_cb)? as i16;
-                            validate!((scale >= 0) && (scale < 128));
+                        let mut all_zero = true;
+                        let mut band2 = cur_band;
+                        for wg2 in wg + 1..self.windows {
+                            if self.win_grp[wg2] {
+                                break;
+                            }
+                            band2 += bands;
+                            if self.cbs[band2] != 0 {
+                                all_zero = false;
+                                break;
+                            }
                         }
-                        self.scales[cur_band] = scale as u8;
+                        if all_zero {
+                            self.scales[cur_band] = 0;
+                            cur_band += 1;
+                            continue;
+                        }
+                    }
+                    if first {
+                        scale                   = br.read(7)? as i16;
+                        first = false;
+                    } else {
+                        scale                   += i16::from(br.read_cb(&self.codebooks.scale_cb)?);
+                        validate!((0..128).contains(&scale));
                     }
+                    self.scales[cur_band] = scale as u8;
                     cur_band += 1;
                 }
             } else {
@@ -329,140 +329,82 @@ impl AVCDecoder {
         }
         Ok(())
     }
+    #[allow(clippy::cognitive_complexity)]
     fn synth_channel(&mut self, chno: usize, dst: &mut [f32]) {
         let coeffs = &mut self.coeffs[chno];
         let delay  = &mut self.delay[chno];
 
         match self.cur_win {
             0 | 1 => {
-                self.imdct_long.imdct(coeffs, &mut self.tmp);
-                overlap(dst, &self.tmp, delay, self.win_long);
-                delay.copy_from_slice(&self.tmp[COEFFS..]);
-            },
-            2 => {
-                self.imdct_long.imdct(coeffs, &mut self.tmp);
-                for i in 0..SHORT_WIN_POINT0 {
-                    dst[i] = delay[i];
-                }
-                overlap(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &self.tmp[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    dst[i] = self.tmp[i];
+                self.imdct_long.imdct_half(coeffs, &mut self.tmp);
+                overlap_half(dst, &self.tmp, delay, self.win_long);
+                delay[0..COEFFS/2].copy_from_slice(&self.tmp[COEFFS/2..COEFFS]);
+                for i in COEFFS/2..COEFFS {
+                    delay[i] = delay[COEFFS - 1 - i];
                 }
-                delay.copy_from_slice(&self.tmp[COEFFS..]);
+            },
+            2 | 7 => {
+                self.imdct_long.imdct_half(coeffs, &mut self.ew_buf);
             },
             3 => {
                 for (ain, aout) in coeffs.chunks(128).zip(self.tmp.chunks_mut(256)) {
                     self.imdct_short.imdct(ain, aout);
                 }
                 self.ew_buf = [0.0; 1152];
-                for i in 0..128 {
-                    self.ew_buf[i] = self.tmp[i];
-                }
+                self.ew_buf[..128].copy_from_slice(&self.tmp[..128]);
                 for w in 0..7 {
                     overlap(&mut self.ew_buf[(w + 1) * 128..][..128],
                             &self.tmp[(w + 1) * 256..][..128],
                             &self.tmp[w * 256 + 128..][..128],
                             AVC_WIN_SHORT);
                 }
-                for i in 0..128 {
-                    self.ew_buf[1024 + i] = self.tmp[7 * 256 + 128 + i];
-                }
-                for i in 0..SHORT_WIN_POINT0 {
-                    dst[i] = delay[i];
-                }
+                self.ew_buf[1024..][..128].copy_from_slice(&self.tmp[7 * 256 + 128..][..128]);
+                dst[..SHORT_WIN_POINT0].copy_from_slice(&delay[..SHORT_WIN_POINT0]);
                 overlap(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
                         &self.ew_buf[0..128],
                         &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    dst[i] = self.ew_buf[i - SHORT_WIN_POINT1 + 128];
-                }
-                for i in 0..SHORT_WIN_POINT1 {
-                    delay[i] = self.ew_buf[SHORT_WIN_POINT1 + i];
-                }
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    delay[i] = 0.0;
+                dst[SHORT_WIN_POINT1..COEFFS].copy_from_slice(&self.ew_buf[128..][..COEFFS-SHORT_WIN_POINT1]);
+                delay[..SHORT_WIN_POINT1].copy_from_slice(&self.ew_buf[SHORT_WIN_POINT1..][..SHORT_WIN_POINT1]);
+                for i in COEFFS/2..COEFFS {
+                    delay[i] = delay[COEFFS - 1 - i];
                 }
             },
             4 => {
-                for i in 0..SHORT_WIN_POINT0 {
-                    dst[i] = delay[i];
-                }
-                synth1024(&mut self.dsp, coeffs, &mut self.ew_buf, &mut self.tmp, self.is_40khz);
-                let tmp = &mut self.ew_buf[0..COEFFS];
-                tmp.reverse();
-                overlap(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &self.ew_buf[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    dst[i] = self.ew_buf[i];
-                }
-                *delay = [0.0; COEFFS];
-                for i in 0..SHORT_WIN_POINT1 {
-                    delay[i] = self.ew_buf[i];
+                if !self.use_generic {
+                    synth1024(&mut self.dsp, coeffs, &mut self.ew_buf, &mut self.tmp, self.is_40khz);
+                } else {
+                    synth_generic(coeffs, &mut self.ew_buf, &mut self.tmp, self.is_40khz, 1024);
                 }
-            },
+             },
             5 => {
-                for i in 0..SHORT_WIN_POINT0 {
-                    dst[i] = delay[i];
-                }
-                synth512(&mut self.dsp, coeffs, &mut self.ew_buf, &mut self.tmp, self.is_40khz);
-                self.imdct_mid.imdct(&coeffs[512..], &mut self.ew_buf[512..]);
-                let tmp = &mut self.ew_buf[512..1024];
-                tmp.reverse();
-                let tmp = &mut self.ew_buf[0..1024];
-                tmp.reverse();
-                overlap(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &self.ew_buf[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    dst[i] = self.ew_buf[i];
-                }
-                *delay = [0.0; COEFFS];
-                for i in 0..SHORT_WIN_POINT1 {
-                    delay[i] = self.ew_buf[i];
+                if !self.use_generic {
+                    synth512(&mut self.dsp, coeffs, &mut self.ew_buf, &mut self.tmp, self.is_40khz);
+                } else {
+                    synth_generic(coeffs, &mut self.ew_buf, &mut self.tmp, self.is_40khz, 512);
                 }
+                self.imdct_mid.imdct_half(&coeffs[512..], &mut self.ew_buf[512..]);
             },
             6 => {
-                for i in 0..SHORT_WIN_POINT0 {
-                    dst[i] = delay[i];
-                }
-                self.imdct_mid.imdct(coeffs, &mut self.ew_buf);
-                let tmp = &mut self.ew_buf[0..512];
-                tmp.reverse();
-                synth512(&mut self.dsp, &coeffs[512..], &mut self.ew_buf[512..], &mut self.tmp, self.is_40khz);
-                let tmp = &mut self.ew_buf[0..1024];
-                tmp.reverse();
-                overlap(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &self.ew_buf[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    dst[i] = self.ew_buf[i];
-                }
-                *delay = [0.0; COEFFS];
-                for i in 0..SHORT_WIN_POINT1 {
-                    delay[i] = self.ew_buf[i];
-                }
-            },
-            7 => {
-                for i in 0..SHORT_WIN_POINT0 {
-                    dst[i] = delay[i];
-                }
-                self.imdct_long.imdct(coeffs, &mut self.tmp);
-                overlap(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &self.tmp[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
-                        &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
-                for i in SHORT_WIN_POINT1..COEFFS {
-                    dst[i] = self.tmp[i];
-                }
-                *delay = [0.0; COEFFS];
-                for i in 0..SHORT_WIN_POINT1 {
-                    delay[i] = self.ew_buf[i];
+                self.imdct_mid.imdct_half(coeffs, &mut self.ew_buf);
+                if !self.use_generic {
+                    synth512(&mut self.dsp, &coeffs[512..], &mut self.ew_buf[512..], &mut self.tmp, self.is_40khz);
+                } else {
+                    synth_generic(&coeffs[512..], &mut self.ew_buf[512..], &mut self.tmp, self.is_40khz, 512);
                 }
             },
             _ => unreachable!(),
         };
+        if (self.cur_win == 2) || (self.cur_win >= 4) {
+            dst[..SHORT_WIN_POINT0].copy_from_slice(&delay[..SHORT_WIN_POINT0]);
+            overlap_half(&mut dst[SHORT_WIN_POINT0..SHORT_WIN_POINT1],
+                         &self.ew_buf[0..64],
+                         &delay[SHORT_WIN_POINT0..SHORT_WIN_POINT1], AVC_WIN_SHORT);
+            dst[SHORT_WIN_POINT1..COEFFS].copy_from_slice(&self.ew_buf[64..][..COEFFS-SHORT_WIN_POINT1]);
+            delay[..COEFFS/2].copy_from_slice(&self.ew_buf[COEFFS/2..COEFFS]);
+            for i in COEFFS/2..COEFFS {
+                delay[i] = delay[COEFFS - 1 - i];
+            }
+        }
     }
 }
 
@@ -472,6 +414,19 @@ fn overlap(dst: &mut [f32], src: &[f32], delay: &[f32], win: &[f32]) {
     }
 }
 
+fn overlap_half(dst: &mut [f32], src: &[f32], delay: &[f32], win: &[f32]) {
+    let n = win.len();
+    for i in 0..n/2 {
+        let ii = n - 1 - i;
+        let c = src  [n/2 - 1 - i];
+        let d = delay[i];
+        let w0 = win[i];
+        let w1 = win[ii];
+        dst[i]      = d * w1 - c * w0;
+        dst[ii]     = d * w0 + c * w1;
+    }
+}
+
 #[derive(Clone,Copy)]
 struct SynthParams {
     p0:     usize,
@@ -484,12 +439,12 @@ macro_rules! synth_step0_template {
         fn $name(src: &[f32], dst: &mut [f32], step: usize, off: usize, sp: &SynthParams) {
             for i in 0..step {
                 for j in 0..sp.p0 {
-                    dst[i] += ((src[j] as f64) * $tab[sp.idx][j][i]) as f32;
+                    dst[i] += (f64::from(src[j]) * $tab[sp.idx][j][i]) as f32;
                 }
             }
             for i in 0..step {
                 for j in 0..sp.p1 {
-                    dst[$size - step + i] += ((src[sp.p0 + off + j] as f64) * $tab[sp.idx][sp.p0 + j][i]) as f32;
+                    dst[$size - step + i] += (f64::from(src[sp.p0 + off + j]) * $tab[sp.idx][sp.p0 + j][i]) as f32;
                 }
             }
         }
@@ -505,7 +460,7 @@ fn synth_step1(src: &[f32], dst: &mut [f32], size: usize, stride: usize, step: u
 {
     let mut pos = step - 1;
     for _ in 0..off {
-        let scale = src[p0] as f64;
+        let scale = f64::from(src[p0]);
         p0 += 1;
         pos &= size - 1;
         for i in 0..pos.min(step) {
@@ -533,6 +488,7 @@ fn zero_some(buf: &mut [FFTComplex], p0: usize, p1: usize)
     }
 }
 
+#[allow(clippy::identity_op)]
 fn merge_bands(src: &[FFTComplex], dst: &mut [FFTComplex], size: usize) {
     let step = if size == 512 { 2 } else { 4 };
     let (s01, s23) = src.split_at(size / 2);
@@ -594,12 +550,92 @@ fn merge_bands(src: &[FFTComplex], dst: &mut [FFTComplex], size: usize) {
     }
 }
 
+const SPARAMS10: [SynthParams; 2] = [
+    SynthParams { p0: 1, p1: 3, idx: 0 },
+    SynthParams { p0: 3, p1: 1, idx: 1 } ];
+const SPARAMS20: [SynthParams; 2] = [
+    SynthParams { p0: 5, p1: 4, idx: 0 },
+    SynthParams { p0: 4, p1: 5, idx: 1 } ];
+const SPARAMS40: [SynthParams; 2] = [
+    SynthParams { p0: 11, p1:  8, idx: 0 },
+    SynthParams { p0:  8, p1: 11, idx: 1 } ];
 const SPARAMS84: [SynthParams; 4] = [
     SynthParams { p0: 16, p1: 4, idx: 0 },
     SynthParams { p0: 16, p1: 4, idx: 1 },
     SynthParams { p0: 13, p1: 7, idx: 2 },
     SynthParams { p0: 15, p1: 5, idx: 3 } ];
 
+const MERGE_ORDER_44K: &[u8] = &[
+    4, 4, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 0, 0,
+    2, 0, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0
+];
+const MERGE_ORDER_40K: &[u8] = &[
+    4, 4, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 0, 0,
+    2, 0, 0, 4, 2, 0, 0, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0
+];
+
+fn synth_filter(src: &[f32], dst: &mut [f32], len: usize, step: usize, bands: usize, idx: usize)
+{
+    let off = (len - step) / bands + 1;
+    let params = match step {
+            10 => &SPARAMS10[idx],
+            20 => &SPARAMS20[idx],
+            40 => &SPARAMS40[idx],
+            _  => &SPARAMS84[idx],
+        };
+
+    if step == 10 {
+        synth_step0_10(src, dst, step, off, params);
+        synth_step1(src, dst, len, bands, step, off, params.p0, &AVC_TAB10[idx]);
+    } else if step == 20 {
+        synth_step0_20(src, dst, step, off, params);
+        synth_step1(src, dst, len, bands, step, off, params.p0, &AVC_TAB20[idx]);
+    } else if step == 40 {
+        synth_step0_40(src, dst, step, off, params);
+        synth_step1(src, dst, len, bands, step, off, params.p0, &AVC_TAB40[idx]);
+    } else {
+        synth_step0_84(src, dst, step, off, params);
+        synth_step1(src, dst, len, bands, step, off, params.p0, &AVC_TAB84[idx]);
+    }
+}
+
+fn synth_recursive(dst: &mut [f32], tmp: &mut [f32], size: usize, order: &[u8], order_idx: &mut usize, dir: bool) {
+    let bands = order[*order_idx] as usize;
+    *order_idx += 1;
+    if bands == 0 { return; }
+    let sub_size = size / bands;
+    let mut sub_dir = false;
+    for (dst, tmp) in dst.chunks_mut(sub_size).take(bands).zip(tmp.chunks_mut(sub_size)) {
+        synth_recursive(dst, tmp, sub_size, order, order_idx, sub_dir);
+        sub_dir = !sub_dir;
+    }
+    for el in tmp.iter_mut().take(size) { *el = 0.0; }
+    let step = if bands == 2 {
+            if sub_size <= 20 {
+                10
+            } else if sub_size <= 40 {
+                20
+            } else {
+                40
+            }
+        } else {
+            84
+        };
+    for (i, src) in dst.chunks_mut(sub_size).take(bands).enumerate() {
+        let idx = if !dir { i } else { bands - 1 - i };
+        synth_filter(src, tmp, size, step, bands, idx);
+    }
+    dst[..size].copy_from_slice(&tmp[..size]);
+}
+
+fn synth_generic(src: &[f32], dst: &mut [f32], tmpbuf: &mut [f32; COEFFS * 2], is_40khz: bool, size: usize) {
+    let order = if is_40khz { MERGE_ORDER_40K } else { MERGE_ORDER_44K };
+    dst[..size].copy_from_slice(&src[..size]);
+    let mut order_idx = 0;
+    synth_recursive(dst, tmpbuf, size, order, &mut order_idx, false);
+    for el in dst.iter_mut().take(COEFFS) { *el *= 0.125; }
+}
+
 fn synth1024(dsp: &mut SynthDSP, src: &[f32], dst: &mut [f32], tmpbuf: &mut [f32; COEFFS * 2], is_40khz: bool) {
     for el in tmpbuf.iter_mut() {
         *el = 0.0;
@@ -840,7 +876,7 @@ fn dequant(val: i16, qtab: &[f32; QTAB_SIZE], scale: f32) -> f32 {
     if val >= 0 {
         qtab[val as usize] * scale
     } else {
-        -qtab[val.abs() as usize] * scale
+        -qtab[val.unsigned_abs() as usize] * scale
     }
 }
 
@@ -926,7 +962,7 @@ impl NADecoder for AVCDecoder {
         if self.version == 500 {
             abuf = alloc_audio_buffer(self.ainfo, COEFFS, self.chmap.clone())?;
             let mut adata = abuf.get_abuf_f32().unwrap();
-            let mut br = BitReader::new(src.as_slice(), src.len(), BitReaderMode::BE);
+            let mut br = BitReader::new(src.as_slice(), BitReaderMode::BE);
             self.decode_frame(&mut br, &mut adata, 0)?;
         } else {
             let mut offsets: Vec<usize> = Vec::new();
@@ -948,7 +984,7 @@ impl NADecoder for AVCDecoder {
             let mut adata = abuf.get_abuf_f32().unwrap();
             let mut aoffset = 0;
             for (o, s) in offsets.iter().zip(sizes.iter()) {
-                let mut br = BitReader::new(&src[*o..], *s, BitReaderMode::BE);
+                let mut br = BitReader::new(&src[*o..][..*s], BitReaderMode::BE);
                 self.decode_frame(&mut br, &mut adata, aoffset)?;
                 aoffset += COEFFS;
             }
@@ -958,13 +994,21 @@ impl NADecoder for AVCDecoder {
         frm.set_keyframe(true);
         Ok(frm.into_ref())
     }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for AVCDecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
 }
 
-pub fn get_decoder_500() -> Box<dyn NADecoder> {
+pub fn get_decoder_500() -> Box<dyn NADecoder + Send> {
     Box::new(AVCDecoder::new(500))
 }
 
-pub fn get_decoder_501() -> Box<dyn NADecoder> {
+pub fn get_decoder_501() -> Box<dyn NADecoder + Send> {
     Box::new(AVCDecoder::new(501))
 }
 
@@ -972,21 +1016,21 @@ pub fn get_decoder_501() -> Box<dyn NADecoder> {
 mod test {
     use nihav_core::codecs::RegisteredDecoders;
     use nihav_core::demuxers::RegisteredDemuxers;
-    use nihav_core::test::dec_video::*;
-    use crate::codecs::duck_register_all_codecs;
-    use nihav_commonfmt::demuxers::generic_register_all_demuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::duck_register_all_decoders;
+    use nihav_commonfmt::generic_register_all_demuxers;
     #[test]
     fn test_avc() {
         let mut dmx_reg = RegisteredDemuxers::new();
         generic_register_all_demuxers(&mut dmx_reg);
         let mut dec_reg = RegisteredDecoders::new();
-        duck_register_all_codecs(&mut dec_reg);
+        duck_register_all_decoders(&mut dec_reg);
 
         //let file = "assets/Duck/Cell-140.vp5";
         //let file = "assets/Duck/Chocolat-500.vp5";
+        // sample: https://samples.mplayerhq.hu/V-codecs/VP7/potter-500.vp7
         let file = "assets/Duck/potter-500.vp7";
-        test_decode_audio("avi", file, Some(1500), "avc", &dmx_reg, &dec_reg);
-panic!("end");
+        test_decode_audio("avi", file, Some(1500), None/*Some("avc")*/, &dmx_reg, &dec_reg);
     }
 }