mostly working ITU H.264 decoder
[nihav.git] / nihav-itu / src / codecs / h264 / cabac.rs
diff --git a/nihav-itu/src/codecs/h264/cabac.rs b/nihav-itu/src/codecs/h264/cabac.rs
new file mode 100644 (file)
index 0000000..554da2a
--- /dev/null
@@ -0,0 +1,887 @@
+//use nihav_core::codecs::{DecoderResult, DecoderError};
+
+use super::*;
+use super::cabac_coder::*;
+use super::dsp::{CHROMA_DC_SCAN, ZIGZAG, ZIGZAG1, ZIGZAG8X8};
+use super::slice::SliceHeader;
+
+pub fn cabac_decode_mbskip(cabac: &mut CABAC, sstate: &SliceState, slice_hdr: &SliceHeader) -> bool {
+    let skip_idx = if slice_hdr.slice_type.is_p() { 11 } else { 24 };
+    let mut mb_skip_ctx = 0;
+    let left_mbt = sstate.get_left_mb().mb_type;
+    let top_mbt  = sstate.get_top_mb().mb_type;
+    if left_mbt != CompactMBType::None && !left_mbt.is_skip() {
+        mb_skip_ctx += 1;
+    }
+    if top_mbt != CompactMBType::None && !top_mbt.is_skip() {
+        mb_skip_ctx += 1;
+    }
+    if !slice_hdr.slice_type.is_intra() {
+        cabac.decode_bit(skip_idx + mb_skip_ctx)
+    } else {
+        false
+    }
+}
+
+fn decode_i_type(cabac: &mut CABAC, start: usize, ctx: usize) -> MBType {
+    if !cabac.decode_bit(start + ctx) {
+        MBType::Intra4x4
+    } else if !cabac.decode_terminate() {
+        let cbpy = if cabac.decode_bit(start + 3) { 0xF } else { 0x0 };
+        let cbpc = cabac.decode_012(start + 4);
+        let ipred = cabac.decode_bits(start + 6, start + 7, 2);
+
+        MBType::Intra16x16(ipred, cbpy, cbpc)
+    } else {
+        MBType::PCM
+    }
+}
+
+fn decode_i_type_inter(cabac: &mut CABAC, start: usize) -> MBType {
+    if !cabac.decode_bit(start) {
+        MBType::Intra4x4
+    } else if !cabac.decode_terminate() {
+        let cbpy = if cabac.decode_bit(start + 1) { 0xF } else { 0x0 };
+        let cbpc = if !cabac.decode_bit(start + 2) {
+                0
+            } else if !cabac.decode_bit(start + 2) {
+                1
+            } else {
+                2
+            };
+        let ipred = cabac.decode_bits(start + 3, start + 3, 2);
+
+        MBType::Intra16x16(ipred, cbpy, cbpc)
+    } else {
+        MBType::PCM
+    }
+}
+
+fn remap_si_mbtype(mbtype: MBType) -> MBType {
+    match mbtype {
+        MBType::Intra16x16(0, 0, 0) => MBType::Intra4x4,
+        MBType::Intra16x16(imode, cbpy, cbpc) => {
+            let idx = imode + if cbpy != 0 { 12 } else { 0 } + cbpc * 4 - 1;
+            let nimode = idx & 3;
+            let (ncbpy, ncbpc) = if (idx >> 2) >= 3 {
+                    (0xF, (idx >> 2) - 3)
+                } else {
+                    (0x0, idx >> 2)
+                };
+            MBType::Intra16x16(nimode, ncbpy, ncbpc)
+        },
+        MBType::PCM => MBType::Intra16x16(3, 1, 2),
+        _ => mbtype,
+    }
+}
+
+pub fn cabac_decode_mb_type(cabac: &mut CABAC, slice_hdr: &SliceHeader, sstate: &SliceState) -> MBType {
+    match slice_hdr.slice_type {
+        SliceType::I | SliceType::SI => {
+            let mut ctx = 0;
+            if sstate.get_left_mb().mb_type.is_intra16orpcm() {
+                ctx += 1;
+            }
+            if sstate.get_top_mb().mb_type.is_intra16orpcm() {
+                ctx += 1;
+            }
+            let mbtype = decode_i_type(cabac, 3, ctx);
+            if slice_hdr.slice_type == SliceType::I {
+                mbtype
+            } else {
+                remap_si_mbtype(mbtype)
+            }
+        },
+        SliceType::P | SliceType::SP => {
+            if cabac.decode_bit(14) {
+                decode_i_type_inter(cabac, 17)
+            } else if !cabac.decode_bit(15) {
+                if !cabac.decode_bit(16) {
+                    MBType::P16x16
+                } else {
+                    MBType::P8x8
+                }
+            } else {
+                if !cabac.decode_bit(17) {
+                    MBType::P8x16
+                } else {
+                    MBType::P16x8
+                }
+            }
+        },
+        SliceType::B => {
+            let mut ctx = 0;
+            if !sstate.get_left_mb().mb_type.is_direct() {
+                ctx += 1;
+            }
+            if !sstate.get_top_mb().mb_type.is_direct() {
+                ctx += 1;
+            }
+            if !cabac.decode_bit(27 + ctx) {
+                MBType::Direct
+            } else if !cabac.decode_bit(30) {
+                if !cabac.decode_bit(32) {
+                    MBType::B16x16(BMode::L0)
+                } else {
+                    MBType::B16x16(BMode::L1)
+                }
+            } else {
+                let idx = cabac.decode_bits(31, 32, 4);
+                match idx {
+                    0x0 => MBType::B16x16(BMode::Bi),
+                    0x1 => MBType::B16x8(BMode::L0, BMode::L0),
+                    0x2 => MBType::B8x16(BMode::L0, BMode::L0),
+                    0x3 => MBType::B16x8(BMode::L1, BMode::L1),
+                    0x4 => MBType::B8x16(BMode::L1, BMode::L1),
+                    0x5 => MBType::B16x8(BMode::L0, BMode::L1),
+                    0x6 => MBType::B8x16(BMode::L0, BMode::L1),
+                    0x7 => MBType::B16x8(BMode::L1, BMode::L0),
+                    0xE => MBType::B8x16(BMode::L1, BMode::L0),
+                    0xF => MBType::B8x8,
+                    0xD => decode_i_type_inter(cabac, 32),
+                    _ => {
+                        let idx = (idx - 8) * 2 + (cabac.decode_bit(32) as u8);
+                        match idx {
+                            0 => MBType::B16x8(BMode::L0, BMode::Bi),
+                            1 => MBType::B8x16(BMode::L0, BMode::Bi),
+                            2 => MBType::B16x8(BMode::L1, BMode::Bi),
+                            3 => MBType::B8x16(BMode::L1, BMode::Bi),
+                            4 => MBType::B16x8(BMode::Bi, BMode::L0),
+                            5 => MBType::B8x16(BMode::Bi, BMode::L0),
+                            6 => MBType::B16x8(BMode::Bi, BMode::L1),
+                            7 => MBType::B8x16(BMode::Bi, BMode::L1),
+                            8 => MBType::B16x8(BMode::Bi, BMode::Bi),
+                            _ => MBType::B8x16(BMode::Bi, BMode::Bi),
+                        }
+                    },
+                }
+            }
+        },
+    }
+}
+
+fn decode_sub_mb_type_cabac(cabac: &mut CABAC, slice_hdr: &SliceHeader) -> SubMBType {
+    match slice_hdr.slice_type {
+        SliceType::P | SliceType::SP => {
+            if cabac.decode_bit(21) {
+                SubMBType::P8x8
+            } else if !cabac.decode_bit(22) {
+                SubMBType::P8x4
+            } else if cabac.decode_bit(23) {
+                SubMBType::P4x8
+            } else {
+                SubMBType::P4x4
+            }
+        },
+        SliceType::B => {
+            if !cabac.decode_bit(36) {
+                SubMBType::Direct8x8
+            } else if !cabac.decode_bit(37) {
+                if !cabac.decode_bit(39) {
+                    SubMBType::B8x8(BMode::L0)
+                } else {
+                    SubMBType::B8x8(BMode::L1)
+                }
+            } else {
+                let idx = cabac.decode_bits(38, 39, 3);
+                match idx {
+                    0 => SubMBType::B8x8(BMode::Bi),
+                    1 => SubMBType::B8x4(BMode::L0),
+                    2 => SubMBType::B4x8(BMode::L0),
+                    3 => SubMBType::B8x4(BMode::L1),
+                    6 => SubMBType::B4x4(BMode::L1),
+                    7 => SubMBType::B4x4(BMode::Bi),
+                    _ => {
+                        let idx = (idx - 4) * 2 + (cabac.decode_bit(39) as u8);
+                        match idx {
+                            0 => SubMBType::B4x8(BMode::L1),
+                            1 => SubMBType::B8x4(BMode::Bi),
+                            2 => SubMBType::B4x8(BMode::Bi),
+                            _ => SubMBType::B4x4(BMode::L0),
+                        }
+                    },
+                }
+            }
+        },
+        _ => unreachable!(),
+    }
+}
+
+fn decode_ref_idx(cabac: &mut CABAC, num_refs: usize, ctx: usize) -> PicRef {
+    if num_refs == 1 {
+        return ZERO_REF;
+    }
+    if !cabac.decode_bit(54 + ctx) {
+        ZERO_REF
+    } else if !cabac.decode_bit(54 + 4) {
+        PicRef::new(1)
+    } else {
+        let mut idx = 2;
+        while cabac.decode_bit(54 + 5) && idx < 32 {
+            idx += 1;
+        }
+        if idx < num_refs {
+            PicRef::new(idx as u8)
+        } else {
+            INVALID_REF
+        }
+    }
+}
+
+fn decode_mv_component(cabac: &mut CABAC, base: usize, ctx: usize) -> i16 {
+    if !cabac.decode_bit(base + ctx) {
+        0
+    } else {
+        let mut val = 1;
+        while val < 9 && cabac.decode_bit(base + (2 + val).min(6)) {
+            val += 1;
+        }
+        if val >= 9 {
+            let mut pfx = 3;
+            while pfx < 16 && cabac.decode_bypass() {
+                val += 1 << pfx;
+                pfx += 1;
+            }
+            val += cabac.decode_bypass_bits(pfx) as usize;
+        }
+        if val == 0 || !cabac.decode_bypass() {
+            val as i16
+        } else {
+            -(val as i16)
+        }
+    }
+}
+
+fn decode_mv(cabac: &mut CABAC, ctx0: usize, ctx1: usize) -> MV {
+    let x = decode_mv_component(cabac, 40, ctx0);
+    let y = decode_mv_component(cabac, 47, ctx1);
+    MV{ x, y }
+}
+
+pub fn decode_mb_pred_cabac(cabac: &mut CABAC, slice_hdr: &SliceHeader, mb_type: MBType, sstate: &mut SliceState, mb_info: &mut CurrentMBInfo) {
+    mb_info.mb_type = mb_type;
+    let num_l0 = slice_hdr.num_ref_idx_l0_active;
+    let num_l1 = slice_hdr.num_ref_idx_l1_active;
+    sstate.reset_mb_mv();
+    match mb_type {
+        MBType::Intra4x4 => {
+            for &(x, y) in I4X4_SCAN.iter() {
+                let x = x as usize;
+                let y = y as usize;
+                let top_pred  = sstate.get_top_blk4(x + y * 4).ipred;
+                let left_pred = sstate.get_left_blk4(x + y * 4).ipred;
+
+                let top_idx = top_pred.into_pred_idx();
+                let left_idx = left_pred.into_pred_idx();
+                let pred_mode = top_idx.min(left_idx);
+                let mut pred_mode = if pred_mode != -1 { pred_mode as u8 } else { 2 };
+
+                if !cabac.decode_bit(68) {
+                    let m0 = cabac.decode_bit(69) as u8;
+                    let m1 = cabac.decode_bit(69) as u8;
+                    let m2 = cabac.decode_bit(69) as u8;
+                    let new_mode = (m2 << 2) | (m1 << 1) | m0;
+                    pred_mode = if new_mode >= pred_mode {
+                            new_mode + 1
+                        } else { new_mode };
+                }
+                mb_info.ipred[x + y * 4] = pred_mode.into();
+                sstate.get_cur_blk4(x + y * 4).ipred = (pred_mode as u8).into();
+            }
+            let mut ctx = 0;
+            if sstate.get_left_mb().cmode != 0 {
+                ctx += 1;
+            }
+            if sstate.get_top_mb().cmode != 0 {
+                ctx += 1;
+            }
+            mb_info.chroma_ipred = if !cabac.decode_bit(64 + ctx) {
+                    0
+                } else if !cabac.decode_bit(67) {
+                    1
+                } else if !cabac.decode_bit(67) {
+                    2
+                } else {
+                    3
+                };
+        },
+        MBType::Intra8x8 => {
+            for part in 0..4 {
+                let blk4 = (part & 1) * 2 + (part & 2) * 4;
+                let top_pred  = sstate.get_top_blk4(blk4).ipred;
+                let left_pred = sstate.get_left_blk4(blk4).ipred;
+
+                let top_idx = top_pred.into_pred_idx();
+                let left_idx = left_pred.into_pred_idx();
+                let pred_mode = top_idx.min(left_idx);
+                let mut pred_mode = if pred_mode != -1 { pred_mode as u8 } else { 2 };
+                if !cabac.decode_bit(68) {
+                    let m0 = cabac.decode_bit(69) as u8;
+                    let m1 = cabac.decode_bit(69) as u8;
+                    let m2 = cabac.decode_bit(69) as u8;
+                    let new_mode = (m2 << 2) | (m1 << 1) | m0;
+                    pred_mode = if new_mode >= pred_mode {
+                            new_mode + 1
+                        } else { new_mode };
+                }
+                mb_info.ipred[blk4]     = pred_mode.into();
+                mb_info.ipred[blk4 + 1] = pred_mode.into();
+                mb_info.ipred[blk4 + 4] = pred_mode.into();
+                mb_info.ipred[blk4 + 5] = pred_mode.into();
+                sstate.get_cur_blk4(blk4).ipred = (pred_mode as u8).into();
+                sstate.get_cur_blk4(blk4 + 1).ipred = (pred_mode as u8).into();
+                sstate.get_cur_blk4(blk4 + 4).ipred = (pred_mode as u8).into();
+                sstate.get_cur_blk4(blk4 + 5).ipred = (pred_mode as u8).into();
+            }
+            let mut ctx = 0;
+            if sstate.get_left_mb().cmode != 0 {
+                ctx += 1;
+            }
+            if sstate.get_top_mb().cmode != 0 {
+                ctx += 1;
+            }
+            mb_info.chroma_ipred = if !cabac.decode_bit(64 + ctx) {
+                    0
+                } else if !cabac.decode_bit(67) {
+                    1
+                } else if !cabac.decode_bit(67) {
+                    2
+                } else {
+                    3
+                };
+        },
+        MBType::Intra16x16(_ipred, _, _) => {
+            let mut ctx = 0;
+            if sstate.get_left_mb().cmode != 0 {
+                ctx += 1;
+            }
+            if sstate.get_top_mb().cmode != 0 {
+                ctx += 1;
+            }
+            mb_info.chroma_ipred = if !cabac.decode_bit(64 + ctx) {
+                    0
+                } else if !cabac.decode_bit(67) {
+                    1
+                } else if !cabac.decode_bit(67) {
+                    2
+                } else {
+                    3
+                };
+        },
+        MBType::P16x16 | MBType::P16x8 | MBType::P8x16 => {
+            let num_subparts = mb_type.num_parts();
+            let (pw, ph) = mb_type.size();
+            let mut xoff = 0;
+            let mut yoff = 0;
+            for i in 0..num_subparts {
+                let ctx = sstate.get_mv_ref_ctx(xoff, yoff, 0);
+                let ref_idx = decode_ref_idx(cabac, num_l0, ctx);
+                mb_info.ref_l0[i] = ref_idx;
+                sstate.fill_ref(xoff, yoff, pw, ph, 0, ref_idx);
+                xoff += pw;
+                if xoff == 16 {
+                    xoff = 0;
+                    yoff += ph;
+                }
+            }
+            let mut xoff = 0;
+            let mut yoff = 0;
+            for i in 0..num_subparts {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(xoff, yoff, 0);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l0[i] = mv;
+                sstate.fill_mvd(xoff, yoff, pw, ph, 0, mv);
+                xoff += pw;
+                if xoff == 16 {
+                    xoff = 0;
+                    yoff += ph;
+                }
+            }
+        },
+        MBType::B16x16(mode) => {
+            if mode != BMode::L1 {
+                let ctx = sstate.get_mv_ref_ctx(0, 0, 0);
+                let ref_idx = decode_ref_idx(cabac, num_l0, ctx);
+                mb_info.ref_l0[0] = ref_idx;
+                sstate.fill_ref(0, 0, 16, 16, 0, ref_idx);
+            }
+            if mode != BMode::L0 {
+                let ctx = sstate.get_mv_ref_ctx(0, 0, 1);
+                let ref_idx = decode_ref_idx(cabac, num_l1, ctx);
+                mb_info.ref_l1[0] = ref_idx;
+                sstate.fill_ref(0, 0, 16, 16, 1, ref_idx);
+            }
+            if mode != BMode::L1 {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(0, 0, 0);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l0[0] = mv;
+                sstate.fill_mvd(0, 0, 16, 16, 0, mv);
+            }
+            if mode != BMode::L0 {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(0, 0, 1);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l1[0] = mv;
+                sstate.fill_mvd(0, 0, 16, 16, 1, mv);
+            }
+        },
+        MBType::B16x8(mode0, mode1) | MBType::B8x16(mode0, mode1) => {
+            let (pw, ph) = mb_info.mb_type.size();
+            let (px, py) = (pw & 8, ph & 8);
+            if mode0 != BMode::L1 {
+                let ctx = sstate.get_mv_ref_ctx(0, 0, 0);
+                let ref_idx = decode_ref_idx(cabac, num_l0, ctx);
+                mb_info.ref_l0[0] = ref_idx;
+                sstate.fill_ref(0, 0, pw, ph, 0, ref_idx);
+            }
+            if mode1 != BMode::L1 {
+                let ctx = sstate.get_mv_ref_ctx(pw & 8, ph & 8, 0);
+                let ref_idx = decode_ref_idx(cabac, num_l0, ctx);
+                mb_info.ref_l0[1] = ref_idx;
+                sstate.fill_ref(px, py, pw, ph, 0, ref_idx);
+            }
+            if mode0 != BMode::L0 {
+                let ctx = sstate.get_mv_ref_ctx(0, 0, 1);
+                let ref_idx = decode_ref_idx(cabac, num_l1, ctx);
+                mb_info.ref_l1[0] = ref_idx;
+                sstate.fill_ref(0, 0, pw, ph, 1, ref_idx);
+            }
+            if mode1 != BMode::L0 {
+                let ctx = sstate.get_mv_ref_ctx(pw & 8, ph & 8, 1);
+                let ref_idx = decode_ref_idx(cabac, num_l1, ctx);
+                mb_info.ref_l1[1] = ref_idx;
+                sstate.fill_ref(px, py, pw, ph, 1, ref_idx);
+            }
+            if mode0 != BMode::L1 {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(0, 0, 0);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l0[0] = mv;
+                sstate.fill_mvd(0, 0, pw, ph, 0, mv);
+            }
+            if mode1 != BMode::L1 {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(pw & 8, ph & 8, 0);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l0[1] = mv;
+                sstate.fill_mvd(px, py, pw, ph, 0, mv);
+            }
+            if mode0 != BMode::L0 {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(0, 0, 1);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l1[0] = mv;
+                sstate.fill_mvd(0, 0, pw, ph, 1, mv);
+            }
+            if mode1 != BMode::L0 {
+                let (ctx0, ctx1) = sstate.get_mv_ctx(pw & 8, ph & 8, 1);
+                let mv = decode_mv(cabac, ctx0, ctx1);
+                mb_info.mv_l1[1] = mv;
+                sstate.fill_mvd(px, py, pw, ph, 1, mv);
+            }
+        },
+        MBType::P8x8 | MBType::B8x8 => {
+            for sub_type in mb_info.sub_mb_type.iter_mut() {
+                *sub_type = decode_sub_mb_type_cabac(cabac, slice_hdr);
+            }
+            let num_l = [num_l0, num_l1];
+            let dst_ref = [&mut mb_info.ref_l0, &mut mb_info.ref_l1];
+            for ref_l in 0..2 {
+                for spart in 0..4 {
+                    let stype = mb_info.sub_mb_type[spart];
+                    if stype != SubMBType::Direct8x8 && ((ref_l == 0 && !stype.is_l1()) || (ref_l == 1 && !stype.is_l0())) {
+                        let ctx = sstate.get_mv_ref_ctx((spart & 1) * 8, (spart & 2) * 4, ref_l);
+                        let ref_idx = decode_ref_idx(cabac, num_l[ref_l], ctx);
+                        dst_ref[ref_l][spart] = ref_idx;
+                        sstate.get_cur_blk8(spart).ref_idx[ref_l] = ref_idx;
+                    }
+                }
+            }
+            let dst_mv = [&mut mb_info.mv_l0, &mut mb_info.mv_l1];
+            for ref_l in 0..2 {
+                for spart in 0..4 {
+                    let stype = mb_info.sub_mb_type[spart];
+                    if stype == SubMBType::Direct8x8 || (ref_l == 0 && stype.is_l1()) || (ref_l == 1 && stype.is_l0()) {
+                        continue;
+                    }
+                    let (pw, ph) = stype.size();
+                    let mut xoff = (spart & 1) * 8;
+                    let mut yoff = (spart & 2) * 4;
+                    let num_sub = stype.num_parts();
+                    let orig_x = xoff;
+                    for i in 0..num_sub {
+                        let (ctx0, ctx1) = sstate.get_mv_ctx(xoff, yoff, ref_l);
+                        let mv = decode_mv(cabac, ctx0, ctx1);
+                        dst_mv[ref_l][spart * 4 + i] = mv;
+                        sstate.fill_mvd(xoff, yoff, pw, ph, ref_l, mv);
+                        xoff += pw;
+                        if xoff == orig_x + 8 {
+                            xoff -= 8;
+                            yoff += ph;
+                        }
+                    }
+                }
+            }
+        },
+        _ => {},
+    };
+}
+
+pub fn decode_cbp_cabac(cabac: &mut CABAC, sstate: &SliceState) -> (u8, u8) {
+    let mbt_a = sstate.get_left_mb().mb_type;
+    let mbt_b = sstate.get_top_mb().mb_type;
+    let left = if mbt_a == CompactMBType::None || mbt_a == CompactMBType::PCM {
+            0x3F
+        } else if !mbt_a.is_skip() {
+            sstate.get_left_mb().cbp
+        } else {
+            0
+        };
+    let top = if mbt_b == CompactMBType::None || mbt_b == CompactMBType::PCM {
+            0x3F
+        } else if !mbt_b.is_skip() {
+            sstate.get_top_mb().cbp
+        } else {
+            0
+        };
+
+    let cbp_ctx = if (left & 2) != 0 { 0 } else { 1 } + if (top & 4) != 0 { 0 } else { 2 };
+    let mut cbpy = cabac.decode_bit(73 + cbp_ctx) as u8;
+    let cbp_ctx = if cbpy != 0 { 0 } else { 1 } + if (top & 8) != 0 { 0 } else { 2 };
+    cbpy |= (cabac.decode_bit(73 + cbp_ctx) as u8) << 1;
+    let cbp_ctx = if (left & 8) != 0 { 0 } else { 1 } + if (cbpy & 1) != 0 { 0 } else { 2 };
+    cbpy |= (cabac.decode_bit(73 + cbp_ctx) as u8) << 2;
+    let cbp_ctx = if (cbpy & 4) != 0 { 0 } else { 1 } + if (cbpy & 2) != 0 { 0 } else { 2 };
+    cbpy |= (cabac.decode_bit(73 + cbp_ctx) as u8) << 3;
+
+    let left = if mbt_a == CompactMBType::PCM {
+            0x2F
+        } else if mbt_a == CompactMBType::None || !mbt_a.is_skip() {
+            sstate.get_left_mb().cbp
+        } else {
+            0
+        };
+    let top = if mbt_b == CompactMBType::PCM {
+            0x2F
+        } else if mbt_b == CompactMBType::None || !mbt_b.is_skip() {
+            sstate.get_top_mb().cbp
+        } else {
+            0
+        };
+    let cleft = left >> 4;
+    let ctop  = top  >> 4;
+    let cbp_ctx0 = if cleft != 0 { 1 } else { 0 } + if ctop != 0 { 2 } else { 0 };
+    let cbp_ctx1 = if cleft == 2 { 1 } else { 0 } + if ctop == 2 { 2 } else { 0 };
+    let cbpc = if !cabac.decode_bit(77 + cbp_ctx0) {
+            0
+        } else {
+            cabac.decode_bit(81 + cbp_ctx1) as u8 + 1
+        };
+
+    (cbpy, cbpc)
+}
+
+pub fn decode_mb_qp_delta_cabac(cabac: &mut CABAC, ctx: usize) -> i32 {
+    if !cabac.decode_bit(60 + ctx) {
+        0
+    } else if !cabac.decode_bit(62) {
+        1
+    } else {
+        let mut val = 0;
+        while val < 128 && cabac.decode_bit(63) {
+            val += 1;
+        }
+        if (val & 1) != 0 {
+            ((val >> 1) as i32) + 2
+        } else {
+            -((val >> 1) as i32) - 1
+        }
+    }
+}
+
+fn decode_block(cabac: &mut CABAC, coeffs: &mut [i16], cat: usize, ctx_off: usize) -> bool {
+    const CTX_BASE: [(usize, usize); 5] = [
+        (0, 0), (15, 10), (29, 20), (44, 30), (47, 39)
+    ];
+    let (flag_off, coef_off) = CTX_BASE[cat];
+    let scan: &[usize] = match coeffs.len() {
+            4 => &CHROMA_DC_SCAN,
+            15 => &ZIGZAG1,
+            16 => &ZIGZAG,
+            _ => unreachable!(),
+        };
+
+    let coded_block_flag = cabac.decode_bit(85 + ctx_off);
+    let mut coded = [false; 16];
+    if coded_block_flag {
+        let mut last_idx = coeffs.len() - 1;
+        for i in 0..coeffs.len() - 1 {
+            coded[i] = cabac.decode_bit(105 + flag_off + i); // or 277 for interlaced
+            if coded[i] {
+                let last = cabac.decode_bit(166 + flag_off + i); // or 338 for interlaced
+                if last {
+                    last_idx = i;
+                    break;
+                }
+            }
+        }
+        coded[last_idx] = true;
+        let mut coef_ctx = 0;
+        for i in (0..=last_idx).rev() {
+            if coded[i] {
+                let zero_ctx = if coef_ctx < 4 { coef_ctx + 1 } else { 0 };
+                coeffs[scan[i]] = if !cabac.decode_bit(227 + coef_off + zero_ctx) {
+                        if coef_ctx < 3 {
+                            coef_ctx += 1;
+                        }
+                        1
+                    } else {
+                        let cur_ctx = 227 + coef_off + (coef_ctx + 2).max(5);
+                        coef_ctx = (coef_ctx + 1).max(4).min(7);
+
+                        let mut coef = 2;
+                        while coef < 15 && cabac.decode_bit(cur_ctx) {
+                            coef += 1;
+                        }
+                        if coef == 15 {
+                            let mut pfx = 0;
+                            while pfx < 15 && cabac.decode_bypass() {
+                                pfx += 1;
+                            }
+                            let mut tail = 1;
+                            for _ in 0..pfx {
+                                tail = (tail << 1) + (cabac.decode_bypass() as i16);
+                            }
+                            coef + tail - 1
+                        } else {
+                            coef
+                        }
+                    };
+                if cabac.decode_bypass() {
+                    coeffs[scan[i]] = -coeffs[scan[i]];
+                }
+            }
+        }
+    }
+    coded_block_flag
+}
+
+fn decode_block8x8(cabac: &mut CABAC, coeffs: &mut [i16; 64], _cat: usize) {
+    const SIG_FLAG_MAP: [usize; 63] = [
+         0,  1,  2,  3,  4,  5,  5,  4,  4,  3,  3,  4,  4,  4,  5,  5,
+         4,  4,  4,  4,  3,  3,  6,  7,  7,  7,  8,  9, 10,  9,  8,  7,
+         7,  6, 11, 12, 13, 11,  6,  7,  8,  9, 14, 10,  9,  8,  6, 11,
+        12, 13, 11,  6,  9, 14, 10,  9, 11, 12, 13, 11, 14, 10, 12
+    ];
+    const LAST_SIG_FLAG_MAP: [usize; 63] = [
+        0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+        5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8
+    ];
+    let (flag_off, coef_off) = (0, 0);
+    let scan = &ZIGZAG8X8;
+
+    let mut coded = [false; 64];
+    let mut last_idx = coeffs.len() - 1;
+    for i in 0..coeffs.len() - 1 {
+        coded[i] = cabac.decode_bit(402 + flag_off + SIG_FLAG_MAP[i]);
+        if coded[i] {
+            let last = cabac.decode_bit(417 + flag_off + LAST_SIG_FLAG_MAP[i]);
+            if last {
+                last_idx = i;
+                break;
+            }
+        }
+    }
+    coded[last_idx] = true;
+    let mut coef_ctx = 0;
+    for i in (0..=last_idx).rev() {
+        if coded[i] {
+            let zero_ctx = if coef_ctx < 4 { coef_ctx + 1 } else { 0 };
+            coeffs[scan[i]] = if !cabac.decode_bit(426 + coef_off + zero_ctx) {
+                    if coef_ctx < 3 {
+                        coef_ctx += 1;
+                    }
+                    1
+                } else {
+                    let cur_ctx = 426 + coef_off + (coef_ctx + 2).max(5);
+                    coef_ctx = (coef_ctx + 1).max(4).min(7);
+
+                    let mut coef = 2;
+                    while coef < 15 && cabac.decode_bit(cur_ctx) {
+                        coef += 1;
+                    }
+                    if coef == 15 {
+                        let mut pfx = 0;
+                        while pfx < 15 && cabac.decode_bypass() {
+                            pfx += 1;
+                        }
+                        let mut tail = 1;
+                        for _ in 0..pfx {
+                            tail = (tail << 1) + (cabac.decode_bypass() as i16);
+                        }
+                        coef + tail - 1
+                    } else {
+                        coef
+                    }
+                };
+            if cabac.decode_bypass() {
+                coeffs[scan[i]] = -coeffs[scan[i]];
+            }
+        }
+    }
+}
+
+fn derive_ctx_off(sstate: &mut SliceState, cat: usize, blk_no: usize) -> usize {
+    let mbt   = sstate.get_cur_mb().mb_type;
+    let mut mbt_a = sstate.get_left_mb().mb_type;
+    let mut mbt_b = sstate.get_top_mb().mb_type;
+    let (trans_a, trans_b, mut cond_term_a, mut cond_term_b) = match cat {
+            0 => {
+                (mbt_a == CompactMBType::Intra16x16,
+                 mbt_b == CompactMBType::Intra16x16,
+                 (sstate.get_left_mb().coded_flags & 1) as usize,
+                 (sstate.get_top_mb().coded_flags  & 1) as usize)
+            },
+            1 | 2 => {
+                if (blk_no & 3) != 0 {
+                    mbt_a = mbt;
+                }
+                if blk_no >= 4 {
+                    mbt_b = mbt;
+                }
+                let nc_left = sstate.get_left_blk4(blk_no).ncoded;
+                let nc_top  = sstate.get_top_blk4(blk_no).ncoded;
+                (nc_left != 0,
+                 nc_top != 0,
+                 (nc_left != 0) as usize,
+                 (nc_top != 0) as usize)
+            },
+            3 => {
+                ((sstate.get_left_mb().cbp & 0x30) != 0,
+                 (sstate.get_top_mb().cbp & 0x30) != 0,
+                 ((sstate.get_left_mb().coded_flags & (1 << (blk_no + 1 + 16))) != 0) as usize,
+                 ((sstate.get_top_mb().coded_flags & (1 << (blk_no + 1 + 16))) != 0) as usize)
+            },
+            4 => {
+                let chroma = blk_no >> 2;
+                if (blk_no & 1) != 0 {
+                    mbt_a = mbt;
+                }
+                if (blk_no & 2) != 0 {
+                    mbt_b = mbt;
+                }
+                ((blk_no & 1) != 0 || (sstate.get_left_mb().cbp & 0x20) != 0,
+                 (blk_no & 2) != 0 || (sstate.get_top_mb().cbp & 0x20) != 0,
+                 (sstate.get_left_blk8(blk_no & 3).ncoded_c[chroma] != 0) as usize,
+                 (sstate.get_top_blk8(blk_no & 3).ncoded_c[chroma] != 0) as usize)
+            },
+            _ => unreachable!(),
+        };
+    /*let coded_no = match cat {
+            0     => 0,
+            1 | 2 => blk_no + 1,
+            3     => 1 + 16 + blk_no,
+            4     => 1 + 16 + 2 + blk_no,
+            _ => unreachable!(),
+        };*/
+
+    if mbt_a == CompactMBType::None && mbt.is_inter() {
+        cond_term_a = 0;
+    }
+    if !trans_a && mbt_a != CompactMBType::PCM {
+        cond_term_a = 0;
+    }
+    /*if mbt.is_intra() && pps.constrained_intra_pred && mbt_a.is_inter() && slice_partitioning {
+        cond_term_a = 0;
+    }*/
+    if (mbt_a == CompactMBType::PCM) || (mbt_a == CompactMBType::None && mbt.is_intra()) {
+        cond_term_a = 1;
+    }
+
+    if mbt_b == CompactMBType::None && mbt.is_inter() {
+        cond_term_b = 0;
+    }
+    if !trans_b && mbt_b != CompactMBType::PCM {
+        cond_term_b = 0;
+    }
+    /*if mbt.is_intra() && pps.constrained_intra_pred && mbt_b.is_inter() && slice_partitioning {
+        cond_term_b = 0;
+    }*/
+    if (mbt_b == CompactMBType::PCM) || (mbt_b == CompactMBType::None && mbt.is_intra()) {
+        cond_term_b = 1;
+    }
+
+    cat * 4 + cond_term_b * 2 + cond_term_a
+}
+
+pub fn decode_residual_cabac(cabac: &mut CABAC, sstate: &mut SliceState, mb_info: &mut CurrentMBInfo) {
+    sstate.get_cur_mb().mb_type = mb_info.mb_type.into();
+    let mut coded_flags = 0;
+    if mb_info.mb_type.is_intra16x16() {
+        let off = derive_ctx_off(sstate, 0, 0);
+        let coded = decode_block(cabac, &mut mb_info.coeffs[24], 0, off);
+        mb_info.coded[24] = coded;
+        if coded {
+            coded_flags |= 1;
+        }
+    }
+    if !mb_info.transform_size_8x8 {
+        for blk8 in 0..4 {
+            if (mb_info.cbpy & (1 << blk8)) != 0 {
+                for blk4 in 0..4 {
+                    let blk_no = (blk8 & 1) * 2 + (blk8 & 2) * 4 + (blk4 & 1) + (blk4 & 2) * 2;
+                    let coded = if mb_info.mb_type.is_intra16x16() {
+                            let off = derive_ctx_off(sstate, 1, blk_no);
+                            decode_block(cabac, &mut mb_info.coeffs[blk_no][1..], 1, off)
+                        } else {
+                            let off = derive_ctx_off(sstate, 2, blk_no);
+                            decode_block(cabac, &mut mb_info.coeffs[blk_no], 2, off)
+                        };
+                    sstate.get_cur_blk4(blk_no).ncoded = coded as u8;
+                    mb_info.coded[blk_no] = coded;
+                    if coded {
+                        coded_flags |= 1 << (1 + blk_no);
+                    }
+                }
+            }
+        }
+    } else {
+        for blk8 in 0..4 {
+            if (mb_info.cbpy & (1 << blk8)) != 0 {
+                let blk4 = (blk8 & 1) * 2 + (blk8 & 2) * 4;
+                decode_block8x8(cabac, &mut mb_info.coeffs8x8[blk8].coeffs, 5);
+                coded_flags |= 0x33 << blk4;
+                mb_info.coded[blk4]     = true;
+                mb_info.coded[blk4 + 1] = true;
+                mb_info.coded[blk4 + 4] = true;
+                mb_info.coded[blk4 + 5] = true;
+                sstate.get_cur_blk4(blk4).ncoded     = 1;
+                sstate.get_cur_blk4(blk4 + 1).ncoded = 1;
+                sstate.get_cur_blk4(blk4 + 4).ncoded = 1;
+                sstate.get_cur_blk4(blk4 + 5).ncoded = 1;
+            }
+        }
+    }
+    for chroma in 0..2 {
+        if (mb_info.cbpc & 3) != 0 {
+            let off = derive_ctx_off(sstate, 3, chroma);
+            let coded = decode_block(cabac, &mut mb_info.chroma_dc[chroma], 3, off);
+            if coded {
+                coded_flags |= 1 << (16 + 1 + chroma);
+            }
+        }
+    }
+    for chroma in 0..2 {
+        if (mb_info.cbpc & 2) != 0 {
+            for blk4 in 0..4 {
+                let blk_no = 16 + chroma * 4 + blk4;
+                let off = derive_ctx_off(sstate, 4, blk_no - 16);
+                let coded = decode_block(cabac, &mut mb_info.coeffs[blk_no][1..], 4, off);
+                sstate.get_cur_blk8(blk4).ncoded_c[chroma] = coded as u8;
+                mb_info.coded[blk_no] = coded;
+                if coded {
+                    coded_flags |= 1 << (1 + 2 + blk_no);
+                }
+            }
+        }
+    }
+    sstate.get_cur_mb().coded_flags = coded_flags;
+}