Files
soundcraft/crates/video/src/h264/cabac_mb.rs
T
Dylan M. Taylor 64669e9a7c chore: resolve SonarCloud maintainability issues (#1003)
* chore: resolve SonarCloud maintainability issues

* fix(packaging): extract verify_sha256 helper in package.sh

* style: apply rustfmt formatting

* fix(video): ensure prefix is i32 in cabac_mb
2026-10-23 22:33:59 -04:00

690 lines
28 KiB
Rust

//! CABAC slice data and macroblock layer parsing (7.3.4, 7.3.5 with 9.3 binarisations and context
//! index derivations).
use crate::h264::cabac::Cabac;
use crate::h264::error::{Result, ensure, invalid};
use crate::h264::mbtypes::{MbTypeInfo, Part, SubMbInfo, b_mb_type, b_sub_mb_type, intra_mb_type, p_mb_type, p_sub_mb_type};
use crate::h264::picture::MbKind;
use crate::h264::slice::SliceType;
use crate::h264::slicedec::{MbCur, SliceDecoder};
/// Table 9-43: significant_coeff_flag ctxIdxInc for 8x8 frame blocks.
#[rustfmt::skip]
const SIG8_FRAME: [u8; 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,
];
/// Table 9-43: last_significant_coeff_flag ctxIdxInc for 8x8 blocks.
#[rustfmt::skip]
const LAST8: [u8; 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,
];
/// ctxIdxInc = levelListIdx (ctxBlockCat 0, 1, 2, 4).
const IDENT_CTX: [u8; 64] = {
let mut t = [0u8; 64];
let mut i = 0;
while i < 64 {
t[i] = i as u8;
i += 1;
}
t
};
/// ctxIdxInc = Min(levelListIdx / NumC8x8, 2) for 4:2:0 chroma DC (ctxBlockCat 3).
const CHROMA_DC_CTX: [u8; 4] = [0, 1, 2, 2];
/// Table 9-40 ctxIdxBlockCatOffset for ctxBlockCat 0..=5: (coded_block_flag, significant/last, abs level).
const CAT_OFFSET: [(usize, usize, usize); 6] = [(0, 0, 0), (4, 15, 10), (8, 29, 20), (12, 44, 30), (16, 47, 39), (0, 0, 0)];
impl SliceDecoder<'_> {
/// Decode slice_data() with CABAC. `rbsp` is the whole slice RBSP.
pub fn decode_cabac(&mut self, rbsp: &[u8]) -> Result<()> {
let start = self.sh.header_bits.div_ceil(8) * 8;
let init = if self.sh.slice_type.is_intra() { 3 } else { self.sh.cabac_init_idc as usize };
let mut c = Cabac::new(rbsp, start, self.sh.qp(self.pps), init)?;
let total = self.mb_w * self.mb_h;
let mut addr = self.sh.first_mb_in_slice as usize;
let intra_slice = self.sh.slice_type.is_intra();
loop {
ensure!(addr < total, "macroblock address {addr} out of range");
self.start_mb(addr);
let skip = !intra_slice && self.decode_skip_flag(&mut c);
if skip {
self.decode_skip()?;
} else {
self.decode_mb_cabac(&mut c)?;
}
self.pic.mb_done(addr);
ensure!(!c.overrun(), "CABAC read past end of slice data");
if c.decode_terminate() == 1 {
break;
}
addr += 1;
}
Ok(())
}
fn decode_skip_flag(&mut self, c: &mut Cabac) -> bool {
let cond = |n: Option<usize>| n.map(|m| !self.pic.mbs[m].kind_is_skip()).unwrap_or(false) as usize;
let inc = cond(self.nb[0]) + cond(self.nb[1]);
let base = if self.sh.slice_type.is_b() { 24 } else { 11 };
c.decode_decision(base + inc) == 1
}
/// Intra mb_type suffix / I-slice mb_type (Table 9-36). `base` is 3 (I slice) or 17/32 (prefix
/// offsets in P/B slices). Returns the I-slice mb_type value 0..=25.
fn decode_mb_type_i(&mut self, c: &mut Cabac, base: usize) -> u32 {
let islice = base == 3;
let b0 = if islice {
let cond = |n: Option<usize>| n.map(|m| !matches!(self.pic.mbs[m].kind, MbKind::I4x4 | MbKind::I8x8)).unwrap_or(false) as usize;
let inc = cond(self.nb[0]) + cond(self.nb[1]);
c.decode_decision(base + inc)
} else {
c.decode_decision(base)
};
if b0 == 0 {
return 0;
}
if c.decode_terminate() == 1 {
return 25;
}
let (c_luma, c_chroma, c_chroma2, c_pred0, c_pred1) =
if islice { (base + 3, base + 4, base + 5, base + 6, base + 7) } else { (base + 1, base + 2, base + 2, base + 3, base + 3) };
let luma = c.decode_decision(c_luma);
let mut chroma = c.decode_decision(c_chroma);
if chroma != 0 {
chroma += c.decode_decision(c_chroma2);
}
let p0 = c.decode_decision(c_pred0);
let p1 = c.decode_decision(c_pred1);
1 + (p0 * 2 + p1) + 4 * chroma + 12 * luma
}
fn decode_mb_type(&mut self, c: &mut Cabac) -> Result<MbTypeInfo> {
let info = match self.sh.slice_type {
SliceType::I | SliceType::Si => intra_mb_type(self.decode_mb_type_i(c, 3)),
SliceType::P | SliceType::Sp => {
if c.decode_decision(14) == 1 {
intra_mb_type(self.decode_mb_type_i(c, 17))
} else if c.decode_decision(15) == 0 {
p_mb_type(if c.decode_decision(16) == 0 { 0 } else { 3 })
} else {
p_mb_type(if c.decode_decision(17) == 1 { 1 } else { 2 })
}
}
SliceType::B => {
let cond =
|n: Option<usize>| n.map(|m| !matches!(self.pic.mbs[m].kind, MbKind::BSkip | MbKind::BDirect16x16)).unwrap_or(false) as usize;
let inc = cond(self.nb[0]) + cond(self.nb[1]);
if c.decode_decision(27 + inc) == 0 {
b_mb_type(0)
} else if c.decode_decision(27 + 3) == 0 {
b_mb_type(1 + c.decode_decision(27 + 5))
} else {
let b2 = c.decode_decision(27 + 4);
let b3 = c.decode_decision(27 + 5);
let b4 = c.decode_decision(27 + 5);
let b5 = c.decode_decision(27 + 5);
let v = (b2 << 3) | (b3 << 2) | (b4 << 1) | b5;
match v {
0b1101 => intra_mb_type(self.decode_mb_type_i(c, 32)),
0b1111 => b_mb_type(22),
0b1110 => b_mb_type(11),
_ if b2 == 0 => b_mb_type(3 + v),
_ => {
let b6 = c.decode_decision(27 + 5);
b_mb_type(12 + (((v & 7) << 1) | b6))
}
}
}
}
};
match info {
Some(i) => Ok(i),
None => invalid("invalid CABAC mb_type"),
}
}
fn decode_sub_mb_type(&mut self, c: &mut Cabac) -> Result<SubMbInfo> {
let r = if self.sh.slice_type.is_b() {
if c.decode_decision(36) == 0 {
b_sub_mb_type(0)
} else if c.decode_decision(37) == 0 {
b_sub_mb_type(1 + c.decode_decision(39))
} else if c.decode_decision(38) == 1 {
if c.decode_decision(39) == 1 {
b_sub_mb_type(11 + c.decode_decision(39))
} else {
let b4 = c.decode_decision(39);
let b5 = c.decode_decision(39);
b_sub_mb_type(7 + (b4 << 1) + b5)
}
} else {
let b3 = c.decode_decision(39);
let b4 = c.decode_decision(39);
b_sub_mb_type(3 + (b3 << 1) + b4)
}
} else if c.decode_decision(21) == 1 {
p_sub_mb_type(0)
} else if c.decode_decision(22) == 0 {
p_sub_mb_type(1)
} else {
p_sub_mb_type(if c.decode_decision(23) == 1 { 2 } else { 3 })
};
match r {
Some(s) => Ok(s),
None => invalid("invalid CABAC sub_mb_type"),
}
}
/// ref_idx_lX for the partition whose top-left 4x4 block is (x, y) (9.3.3.1.1.6).
fn decode_ref_idx(&mut self, c: &mut Cabac, list: usize, x: usize, y: usize) -> u32 {
let cond = |xx: i32, yy: i32| -> usize {
let (mb, bx, by) = if xx < 0 {
(self.nb[0], 3usize, yy as usize)
} else if yy < 0 {
(self.nb[1], xx as usize, 3usize)
} else {
(Some(self.mb_addr), xx as usize, yy as usize)
};
let Some(m) = mb else { return 0 };
let st = &self.pic.mbs[m];
let b8 = (by >> 1) * 2 + (bx >> 1);
if st.kind.is_intra() || st.kind_is_skip() || st.direct8x8 & (1 << b8) != 0 {
return 0;
}
(st.ref_idx[list][b8] > 0) as usize
};
let inc = cond(x as i32 - 1, y as i32) + 2 * cond(x as i32, y as i32 - 1);
let mut v = 0u32;
if c.decode_decision(54 + inc) == 1 {
v = 1;
if c.decode_decision(54 + 4) == 1 {
v = 2;
while c.decode_decision(54 + 5) == 1 {
v += 1;
if v > 32 {
break;
}
}
}
}
v
}
/// One mvd component for the (sub-)partition with top-left 4x4 block (x, y) (9.3.3.1.1.7, UEG3).
fn decode_mvd(&mut self, c: &mut Cabac, list: usize, comp: usize, x: usize, y: usize) -> i32 {
let absn = |xx: i32, yy: i32| -> u32 {
let (mb, bx, by) = if xx < 0 {
(self.nb[0], 3usize, yy as usize)
} else if yy < 0 {
(self.nb[1], xx as usize, 3usize)
} else {
(Some(self.mb_addr), xx as usize, yy as usize)
};
match mb {
Some(m) => self.pic.mbs[m].mvd[list][by * 4 + bx][comp] as u32,
None => 0,
}
};
let sum = absn(x as i32 - 1, y as i32) + absn(x as i32, y as i32 - 1);
let inc = if sum > 32 {
2
} else if sum > 2 {
1
} else {
0
};
let base = if comp == 0 { 40 } else { 47 };
if c.decode_decision(base + inc) == 0 {
return 0;
}
let mut prefix: i32 = 1;
while prefix < 9 && c.decode_decision(base + (prefix + 2).min(6) as usize) == 1 {
prefix += 1;
}
let mut val = prefix;
if prefix >= 9 {
// EG3 suffix
let mut k = 3;
while c.decode_bypass() == 1 {
val += 1 << k;
k += 1;
if k > 24 {
break;
}
}
while k > 0 {
k -= 1;
val += (c.decode_bypass() as i32) << k;
}
}
if c.decode_bypass() == 1 { -val } else { val }
}
fn set_cur_ref(&mut self, list: usize, x: usize, y: usize, w: usize, h: usize, r: i8) {
let st = self.mb_mut();
for yy in (y..y + h).step_by(2) {
for xx in (x..x + w).step_by(2) {
st.ref_idx[list][(yy >> 1) * 2 + (xx >> 1)] = r;
}
}
}
fn set_cur_mvd(&mut self, list: usize, x: usize, y: usize, w: usize, h: usize, d: [i32; 2]) {
let a = [d[0].unsigned_abs().min(127) as u8, d[1].unsigned_abs().min(127) as u8];
let st = self.mb_mut();
for yy in y..y + h {
for xx in x..x + w {
st.mvd[list][yy * 4 + xx] = a;
}
}
}
fn decode_cbp(&mut self, c: &mut Cabac) -> u8 {
let mut luma = 0u8;
for b8 in 0..4usize {
let (bx, by) = ((b8 & 1) * 2, (b8 >> 1) * 2);
// A
let ca = if bx > 0 { ((luma >> (b8 - 1)) & 1 == 0) as usize } else { self.cbp_luma_cond(self.nb[0], b8 + 1) };
let cb = if by > 0 { ((luma >> (b8 - 2)) & 1 == 0) as usize } else { self.cbp_luma_cond(self.nb[1], b8 + 2) };
let _ = (bx, by);
let bin = c.decode_decision(73 + ca + 2 * cb);
luma |= (bin as u8) << b8;
}
let cond = |n: Option<usize>, bin: usize| -> usize {
let Some(m) = n else { return 0 };
let st = &self.pic.mbs[m];
if st.kind == MbKind::IPcm {
return 1;
}
if st.kind_is_skip() {
return 0;
}
let ch = st.cbp >> 4;
if bin == 0 { (ch != 0) as usize } else { (ch == 2) as usize }
};
let inc0 = cond(self.nb[0], 0) + 2 * cond(self.nb[1], 0);
let mut chroma = 0u8;
if c.decode_decision(77 + inc0) == 1 {
let inc1 = cond(self.nb[0], 1) + 2 * cond(self.nb[1], 1) + 4;
chroma = 1 + c.decode_decision(77 + inc1) as u8;
}
luma | (chroma << 4)
}
/// condTermFlagN for coded_block_pattern luma bin from a neighbouring MB; `b8n` is the neighbouring
/// 8x8 block index within that MB.
fn cbp_luma_cond(&self, n: Option<usize>, b8n: usize) -> usize {
let Some(m) = n else { return 0 };
let st = &self.pic.mbs[m];
if st.kind == MbKind::IPcm {
return 0;
}
if st.kind_is_skip() {
return 1;
}
((st.cbp >> (b8n & 3)) & 1 == 0) as usize
}
fn decode_qp_delta(&mut self, c: &mut Cabac) -> Result<i32> {
let inc = self.prev_qp_delta_nz as usize;
if c.decode_decision(60 + inc) == 0 {
return Ok(0);
}
let mut k = 1u32;
let mut ctx = 62;
while c.decode_decision(ctx) == 1 {
k += 1;
ctx = 63;
ensure!(k <= 128, "mb_qp_delta too large");
}
let v = k.div_ceil(2) as i32;
Ok(if k % 2 == 1 { v } else { -v })
}
/// coded_block_flag ctxIdxInc condition for a neighbouring luma 4x4 block (cat 0..2) or chroma.
fn cbf_luma_cond(&self, bx: i32, by: i32, intra_cur: bool) -> usize {
if bx >= 0 && by >= 0 {
return (self.mb().nnz[(by * 4 + bx) as usize] != 0) as usize;
}
let n = if bx < 0 { self.nb[0] } else { self.nb[1] };
let Some(m) = n else { return intra_cur as usize };
let st = &self.pic.mbs[m];
let (x, y) = if bx < 0 { (3, by as usize) } else { (bx as usize, 3) };
(st.nnz[y * 4 + x] != 0) as usize
}
fn cbf_dc_cond(&self, n: Option<usize>, bit: u8, intra_cur: bool) -> usize {
let Some(m) = n else { return intra_cur as usize };
let st = &self.pic.mbs[m];
if st.kind == MbKind::IPcm {
return 1;
}
(st.cbf_dc & (1 << bit) != 0) as usize
}
fn cbf_chroma_ac_cond(&self, comp: usize, bx: i32, by: i32, intra_cur: bool) -> usize {
if bx >= 0 && by >= 0 {
return (self.mb().nnz_c[comp][(by * 2 + bx) as usize] != 0) as usize;
}
let n = if bx < 0 { self.nb[0] } else { self.nb[1] };
let Some(m) = n else { return intra_cur as usize };
let st = &self.pic.mbs[m];
let (x, y) = if bx < 0 { (1, by as usize) } else { (bx as usize, 1) };
(st.nnz_c[comp][y * 2 + x] != 0) as usize
}
/// residual_block_cabac for ctxBlockCat `cat` (0..=5). Coefficients are written to `coeff`
/// in list order (indices 0..max_num). `cbf_inc` is the coded_block_flag ctxIdxInc (ignored for cat 5).
/// Returns the number of non-zero coefficients.
fn residual_block_cabac(&mut self, c: &mut Cabac, coeff: &mut [i32], cat: usize, max_num: usize, cbf_inc: usize) -> u8 {
if cat != 5 && c.decode_decision(85 + CAT_OFFSET[cat].0 + cbf_inc) == 0 {
return 0;
}
let (sig_base, last_base, abs_base) =
if cat == 5 { (402, 417, 426) } else { (105 + CAT_OFFSET[cat].1, 166 + CAT_OFFSET[cat].1, 227 + CAT_OFFSET[cat].2) };
let (sig_tab, last_tab): (&[u8], &[u8]) = match cat {
3 => (&CHROMA_DC_CTX, &CHROMA_DC_CTX),
5 => (&SIG8_FRAME, &LAST8),
_ => (&IDENT_CTX, &IDENT_CTX),
};
// significance map: positions of the significant coefficients in scan order
let mut pos = [0u8; 64];
let mut n = 0usize;
let last_i = max_num - 1;
let mut found_last = false;
for i in 0..last_i {
if c.decode_decision(sig_base + sig_tab[i] as usize) == 1 {
pos[n] = i as u8;
n += 1;
if c.decode_decision(last_base + last_tab[i] as usize) == 1 {
found_last = true;
break;
}
}
}
if !found_last {
pos[n] = last_i as u8;
n += 1;
}
let mut eq1 = 0usize;
let mut gt1 = 0usize;
let gt1_cap = if cat == 3 { 3 } else { 4 };
for &p in pos[..n].iter().rev() {
let inc0 = if gt1 != 0 { 0 } else { (1 + eq1).min(4) };
let mut abs = 1i32;
if c.decode_decision(abs_base + inc0) == 1 {
let ctx = abs_base + 5 + gt1.min(gt1_cap);
let mut prefix = 1;
while prefix < 14 && c.decode_decision(ctx) == 1 {
prefix += 1;
}
abs = prefix + 1;
if prefix == 14 {
let mut k = 0;
let mut suf = 0i32;
while c.decode_bypass() == 1 {
suf += 1 << k;
k += 1;
if k > 24 {
break;
}
}
while k > 0 {
k -= 1;
suf += (c.decode_bypass() as i32) << k;
}
abs += suf;
}
gt1 += 1;
} else {
eq1 += 1;
}
coeff[p as usize] = if c.decode_bypass() == 1 { -abs } else { abs };
}
n as u8
}
fn residual_cabac(&mut self, c: &mut Cabac, cbp: u8) -> Result<()> {
let kind = self.mb().kind;
let intra = kind.is_intra();
let t8 = self.mb().transform_8x8;
if kind == MbKind::I16x16 {
let inc = self.cbf_dc_cond(self.nb[0], 0, intra) + 2 * self.cbf_dc_cond(self.nb[1], 0, intra);
let mut lv = [0i32; 16];
if self.residual_block_cabac(c, &mut lv, 0, 16, inc) > 0 {
self.mb_mut().cbf_dc |= 1;
self.put_luma_dc(&lv);
}
}
for b8 in 0..4 {
let (bx8, by8) = ((b8 & 1) * 2, (b8 >> 1) * 2);
if cbp & (1 << b8) == 0 {
continue;
}
if t8 {
let mut lv = [0i32; 64];
self.residual_block_cabac(c, &mut lv, 5, 64, 0);
let st = self.mb_mut();
for r in [by8 * 4 + bx8, by8 * 4 + bx8 + 1, (by8 + 1) * 4 + bx8, (by8 + 1) * 4 + bx8 + 1] {
st.nnz[r] = 1;
}
self.put_luma8(b8, &lv);
} else {
for i4 in 0..4 {
let (bx, by) = (bx8 + (i4 & 1), by8 + (i4 >> 1));
let raster = by * 4 + bx;
let inc = self.cbf_luma_cond(bx as i32 - 1, by as i32, intra) + 2 * self.cbf_luma_cond(bx as i32, by as i32 - 1, intra);
let mut lv = [0i32; 16];
let n = if kind == MbKind::I16x16 {
self.residual_block_cabac(c, &mut lv[1..], 1, 15, inc)
} else {
self.residual_block_cabac(c, &mut lv, 2, 16, inc)
};
self.mb_mut().nnz[raster] = n;
if n > 0 {
self.put_luma4(raster, &lv, kind == MbKind::I16x16);
}
}
}
}
let cbp_c = cbp >> 4;
if cbp_c != 0 {
for comp in 0..2 {
let bit = 1 + comp as u8;
let inc = self.cbf_dc_cond(self.nb[0], bit, intra) + 2 * self.cbf_dc_cond(self.nb[1], bit, intra);
let mut lv = [0i32; 4];
if self.residual_block_cabac(c, &mut lv, 3, 4, inc) > 0 {
self.mb_mut().cbf_dc |= 1 << bit;
self.put_chroma_dc(comp, &lv);
}
}
}
if cbp_c == 2 {
for comp in 0..2 {
for b in 0..4 {
let (bx, by) = ((b & 1) as i32, (b >> 1) as i32);
let inc = self.cbf_chroma_ac_cond(comp, bx - 1, by, intra) + 2 * self.cbf_chroma_ac_cond(comp, bx, by - 1, intra);
let mut lv = [0i32; 16];
let n = self.residual_block_cabac(c, &mut lv[1..], 4, 15, inc);
self.mb_mut().nnz_c[comp][b] = n;
if n > 0 {
self.put_chroma_ac(comp, b, &lv);
}
}
}
}
Ok(())
}
/// Parse and reconstruct one macroblock_layer() with CABAC.
fn decode_mb_cabac(&mut self, c: &mut Cabac) -> Result<()> {
let mut info = self.decode_mb_type(c)?;
self.cur = MbCur { info, ..Default::default() };
if info.kind == MbKind::IPcm {
// pcm alignment + samples, then re-initialise the arithmetic decoder
let pos = c.bit_pos().div_ceil(8);
let data = c.data();
ensure!(data.len() >= pos + 384, "truncated I_PCM macroblock");
let Some(&samples) = data.get(pos..).and_then(|d| d.first_chunk::<384>()) else {
return invalid("truncated I_PCM macroblock");
};
c.set_bit_pos((pos + 384) * 8);
c.init_engine()?;
self.finish_pcm();
self.write_pcm(&samples);
self.prev_qp_delta_nz = false;
return Ok(());
}
let intra = info.kind.is_intra();
if info.kind == MbKind::I4x4 && self.pps.transform_8x8_mode && self.decode_t8x8_flag(c) {
info.kind = MbKind::I8x8;
self.cur.info.kind = MbKind::I8x8;
self.mb_mut().transform_8x8 = true;
}
self.mb_mut().kind = info.kind;
let n_ref = self.sh.num_ref_idx_active;
match info.kind {
MbKind::I4x4 | MbKind::I8x8 => {
let n = if info.kind == MbKind::I8x8 { 4 } else { 16 };
for i in 0..n {
self.cur.rem_mode[i] = if c.decode_decision(68) == 1 {
-1
} else {
let b0 = c.decode_decision(69);
let b1 = c.decode_decision(69);
let b2 = c.decode_decision(69);
(b0 | (b1 << 1) | (b2 << 2)) as i8
};
}
self.derive_intra_modes(info.kind == MbKind::I8x8);
let m = self.decode_chroma_mode(c);
self.mb_mut().intra_chroma_mode = m;
}
MbKind::I16x16 => {
let m = self.decode_chroma_mode(c);
self.mb_mut().intra_chroma_mode = m;
}
MbKind::BDirect16x16 => {
self.mb_mut().direct8x8 = 0xf;
}
_ => {
if info.part == Part::P8x8 {
for p in 0..4 {
self.cur.sub[p] = self.decode_sub_mb_type(c)?;
}
let direct_mask: u8 = (0..4).filter(|&p| self.cur.sub[p].direct).map(|p| 1u8 << p).sum();
self.mb_mut().direct8x8 = direct_mask;
for l in 0..2 {
for p in 0..4 {
let sub = self.cur.sub[p];
if sub.direct || sub.pred & (1 << l) == 0 {
continue;
}
let (x, y) = ((p & 1) * 2, (p >> 1) * 2);
let r = if n_ref[l] > 1 && !info.ref0 { self.decode_ref_idx(c, l, x, y) as i8 } else { 0 };
self.cur.ref_idx[l][p] = r;
self.set_cur_ref(l, x, y, 2, 2, r);
}
}
for l in 0..2 {
for p in 0..4 {
let sub = self.cur.sub[p];
if sub.direct || sub.pred & (1 << l) == 0 {
continue;
}
let (x8, y8) = ((p & 1) * 2, (p >> 1) * 2);
for j in 0..sub.shape.num_parts() {
let (sx, sy, w, h) = sub.shape.rect(j);
let (x, y) = (x8 + sx, y8 + sy);
let dx = self.decode_mvd(c, l, 0, x, y);
let dy = self.decode_mvd(c, l, 1, x, y);
self.set_cur_mvd(l, x, y, w, h, [dx, dy]);
self.cur.mvd[l][p * 4 + j] = [dx as i16, dy as i16];
}
}
}
} else {
let np = info.part.num_parts();
for l in 0..2 {
for p in 0..np {
if info.pred[p] & (1 << l) == 0 {
continue;
}
let (x, y, w, h) = info.part.rect(p);
let r = if n_ref[l] > 1 { self.decode_ref_idx(c, l, x, y) as i8 } else { 0 };
self.cur.ref_idx[l][p] = r;
self.set_cur_ref(l, x, y, w, h, r);
}
}
for l in 0..2 {
for p in 0..np {
if info.pred[p] & (1 << l) == 0 {
continue;
}
let (x, y, w, h) = info.part.rect(p);
let dx = self.decode_mvd(c, l, 0, x, y);
let dy = self.decode_mvd(c, l, 1, x, y);
self.set_cur_mvd(l, x, y, w, h, [dx, dy]);
self.cur.mvd[l][p * 4] = [dx as i16, dy as i16];
}
}
}
}
}
let cbp = if info.kind == MbKind::I16x16 { info.i16_cbp } else { self.decode_cbp(c) };
self.cur.cbp = cbp;
self.mb_mut().cbp = cbp;
if !intra && cbp & 15 != 0 && self.pps.transform_8x8_mode && self.no_sub_8x8_lt() {
let t = self.decode_t8x8_flag(c);
self.mb_mut().transform_8x8 = t;
}
if !intra {
// ref_idx written during parsing is replaced by the derived motion
self.derive_inter_motion()?;
}
if cbp != 0 || info.kind == MbKind::I16x16 {
let d = self.decode_qp_delta(c)?;
self.apply_qp_delta(d)?;
self.prev_qp_delta_nz = d != 0;
} else {
self.prev_qp_delta_nz = false;
}
self.store_qp();
self.residual_cabac(c, cbp)?;
if intra {
self.reconstruct_intra();
} else {
self.predict_inter();
self.reconstruct_inter_residual();
}
Ok(())
}
fn decode_t8x8_flag(&mut self, c: &mut Cabac) -> bool {
let cond = |n: Option<usize>| n.map(|m| self.pic.mbs[m].transform_8x8).unwrap_or(false) as usize;
let inc = cond(self.nb[0]) + cond(self.nb[1]);
c.decode_decision(399 + inc) == 1
}
fn decode_chroma_mode(&mut self, c: &mut Cabac) -> u8 {
let cond = |n: Option<usize>| {
n.map(|m| {
let st = &self.pic.mbs[m];
st.kind.is_intra() && st.kind != MbKind::IPcm && st.intra_chroma_mode != 0
})
.unwrap_or(false) as usize
};
let inc = cond(self.nb[0]) + cond(self.nb[1]);
if c.decode_decision(64 + inc) == 0 {
return 0;
}
if c.decode_decision(67) == 0 {
return 1;
}
if c.decode_decision(67) == 0 { 2 } else { 3 }
}
}