VP3 decoder
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 18 May 2019 17:00:52 +0000 (19:00 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 18 May 2019 17:00:52 +0000 (19:00 +0200)
nihav-duck/Cargo.toml
nihav-duck/src/codecs/mod.rs
nihav-duck/src/codecs/vp3.rs [new file with mode: 0644]
nihav-duck/src/codecs/vpcommon.rs [new file with mode: 0644]

index 4008b5a8ac9eed7c38b62ce450e9d29bfb617115..c2d0dfe990aaebfe27454357065a9d17599d84d3 100644 (file)
@@ -14,7 +14,7 @@ nihav_commonfmt = { path = "../nihav-commonfmt" }
 [features]
 default = ["all_decoders"]
 
-all_decoders = ["decoder_truemotion1", "decoder_truemotionrt", "decoder_dk3_adpcm", "decoder_dk4_adpcm", "decoder_truemotion2", "decoder_truemotion2x"]#, "decoder_vp3", "decoder_vp4", "decoder_vp5", "decoder_vp6", "decoder_vp7", "decoder_on2avc"]
+all_decoders = ["decoder_truemotion1", "decoder_truemotionrt", "decoder_dk3_adpcm", "decoder_dk4_adpcm", "decoder_truemotion2", "decoder_truemotion2x", "decoder_vp3"]#, "decoder_vp4", "decoder_vp5", "decoder_vp6", "decoder_vp7", "decoder_on2avc"]
 decoders = []
 
 decoder_truemotion1 = ["decoders"]
index c614b87fc989148d5b74f9676c0d4728da8c8605..6a00e0f21715678277fa0c6d6b55a30b97424f10 100644 (file)
@@ -18,6 +18,8 @@ mod vp3;
 mod vp56;
 #[cfg(feature="decoder_vp7")]
 mod vp7;
+#[cfg(any(feature="decoder_vp3", feature="decoder_vp4", feature="decoder_vp5", feature="decoder_vp6", feature="decoder_vp7"))]
+mod vpcommon;
 
 #[cfg(any(feature="decoder_dk3_adpcm", feature="decoder_dk4_adpcm"))]
 mod dkadpcm;
diff --git a/nihav-duck/src/codecs/vp3.rs b/nihav-duck/src/codecs/vp3.rs
new file mode 100644 (file)
index 0000000..1d85a79
--- /dev/null
@@ -0,0 +1,1883 @@
+use std::mem;
+use std::ptr;
+use nihav_core::codecs::*;
+use nihav_core::codecs::blockdsp::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_core::io::intcode::*;
+use super::vpcommon::*;
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+enum SBState {
+    Coded,
+    Partial,
+    Uncoded,
+}
+
+struct VP3Codes {
+    dc_cb:      [Codebook<u8>; 16],
+    ac0_cb:     [Codebook<u8>; 16],
+    ac1_cb:     [Codebook<u8>; 16],
+    ac2_cb:     [Codebook<u8>; 16],
+    ac3_cb:     [Codebook<u8>; 16],
+}
+
+fn map_idx(idx: usize) -> u8 {
+    idx as u8
+}
+
+impl VP3Codes {
+    fn new() -> Self {
+        let mut dc_cb: [Codebook<u8>; 16];
+        let mut ac0_cb: [Codebook<u8>; 16];
+        let mut ac1_cb: [Codebook<u8>; 16];
+        let mut ac2_cb: [Codebook<u8>; 16];
+        let mut ac3_cb: [Codebook<u8>; 16];
+        unsafe {
+            dc_cb = mem::uninitialized();
+            ac0_cb = mem::uninitialized();
+            ac1_cb = mem::uninitialized();
+            ac2_cb = mem::uninitialized();
+            ac3_cb = mem::uninitialized();
+            for i in 0..16 {
+                let mut cr = TableCodebookDescReader::new(&VP3_DC_CODES[i], &VP3_DC_BITS[i], map_idx);
+                let cb = Codebook::new(&mut cr, CodebookMode::MSB).unwrap();
+                ptr::write(&mut dc_cb[i], cb);
+
+                let mut cr = TableCodebookDescReader::new(&VP3_AC_CAT0_CODES[i], &VP3_AC_CAT0_BITS[i], map_idx);
+                let cb = Codebook::new(&mut cr, CodebookMode::MSB).unwrap();
+                ptr::write(&mut ac0_cb[i], cb);
+                let mut cr = TableCodebookDescReader::new(&VP3_AC_CAT1_CODES[i], &VP3_AC_CAT1_BITS[i], map_idx);
+                let cb = Codebook::new(&mut cr, CodebookMode::MSB).unwrap();
+                ptr::write(&mut ac1_cb[i], cb);
+                let mut cr = TableCodebookDescReader::new(&VP3_AC_CAT2_CODES[i], &VP3_AC_CAT2_BITS[i], map_idx);
+                let cb = Codebook::new(&mut cr, CodebookMode::MSB).unwrap();
+                ptr::write(&mut ac2_cb[i], cb);
+                let mut cr = TableCodebookDescReader::new(&VP3_AC_CAT3_CODES[i], &VP3_AC_CAT3_BITS[i], map_idx);
+                let cb = Codebook::new(&mut cr, CodebookMode::MSB).unwrap();
+                ptr::write(&mut ac3_cb[i], cb);
+            }
+        }
+        Self { dc_cb, ac0_cb, ac1_cb, ac2_cb, ac3_cb }
+    }
+}
+
+#[derive(Clone)]
+struct Block {
+    btype:      VPMBType,
+    coeffs:     [i16; 64],
+    has_ac:     bool,
+    idx:        usize,
+    mv:         MV,
+    coded:      bool,
+}
+
+impl Block {
+    fn new() -> Self {
+        Self {
+            btype:      VPMBType::Intra,
+            coeffs:     [0; 64],
+            has_ac:     false,
+            idx:        0,
+            mv:         ZERO_MV,
+            coded:      false,
+        }
+    }
+}
+
+type ReadRunFunc = fn (&mut BitReader) -> DecoderResult<usize>;
+
+const VP3_LONG_RUN_BASE: [usize; 7] = [ 1, 2, 4, 6, 10, 18, 34 ];
+const VP3_LONG_RUN_BITS: [u8;    7] = [ 0, 1, 1, 2,  3,  4, 12 ];
+fn read_long_run(br: &mut BitReader) -> DecoderResult<usize> {
+    let pfx                                     = br.read_code(UintCodeType::LimitedUnary(6, 0))? as usize;
+    if pfx == 0 { return Ok(1); }
+    Ok(VP3_LONG_RUN_BASE[pfx] + (br.read(VP3_LONG_RUN_BITS[pfx])? as usize))
+}
+
+const VP3_SHORT_RUN_BASE: [usize; 6] = [ 1, 3, 5, 7, 11, 15 ];
+const VP3_SHORT_RUN_BITS: [u8;    6] = [ 1, 1, 1, 2,  2,  4 ];
+fn read_short_run(br: &mut BitReader) -> DecoderResult<usize> {
+    let pfx                                     = br.read_code(UintCodeType::LimitedUnary(5, 0))? as usize;
+    Ok(VP3_SHORT_RUN_BASE[pfx] + (br.read(VP3_SHORT_RUN_BITS[pfx])? as usize))
+}
+
+struct BitRunDecoder {
+    value:      bool,
+    run:        usize,
+    read_run:   ReadRunFunc,
+}
+
+impl BitRunDecoder {
+    fn new(br: &mut BitReader, read_run: ReadRunFunc) -> DecoderResult<Self> {
+        let value                               = !br.read_bool()?; // it will be flipped before run decoding
+        Ok(Self { value, run: 0, read_run })
+    }
+    fn get_val(&mut self, br: &mut BitReader) -> DecoderResult<bool> {
+        if self.run == 0 {
+            self.value = !self.value;
+            self.run = (self.read_run)(br)?;
+        }
+        self.run -= 1;
+        Ok(self.value)        
+    }
+}
+
+struct VP34Decoder {
+    info:       NACodecInfoRef,
+    width:      usize,
+    height:     usize,
+    mb_w:       usize,
+    mb_h:       usize,
+    version:    u8,
+    is_intra:   bool,
+    quant:      usize,
+    shuf:       VPShuffler,
+    codes:      VP3Codes,
+    loop_str:   i16,
+
+    blocks:     Vec<Block>,
+    y_blocks:   usize,
+    y_sbs:      usize,
+    qmat_y:     [i16; 64],
+    qmat_c:     [i16; 64],
+    qmat_inter: [i16; 64],
+
+    eob_run:    usize,
+    last_dc:    [i16; 3],
+
+    blk_addr:   Vec<usize>,
+    sb_info:    Vec<SBState>,
+    sb_blocks:  Vec<u8>,
+}
+
+fn read_mv_comp_packed(br: &mut BitReader) -> DecoderResult<i16> {
+    let code                                    = br.read(3)?;
+    match code {
+        0 => Ok(0),
+        1 => Ok(1),
+        2 => Ok(-1),
+        3 => if br.read_bool()? { Ok(-2) } else { Ok(2) },
+        4 => if br.read_bool()? { Ok(-3) } else { Ok(3) },
+        5 => {
+            let val                             = (br.read(2)? as i16) + 4;
+            if br.read_bool()? {
+                Ok(-val)
+            } else {
+                Ok(val)
+            }
+        },
+        6 => {
+            let val                             = (br.read(3)? as i16) + 8;
+            if br.read_bool()? {
+                Ok(-val)
+            } else {
+                Ok(val)
+            }
+        },
+        _ => {
+            let val                             = (br.read(4)? as i16) + 16;
+            if br.read_bool()? {
+                Ok(-val)
+            } else {
+                Ok(val)
+            }
+        },
+    }
+}
+
+fn read_mv_packed(br: &mut BitReader) -> DecoderResult<MV> {
+    let x = read_mv_comp_packed(br)?;
+    let y = read_mv_comp_packed(br)?;
+    Ok(MV{ x, y })
+}
+
+fn read_mv_comp_raw(br: &mut BitReader) -> DecoderResult<i16> {
+    let val                                     = br.read(5)? as i16;
+    if br.read_bool()? {
+        Ok(-val)
+    } else {
+        Ok(val)
+    }
+}
+
+fn read_mv_raw(br: &mut BitReader) -> DecoderResult<MV> {
+    let x = read_mv_comp_raw(br)?;
+    let y = read_mv_comp_raw(br)?;
+    Ok(MV{ x, y })
+}
+
+fn rescale_qmat(dst_qmat: &mut [i16; 64], base_qmat: &[i16; 64], dc_quant: i16, ac_quant: i16) {
+    for (dst, src) in dst_qmat.iter_mut().zip(base_qmat.iter()) {
+        *dst = (src.wrapping_mul(ac_quant) / 100).max(2) << 2;
+    }
+    dst_qmat[0] = (base_qmat[0] * dc_quant / 100).max(4) << 2;
+}
+
+macro_rules! fill_dc_pred {
+    ($self: expr, $ref_id: expr, $pred: expr, $pp: expr, $bit: expr, $idx: expr) => {
+        if $self.blocks[$idx].coded && $self.blocks[$idx].btype.get_ref_id() == $ref_id {
+            $pred[$bit] = $self.blocks[$idx].coeffs[0] as i32;
+            $pp |= 1 << $bit;
+        }
+    };
+}
+
+fn vp3_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw { dst[didx + x] = src[sidx + x]; }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn vp3_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + 1] as u16)) >> 1) as u8; }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn vp3_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16)) >> 1) as u8; }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn vp3_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
+{
+    let mut didx = 0;
+    let mut sidx = 0;
+    for _ in 0..bh {
+        for x in 0..bw {
+            dst[didx + x] = (((src[sidx + x] as u16) +
+                              (src[sidx + x + 1] as u16) +
+                              (src[sidx + x + sstride] as u16) +
+                              (src[sidx + x + sstride + 1] as u16)) >> 2) as u8;
+        }
+        didx += dstride;
+        sidx += sstride;
+    }
+}
+
+fn vp3_loop_filter(data: &mut [u8], mut off: usize, step: usize, stride: usize, loop_str: i16) {
+    for _ in 0..8 {
+        let a = data[off - step * 2] as i16;
+        let b = data[off - step] as i16;
+        let c = data[off] as i16;
+        let d = data[off + step] as i16;
+        let mut diff = ((a - d) + 3 * (c - b) + 4) >> 3;
+        if diff.abs() >= 2 * loop_str {
+            diff = 0;
+        } else if diff.abs() >= loop_str {
+            if diff < 0 {
+                diff = -diff - 2 * loop_str;
+            } else {
+                diff = -diff + 2 * loop_str;
+            }
+        }
+        if diff != 0 {
+            data[off - step] = (b + diff).max(0).min(255) as u8;
+            data[off]        = (c - diff).max(0).min(255) as u8;
+        }
+
+        off += stride;
+    }
+}
+
+fn vp3_loop_filter_v(frm: &mut NASimpleVideoFrame<u8>, x: usize, y: usize, plane: usize, loop_str: i16) {
+    let off = frm.offset[plane] + x + y * frm.stride[plane];
+    vp3_loop_filter(frm.data, off, 1, frm.stride[plane], loop_str);
+}
+
+fn vp3_loop_filter_h(frm: &mut NASimpleVideoFrame<u8>, x: usize, y: usize, plane: usize, loop_str: i16) {
+    let off = frm.offset[plane] + x + y * frm.stride[plane];
+    vp3_loop_filter(frm.data, off, frm.stride[plane], 1, loop_str);
+}
+
+pub const VP3_INTERP_FUNCS: &[blockdsp::BlkInterpFunc] = &[ vp3_interp00, vp3_interp01, vp3_interp10, vp3_interp11 ];
+
+impl VP34Decoder {
+    fn new(version: u8) -> Self {
+        Self {
+            info:       NACodecInfoRef::default(),
+            width:      0,
+            height:     0,
+            mb_w:       0,
+            mb_h:       0,
+            version,
+            is_intra:   true,
+            quant:      0,
+            shuf:       VPShuffler::new(),
+            codes:      VP3Codes::new(),
+            loop_str:   0,
+
+            blocks:     Vec::new(),
+            y_blocks:   0,
+            y_sbs:      0,
+
+            qmat_y:     [0; 64],
+            qmat_c:     [0; 64],
+            qmat_inter: [0; 64],
+
+            eob_run:    0,
+            last_dc:    [0; 3],
+
+            blk_addr:   Vec::new(),
+            sb_info:    Vec::new(),
+            sb_blocks:  Vec::new(),
+        }
+    }
+    fn parse_header(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+        self.is_intra                           = !br.read_bool()?;
+                                                  br.skip(1)?;
+        self.quant                              = br.read(6)? as usize;
+        self.loop_str = VP3_LOOP_STRENGTH[self.quant];
+println!("quant = {}", self.quant);
+        if self.is_intra {
+            if br.peek(8) != 0 {
+                unimplemented!();
+            }
+            let version                         = br.read(13)?;
+println!("intra, ver {} (self {})", version, self.version);
+            validate!((self.version == 3 && version == 1) || (self.version == 4 && version == 3));
+            let coding_type                     = br.read(1)?;
+            validate!(coding_type == 0);
+                                                  br.skip(2)?;
+        }
+        Ok(())
+    }
+    fn unpack_sb_info(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+        let mut has_uncoded = false;
+        let mut has_partial = false;
+        {
+            let mut brun = BitRunDecoder::new(br, read_long_run)?;
+            for sb in self.sb_info.iter_mut() {
+                if brun.get_val(br)? {
+                    *sb = SBState::Partial;
+                    has_partial = true;
+                } else {
+                    *sb = SBState::Uncoded;
+                    has_uncoded = true;
+                }
+            }
+        }
+        if has_uncoded {
+            let mut brun = BitRunDecoder::new(br, read_long_run)?;
+            let mut cur_blk = 0;
+            for (sb, nblk) in self.sb_info.iter_mut().zip(self.sb_blocks.iter()) {
+                let nblks = *nblk as usize;
+                if *sb != SBState::Partial && brun.get_val(br)? {
+                    *sb = SBState::Coded;
+                    for _ in 0..nblks {
+                        let blk_idx = self.blk_addr[cur_blk] >> 2;
+                        self.blocks[blk_idx].coded = true;
+                        cur_blk += 1;
+                    }
+                } else {
+                    for _ in 0..nblks {
+                        let blk_idx = self.blk_addr[cur_blk] >> 2;
+                        self.blocks[blk_idx].coded = false;
+                        cur_blk += 1;
+                    }
+                }
+            }
+        }
+        if has_partial {
+            let mut brun = BitRunDecoder::new(br, read_short_run)?;
+            let mut cur_blk = 0;
+            for (sb, nblk) in self.sb_info.iter_mut().zip(self.sb_blocks.iter()) {
+                let nblks = *nblk as usize;
+                if *sb == SBState::Partial {
+                    for _ in 0..nblks {
+                        let blk_idx = self.blk_addr[cur_blk] >> 2;
+                        self.blocks[blk_idx].coded = brun.get_val(br)?;
+                        cur_blk += 1;
+                    }
+                } else {
+                    cur_blk += nblks;
+                }
+            }
+        }
+        Ok(())
+    }
+    fn unpack_mb_info(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+        let mut modes = [VPMBType::InterNoMV; 8];
+        let alphabet                            = br.read(3)? as usize;
+        let raw_modes = alphabet >= 7;
+        if alphabet == 0 {
+            for mode in VP3_DEFAULT_MB_MODES.iter() {
+                modes[br.read(3)? as usize] = *mode;
+            }
+        } else if alphabet < 7 {
+            modes.copy_from_slice(&VP3_MB_MODES[alphabet - 1]);
+        }
+
+        let mut cur_blk = 0;
+        for (sb, nblk) in self.sb_info.iter_mut().zip(self.sb_blocks.iter()).take(self.y_sbs) {
+            let nblks = *nblk as usize;
+            if *sb == SBState::Uncoded {
+                for _ in 0..nblks {
+                    self.blocks[self.blk_addr[cur_blk] >> 2].btype = VPMBType::InterNoMV;
+                    cur_blk += 1;
+                }
+            } else {
+                for _ in 0..nblks/4 {
+                    let mut coded = *sb == SBState::Coded;
+                    if !coded {
+                        for blk in 0..4 {
+                            if self.blocks[self.blk_addr[cur_blk + blk] >> 2].coded {
+                                coded = true;
+                                break;
+                            }
+                        }
+                    }
+                    let mode = if !coded {
+                            VPMBType::InterNoMV
+                        } else if !raw_modes {
+                            let code            = br.read_code(UintCodeType::LimitedUnary(7, 0))?;
+                            modes[code as usize]
+                        } else {
+                                                VP3_DEFAULT_MB_MODES[br.read(3)? as usize]
+                        };
+                    for _ in 0..4 {
+                        self.blocks[self.blk_addr[cur_blk] >> 2].btype = mode;
+                        cur_blk += 1;
+                    }
+                }
+            }
+        }
+        // replicate types for chroma
+        let mut off_y = 0;
+        let mut off_u = self.y_blocks;
+        let mut off_v = off_u + self.mb_w * self.mb_h;
+        for _blk_y in 0..self.mb_h {
+            for blk_x in 0..self.mb_w {
+                let btype = self.blocks[off_y + blk_x * 2].btype;
+                self.blocks[off_u + blk_x].btype = btype;
+                self.blocks[off_v + blk_x].btype = btype;
+            }
+            off_y += self.mb_w * 2 * 2;
+            off_u += self.mb_w;
+            off_v += self.mb_w;
+        }
+        Ok(())
+    }
+    fn unpack_mv_info(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+        let mut last_mv = ZERO_MV;
+        let mut last2_mv = ZERO_MV;
+        let read_mv                             = if br.read_bool()? { read_mv_raw } else { read_mv_packed };
+
+        let mut cur_blk = 0;
+        for _ in 0..self.y_blocks/4 {
+            if self.blocks[self.blk_addr[cur_blk] >> 2].btype == VPMBType::InterFourMV {
+                for _ in 0..4 {
+                    let blk = &mut self.blocks[self.blk_addr[cur_blk] >> 2];
+                    if blk.coded {
+                        blk.mv = (read_mv)(br)?;
+                        last2_mv = last_mv;
+                        last_mv = blk.mv;
+                    }
+                    cur_blk += 1;
+                }
+            } else {
+                let cur_mv;
+                match self.blocks[self.blk_addr[cur_blk] >> 2].btype {
+                    VPMBType::Intra | VPMBType::InterNoMV | VPMBType::GoldenNoMV => {
+                        cur_mv = ZERO_MV;
+                    },
+                    VPMBType::InterMV => {
+                        cur_mv = (read_mv)(br)?;
+                        last2_mv = last_mv;
+                        last_mv = cur_mv;
+                    },
+                    VPMBType::InterNearest => {
+                        cur_mv = last_mv;
+                    },
+                    VPMBType::InterNear => {
+                        cur_mv = last2_mv;
+                        std::mem::swap(&mut last_mv, &mut last2_mv);
+                    },
+                    _ => { // GoldenMV
+                        cur_mv = (read_mv)(br)?;
+                    },
+                };
+                for _ in 0..4 {
+                    self.blocks[self.blk_addr[cur_blk] >> 2].mv = cur_mv;
+                    cur_blk += 1;
+                }
+            }
+        }
+        Ok(())
+    }
+    fn unpack_coeffs(&mut self, br: &mut BitReader, coef_no: usize, table_y: usize, table_c: usize) -> DecoderResult<()> {
+        let cbs = if coef_no == 0 {
+                [&self.codes.dc_cb[table_y], &self.codes.dc_cb[table_c]]
+            } else if coef_no < 6 {
+                [&self.codes.ac0_cb[table_y], &self.codes.ac0_cb[table_c]]
+            } else if coef_no < 15 {
+                [&self.codes.ac1_cb[table_y], &self.codes.ac1_cb[table_c]]
+            } else if coef_no < 28 {
+                [&self.codes.ac2_cb[table_y], &self.codes.ac2_cb[table_c]]
+            } else {
+                [&self.codes.ac3_cb[table_y], &self.codes.ac3_cb[table_c]]
+            };
+        for blkaddr in self.blk_addr.iter() {
+            let blk: &mut Block = &mut self.blocks[blkaddr >> 2];
+            if !blk.coded || blk.idx != coef_no { continue; }
+            if self.eob_run > 0 {
+                blk.idx = 64;
+                self.eob_run -= 1;
+                continue;
+            }
+            let cb = if (blkaddr & 3) == 0 { cbs[0] } else { cbs[1] };
+            let token                           = br.read_cb(cb)?;
+            match token {
+                // EOBs
+                0 | 1 | 2 => { self.eob_run = (token as usize) + 1; },
+                3 | 4 | 5 => {
+                    let bits = token - 1;
+                    self.eob_run                = (br.read(bits)? as usize) + (1 << bits);
+                },
+                6 => { self.eob_run             = br.read(12)? as usize; },
+                // zero runs
+                7 | 8 => {
+                    let bits = if token == 7 { 3 } else { 6 };
+                    let run                     = (br.read(bits)? as usize) + 1;
+                    blk.idx += run;
+                    validate!(blk.idx <= 64);
+                },
+                // single coefficients
+                9 | 10 | 11 | 12 => {
+                    let val = (i16::from(token) - 7) >> 1;
+                    if (token & 1) == 1 {
+                        blk.coeffs[ZIGZAG[blk.idx]] = val;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -val;
+                    }
+                    blk.idx += 1;
+                },
+                13 | 14 | 15 | 16 => {
+                    let val = i16::from(token) - 10;
+                    if !br.read_bool()? {
+                        blk.coeffs[ZIGZAG[blk.idx]] = val;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -val;
+                    }
+                    blk.idx += 1;
+                },
+                17 | 18 | 19 | 20 | 21 | 22 => {
+                    let add_bits = if token == 22 { 9 } else { token - 16 };
+                    let sign                    = br.read_bool()?;
+                    let val                     = (br.read(add_bits)? as i16) + VP3_LITERAL_BASE[(token - 17) as usize];
+                    if !sign {
+                        blk.coeffs[ZIGZAG[blk.idx]] = val;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -val;
+                    }
+                    blk.idx += 1;
+                }
+                // zero run plus coefficient
+                23 | 24 | 25 | 26 | 27 => {
+                    blk.idx += (token - 22) as usize;
+                    validate!(blk.idx < 64);
+                    if !br.read_bool()? {
+                        blk.coeffs[ZIGZAG[blk.idx]] = 1;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -1;
+                    }
+                    blk.idx += 1;
+                },
+                28 | 29 => {
+                    let run_bits = token - 26;
+                    if token == 28 {
+                        blk.idx += 6;
+                    } else {
+                        blk.idx += 10;
+                    }
+                    let sign                    = br.read_bool()?;
+                    blk.idx                     += br.read(run_bits)? as usize;
+                    validate!(blk.idx < 64);
+                    if !sign {
+                        blk.coeffs[ZIGZAG[blk.idx]] = 1;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -1;
+                    }
+                    blk.idx += 1;
+                },
+                30 => {
+                    blk.idx += 1;
+                    validate!(blk.idx < 64);
+                    let sign                    = br.read_bool()?;
+                    let val                     = (br.read(1)? as i16) + 2;
+                    if !sign {
+                        blk.coeffs[ZIGZAG[blk.idx]] = val;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -val;
+                    }
+                    blk.idx += 1;
+                },
+                _ => {
+                    let sign                    = br.read_bool()?;
+                    let val                     = (br.read(1)? as i16) + 2;
+                    blk.idx                    += (br.read(1)? as usize) + 2;
+                    validate!(blk.idx < 64);
+                    if !sign {
+                        blk.coeffs[ZIGZAG[blk.idx]] = val;
+                    } else {
+                        blk.coeffs[ZIGZAG[blk.idx]] = -val;
+                    }
+                    blk.idx += 1;
+                },
+            };
+            if self.eob_run > 0 {
+                blk.idx = 64;
+                self.eob_run -= 1;
+            } else if coef_no > 0 {
+                blk.has_ac = true;
+            }
+        }
+        Ok(())
+    }
+    fn decode_vp3(&mut self, br: &mut BitReader, frm: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
+        for blk in self.blocks.iter_mut() {
+            blk.coeffs = [0; 64];
+            blk.idx = 0;
+            blk.coded = false;
+            blk.has_ac = false;
+        }
+        if self.is_intra {
+            for sb in self.sb_info.iter_mut() { *sb = SBState::Coded; }
+            for blk in self.blocks.iter_mut() {
+                blk.btype = VPMBType::Intra;
+                blk.coded = true;
+            }
+        } else {
+            if self.shuf.get_last().is_none() || self.shuf.get_golden().is_none() {
+                return Err(DecoderError::MissingReference);
+            }
+            self.unpack_sb_info(br)?;
+            self.unpack_mb_info(br)?;
+            self.unpack_mv_info(br)?;
+        }
+        let dc_quant = VP3_DC_SCALES[self.quant];
+        let ac_quant = VP3_AC_SCALES[self.quant];
+        rescale_qmat(&mut self.qmat_y, VP3_QMAT_Y, dc_quant, ac_quant);
+        rescale_qmat(&mut self.qmat_c, VP3_QMAT_C, dc_quant, ac_quant);
+        rescale_qmat(&mut self.qmat_inter, VP3_QMAT_INTER, dc_quant, ac_quant);
+
+        self.eob_run = 0;
+        let dc_table_y                          = br.read(4)? as usize;
+        let dc_table_c                          = br.read(4)? as usize;
+        self.unpack_coeffs(br, 0, dc_table_y, dc_table_c)?;
+        self.restore_dcs();
+
+        let ac_table_y                          = br.read(4)? as usize;
+        let ac_table_c                          = br.read(4)? as usize;
+        for coef_no in 1..64 {
+            self.unpack_coeffs(br, coef_no, ac_table_y, ac_table_c)?;
+        }
+
+        if self.is_intra {
+            self.output_blocks_intra(frm);
+        } else {
+            self.output_blocks_inter(frm);
+        }
+        if self.loop_str > 0 {
+            self.loop_filter(frm);
+        }
+
+        Ok(())
+    }
+    fn decode_vp4(&mut self) -> DecoderResult<()> {
+unimplemented!();
+    }
+    fn predict_dc(&self, bx: usize, by: usize, bw: usize, blk_idx: usize) -> i16 {
+        let mut preds = [0i32; 4];
+        let mut pp: usize = 0;
+        let ref_id = self.blocks[blk_idx].btype.get_ref_id();
+        let is_right = bx == bw - 1;
+        if bx > 0 {
+            fill_dc_pred!(self, ref_id, preds, pp, 0, blk_idx - 1);
+            if by > 0 {
+                fill_dc_pred!(self, ref_id, preds, pp, 1, blk_idx - 1 - bw);
+            }
+        }
+        if by > 0 {
+            fill_dc_pred!(self, ref_id, preds, pp, 2, blk_idx - bw);
+            if !is_right {
+                fill_dc_pred!(self, ref_id, preds, pp, 3, blk_idx + 1 - bw);
+            }
+        }
+        if pp == 0 { return self.last_dc[ref_id as usize]; }
+        let mut pred = 0i32;
+        for i in 0..4 {
+            if (pp & (1 << i)) != 0 {
+                pred += (preds[i] as i32) * (VP3_DC_WEIGHTS[pp][i] as i32);
+            }
+        }
+        pred /= VP3_DC_WEIGHTS[pp][4] as i32;
+        if (pp & 7) == 7 {
+            if (pred - preds[2]).abs() > 128 { return preds[2] as i16; }
+            if (pred - preds[0]).abs() > 128 { return preds[0] as i16; }
+            if (pred - preds[1]).abs() > 128 { return preds[1] as i16; }
+        }
+        pred as i16
+    }
+    fn restore_dcs(&mut self) {
+        let blk_stride = self.mb_w * 2;
+        let mut blk_idx = 0;
+        self.last_dc = [0; 3];
+        for by in 0..self.mb_h*2 {
+            for bx in 0..self.mb_w*2 {
+                if !self.blocks[blk_idx + bx].coded { continue; }
+                let dc = self.predict_dc(bx, by, self.mb_w*2, blk_idx + bx);
+                self.blocks[blk_idx + bx].coeffs[0] += dc;
+                self.last_dc[self.blocks[blk_idx + bx].btype.get_ref_id() as usize] = self.blocks[blk_idx + bx].coeffs[0];
+            }
+            blk_idx += blk_stride;
+        }
+        let blk_stride = self.mb_w;
+        for _plane in 1..3 {
+            self.last_dc = [0; 3];
+            for by in 0..self.mb_h {
+                for bx in 0..self.mb_w {
+                    if !self.blocks[blk_idx + bx].coded { continue; }
+                    let dc = self.predict_dc(bx, by, self.mb_w, blk_idx + bx);
+                    self.blocks[blk_idx + bx].coeffs[0] += dc;
+                    self.last_dc[self.blocks[blk_idx + bx].btype.get_ref_id() as usize] = self.blocks[blk_idx + bx].coeffs[0];
+                }
+                blk_idx += blk_stride;
+            }
+        }
+    }
+    fn output_blocks_intra(&mut self, frm: &mut NASimpleVideoFrame<u8>) {
+        let mut biter = self.blocks.iter_mut();
+        for by in 0..self.mb_h*2 {
+            for bx in 0..self.mb_w*2 {
+                let mut blk = biter.next().unwrap();
+                let qmat = if blk.btype == VPMBType::Intra { &self.qmat_y } else { &self.qmat_inter };
+                blk.coeffs[0] *= qmat[0];
+                if blk.has_ac {
+                    unquant(&mut blk.coeffs, qmat);
+                    vp_put_block(&mut blk.coeffs, bx, by, 0, frm);
+                } else {
+                    vp_put_block_dc(&mut blk.coeffs, bx, by, 0, frm);
+                }
+            }
+        }
+        for plane in 1..3 {
+            for by in 0..self.mb_h {
+                for bx in 0..self.mb_w {
+                    let mut blk = biter.next().unwrap();
+                    let qmat = if blk.btype == VPMBType::Intra { &self.qmat_c } else { &self.qmat_inter };
+                    blk.coeffs[0] *= qmat[0];
+                    if blk.has_ac {
+                        unquant(&mut blk.coeffs, qmat);
+                        vp_put_block(&mut blk.coeffs, bx, by, plane, frm);
+                    } else {
+                        vp_put_block_dc(&mut blk.coeffs, bx, by, plane, frm);
+                    }
+                }
+            }
+        }
+    }
+    fn output_blocks_inter(&mut self, frm: &mut NASimpleVideoFrame<u8>) {
+        let mut blk_idx = 0;
+        let bstride = self.mb_w * 2;
+        for by in (0..self.mb_h*2).step_by(2) {
+            for bx in (0..self.mb_w*2).step_by(2) {
+                if self.blocks[blk_idx + bx].btype != VPMBType::InterFourMV {
+                    continue;
+                }
+                let mv_a = self.blocks[blk_idx + bx].mv;
+                let mv_b = self.blocks[blk_idx + bx + 1].mv;
+                let mv_c = self.blocks[blk_idx + bx     + bstride].mv;
+                let mv_d = self.blocks[blk_idx + bx + 1 + bstride].mv;
+                let mut mv_sum = mv_a + mv_b + mv_c + mv_d;
+                mv_sum.x = (mv_sum.x + 2) >> 2;
+                mv_sum.y = (mv_sum.y + 2) >> 2;
+
+                let src = self.shuf.get_last().unwrap();
+                let mode = ((mv_a.x & 1) + (mv_a.y & 1) * 2) as usize;
+                copy_block(frm, src.clone(), 0, bx * 8, by * 8, mv_a.x >> 1, mv_a.y >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+                let mode = ((mv_b.x & 1) + (mv_b.y & 1) * 2) as usize;
+                copy_block(frm, src.clone(), 0, bx * 8 + 8, by * 8, mv_b.x >> 1, mv_b.y >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+                let mode = ((mv_c.x & 1) + (mv_c.y & 1) * 2) as usize;
+                copy_block(frm, src.clone(), 0, bx * 8, by * 8 + 8, mv_c.x >> 1, mv_c.y >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+                let mode = ((mv_d.x & 1) + (mv_d.y & 1) * 2) as usize;
+                copy_block(frm, src.clone(), 0, bx * 8 + 8, by * 8 + 8, mv_d.x >> 1, mv_d.y >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+
+                let mx = (mv_sum.x >> 1) | (mv_sum.x & 1);
+                let my = (mv_sum.y >> 1) | (mv_sum.y & 1);
+                let mode = ((mx & 1) + (my & 1) * 2) as usize;
+                copy_block(frm, src.clone(), 1, bx * 4, by * 4, mx >> 1, my >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+                copy_block(frm, src.clone(), 2, bx * 4, by * 4, mx >> 1, my >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+            }
+            blk_idx += bstride;
+        }
+
+        let mut biter = self.blocks.iter_mut();
+        for by in 0..self.mb_h*2 {
+            for bx in 0..self.mb_w*2 {
+                let mut blk = biter.next().unwrap();
+                // do MC for whole macroblock
+                if !blk.btype.is_intra() && (((bx | by) & 1) == 0) && (blk.btype != VPMBType::InterFourMV) {
+                    let src = if blk.btype.get_ref_id() == 1 {
+                            self.shuf.get_last().unwrap()
+                        } else {
+                            self.shuf.get_golden().unwrap()
+                        };
+                    let mode = ((blk.mv.x & 1) + (blk.mv.y & 1) * 2) as usize;
+                    copy_block(frm, src.clone(), 0, bx * 8, by * 8, blk.mv.x >> 1, blk.mv.y >> 1, 16, 16, 0, 1, mode, VP3_INTERP_FUNCS);
+                    let mx = (blk.mv.x >> 1) | (blk.mv.x & 1);
+                    let my = (blk.mv.y >> 1) | (blk.mv.y & 1);
+                    let mode = ((mx & 1) + (my & 1) * 2) as usize;
+                    copy_block(frm, src.clone(), 1, bx * 4, by * 4, mx >> 1, my >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+                    copy_block(frm, src.clone(), 2, bx * 4, by * 4, mx >> 1, my >> 1, 8, 8, 0, 1, mode, VP3_INTERP_FUNCS);
+                }
+                let qmat = if blk.btype.is_intra() { &self.qmat_y } else { &self.qmat_inter };
+                blk.coeffs[0] *= qmat[0];
+                if blk.has_ac {
+                    unquant(&mut blk.coeffs, qmat);
+                }
+                if blk.btype.is_intra() {
+                    if !blk.coded {
+                        copy_block(frm, self.shuf.get_last().unwrap(), 0, bx * 8, by * 8, 0, 0, 8, 8, 0, 1, 0, VP3_INTERP_FUNCS);
+                    } else if blk.has_ac {
+                        vp_put_block(&mut blk.coeffs, bx, by, 0, frm);
+                    } else {
+                        vp_put_block_dc(&mut blk.coeffs, bx, by, 0, frm);
+                    }
+                } else if blk.coded {
+                    if blk.has_ac {
+                        vp_add_block(&mut blk.coeffs, bx, by, 0, frm);
+                    } else {
+                        vp_add_block_dc(&mut blk.coeffs, bx, by, 0, frm);
+                    }
+                }
+            }
+        }
+        for plane in 1..3 {
+            for by in 0..self.mb_h {
+                for bx in 0..self.mb_w {
+                    let mut blk = biter.next().unwrap();
+                    let qmat = if blk.btype.is_intra() { &self.qmat_c } else { &self.qmat_inter };
+                    blk.coeffs[0] *= qmat[0];
+                    if blk.has_ac {
+                        unquant(&mut blk.coeffs, qmat);
+                    }
+                    if blk.btype.is_intra() {
+                        if !blk.coded {
+                            copy_block(frm, self.shuf.get_last().unwrap(), plane, bx * 8, by * 8, 0, 0, 8, 8, 0, 1, 0, VP3_INTERP_FUNCS);
+                        } else if blk.has_ac {
+                            vp_put_block(&mut blk.coeffs, bx, by, plane, frm);
+                        } else {
+                            vp_put_block_dc(&mut blk.coeffs, bx, by, plane, frm);
+                        }
+                    } else if blk.coded {
+                        if blk.has_ac {
+                            vp_add_block(&mut blk.coeffs, bx, by, plane, frm);
+                        } else {
+                            vp_add_block_dc(&mut blk.coeffs, bx, by, plane, frm);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    fn loop_filter(&mut self, frm: &mut NASimpleVideoFrame<u8>) {
+        let mut blk_idx = 0;
+        let blk_w = self.mb_w * 2;
+        for by in 0..self.mb_h*2 {
+            for bx in 0..blk_w {
+                let blk = &self.blocks[blk_idx + bx];
+                if (bx > 0) && blk.coded {
+                    vp3_loop_filter_v(frm, bx * 8, by * 8, 0, self.loop_str);
+                }
+                if (by > 0) && blk.coded {
+                    vp3_loop_filter_h(frm, bx * 8, by * 8, 0, self.loop_str);
+                }
+                if (bx < blk_w - 1) && !self.blocks[blk_idx + bx + 1].coded {
+                    vp3_loop_filter_v(frm, bx * 8 + 8, by * 8, 0, self.loop_str);
+                }
+                if (by < self.mb_h * 2 - 1) && !self.blocks[blk_idx + bx + blk_w].coded {
+                    vp3_loop_filter_h(frm, bx * 8, by * 8 + 8, 0, self.loop_str);
+                }
+            }
+            blk_idx += blk_w;
+        }
+/*        for plane in 1..3 {
+            for by in 0..self.mb_h {
+                for bx in 0..self.mb_w {
+                }
+            }
+        }*/
+    }
+    fn generate_block_addr(&mut self) {
+        let sb_w_y = (self.width         + 31) >> 5;
+        let sb_h_y = (self.height        + 31) >> 5;
+        let sb_w_c = ((self.width  >> 1) + 31) >> 5;
+        let sb_h_c = ((self.height >> 1) + 31) >> 5;
+        self.y_sbs = sb_w_y * sb_h_y;
+        let tot_sb = sb_w_y * sb_h_y + 2 * sb_w_c * sb_h_c;
+        let bw = self.width >> 3;
+        let bh = self.height >> 3;
+        let tot_blk = bw * bh * 3 / 2;
+        self.sb_info.resize(tot_sb, SBState::Uncoded);
+        self.sb_blocks = Vec::with_capacity(tot_sb);
+        self.blk_addr = Vec::with_capacity(tot_blk);
+        self.y_blocks = bw * bh;
+        let mut base_idx = 0;
+        for plane in 0..3 {
+            let w = if plane > 0 { self.width  >> 1 } else { self.width };
+            let h = if plane > 0 { self.height >> 1 } else { self.height };
+            let sb_w = (w + 31) >> 5;
+            let sb_h = (h + 31) >> 5;
+            let blk_w = w >> 3;
+            let blk_h = h >> 3;
+            for y in 0..sb_h {
+                for x in 0..sb_w {
+                    let mut nblocks = 0;
+                    for blk_no in 0..16 {
+                        let bx = x * 4 + HILBERT_ORDER[blk_no][0];
+                        let by = y * 4 + HILBERT_ORDER[blk_no][1];
+                        if (bx >= blk_w) || (by >= blk_h) { continue; }
+                        let idx = base_idx + bx + by * blk_w;
+                        self.blk_addr.push(idx * 4 + plane);
+                        nblocks += 1;
+                    }
+                    self.sb_blocks.push(nblocks);
+                }
+            }
+            base_idx += blk_w * blk_h;
+        }
+        self.blocks.resize(tot_blk, Block::new());
+    }
+}
+
+impl NADecoder for VP34Decoder {
+    fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            let fmt = YUV420_FORMAT;
+            self.width  = vinfo.get_width();
+            self.height = vinfo.get_height();
+            validate!(((self.width | self.height) & 15) == 0);
+            self.mb_w   = self.width  >> 4;
+            self.mb_h   = self.height >> 4;
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), true, fmt));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+            supp.pool_u8.set_dec_bufs(3);
+            supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt), 4)?;
+
+            if self.version == 3 {
+                self.generate_block_addr();
+            }
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() > 0);
+        let mut br = BitReader::new(&src, src.len(), BitReaderMode::BE);
+
+        self.parse_header(&mut br)?;
+        if self.is_intra {
+            self.shuf.clear();
+        }
+
+        let ret = supp.pool_u8.get_free();
+        if ret.is_none() {
+            return Err(DecoderError::AllocError);
+        }
+        let mut buf = ret.unwrap();
+        let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+        if self.version == 3 {
+            self.decode_vp3(&mut br, &mut dframe)?;
+        } else {
+            self.decode_vp4()?;
+        }
+
+        if self.is_intra {
+            self.shuf.add_golden_frame(buf.clone());
+        }
+        self.shuf.add_frame(buf.clone());
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
+        frm.set_keyframe(self.is_intra);
+        frm.set_frame_type(if self.is_intra { FrameType::I } else { FrameType::P });
+        Ok(frm.into_ref())
+    }
+}
+
+pub fn get_decoder_vp3() -> Box<NADecoder> {
+    Box::new(VP34Decoder::new(3))
+}
+
+/*pub fn get_decoder_vp4() -> Box<NADecoder> {
+    Box::new(VP34Decoder::new(4))
+}*/
+
+#[cfg(test)]
+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;
+
+    #[test]
+    fn test_vp3() {
+        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);
+
+//        let file = "assets/Duck/vp30-logo.avi";
+        let file = "assets/Duck/vp31.avi";
+//        let file = "assets/Duck/vp31_crash.avi";
+//        let file = "assets/Duck/01-vp31-0500.avi";
+        test_file_decoding("avi", file, Some(3), true, false, Some("vp3"), &dmx_reg, &dec_reg);
+//panic!("end");
+    }
+
+    #[test]
+    fn test_vp4() {
+        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);
+
+        let file = "assets/Duck/ot171_vp40.avi";
+        test_file_decoding("avi", file, Some(16), true, false, Some("vp4"), &dmx_reg, &dec_reg);
+    }
+}
+
+const HILBERT_ORDER: [[usize; 2]; 16] = [
+    [ 0, 0 ], [ 1, 0 ], [ 1, 1 ], [ 0, 1 ],
+    [ 0, 2 ], [ 0, 3 ], [ 1, 3 ], [ 1, 2 ],
+    [ 2, 2 ], [ 2, 3 ], [ 3, 3 ], [ 3, 2 ],
+    [ 3, 1 ], [ 2, 1 ], [ 2, 0 ], [ 3, 0 ]
+];
+
+const VP3_LOOP_STRENGTH: [i16; 64] = [
+    30, 25, 20, 20, 15, 15, 14, 14,
+    13, 13, 12, 12, 11, 11, 10, 10,
+     9,  9,  8,  8,  7,  7,  7,  7,
+     6,  6,  6,  6,  5,  5,  5,  5,
+     4,  4,  4,  4,  3,  3,  3,  3,
+     2,  2,  2,  2,  2,  2,  2,  2,
+     0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0
+];
+
+const VP3_DEFAULT_MB_MODES: [VPMBType; 8] = [
+    VPMBType::InterNoMV,    VPMBType::Intra,        VPMBType::InterMV,      VPMBType::InterNearest,
+    VPMBType::InterNear,    VPMBType::GoldenNoMV,   VPMBType::GoldenMV,     VPMBType::InterFourMV
+];
+
+const VP3_MB_MODES: [[VPMBType; 8]; 6] = [
+  [
+    VPMBType::InterNearest, VPMBType::InterNear,    VPMBType::InterMV,      VPMBType::InterNoMV,
+    VPMBType::Intra,        VPMBType::GoldenNoMV,   VPMBType::GoldenMV,     VPMBType::InterFourMV
+  ], [
+    VPMBType::InterNearest, VPMBType::InterNear,    VPMBType::InterNoMV,    VPMBType::InterMV,
+    VPMBType::Intra,        VPMBType::GoldenNoMV,   VPMBType::GoldenMV,     VPMBType::InterFourMV
+  ], [
+    VPMBType::InterNearest, VPMBType::InterMV,      VPMBType::InterNear,    VPMBType::InterNoMV,
+    VPMBType::Intra,        VPMBType::GoldenNoMV,   VPMBType::GoldenMV,     VPMBType::InterFourMV
+  ], [
+    VPMBType::InterNearest, VPMBType::InterMV,      VPMBType::InterNoMV,    VPMBType::InterNear,
+    VPMBType::Intra,        VPMBType::GoldenNoMV,   VPMBType::GoldenMV,     VPMBType::InterFourMV
+  ], [
+    VPMBType::InterNoMV,    VPMBType::InterNearest, VPMBType::InterNear,    VPMBType::InterMV,
+    VPMBType::Intra,        VPMBType::GoldenNoMV,   VPMBType::GoldenMV,     VPMBType::InterFourMV
+  ], [
+    VPMBType::InterNoMV,    VPMBType::GoldenNoMV,   VPMBType::InterNearest, VPMBType::InterNear,
+    VPMBType::InterMV,      VPMBType::Intra,        VPMBType::GoldenMV,     VPMBType::InterFourMV
+  ]
+];
+
+const VP3_LITERAL_BASE: [i16; 6] = [ 7, 9, 13, 21, 37, 69 ];
+
+const VP3_AC_SCALES: [i16; 64] = [
+    500, 450, 400, 370, 340, 310, 285, 265,
+    245, 225, 210, 195, 185, 180, 170, 160,
+    150, 145, 135, 130, 125, 115, 110, 107,
+    100,  96,  93,  89,  85,  82,  75,  74,
+     70,  68,  64,  60,  57,  56,  52,  50,
+     49,  45,  44,  43,  40,  38,  37,  35,
+     33,  32,  30,  29,  28,  25,  24,  22,
+     21,  19,  18,  17,  15,  13,  12,  10
+];
+
+const VP3_DC_SCALES: [i16; 64] = [
+    220, 200, 190, 180, 170, 170, 160, 160,
+    150, 150, 140, 140, 130, 130, 120, 120,
+    110, 110, 100, 100,  90,  90,  90,  80,
+     80,  80,  70,  70,  70,  60,  60,  60,
+     60,  50,  50,  50,  50,  40,  40,  40,
+     40,  40,  30,  30,  30,  30,  30,  30,
+     30,  20,  20,  20,  20,  20,  20,  20,
+     20,  10,  10,  10,  10,  10,  10,  10
+];
+
+const VP3_QMAT_Y: &[i16; 64] = &[
+    16,  11,  10,  16,  24,  40,  51,  61,
+    12,  12,  14,  19,  26,  58,  60,  55,
+    14,  13,  16,  24,  40,  57,  69,  56,
+    14,  17,  22,  29,  51,  87,  80,  62,
+    18,  22,  37,  58,  68, 109, 103,  77,
+    24,  35,  55,  64,  81, 104, 113,  92,
+    49,  64,  78,  87, 103, 121, 120, 101,
+    72,  92,  95,  98, 112, 100, 103,  99
+];
+
+const VP3_QMAT_C: &[i16; 64] = &[
+    17, 18, 24, 47, 99, 99, 99, 99,
+    18, 21, 26, 66, 99, 99, 99, 99,
+    24, 26, 56, 99, 99, 99, 99, 99,
+    47, 66, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99,
+    99, 99, 99, 99, 99, 99, 99, 99
+];
+
+const VP3_QMAT_INTER: &[i16; 64] = &[
+    16,  16,  16,  20,  24,  28,  32,  40,
+    16,  16,  20,  24,  28,  32,  40,  48,
+    16,  20,  24,  28,  32,  40,  48,  64,
+    20,  24,  28,  32,  40,  48,  64,  64,
+    24,  28,  32,  40,  48,  64,  64,  64,
+    28,  32,  40,  48,  64,  64,  64,  96,
+    32,  40,  48,  64,  64,  64,  96, 128,
+    40,  48,  64,  64,  64,  96, 128, 128
+];
+
+const ZIGZAG: [usize; 64] = [
+     0,  1,  8, 16,  9,  2,  3, 10,
+    17, 24, 32, 25, 18, 11,  4,  5,
+    12, 19, 26, 33, 40, 48, 41, 34,
+    27, 20, 13,  6,  7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46,
+    53, 60, 61, 54, 47, 55, 62, 63
+];
+
+const VP3_DC_CODES: [[u16; 32]; 16] = [
+  [
+    0x002D, 0x0026, 0x0166, 0x004E, 0x02CE, 0x059E, 0x027D, 0x0008,
+    0x04F9, 0x000F, 0x000E, 0x001B, 0x0006, 0x0008, 0x0005, 0x001A,
+    0x0015, 0x0007, 0x000C, 0x0001, 0x0000, 0x0009, 0x0017, 0x0029,
+    0x0028, 0x00B2, 0x04F8, 0x059F, 0x009E, 0x013F, 0x0012, 0x0058,
+  ], [
+    0x0010, 0x0047, 0x01FF, 0x008C, 0x03FC, 0x046A, 0x0469, 0x0022,
+    0x11A1, 0x000E, 0x000D, 0x0004, 0x0005, 0x0009, 0x0006, 0x001E,
+    0x0016, 0x0007, 0x000C, 0x0001, 0x0000, 0x000A, 0x0017, 0x007D,
+    0x007E, 0x011B, 0x08D1, 0x03FD, 0x046B, 0x11A0, 0x007C, 0x00FE,
+  ], [
+    0x0016, 0x0020, 0x0086, 0x0087, 0x0367, 0x06CC, 0x06CB, 0x006E,
+    0x366D, 0x000F, 0x000E, 0x0004, 0x0005, 0x000A, 0x0006, 0x001A,
+    0x0011, 0x0007, 0x000C, 0x0001, 0x0000, 0x0009, 0x0017, 0x006F,
+    0x006D, 0x0364, 0x0D9A, 0x06CA, 0x1B37, 0x366C, 0x0042, 0x00D8,
+  ], [
+    0x0000, 0x002D, 0x00F7, 0x0058, 0x0167, 0x02CB, 0x02CA, 0x000E,
+    0x1661, 0x0003, 0x0002, 0x0008, 0x0009, 0x000D, 0x0002, 0x001F,
+    0x0017, 0x0001, 0x000C, 0x000E, 0x000A, 0x0006, 0x0078, 0x000F,
+    0x007A, 0x0164, 0x0599, 0x02CD, 0x0B31, 0x1660, 0x0079, 0x00F6,
+  ], [
+    0x0003, 0x003C, 0x000F, 0x007A, 0x001D, 0x0020, 0x0072, 0x0006,
+    0x0399, 0x0004, 0x0005, 0x0005, 0x0006, 0x000E, 0x0004, 0x0000,
+    0x0019, 0x0002, 0x000D, 0x0007, 0x001F, 0x0030, 0x0011, 0x0031,
+    0x0005, 0x0021, 0x00E7, 0x0038, 0x01CD, 0x0398, 0x007B, 0x0009,
+  ], [
+    0x0009, 0x0002, 0x0074, 0x0007, 0x00EC, 0x00D1, 0x01A6, 0x0006,
+    0x0D21, 0x0005, 0x0006, 0x0008, 0x0007, 0x000F, 0x0004, 0x0000,
+    0x001C, 0x0002, 0x0005, 0x0003, 0x000C, 0x0035, 0x01A7, 0x001B,
+    0x0077, 0x01A5, 0x0349, 0x00D0, 0x0691, 0x0D20, 0x0075, 0x00ED,
+  ], [
+    0x000A, 0x000C, 0x0012, 0x001B, 0x00B7, 0x016C, 0x0099, 0x005A,
+    0x16D8, 0x0007, 0x0006, 0x0009, 0x0008, 0x0000, 0x0005, 0x0017,
+    0x000E, 0x0002, 0x0003, 0x000F, 0x001A, 0x004D, 0x2DB3, 0x002C,
+    0x0011, 0x02DA, 0x05B7, 0x0098, 0x0B6D, 0x2DB2, 0x0010, 0x0027,
+  ], [
+    0x000D, 0x000F, 0x001D, 0x0008, 0x0051, 0x0056, 0x00AF, 0x002A,
+    0x148A, 0x0007, 0x0000, 0x0008, 0x0009, 0x000C, 0x0006, 0x0017,
+    0x000B, 0x0016, 0x0015, 0x0009, 0x0050, 0x00AE, 0x2917, 0x001C,
+    0x0014, 0x0290, 0x0523, 0x0149, 0x0A44, 0x2916, 0x0053, 0x00A5,
+  ], [
+    0x0001, 0x001D, 0x00F5, 0x00F4, 0x024D, 0x0499, 0x0498, 0x0001,
+    0x0021, 0x0006, 0x0005, 0x0006, 0x0005, 0x0002, 0x0007, 0x0025,
+    0x007B, 0x001C, 0x0020, 0x000D, 0x0048, 0x0092, 0x0127, 0x000E,
+    0x0004, 0x0011, 0x000C, 0x003C, 0x000F, 0x0000, 0x001F, 0x0013,
+  ], [
+    0x0005, 0x003C, 0x0040, 0x000D, 0x0031, 0x0061, 0x0060, 0x0002,
+    0x00F5, 0x0006, 0x0005, 0x0007, 0x0006, 0x0002, 0x0009, 0x0025,
+    0x0007, 0x0021, 0x0024, 0x0010, 0x0041, 0x00F4, 0x0019, 0x000E,
+    0x0003, 0x0011, 0x0011, 0x003F, 0x003E, 0x007B, 0x0000, 0x0013,
+  ], [
+    0x000A, 0x0007, 0x0001, 0x0009, 0x0131, 0x0261, 0x0260, 0x0015,
+    0x0001, 0x0007, 0x0006, 0x0008, 0x0007, 0x0006, 0x0012, 0x002F,
+    0x0014, 0x0027, 0x002D, 0x0016, 0x004D, 0x0099, 0x0000, 0x0004,
+    0x0001, 0x0005, 0x0017, 0x002E, 0x002C, 0x0008, 0x0006, 0x0001,
+  ], [
+    0x0000, 0x000E, 0x0017, 0x002A, 0x0010, 0x00F9, 0x00F8, 0x001E,
+    0x003F, 0x0007, 0x0006, 0x0009, 0x0008, 0x0006, 0x000F, 0x0005,
+    0x0016, 0x0029, 0x002B, 0x0015, 0x0050, 0x0011, 0x007D, 0x0004,
+    0x0017, 0x0006, 0x0014, 0x002C, 0x002D, 0x000E, 0x0009, 0x0051,
+  ], [
+    0x0002, 0x0018, 0x002F, 0x000D, 0x0053, 0x0295, 0x0294, 0x00A4,
+    0x007C, 0x0000, 0x0007, 0x0009, 0x0008, 0x001B, 0x000C, 0x0028,
+    0x006A, 0x001E, 0x001D, 0x0069, 0x00D7, 0x007D, 0x014B, 0x0019,
+    0x0016, 0x002E, 0x001C, 0x002B, 0x002A, 0x0068, 0x003F, 0x00D6,
+  ], [
+    0x0002, 0x001B, 0x000C, 0x0018, 0x0029, 0x007F, 0x02F0, 0x0198,
+    0x0179, 0x0000, 0x0007, 0x0009, 0x0008, 0x001A, 0x000D, 0x002A,
+    0x0064, 0x001E, 0x0067, 0x005F, 0x00CD, 0x007E, 0x02F1, 0x0016,
+    0x000E, 0x002E, 0x0065, 0x002B, 0x0028, 0x003E, 0x00BD, 0x0199,
+  ], [
+    0x0002, 0x0007, 0x0016, 0x0006, 0x0036, 0x005C, 0x015D, 0x015C,
+    0x02BF, 0x0000, 0x0007, 0x0009, 0x0008, 0x0018, 0x0034, 0x002A,
+    0x005E, 0x006A, 0x0064, 0x005D, 0x00CB, 0x00AD, 0x02BE, 0x0014,
+    0x0033, 0x006E, 0x005F, 0x006F, 0x006B, 0x00CA, 0x00AC, 0x015E,
+  ], [
+    0x000F, 0x001D, 0x0018, 0x000B, 0x0019, 0x0029, 0x00D6, 0x0551,
+    0x0AA1, 0x0001, 0x0000, 0x0009, 0x0008, 0x001B, 0x0038, 0x0028,
+    0x0057, 0x006A, 0x0068, 0x0056, 0x00E5, 0x0155, 0x0AA0, 0x0073,
+    0x0069, 0x00D7, 0x00AB, 0x00E4, 0x00A9, 0x0151, 0x0150, 0x02A9,
+  ]
+];
+
+const VP3_DC_BITS: [[u8; 32]; 16] = [
+  [
+     6,  7,  9,  8, 10, 11, 11,  5, 12,  4,  4,  5,  4,  4,  4,  5,
+     5,  4,  4,  3,  3,  4,  5,  6,  6,  8, 12, 11,  9, 10,  6,  7,
+  ], [
+     5,  7,  9,  8, 10, 11, 11,  6, 13,  4,  4,  4,  4,  4,  4,  5,
+     5,  4,  4,  3,  3,  4,  5,  7,  7,  9, 12, 10, 11, 13,  7,  8,
+  ], [
+     5,  6,  8,  8, 10, 11, 11,  7, 14,  4,  4,  4,  4,  4,  4,  5,
+     5,  4,  4,  3,  3,  4,  5,  7,  7, 10, 12, 11, 13, 14,  7,  8,
+  ], [
+     4,  6,  8,  7,  9, 10, 10,  6, 13,  3,  3,  4,  4,  4,  4,  5,
+     5,  4,  4,  4,  4,  5,  7,  6,  7,  9, 11, 10, 12, 13,  7,  8,
+  ], [
+     4,  6,  7,  7,  8,  9, 10,  6, 13,  3,  3,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  5,  6,  8,  6,  6,  9, 11,  9, 12, 13,  7,  7,
+  ], [
+     4,  5,  7,  6,  8,  9, 10,  6, 13,  3,  3,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  5,  7, 10,  6,  7, 10, 11,  9, 12, 13,  7,  8,
+  ], [
+     4,  5,  6,  6,  8,  9,  9,  7, 13,  3,  3,  4,  4,  3,  4,  5,
+     5,  4,  4,  5,  6,  8, 14,  6,  6, 10, 11,  9, 12, 14,  6,  7,
+  ], [
+     4,  5,  6,  5,  7,  8,  9,  7, 13,  3,  2,  4,  4,  4,  4,  5,
+     5,  5,  5,  5,  7,  9, 14,  6,  6, 10, 11,  9, 12, 14,  7,  8,
+  ], [
+     4,  6,  8,  8, 10, 11, 11,  5,  6,  3,  3,  4,  4,  4,  5,  6,
+     7,  6,  6,  6,  7,  8,  9,  4,  4,  5,  6,  6,  5,  5,  5,  5,
+  ], [
+     4,  6,  7,  7,  9, 10, 10,  5,  8,  3,  3,  4,  4,  4,  5,  6,
+     6,  6,  6,  6,  7,  8,  8,  4,  4,  5,  6,  6,  6,  7,  4,  5,
+  ], [
+     4,  5,  6,  6,  9, 10, 10,  6,  7,  3,  3,  4,  4,  4,  5,  6,
+     6,  6,  6,  6,  7,  8,  7,  4,  4,  5,  6,  6,  6,  6,  5,  5,
+  ], [
+     3,  5,  6,  6,  7, 10, 10,  7,  8,  3,  3,  4,  4,  4,  5,  5,
+     6,  6,  6,  6,  7,  7,  9,  4,  5,  5,  6,  6,  6,  6,  6,  7,
+  ], [
+     3,  5,  6,  5,  7, 10, 10,  8,  8,  2,  3,  4,  4,  5,  5,  6,
+     7,  6,  6,  7,  8,  8,  9,  5,  5,  6,  6,  6,  6,  7,  7,  8,
+  ], [
+     3,  5,  5,  5,  6,  8, 10,  9,  9,  2,  3,  4,  4,  5,  5,  6,
+     7,  6,  7,  7,  8,  8, 10,  5,  5,  6,  7,  6,  6,  7,  8,  9,
+  ], [
+     3,  4,  5,  4,  6,  7,  9,  9, 10,  2,  3,  4,  4,  5,  6,  6,
+     7,  7,  7,  7,  8,  8, 10,  5,  6,  7,  7,  7,  7,  8,  8,  9,
+  ], [
+     4,  5,  5,  4,  5,  6,  8, 11, 12,  2,  2,  4,  4,  5,  6,  6,
+     7,  7,  7,  7,  8,  9, 12,  7,  7,  8,  8,  8,  8,  9,  9, 10,
+  ]
+];
+
+const VP3_AC_CAT0_CODES: [[u16; 32]; 16] = [
+  [
+    0x0008, 0x0025, 0x017A, 0x02F7, 0x0BDB, 0x17B4, 0x2F6B, 0x001D,
+    0x2F6A, 0x0008, 0x0007, 0x0001, 0x0002, 0x000A, 0x0006, 0x0000,
+    0x001C, 0x0009, 0x000D, 0x000F, 0x000C, 0x0003, 0x000A, 0x0016,
+    0x0013, 0x005D, 0x0024, 0x00BC, 0x005C, 0x05EC, 0x000B, 0x005F,
+  ], [
+    0x000F, 0x0010, 0x004B, 0x00C6, 0x031D, 0x0C71, 0x0C70, 0x0001,
+    0x0C73, 0x0008, 0x0009, 0x0002, 0x0003, 0x000B, 0x0006, 0x0000,
+    0x001C, 0x0005, 0x000D, 0x000F, 0x000A, 0x0019, 0x0013, 0x001D,
+    0x0030, 0x0062, 0x0024, 0x004A, 0x018F, 0x0C72, 0x000E, 0x0011,
+  ], [
+    0x001B, 0x0003, 0x008D, 0x0040, 0x0239, 0x0471, 0x08E0, 0x0003,
+    0x11C3, 0x000A, 0x0009, 0x0004, 0x0005, 0x000E, 0x0007, 0x0001,
+    0x001E, 0x0006, 0x000C, 0x000B, 0x0002, 0x0000, 0x0041, 0x001F,
+    0x0022, 0x0002, 0x008F, 0x008C, 0x011D, 0x11C2, 0x001A, 0x0021,
+  ], [
+    0x001F, 0x0003, 0x0003, 0x0043, 0x000B, 0x0015, 0x0051, 0x0003,
+    0x0050, 0x000D, 0x000C, 0x0004, 0x0006, 0x000E, 0x000A, 0x0001,
+    0x001E, 0x0005, 0x0009, 0x0007, 0x0011, 0x0002, 0x0004, 0x0002,
+    0x002D, 0x0020, 0x0042, 0x0001, 0x0000, 0x0029, 0x0017, 0x002C,
+  ], [
+    0x0003, 0x001F, 0x003A, 0x005D, 0x0173, 0x02E4, 0x172D, 0x0004,
+    0x172C, 0x000F, 0x000E, 0x0009, 0x0008, 0x000C, 0x000A, 0x0001,
+    0x0016, 0x0002, 0x0005, 0x001A, 0x002F, 0x0038, 0x05CA, 0x0006,
+    0x0037, 0x001E, 0x003B, 0x0039, 0x00B8, 0x0B97, 0x0000, 0x0036,
+  ], [
+    0x0006, 0x0037, 0x005D, 0x000C, 0x00B9, 0x02E3, 0x05C4, 0x0004,
+    0x1715, 0x0000, 0x000F, 0x0008, 0x0007, 0x000C, 0x0009, 0x001D,
+    0x0016, 0x001C, 0x001A, 0x000B, 0x005E, 0x0170, 0x1714, 0x000A,
+    0x000A, 0x0036, 0x005F, 0x001B, 0x001A, 0x0B8B, 0x0002, 0x0007,
+  ], [
+    0x000C, 0x000B, 0x0079, 0x0022, 0x00F0, 0x0119, 0x0230, 0x001D,
+    0x08C4, 0x0001, 0x0000, 0x000A, 0x0009, 0x000B, 0x0007, 0x001C,
+    0x003D, 0x000D, 0x0008, 0x0015, 0x008D, 0x118B, 0x118A, 0x000D,
+    0x0010, 0x0009, 0x0014, 0x0047, 0x00F1, 0x0463, 0x001F, 0x000C,
+  ], [
+    0x0000, 0x001A, 0x0033, 0x000C, 0x0046, 0x01E3, 0x03C5, 0x0017,
+    0x1E21, 0x0002, 0x0001, 0x0009, 0x000A, 0x0007, 0x001B, 0x003D,
+    0x001B, 0x0022, 0x0079, 0x00F0, 0x1E20, 0x1E23, 0x1E22, 0x000E,
+    0x0016, 0x0018, 0x0032, 0x001A, 0x0047, 0x0789, 0x001F, 0x0010,
+  ], [
+    0x001D, 0x0061, 0x004E, 0x009E, 0x027C, 0x09F5, 0x09F4, 0x0003,
+    0x0060, 0x0000, 0x000F, 0x000B, 0x000A, 0x0009, 0x0005, 0x000D,
+    0x0031, 0x0008, 0x0038, 0x0012, 0x0026, 0x013F, 0x04FB, 0x000D,
+    0x0002, 0x000C, 0x0039, 0x001C, 0x000F, 0x001D, 0x0008, 0x0019,
+  ], [
+    0x0007, 0x0019, 0x00AB, 0x00AA, 0x0119, 0x0461, 0x0460, 0x001B,
+    0x0047, 0x0001, 0x0000, 0x000C, 0x000B, 0x0009, 0x0005, 0x000D,
+    0x0035, 0x003D, 0x003C, 0x0018, 0x0022, 0x008D, 0x0231, 0x000E,
+    0x001F, 0x0009, 0x002B, 0x0010, 0x0034, 0x0054, 0x0008, 0x0014,
+  ], [
+    0x000C, 0x0005, 0x0008, 0x005B, 0x004D, 0x0131, 0x0261, 0x001A,
+    0x0012, 0x0000, 0x000F, 0x000A, 0x0009, 0x0006, 0x001B, 0x0006,
+    0x001C, 0x002C, 0x0015, 0x005A, 0x0027, 0x0099, 0x0260, 0x000E,
+    0x0004, 0x000F, 0x0007, 0x001D, 0x000B, 0x0014, 0x0008, 0x0017,
+  ], [
+    0x000F, 0x0013, 0x0075, 0x0024, 0x0095, 0x0251, 0x04A0, 0x0010,
+    0x00C8, 0x0002, 0x0001, 0x0001, 0x0000, 0x001A, 0x0011, 0x002C,
+    0x0065, 0x0074, 0x004B, 0x00C9, 0x0129, 0x0943, 0x0942, 0x0003,
+    0x000A, 0x001C, 0x0018, 0x0033, 0x0017, 0x002D, 0x001B, 0x003B,
+  ], [
+    0x0003, 0x001A, 0x002D, 0x0038, 0x0028, 0x0395, 0x0E51, 0x0037,
+    0x00E4, 0x0001, 0x0000, 0x001F, 0x001E, 0x0017, 0x003A, 0x0073,
+    0x002A, 0x002B, 0x0029, 0x01CB, 0x0729, 0x1CA1, 0x1CA0, 0x0004,
+    0x000A, 0x0004, 0x0018, 0x0036, 0x000B, 0x002C, 0x0019, 0x003B,
+  ], [
+    0x0004, 0x0004, 0x003F, 0x0017, 0x0075, 0x01F5, 0x07D1, 0x0017,
+    0x01F6, 0x0001, 0x0000, 0x001B, 0x001A, 0x000A, 0x0032, 0x0074,
+    0x00F8, 0x00F9, 0x01F7, 0x03E9, 0x0FA0, 0x1F43, 0x1F42, 0x0003,
+    0x000A, 0x001E, 0x001C, 0x003B, 0x0018, 0x0016, 0x0016, 0x0033,
+  ], [
+    0x0004, 0x0007, 0x0018, 0x001E, 0x0036, 0x0031, 0x0177, 0x0077,
+    0x0176, 0x0001, 0x0000, 0x001A, 0x0019, 0x003A, 0x0019, 0x005C,
+    0x00BA, 0x0061, 0x00C1, 0x0180, 0x0302, 0x0607, 0x0606, 0x0002,
+    0x000A, 0x001F, 0x001C, 0x0037, 0x0016, 0x0076, 0x000D, 0x002F,
+  ], [
+    0x0000, 0x000A, 0x001A, 0x000C, 0x001D, 0x0039, 0x0078, 0x005E,
+    0x0393, 0x0002, 0x0001, 0x0016, 0x000F, 0x002E, 0x005F, 0x0073,
+    0x00E5, 0x01C8, 0x0E4A, 0x1C97, 0x1C96, 0x0E49, 0x0E48, 0x0004,
+    0x0006, 0x001F, 0x001B, 0x001D, 0x0038, 0x0038, 0x003D, 0x0079,
+  ]
+];
+
+const VP3_AC_CAT0_BITS: [[u8; 32]; 16] = [
+  [
+     5,  7,  9, 10, 12, 13, 14,  5, 14,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  4,  4,  5,  5,  6,  7,  7,  8,  7, 11,  5,  7,
+  ], [
+     5,  6,  8,  8, 10, 12, 12,  4, 12,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  4,  5,  6,  5,  6,  7,  7,  8,  9, 12,  5,  6,
+  ], [
+     5,  6,  8,  7, 10, 11, 12,  4, 13,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  4,  5,  7,  5,  6,  6,  8,  8,  9, 13,  5,  6,
+  ], [
+     5,  6,  7,  7,  9, 10, 12,  4, 12,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  5,  6,  8,  4,  6,  6,  7,  7,  7, 11,  5,  6,
+  ], [
+     4,  6,  7,  7,  9, 10, 13,  4, 13,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  5,  6,  7, 11,  4,  6,  6,  7,  7,  8, 12,  4,  6,
+  ], [
+     4,  6,  7,  6,  8, 10, 11,  4, 13,  3,  4,  4,  4,  4,  4,  5,
+     5,  5,  5,  5,  7,  9, 13,  4,  5,  6,  7,  7,  7, 12,  4,  5,
+  ], [
+     4,  5,  7,  6,  8,  9, 10,  5, 12,  3,  3,  4,  4,  4,  4,  5,
+     6,  5,  5,  6,  8, 13, 13,  4,  5,  5,  6,  7,  8, 11,  5,  5,
+  ], [
+     3,  5,  6,  5,  7,  9, 10,  5, 13,  3,  3,  4,  4,  4,  5,  6,
+     6,  6,  7,  8, 13, 13, 13,  4,  5,  5,  6,  6,  7, 11,  5,  5,
+  ], [
+     5,  7,  8,  9, 11, 13, 13,  4,  7,  3,  4,  4,  4,  4,  4,  5,
+     6,  5,  6,  6,  7, 10, 12,  4,  4,  5,  6,  6,  5,  6,  4,  5,
+  ], [
+     4,  6,  8,  8, 10, 12, 12,  5,  8,  3,  3,  4,  4,  4,  4,  5,
+     6,  6,  6,  6,  7,  9, 11,  4,  5,  5,  6,  6,  6,  7,  4,  5,
+  ], [
+     4,  5,  6,  7,  9, 11, 12,  5,  7,  3,  4,  4,  4,  4,  5,  5,
+     6,  6,  6,  7,  8, 10, 12,  4,  4,  5,  5,  6,  5,  6,  4,  5,
+  ], [
+     4,  5,  7,  6,  8, 10, 11,  5,  8,  3,  3,  4,  4,  5,  5,  6,
+     7,  7,  7,  8,  9, 12, 12,  3,  4,  5,  5,  6,  5,  6,  5,  6,
+  ], [
+     3,  5,  6,  6,  7, 10, 12,  6,  8,  3,  3,  5,  5,  5,  6,  7,
+     7,  7,  7,  9, 11, 13, 13,  3,  4,  4,  5,  6,  5,  6,  5,  6,
+  ], [
+     3,  4,  6,  5,  7,  9, 11,  6,  9,  3,  3,  5,  5,  5,  6,  7,
+     8,  8,  9, 10, 12, 13, 13,  3,  4,  5,  5,  6,  5,  6,  5,  6,
+  ], [
+     3,  4,  5,  5,  6,  7,  9,  7,  9,  3,  3,  5,  5,  6,  6,  7,
+     8,  8,  9, 10, 11, 12, 12,  3,  4,  5,  5,  6,  5,  7,  5,  6,
+  ], [
+     3,  4,  5,  4,  5,  6,  7,  7, 11,  3,  3,  5,  5,  6,  7,  8,
+     9, 10, 13, 14, 14, 13, 13,  3,  4,  5,  5,  6,  6,  7,  6,  7,
+  ]
+];
+
+const VP3_AC_CAT1_CODES: [[u16; 32]; 16] = [
+  [
+    0x000B, 0x002B, 0x0054, 0x01B7, 0x06D9, 0x0DB1, 0x0DB0, 0x0002,
+    0x00AB, 0x0009, 0x000A, 0x0007, 0x0008, 0x000F, 0x000C, 0x0003,
+    0x001D, 0x0004, 0x000B, 0x0006, 0x001A, 0x0003, 0x00AA, 0x0001,
+    0x0000, 0x0014, 0x006C, 0x00DA, 0x0002, 0x036D, 0x001C, 0x0037,
+  ], [
+    0x001D, 0x0004, 0x00B6, 0x006A, 0x05B9, 0x16E1, 0x16E0, 0x0007,
+    0x016F, 0x000C, 0x000D, 0x0009, 0x0008, 0x000F, 0x000A, 0x0003,
+    0x0017, 0x0002, 0x0004, 0x001C, 0x002C, 0x006B, 0x0B71, 0x0005,
+    0x0003, 0x001B, 0x005A, 0x0034, 0x0005, 0x02DD, 0x0000, 0x000C,
+  ], [
+    0x0003, 0x007F, 0x00A1, 0x00A0, 0x020C, 0x0834, 0x106B, 0x0007,
+    0x0082, 0x000E, 0x000D, 0x000B, 0x000C, 0x0000, 0x0009, 0x0002,
+    0x0011, 0x001E, 0x0015, 0x003E, 0x0040, 0x041B, 0x106A, 0x0006,
+    0x000A, 0x0029, 0x007E, 0x0051, 0x0021, 0x0107, 0x0004, 0x000B,
+  ], [
+    0x0007, 0x001B, 0x00F6, 0x00E9, 0x03A1, 0x0740, 0x0E82, 0x001F,
+    0x01EF, 0x0001, 0x0002, 0x000B, 0x000C, 0x000D, 0x0008, 0x001C,
+    0x0003, 0x0012, 0x0002, 0x0075, 0x01D1, 0x1D07, 0x1D06, 0x000A,
+    0x0013, 0x003B, 0x001A, 0x007A, 0x003C, 0x01EE, 0x0000, 0x000C,
+  ], [
+    0x000D, 0x003D, 0x0042, 0x0037, 0x00D9, 0x0362, 0x06C6, 0x001F,
+    0x0086, 0x0001, 0x0002, 0x000C, 0x000B, 0x000A, 0x0001, 0x000F,
+    0x0025, 0x003C, 0x001A, 0x0087, 0x01B0, 0x0D8F, 0x0D8E, 0x000E,
+    0x0013, 0x000C, 0x0024, 0x0020, 0x0011, 0x006D, 0x0000, 0x000E,
+  ], [
+    0x0000, 0x0012, 0x0076, 0x0077, 0x014D, 0x0533, 0x14C9, 0x0013,
+    0x00A5, 0x0002, 0x0003, 0x000B, 0x000C, 0x0008, 0x001A, 0x002B,
+    0x0075, 0x0074, 0x00A7, 0x0298, 0x14C8, 0x14CB, 0x14CA, 0x000F,
+    0x001C, 0x0007, 0x002A, 0x0028, 0x001B, 0x00A4, 0x0002, 0x0006,
+  ], [
+    0x0002, 0x001A, 0x002B, 0x003A, 0x00ED, 0x0283, 0x0A0A, 0x0004,
+    0x00A1, 0x0004, 0x0003, 0x000B, 0x000C, 0x001F, 0x0006, 0x0077,
+    0x00A3, 0x00A2, 0x0140, 0x1417, 0x1416, 0x0A09, 0x0A08, 0x0000,
+    0x001E, 0x0007, 0x002A, 0x0029, 0x001C, 0x00EC, 0x001B, 0x0005,
+  ], [
+    0x0002, 0x0002, 0x0018, 0x001D, 0x0035, 0x00E4, 0x01CF, 0x001D,
+    0x0072, 0x0004, 0x0005, 0x0006, 0x0007, 0x0006, 0x0073, 0x0038,
+    0x01CE, 0x039B, 0x0398, 0x0733, 0x0732, 0x0735, 0x0734, 0x0000,
+    0x001F, 0x001B, 0x0034, 0x000F, 0x001E, 0x00E5, 0x0019, 0x0038,
+  ], [
+    0x0016, 0x0050, 0x0172, 0x02E7, 0x1732, 0x2E67, 0x2E66, 0x0006,
+    0x0051, 0x0001, 0x0000, 0x000D, 0x000C, 0x0009, 0x001C, 0x0009,
+    0x001C, 0x001D, 0x005D, 0x00B8, 0x05CD, 0x1731, 0x1730, 0x000F,
+    0x0005, 0x000F, 0x0008, 0x0029, 0x001D, 0x002F, 0x0008, 0x0015,
+  ], [
+    0x0009, 0x0021, 0x0040, 0x00AD, 0x02B0, 0x1589, 0x1588, 0x001C,
+    0x005F, 0x0000, 0x000F, 0x000D, 0x000C, 0x0006, 0x0011, 0x002A,
+    0x0057, 0x005E, 0x0041, 0x0159, 0x0563, 0x158B, 0x158A, 0x0001,
+    0x0005, 0x0014, 0x003B, 0x002E, 0x0004, 0x003A, 0x0007, 0x0016,
+  ], [
+    0x000E, 0x0007, 0x0046, 0x0045, 0x0064, 0x032A, 0x0657, 0x0018,
+    0x000D, 0x0000, 0x000F, 0x000A, 0x000B, 0x001A, 0x0036, 0x0047,
+    0x0044, 0x0018, 0x0033, 0x00CB, 0x0656, 0x0329, 0x0328, 0x0002,
+    0x0006, 0x0019, 0x000E, 0x0037, 0x0009, 0x000F, 0x0002, 0x0010,
+  ], [
+    0x0003, 0x0018, 0x0023, 0x0077, 0x0194, 0x1956, 0x32AF, 0x003A,
+    0x0076, 0x0002, 0x0001, 0x001F, 0x001E, 0x0014, 0x0022, 0x0064,
+    0x0197, 0x0196, 0x032B, 0x0654, 0x32AE, 0x1955, 0x1954, 0x0000,
+    0x0009, 0x001C, 0x0015, 0x0010, 0x000D, 0x0017, 0x0016, 0x0033,
+  ], [
+    0x0005, 0x0006, 0x003E, 0x0010, 0x0048, 0x093F, 0x24FA, 0x0032,
+    0x0067, 0x0002, 0x0001, 0x001B, 0x001E, 0x0034, 0x0066, 0x0092,
+    0x0126, 0x024E, 0x049E, 0x49F7, 0x49F6, 0x24F9, 0x24F8, 0x0000,
+    0x0007, 0x0018, 0x0011, 0x003F, 0x000E, 0x0013, 0x0035, 0x0025,
+  ], [
+    0x0005, 0x0008, 0x0012, 0x001C, 0x001C, 0x00EA, 0x1D75, 0x001E,
+    0x0066, 0x0001, 0x0002, 0x001B, 0x001A, 0x001F, 0x003B, 0x0074,
+    0x01D6, 0x03AF, 0x1D74, 0x1D77, 0x1D76, 0x0EB9, 0x0EB8, 0x000F,
+    0x0006, 0x0013, 0x003B, 0x003A, 0x0000, 0x0018, 0x0032, 0x0067,
+  ], [
+    0x0004, 0x000A, 0x001B, 0x000C, 0x000D, 0x00E6, 0x0684, 0x0072,
+    0x00E7, 0x0002, 0x0001, 0x0017, 0x0016, 0x0018, 0x00D1, 0x01A0,
+    0x0686, 0x0D0F, 0x0D0A, 0x1A17, 0x1A16, 0x1A1D, 0x1A1C, 0x000F,
+    0x001D, 0x000E, 0x0035, 0x0038, 0x0000, 0x000F, 0x0019, 0x0069,
+  ], [
+    0x0003, 0x000C, 0x001B, 0x0000, 0x0003, 0x002E, 0x0051, 0x00BC,
+    0x0053, 0x0004, 0x0002, 0x0016, 0x0015, 0x0015, 0x0050, 0x00A4,
+    0x0294, 0x052B, 0x052A, 0x052D, 0x052C, 0x052F, 0x052E, 0x000E,
+    0x001A, 0x0004, 0x0028, 0x0029, 0x000F, 0x000B, 0x005F, 0x00BD,
+  ]
+];
+
+const VP3_AC_CAT1_BITS: [[u8; 32]; 16] = [
+  [
+     5,  7,  8,  9, 11, 12, 12,  4,  9,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  4,  5,  6,  9,  4,  5,  6,  7,  8,  6, 10,  5,  6,
+  ], [
+     5,  6,  8,  8, 11, 13, 13,  4,  9,  4,  4,  4,  4,  4,  4,  4,
+     5,  4,  4,  5,  6,  8, 12,  4,  5,  6,  7,  7,  6, 10,  4,  5,
+  ], [
+     4,  7,  8,  8, 10, 12, 13,  4,  8,  4,  4,  4,  4,  3,  4,  4,
+     5,  5,  5,  6,  7, 11, 13,  4,  5,  6,  7,  7,  6,  9,  4,  5,
+  ], [
+     4,  6,  8,  8, 10, 11, 12,  5,  9,  3,  3,  4,  4,  4,  4,  5,
+     5,  5,  5,  7,  9, 13, 13,  4,  5,  6,  6,  7,  6,  9,  4,  5,
+  ], [
+     4,  6,  7,  7,  9, 11, 12,  5,  8,  3,  3,  4,  4,  4,  4,  5,
+     6,  6,  6,  8, 10, 13, 13,  4,  5,  5,  6,  6,  5,  8,  4,  5,
+  ], [
+     3,  5,  7,  7,  9, 11, 13,  5,  8,  3,  3,  4,  4,  4,  5,  6,
+     7,  7,  8, 10, 13, 13, 13,  4,  5,  5,  6,  6,  5,  8,  4,  5,
+  ], [
+     3,  5,  6,  6,  8, 10, 12,  5,  8,  3,  3,  4,  4,  5,  5,  7,
+     8,  8,  9, 13, 13, 12, 12,  3,  5,  5,  6,  6,  5,  8,  5,  5,
+  ], [
+     3,  4,  5,  5,  6,  8, 11,  7,  9,  3,  3,  4,  4,  5,  7,  8,
+    11, 12, 12, 13, 13, 13, 13,  3,  5,  5,  6,  6,  5,  8,  5,  6,
+  ], [
+     5,  7,  9, 10, 13, 14, 14,  4,  7,  3,  3,  4,  4,  4,  5,  5,
+     6,  6,  7,  8, 11, 13, 13,  4,  4,  5,  5,  6,  5,  6,  4,  5,
+  ], [
+     4,  6,  7,  8, 10, 13, 13,  5,  7,  3,  4,  4,  4,  4,  5,  6,
+     7,  7,  7,  9, 11, 13, 13,  3,  4,  5,  6,  6,  4,  6,  4,  5,
+  ], [
+     4,  5,  7,  7,  9, 12, 13,  5,  6,  3,  4,  4,  4,  5,  6,  7,
+     7,  7,  8, 10, 13, 12, 12,  3,  4,  5,  5,  6,  4,  5,  4,  5,
+  ], [
+     3,  5,  6,  7,  9, 13, 14,  6,  7,  3,  3,  5,  5,  5,  6,  7,
+     9,  9, 10, 11, 14, 13, 13,  3,  4,  5,  5,  5,  4,  5,  5,  6,
+  ], [
+     3,  4,  6,  5,  7, 12, 14,  6,  7,  3,  3,  5,  5,  6,  7,  8,
+     9, 10, 11, 15, 15, 14, 14,  3,  4,  5,  5,  6,  4,  5,  6,  6,
+  ], [
+     3,  4,  5,  5,  6,  9, 14,  6,  7,  3,  3,  5,  5,  6,  7,  8,
+    10, 11, 14, 14, 14, 13, 13,  4,  4,  5,  6,  6,  3,  5,  6,  7,
+  ], [
+     3,  4,  5,  4,  5,  8, 11,  7,  8,  3,  3,  5,  5,  6,  8,  9,
+    11, 12, 12, 13, 13, 13, 13,  4,  5,  5,  6,  6,  3,  5,  6,  7,
+  ], [
+     3,  4,  5,  3,  4,  6,  9,  8,  9,  3,  3,  5,  5,  7,  9, 10,
+    12, 13, 13, 13, 13, 13, 13,  4,  5,  5,  6,  6,  4,  6,  7,  8,
+  ]
+];
+
+const VP3_AC_CAT2_CODES: [[u16; 32]; 16] = [
+  [
+    0x0003, 0x0009, 0x00D0, 0x01A3, 0x0344, 0x0D14, 0x1A2B, 0x0004,
+    0x0015, 0x0000, 0x000F, 0x000B, 0x000C, 0x000E, 0x0009, 0x001B,
+    0x000A, 0x0014, 0x000D, 0x002A, 0x0014, 0x068B, 0x1A2A, 0x0008,
+    0x000B, 0x002B, 0x000B, 0x0069, 0x0035, 0x0008, 0x0007, 0x000C,
+  ], [
+    0x000A, 0x003C, 0x0032, 0x0030, 0x00C5, 0x0621, 0x0620, 0x001F,
+    0x0033, 0x0001, 0x0000, 0x000E, 0x000D, 0x000C, 0x0004, 0x000D,
+    0x0026, 0x0027, 0x0014, 0x0063, 0x0189, 0x0623, 0x0622, 0x000B,
+    0x0012, 0x003D, 0x0022, 0x0015, 0x000B, 0x0023, 0x0007, 0x0010,
+  ], [
+    0x000F, 0x000C, 0x0043, 0x0010, 0x0044, 0x0114, 0x0455, 0x0018,
+    0x0023, 0x0001, 0x0000, 0x000E, 0x000D, 0x0009, 0x0019, 0x0009,
+    0x0017, 0x0016, 0x0042, 0x008B, 0x0454, 0x0457, 0x0456, 0x000B,
+    0x0015, 0x000A, 0x0029, 0x0020, 0x000D, 0x0028, 0x0007, 0x0011,
+  ], [
+    0x0001, 0x001A, 0x0029, 0x002A, 0x00A0, 0x0285, 0x1425, 0x0002,
+    0x0000, 0x0002, 0x0003, 0x000C, 0x000B, 0x0008, 0x0012, 0x0001,
+    0x0051, 0x0001, 0x0143, 0x0508, 0x1424, 0x1427, 0x1426, 0x000F,
+    0x001C, 0x0003, 0x0037, 0x002B, 0x0013, 0x0036, 0x001D, 0x0001,
+  ], [
+    0x0004, 0x001F, 0x003D, 0x0006, 0x0016, 0x0053, 0x014A, 0x0034,
+    0x002A, 0x0002, 0x0003, 0x000B, 0x000C, 0x001C, 0x0037, 0x0017,
+    0x002B, 0x0028, 0x00A4, 0x052D, 0x052C, 0x052F, 0x052E, 0x0000,
+    0x001D, 0x0007, 0x0004, 0x0035, 0x0014, 0x0036, 0x0015, 0x003C,
+  ], [
+    0x0004, 0x000A, 0x0007, 0x001D, 0x0009, 0x01F3, 0x07C7, 0x0008,
+    0x01F0, 0x0003, 0x0002, 0x000D, 0x000C, 0x0017, 0x007D, 0x01F2,
+    0x07C6, 0x07C5, 0x1F12, 0x3E27, 0x3E26, 0x1F11, 0x1F10, 0x0000,
+    0x001E, 0x0006, 0x0039, 0x0038, 0x003F, 0x002C, 0x0005, 0x002D,
+  ], [
+    0x0002, 0x0007, 0x0018, 0x0003, 0x0005, 0x0035, 0x004F, 0x0012,
+    0x04E5, 0x0005, 0x0004, 0x000D, 0x000E, 0x0033, 0x0026, 0x009D,
+    0x04E4, 0x04E7, 0x04E6, 0x04E1, 0x04E0, 0x04E3, 0x04E2, 0x0000,
+    0x001F, 0x000C, 0x003D, 0x003C, 0x0032, 0x0034, 0x001B, 0x0008,
+  ], [
+    0x0000, 0x0004, 0x001C, 0x000F, 0x0002, 0x0007, 0x0075, 0x00E8,
+    0x1D2A, 0x0005, 0x0004, 0x000D, 0x000C, 0x0077, 0x0E96, 0x3A57,
+    0x3A56, 0x3A5D, 0x3A5C, 0x3A5F, 0x3A5E, 0x1D29, 0x1D28, 0x0003,
+    0x0006, 0x000A, 0x002C, 0x0017, 0x0076, 0x01D3, 0x03A4, 0x002D,
+  ], [
+    0x000A, 0x0024, 0x00BF, 0x0085, 0x0211, 0x0842, 0x1087, 0x0018,
+    0x0020, 0x0001, 0x0002, 0x000E, 0x000D, 0x0007, 0x0013, 0x0025,
+    0x005E, 0x0043, 0x00BE, 0x0109, 0x1086, 0x0841, 0x0840, 0x000F,
+    0x0001, 0x0011, 0x0000, 0x002E, 0x0019, 0x0001, 0x0006, 0x0016,
+  ], [
+    0x0002, 0x000F, 0x006F, 0x0061, 0x0374, 0x1BA8, 0x3753, 0x0012,
+    0x0036, 0x0000, 0x0001, 0x000A, 0x000B, 0x001A, 0x0031, 0x0060,
+    0x00DC, 0x01BB, 0x06EB, 0x1BAB, 0x3752, 0x3755, 0x3754, 0x000E,
+    0x0006, 0x0013, 0x000E, 0x003E, 0x0008, 0x001E, 0x0019, 0x003F,
+  ], [
+    0x0003, 0x001C, 0x0025, 0x0024, 0x01DA, 0x1DBD, 0x3B7C, 0x003C,
+    0x003D, 0x0000, 0x0001, 0x000B, 0x000A, 0x000B, 0x0077, 0x00EC,
+    0x03B6, 0x076E, 0x1DBF, 0x76FB, 0x76FA, 0x3B79, 0x3B78, 0x000D,
+    0x001F, 0x0013, 0x000A, 0x0008, 0x000C, 0x0008, 0x0009, 0x003A,
+  ], [
+    0x0005, 0x0003, 0x0004, 0x0010, 0x008F, 0x0475, 0x11D1, 0x0079,
+    0x0027, 0x0002, 0x0003, 0x0001, 0x0000, 0x0026, 0x0046, 0x011C,
+    0x0477, 0x08ED, 0x11D0, 0x11D3, 0x11D2, 0x11D9, 0x11D8, 0x000D,
+    0x001F, 0x0012, 0x0005, 0x003D, 0x000C, 0x000E, 0x0022, 0x0078,
+  ], [
+    0x0005, 0x000C, 0x001B, 0x0000, 0x0006, 0x03E2, 0x3E3D, 0x000F,
+    0x0034, 0x0003, 0x0002, 0x001E, 0x001D, 0x007D, 0x01F0, 0x07C6,
+    0x3E3C, 0x3E3F, 0x3E3E, 0x3E39, 0x3E38, 0x3E3B, 0x3E3A, 0x0008,
+    0x001C, 0x0002, 0x003F, 0x0035, 0x0009, 0x0001, 0x000E, 0x00F9,
+  ], [
+    0x0004, 0x000B, 0x0001, 0x000A, 0x001E, 0x00E0, 0x0E1E, 0x0071,
+    0x0039, 0x0007, 0x0006, 0x000D, 0x000C, 0x0020, 0x01C2, 0x1C3F,
+    0x1C3E, 0x0E19, 0x0E18, 0x0E1B, 0x0E1A, 0x0E1D, 0x0E1C, 0x0000,
+    0x0009, 0x001D, 0x001F, 0x0011, 0x0005, 0x0001, 0x0043, 0x0042,
+  ], [
+    0x0004, 0x000D, 0x0007, 0x0002, 0x0014, 0x016C, 0x16D1, 0x02DF,
+    0x016E, 0x0000, 0x0007, 0x002C, 0x002B, 0x02DE, 0x16D0, 0x16D3,
+    0x16D2, 0x2DB5, 0x2DB4, 0x2DB7, 0x2DB6, 0x16D9, 0x16D8, 0x000C,
+    0x002A, 0x005A, 0x001B, 0x001A, 0x0017, 0x000C, 0x05B7, 0x05B5,
+  ], [
+    0x0002, 0x000F, 0x001C, 0x000C, 0x003B, 0x01AC, 0x1AD8, 0x35B3,
+    0x35B2, 0x0001, 0x0000, 0x0069, 0x0068, 0x35BD, 0x35BC, 0x35BF,
+    0x35BE, 0x35B9, 0x35B8, 0x35BB, 0x35BA, 0x35B5, 0x35B4, 0x01A9,
+    0x01A8, 0x035A, 0x00D7, 0x00D5, 0x003A, 0x001B, 0x35B7, 0x35B6,
+  ]
+];
+
+const VP3_AC_CAT2_BITS: [[u8; 32]; 16] = [
+  [
+     4,  6,  8,  9, 10, 12, 13,  4,  7,  3,  4,  4,  4,  4,  4,  5,
+     5,  5,  5,  6,  7, 11, 13,  4,  5,  6,  6,  7,  6,  6,  4,  5,
+  ], [
+     4,  6,  7,  7,  9, 12, 12,  5,  7,  3,  3,  4,  4,  4,  4,  5,
+     6,  6,  6,  8, 10, 12, 12,  4,  5,  6,  6,  6,  5,  6,  4,  5,
+  ], [
+     4,  5,  7,  6,  8, 10, 12,  5,  7,  3,  3,  4,  4,  4,  5,  5,
+     6,  6,  7,  9, 12, 12, 12,  4,  5,  5,  6,  6,  5,  6,  4,  5,
+  ], [
+     3,  5,  6,  6,  8, 10, 13,  5,  7,  3,  3,  4,  4,  4,  5,  6,
+     7,  7,  9, 11, 13, 13, 13,  4,  5,  5,  6,  6,  5,  6,  5,  5,
+  ], [
+     3,  5,  6,  5,  7,  9, 11,  6,  8,  3,  3,  4,  4,  5,  6,  7,
+     8,  8, 10, 13, 13, 13, 13,  3,  5,  5,  5,  6,  5,  6,  5,  6,
+  ], [
+     3,  4,  5,  5,  6,  9, 11,  6,  9,  3,  3,  4,  4,  5,  7,  9,
+    11, 11, 13, 14, 14, 13, 13,  3,  5,  5,  6,  6,  6,  6,  5,  6,
+  ], [
+     3,  4,  5,  4,  5,  7,  9,  7, 13,  3,  3,  4,  4,  6,  8, 10,
+    13, 13, 13, 13, 13, 13, 13,  3,  5,  5,  6,  6,  6,  7,  6,  6,
+  ], [
+     3,  4,  5,  4,  4,  5,  7,  8, 13,  3,  3,  4,  4,  7, 12, 14,
+    14, 14, 14, 14, 14, 13, 13,  3,  5,  5,  7,  6,  7,  9, 10,  7,
+  ], [
+     4,  6,  8,  8, 10, 12, 13,  5,  6,  3,  3,  4,  4,  4,  5,  6,
+     7,  7,  8,  9, 13, 12, 12,  4,  4,  5,  5,  6,  5,  5,  4,  5,
+  ], [
+     3,  5,  7,  7, 10, 13, 14,  5,  6,  3,  3,  4,  4,  5,  6,  7,
+     8,  9, 11, 13, 14, 14, 14,  4,  4,  5,  5,  6,  4,  5,  5,  6,
+  ], [
+     3,  5,  6,  6,  9, 13, 14,  6,  6,  3,  3,  4,  4,  5,  7,  8,
+    10, 11, 13, 15, 15, 14, 14,  4,  5,  5,  5,  5,  4,  4,  5,  6,
+  ], [
+     3,  4,  5,  5,  8, 11, 13,  7,  6,  3,  3,  4,  4,  6,  7,  9,
+    11, 12, 13, 13, 13, 13, 13,  4,  5,  5,  5,  6,  4,  4,  6,  7,
+  ], [
+     3,  4,  5,  4,  6, 10, 14,  7,  6,  3,  3,  5,  5,  7,  9, 11,
+    14, 14, 14, 14, 14, 14, 14,  4,  5,  5,  6,  6,  4,  3,  7,  8,
+  ], [
+     3,  4,  4,  4,  6,  9, 13,  8,  7,  3,  3,  5,  5,  7, 10, 14,
+    14, 13, 13, 13, 13, 13, 13,  4,  5,  6,  6,  6,  4,  3,  8,  8,
+  ], [
+     3,  4,  4,  3,  5,  9, 13, 10,  9,  2,  3,  6,  6, 10, 13, 13,
+    13, 14, 14, 14, 14, 13, 13,  5,  6,  7,  6,  6,  5,  4, 11, 11,
+  ], [
+     2,  4,  5,  4,  6,  9, 13, 14, 14,  2,  2,  7,  7, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14,  9,  9, 10,  8,  8,  6,  5, 14, 14,
+  ]
+];
+
+const VP3_AC_CAT3_CODES: [[u16; 32]; 16] = [
+  [
+    0x0000, 0x0010, 0x0072, 0x0071, 0x0154, 0x0AAB, 0x0AA8, 0x0014,
+    0x0070, 0x0002, 0x0003, 0x000C, 0x000B, 0x0003, 0x0011, 0x0073,
+    0x0054, 0x00AB, 0x02AB, 0x1553, 0x1552, 0x1555, 0x1554, 0x000D,
+    0x001E, 0x0012, 0x003E, 0x002B, 0x0002, 0x003F, 0x001D, 0x0013,
+  ], [
+    0x0003, 0x001F, 0x0029, 0x003D, 0x000C, 0x0069, 0x0345, 0x0002,
+    0x0028, 0x0002, 0x0001, 0x000E, 0x000C, 0x0015, 0x0007, 0x001B,
+    0x006B, 0x006A, 0x0344, 0x0347, 0x0346, 0x01A1, 0x01A0, 0x000B,
+    0x001A, 0x0012, 0x0000, 0x003C, 0x0008, 0x001B, 0x0013, 0x0001,
+  ], [
+    0x0004, 0x0004, 0x003F, 0x0014, 0x0056, 0x015C, 0x15D5, 0x003C,
+    0x002A, 0x0000, 0x0001, 0x000E, 0x000D, 0x000C, 0x00AF, 0x02BB,
+    0x15D4, 0x15D7, 0x15D6, 0x15D1, 0x15D0, 0x15D3, 0x15D2, 0x000B,
+    0x0019, 0x000D, 0x003E, 0x0031, 0x0007, 0x0005, 0x003D, 0x0030,
+  ], [
+    0x0005, 0x0008, 0x001A, 0x0000, 0x0036, 0x0011, 0x0106, 0x000A,
+    0x006E, 0x0002, 0x0003, 0x0003, 0x0002, 0x006F, 0x0021, 0x020F,
+    0x020E, 0x0101, 0x0100, 0x0103, 0x0102, 0x0105, 0x0104, 0x000C,
+    0x001E, 0x0003, 0x003E, 0x003F, 0x0009, 0x000E, 0x000B, 0x0009,
+  ], [
+    0x0002, 0x000E, 0x001E, 0x000C, 0x001F, 0x006E, 0x00AD, 0x00AF,
+    0x0014, 0x0004, 0x0003, 0x001A, 0x0017, 0x002A, 0x0576, 0x0AEF,
+    0x0AEE, 0x0571, 0x0570, 0x0573, 0x0572, 0x0575, 0x0574, 0x0003,
+    0x0016, 0x0004, 0x0036, 0x000B, 0x000A, 0x0000, 0x006F, 0x00AC,
+  ], [
+    0x0004, 0x0005, 0x0003, 0x0001, 0x0004, 0x002F, 0x0526, 0x1495,
+    0x00A6, 0x0007, 0x0006, 0x002D, 0x002C, 0x1494, 0x1497, 0x1496,
+    0x1491, 0x1490, 0x1493, 0x1492, 0x293D, 0x293C, 0x293F, 0x0000,
+    0x0028, 0x00A5, 0x0148, 0x00A7, 0x002E, 0x0015, 0x0A4E, 0x293E,
+  ], [
+    0x0004, 0x0005, 0x0003, 0x0001, 0x0004, 0x002F, 0x0526, 0x1495,
+    0x00A6, 0x0007, 0x0006, 0x002D, 0x002C, 0x1494, 0x1497, 0x1496,
+    0x1491, 0x1490, 0x1493, 0x1492, 0x293D, 0x293C, 0x293F, 0x0000,
+    0x0028, 0x00A5, 0x0148, 0x00A7, 0x002E, 0x0015, 0x0A4E, 0x293E,
+  ], [
+    0x0004, 0x0005, 0x0003, 0x0001, 0x0004, 0x002F, 0x0526, 0x1495,
+    0x00A6, 0x0007, 0x0006, 0x002D, 0x002C, 0x1494, 0x1497, 0x1496,
+    0x1491, 0x1490, 0x1493, 0x1492, 0x293D, 0x293C, 0x293F, 0x0000,
+    0x0028, 0x00A5, 0x0148, 0x00A7, 0x002E, 0x0015, 0x0A4E, 0x293E,
+  ], [
+    0x0003, 0x0011, 0x0020, 0x0074, 0x010D, 0x0863, 0x0860, 0x000A,
+    0x0075, 0x0001, 0x0000, 0x000B, 0x000A, 0x0018, 0x0038, 0x0042,
+    0x010F, 0x010E, 0x0219, 0x10C3, 0x10C2, 0x10C5, 0x10C4, 0x000F,
+    0x0004, 0x0019, 0x000B, 0x0039, 0x0009, 0x001B, 0x001A, 0x003B,
+  ], [
+    0x0005, 0x0001, 0x003E, 0x0001, 0x00E2, 0x1C6F, 0x38D9, 0x0039,
+    0x001F, 0x0002, 0x0001, 0x0009, 0x0008, 0x0000, 0x0070, 0x01C7,
+    0x038C, 0x071A, 0x38D8, 0x38DB, 0x38DA, 0x38DD, 0x38DC, 0x000D,
+    0x001D, 0x000E, 0x003F, 0x003C, 0x000C, 0x0006, 0x003D, 0x001E,
+  ], [
+    0x0006, 0x000B, 0x0011, 0x001E, 0x0074, 0x03AA, 0x1D5C, 0x0001,
+    0x0021, 0x0001, 0x0002, 0x0007, 0x0006, 0x003E, 0x00EB, 0x01D4,
+    0x0EAF, 0x3ABB, 0x3ABA, 0x1D59, 0x1D58, 0x1D5B, 0x1D5A, 0x000A,
+    0x001C, 0x0001, 0x003F, 0x003B, 0x0001, 0x0009, 0x0020, 0x0000,
+  ], [
+    0x0004, 0x000A, 0x0017, 0x0004, 0x0016, 0x016A, 0x16B1, 0x0017,
+    0x005B, 0x0006, 0x0007, 0x0001, 0x0000, 0x000A, 0x02D7, 0x0B5A,
+    0x16B0, 0x16B3, 0x16B2, 0x2D6D, 0x2D6C, 0x2D6F, 0x2D6E, 0x0006,
+    0x000A, 0x0004, 0x002C, 0x0017, 0x0003, 0x0007, 0x0016, 0x00B4,
+  ], [
+    0x0005, 0x000D, 0x0005, 0x0009, 0x0033, 0x0193, 0x192C, 0x0061,
+    0x0031, 0x0000, 0x0007, 0x0010, 0x0011, 0x00C8, 0x192F, 0x325B,
+    0x325A, 0x1929, 0x1928, 0x192B, 0x192A, 0x325D, 0x325C, 0x0018,
+    0x001A, 0x001B, 0x0065, 0x0019, 0x0004, 0x0007, 0x0060, 0x0324,
+  ], [
+    0x0006, 0x0000, 0x0002, 0x000F, 0x0039, 0x01D9, 0x1D82, 0x0761,
+    0x03BE, 0x0001, 0x0002, 0x000F, 0x000E, 0x0762, 0x3B07, 0x3B06,
+    0x3B1D, 0x3B1C, 0x3B1F, 0x3B1E, 0x3B19, 0x3B18, 0x3B1B, 0x0038,
+    0x01DE, 0x00ED, 0x03BF, 0x00EE, 0x003A, 0x0006, 0x0EC0, 0x3B1A,
+  ], [
+    0x0000, 0x0002, 0x000F, 0x0006, 0x001C, 0x01D0, 0x0E8C, 0x1D1B,
+    0x1D1A, 0x0003, 0x0002, 0x00EA, 0x00E9, 0x0E89, 0x0E88, 0x0E8B,
+    0x0E8A, 0x1D65, 0x1D64, 0x1D67, 0x1D66, 0x1D61, 0x1D60, 0x03AD,
+    0x1D63, 0x1D62, 0x1D1D, 0x1D1C, 0x003B, 0x01D7, 0x1D1F, 0x1D1E,
+  ], [
+    0x0002, 0x000F, 0x001C, 0x000C, 0x003B, 0x01AC, 0x1AD8, 0x35B3,
+    0x35B2, 0x0001, 0x0000, 0x0069, 0x0068, 0x35BD, 0x35BC, 0x35BF,
+    0x35BE, 0x35B9, 0x35B8, 0x35BB, 0x35BA, 0x35B5, 0x35B4, 0x01A9,
+    0x01A8, 0x035A, 0x00D7, 0x00D5, 0x003A, 0x001B, 0x35B7, 0x35B6,
+  ]
+];
+
+const VP3_AC_CAT3_BITS: [[u8; 32]; 16] = [
+  [
+     3,  5,  7,  7,  9, 12, 12,  5,  7,  3,  3,  4,  4,  4,  5,  7,
+     7,  8, 10, 13, 13, 13, 13,  4,  5,  5,  6,  6,  4,  6,  5,  5,
+  ], [
+     3,  5,  6,  6,  7, 10, 13,  5,  6,  3,  3,  4,  4,  5,  6,  8,
+    10, 10, 13, 13, 13, 12, 12,  4,  5,  5,  5,  6,  4,  5,  5,  5,
+  ], [
+     3,  4,  6,  5,  7,  9, 13,  6,  6,  3,  3,  4,  4,  5,  8, 10,
+    13, 13, 13, 13, 13, 13, 13,  4,  5,  5,  6,  6,  4,  4,  6,  6,
+  ], [
+     3,  4,  5,  4,  6,  8, 12,  7,  7,  3,  3,  4,  4,  7,  9, 13,
+    13, 12, 12, 12, 12, 12, 12,  4,  5,  5,  6,  6,  4,  4,  7,  7,
+  ], [
+     3,  4,  5,  4,  5,  7, 10, 10,  7,  3,  3,  5,  5,  8, 13, 14,
+    14, 13, 13, 13, 13, 13, 13,  4,  5,  5,  6,  6,  4,  3,  7, 10,
+  ], [
+     3,  4,  3,  3,  4,  6, 11, 13,  8,  3,  3,  6,  6, 13, 13, 13,
+    13, 13, 13, 13, 14, 14, 14,  3,  6,  8,  9,  8,  6,  5, 12, 14,
+  ], [
+     3,  4,  3,  3,  4,  6, 11, 13,  8,  3,  3,  6,  6, 13, 13, 13,
+    13, 13, 13, 13, 14, 14, 14,  3,  6,  8,  9,  8,  6,  5, 12, 14,
+  ], [
+     3,  4,  3,  3,  4,  6, 11, 13,  8,  3,  3,  6,  6, 13, 13, 13,
+    13, 13, 13, 13, 14, 14, 14,  3,  6,  8,  9,  8,  6,  5, 12, 14,
+  ], [
+     3,  5,  6,  7,  9, 12, 12,  5,  7,  3,  3,  4,  4,  5,  6,  7,
+     9,  9, 10, 13, 13, 13, 13,  4,  4,  5,  5,  6,  4,  5,  5,  6,
+  ], [
+     3,  4,  6,  5,  8, 13, 14,  6,  6,  3,  3,  4,  4,  5,  7,  9,
+    10, 11, 14, 14, 14, 14, 14,  4,  5,  5,  6,  6,  4,  4,  6,  6,
+  ], [
+     3,  4,  5,  5,  7, 10, 13,  6,  6,  3,  3,  4,  4,  6,  8,  9,
+    12, 14, 14, 13, 13, 13, 13,  4,  5,  5,  6,  6,  4,  4,  6,  6,
+  ], [
+     3,  4,  5,  4,  6,  9, 13,  7,  7,  3,  3,  4,  4,  6, 10, 12,
+    13, 13, 13, 14, 14, 14, 14,  4,  5,  5,  6,  6,  4,  4,  7,  8,
+  ], [
+     3,  4,  4,  4,  6,  9, 13,  8,  7,  2,  3,  5,  5,  8, 13, 14,
+    14, 13, 13, 13, 13, 14, 14,  5,  6,  6,  7,  6,  4,  4,  8, 10,
+  ], [
+     3,  3,  4,  4,  6,  9, 13, 11, 10,  2,  2,  6,  6, 11, 14, 14,
+    14, 14, 14, 14, 14, 14, 14,  6,  9,  8, 10,  8,  6,  5, 12, 14,
+  ], [
+     2,  3,  5,  4,  6, 10, 13, 14, 14,  2,  2,  9,  9, 13, 13, 13,
+    13, 14, 14, 14, 14, 14, 14, 11, 14, 14, 14, 14,  7, 10, 14, 14,
+  ], [
+     2,  4,  5,  4,  6,  9, 13, 14, 14,  2,  2,  7,  7, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14,  9,  9, 10,  8,  8,  6,  5, 14, 14,
+  ]
+];
+
+const VP3_DC_WEIGHTS: [[i16; 5]; 16] = [
+    [  0,   0,  0,  0,   0 ],
+    [  1,   0,  0,  0,   1 ],
+    [  0,   1,  0,  0,   1 ],
+    [  1,   0,  0,  0,   1 ],
+
+    [  0,   0,  1,  0,   1 ],
+    [  1,   0,  1,  0,   2 ],
+    [  0,   0,  1,  0,   1 ],
+    [ 29, -26, 29,  0,  32 ],
+
+    [  0,   0,  0,  1,   1 ],
+    [ 75,   0,  0, 53, 128 ],
+    [  0,   1,  0,  1,   2 ],
+    [ 75,   0,  0, 53, 128 ],
+
+    [  0,   0,  1,  0,   1 ],
+    [ 75,   0,  0, 53, 128 ],
+    [  0,   3, 10,  3,  16 ],
+    [ 29, -26, 29,  0,  32 ],
+];
diff --git a/nihav-duck/src/codecs/vpcommon.rs b/nihav-duck/src/codecs/vpcommon.rs
new file mode 100644 (file)
index 0000000..cac264b
--- /dev/null
@@ -0,0 +1,188 @@
+use nihav_core::codecs::*;
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+#[allow(dead_code)]
+pub enum VPMBType {
+    Intra,
+    InterNoMV,
+    InterMV,
+    InterNearest,
+    InterNear,
+    InterFourMV,
+    GoldenNoMV,
+    GoldenMV,
+    GoldenNearest,
+    GoldenNear,
+}
+
+#[allow(dead_code)]
+impl VPMBType {
+    pub fn is_intra(self) -> bool { self == VPMBType::Intra }
+    pub fn get_ref_id(self) -> u8 {
+        match self {
+            VPMBType::Intra         => 0,
+            VPMBType::InterNoMV     |
+            VPMBType::InterMV       |
+            VPMBType::InterNearest  |
+            VPMBType::InterNear     |
+            VPMBType::InterFourMV   => 1,
+            _                       => 2,
+        }
+    }
+}
+
+impl Default for VPMBType {
+    fn default() -> Self { VPMBType::Intra }
+}
+
+#[derive(Default)]
+pub struct VPShuffler {
+    lastframe: Option<NAVideoBufferRef<u8>>,
+    goldframe: Option<NAVideoBufferRef<u8>>,
+}
+
+impl VPShuffler {
+    pub fn new() -> Self { VPShuffler { lastframe: None, goldframe: None } }
+    pub fn clear(&mut self) { self.lastframe = None; self.goldframe = None; }
+    pub fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
+        self.lastframe = Some(buf);
+    }
+    pub fn add_golden_frame(&mut self, buf: NAVideoBufferRef<u8>) {
+        self.goldframe = Some(buf);
+    }
+    pub fn get_last(&mut self) -> Option<NAVideoBufferRef<u8>> {
+        if let Some(ref frm) = self.lastframe {
+            Some(frm.clone())
+        } else {
+            None
+        }
+    }
+    pub fn get_golden(&mut self) -> Option<NAVideoBufferRef<u8>> {
+        if let Some(ref frm) = self.goldframe {
+            Some(frm.clone())
+        } else {
+            None
+        }
+    }
+}
+
+const C1S7: i32 = 64277;
+const C2S6: i32 = 60547;
+const C3S5: i32 = 54491;
+const C4S4: i32 = 46341;
+const C5S3: i32 = 36410;
+const C6S2: i32 = 25080;
+const C7S1: i32 = 12785;
+
+fn mul16(a: i32, b: i32) -> i32 {
+    (a * b) >> 16
+}
+
+macro_rules! idct_step {
+    ($s0:expr, $s1:expr, $s2:expr, $s3:expr, $s4:expr, $s5:expr, $s6:expr, $s7:expr,
+     $d0:expr, $d1:expr, $d2:expr, $d3:expr, $d4:expr, $d5:expr, $d6:expr, $d7:expr,
+     $bias:expr, $shift:expr, $otype:ty) => {
+        let t_a  = mul16(C1S7, i32::from($s1)) + mul16(C7S1, i32::from($s7));
+        let t_b  = mul16(C7S1, i32::from($s1)) - mul16(C1S7, i32::from($s7));
+        let t_c  = mul16(C3S5, i32::from($s3)) + mul16(C5S3, i32::from($s5));
+        let t_d  = mul16(C3S5, i32::from($s5)) - mul16(C5S3, i32::from($s3));
+        let t_a1 = mul16(C4S4, t_a - t_c);
+        let t_b1 = mul16(C4S4, t_b - t_d);
+        let t_c  = t_a + t_c;
+        let t_d  = t_b + t_d;
+        let t_e  = mul16(C4S4, i32::from($s0 + $s4)) + $bias;
+        let t_f  = mul16(C4S4, i32::from($s0 - $s4)) + $bias;
+        let t_g  = mul16(C2S6, i32::from($s2)) + mul16(C6S2, i32::from($s6));
+        let t_h  = mul16(C6S2, i32::from($s2)) - mul16(C2S6, i32::from($s6));
+        let t_e1 = t_e  - t_g;
+        let t_g  = t_e  + t_g;
+        let t_a  = t_f  + t_a1;
+        let t_f  = t_f  - t_a1;
+        let t_b  = t_b1 - t_h;
+        let t_h  = t_b1 + t_h;
+
+        $d0 = ((t_g  + t_c) >> $shift) as $otype;
+        $d7 = ((t_g  - t_c) >> $shift) as $otype;
+        $d1 = ((t_a  + t_h) >> $shift) as $otype;
+        $d2 = ((t_a  - t_h) >> $shift) as $otype;
+        $d3 = ((t_e1 + t_d) >> $shift) as $otype;
+        $d4 = ((t_e1 - t_d) >> $shift) as $otype;
+        $d5 = ((t_f  + t_b) >> $shift) as $otype;
+        $d6 = ((t_f  - t_b) >> $shift) as $otype;
+    }
+}
+
+pub fn vp_idct(coeffs: &mut [i16; 64]) {
+    let mut tmp = [0i32; 64];
+    for (src, dst) in coeffs.chunks(8).zip(tmp.chunks_mut(8)) {
+        idct_step!(src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7],
+                   dst[0], dst[1], dst[2], dst[3], dst[4], dst[5], dst[6], dst[7], 0, 0, i32);
+    }
+    let src = &tmp;
+    let dst = coeffs;
+    for i in 0..8 {
+        idct_step!(src[0 * 8 + i], src[1 * 8 + i], src[2 * 8 + i], src[3 * 8 + i],
+                   src[4 * 8 + i], src[5 * 8 + i], src[6 * 8 + i], src[7 * 8 + i],
+                   dst[0 * 8 + i], dst[1 * 8 + i], dst[2 * 8 + i], dst[3 * 8 + i],
+                   dst[4 * 8 + i], dst[5 * 8 + i], dst[6 * 8 + i], dst[7 * 8 + i], 8, 4, i16);
+    }
+}
+
+pub fn vp_idct_dc(coeffs: &mut [i16; 64]) {
+    let dc = ((mul16(C4S4, mul16(C4S4, i32::from(coeffs[0]))) + 8) >> 4) as i16;
+    for i in 0..64 {
+        coeffs[i] = dc;
+    }
+}
+
+pub fn unquant(coeffs: &mut [i16; 64], qmat: &[i16; 64]) {
+    for i in 1..64 {
+        coeffs[i] = coeffs[i].wrapping_mul(qmat[i]);
+    }
+}
+
+pub fn vp_put_block(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame<u8>) {
+    vp_idct(coeffs);
+    let mut off = frm.offset[plane] + bx * 8 + by * 8 * frm.stride[plane];
+    for y in 0..8 {
+        for x in 0..8 {
+            frm.data[off + x] = (coeffs[x + y * 8] + 128).min(255).max(0) as u8;
+        }
+        off += frm.stride[plane];
+    }
+}
+
+pub fn vp_put_block_dc(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame<u8>) {
+    vp_idct_dc(coeffs);
+    let dc = (coeffs[0] + 128).min(255).max(0) as u8;
+    let mut off = frm.offset[plane] + bx * 8 + by * 8 * frm.stride[plane];
+    for _ in 0..8 {
+        for x in 0..8 {
+            frm.data[off + x] = dc;
+        }
+        off += frm.stride[plane];
+    }
+}
+
+pub fn vp_add_block(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame<u8>) {
+    vp_idct(coeffs);
+    let mut off = frm.offset[plane] + bx * 8 + by * 8 * frm.stride[plane];
+    for y in 0..8 {
+        for x in 0..8 {
+            frm.data[off + x] = (coeffs[x + y * 8] + (frm.data[off + x] as i16)).min(255).max(0) as u8;
+        }
+        off += frm.stride[plane];
+    }
+}
+
+pub fn vp_add_block_dc(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame<u8>) {
+    vp_idct_dc(coeffs);
+    let dc = coeffs[0];
+    let mut off = frm.offset[plane] + bx * 8 + by * 8 * frm.stride[plane];
+    for _ in 0..8 {
+        for x in 0..8 {
+            frm.data[off + x] = (dc + (frm.data[off + x] as i16)).min(255).max(0) as u8;
+        }
+        off += frm.stride[plane];
+    }
+}