use crate::coder::*;
use crate::odec::OdEcEncoder;
use crate::tables::*;
pub(crate) fn encode_golomb(enc: &mut OdEcEncoder, v: u32) {
let x = v + 1;
let length = 32 - x.leading_zeros();
for _ in 0..length - 1 {
enc.encode_bool(false, 16384); }
for i in (0..length).rev() {
enc.encode_bool((x >> i) & 1 == 1, 16384); }
}
pub(crate) fn get_lo_ctx_2d(
levels: &[u8],
x: usize,
y: usize,
off: &[[u32; 5]; 5],
stride: usize,
) -> (usize, u32) {
let g = |dx: usize, dy: usize| levels[(x + dx) * stride + (y + dy)] as u32;
let hi_mag = g(0, 1) + g(1, 0) + g(1, 1);
let mag = hi_mag + g(0, 2) + g(2, 0);
let offset = off[y.min(4)][x.min(4)];
let ctx = offset + if mag > 512 { 4 } else { (mag + 64) >> 7 };
(ctx as usize, hi_mag)
}
#[inline]
fn eob_and_cul<const N: usize>(cf: &[i32; N], scan: &[u32]) -> Option<(usize, u32)> {
let eob = scan.iter().rposition(|&rc| cf[rc as usize] != 0)?;
let cul = scan[..=eob]
.iter()
.map(|&rc| cf[rc as usize].unsigned_abs())
.sum();
Some((eob, cul))
}
pub(crate) fn encode_hi_tok(enc: &mut OdEcEncoder, m: u32, br_cdf: &mut [u16]) {
let total_br = (m as i32 - (NUM_BASE_LEVELS + 1)).min(COEFF_BASE_RANGE);
let mut coded = 0;
for _ in 0..(COEFF_BASE_RANGE / 3) {
let s = (total_br - coded).min(3);
enc.encode_symbol(s as usize, br_cdf);
coded += s;
if s < 3 {
break;
}
}
}
pub(crate) fn encode_dc_tail(
enc: &mut OdEcEncoder,
level: i32,
eob_bin_cdf: &mut [u16],
base_eob: &mut [u16],
dc_sign: &mut [u16],
br0: &mut [u16],
) {
enc.encode_symbol(0, eob_bin_cdf);
let m = level.unsigned_abs();
let base = m.min(3);
enc.encode_symbol(base as usize - 1, base_eob);
if base == 3 {
encode_hi_tok(enc, m, br0);
}
enc.encode_symbol((level < 0) as usize, dc_sign);
if m >= 15 {
encode_golomb(enc, m - 15);
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_tx8_coeffs_adapt(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 64],
chroma: bool,
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let pl = chroma as usize;
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_8X8) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[1][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[1][skip_ctx]); if !chroma {
enc.encode_symbol(txtp, &mut cdfs.txtp[y_mode]); }
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
let eb = if chroma {
&mut cdfs.eob_bin_64_c
} else {
&mut cdfs.eob_bin_64_l
};
encode_dc_tail(
enc,
cf[0],
eb,
&mut cdfs.eob_base[1][pl][0],
&mut cdfs.dc_sign[pl][dcs_ctx],
&mut cdfs.br_tok[1][pl][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
{
let eb = if chroma {
&mut cdfs.eob_bin_64_c
} else {
&mut cdfs.eob_bin_64_l
};
enc.encode_symbol(eob_bin, eb);
}
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[1][pl][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384); }
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 8) as usize + (eob > 16) as usize;
let rc = SCAN_8X8[eob] as usize;
let (ex, ey) = (rc >> 3, rc & 7);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1; enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[1][pl][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][pl][bc]);
}
levels[ex * 8 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_8X8[i] as usize;
let (x, y) = (rc_i >> 3, rc_i & 7);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF, 8);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[1][pl][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][pl][bc as usize]);
}
levels[x * 8 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[1][pl][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[8] as u32 + levels[9] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[1][pl][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[pl][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_8X8[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_tx16_coeffs_adapt(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 256],
chroma: bool,
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let pl = chroma as usize;
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_16X16) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[2][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[2][skip_ctx]); if !chroma {
enc.encode_symbol(txtp, &mut cdfs.txtp16[y_mode]); }
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
let eb = if chroma {
&mut cdfs.eob_bin_256_c
} else {
&mut cdfs.eob_bin_256_l
};
encode_dc_tail(
enc,
cf[0],
eb,
&mut cdfs.eob_base[2][pl][0],
&mut cdfs.dc_sign[pl][dcs_ctx],
&mut cdfs.br_tok[2][pl][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
{
let eb = if chroma {
&mut cdfs.eob_bin_256_c
} else {
&mut cdfs.eob_bin_256_l
};
enc.encode_symbol(eob_bin, eb);
}
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[2][pl][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 320]; let ctx_e = 1 + (eob > 32) as usize + (eob > 64) as usize;
let rc = SCAN_16X16[eob] as usize;
let (ex, ey) = (rc >> 4, rc & 15);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1; enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[2][pl][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][pl][bc]);
}
levels[ex * 16 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_16X16[i] as usize;
let (x, y) = (rc_i >> 4, rc_i & 15);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF, 16);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[2][pl][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][pl][bc as usize]);
}
levels[x * 16 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[2][pl][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[16] as u32 + levels[17] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[2][pl][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[pl][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_16X16[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_tx32_coeffs_adapt(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 1024],
chroma: bool,
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let pl = chroma as usize;
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_32X32) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[3][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[3][skip_ctx]); let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
let eb = if chroma {
&mut cdfs.eob_bin_1024_c
} else {
&mut cdfs.eob_bin_1024_l
};
encode_dc_tail(
enc,
cf[0],
eb,
&mut cdfs.eob_base[3][pl][0],
&mut cdfs.dc_sign[pl][dcs_ctx],
&mut cdfs.br_tok[3][pl][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
{
let eb = if chroma {
&mut cdfs.eob_bin_1024_c
} else {
&mut cdfs.eob_bin_1024_l
};
enc.encode_symbol(eob_bin, eb);
}
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[3][pl][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 1156]; let ctx_e = 1 + (eob > 128) as usize + (eob > 256) as usize;
let rc = SCAN_32X32[eob] as usize;
let (ex, ey) = (rc >> 5, rc & 31);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1; enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[3][pl][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][pl][bc]);
}
levels[ex * 32 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_32X32[i] as usize;
let (x, y) = (rc_i >> 5, rc_i & 31);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF, 32);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[3][pl][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][pl][bc as usize]);
}
levels[x * 32 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[3][pl][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[32] as u32 + levels[33] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[3][pl][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[pl][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_32X32[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_4x8_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 32],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_4X8) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[1][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[1][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_32_c,
&mut cdfs.eob_base[1][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[1][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_32_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[1][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 4) as usize + (eob > 8) as usize;
let rc = SCAN_4X8[eob] as usize;
let (ex, ey) = (rc >> 3, rc & 7);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[1][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][1][bc]);
}
levels[ex * 8 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_4X8[i] as usize;
let (x, y) = (rc_i >> 3, rc_i & 7);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WLH, 8);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[1][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][1][bc as usize]);
}
levels[x * 8 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[1][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[8] as u32 + levels[9] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[1][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_4X8[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_4x8_luma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 32],
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_4X8) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[1][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[1][skip_ctx]); enc.encode_symbol(txtp, &mut cdfs.txtp4[y_mode]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_32_l,
&mut cdfs.eob_base[1][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[1][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_32_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[1][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 4) as usize + (eob > 8) as usize;
let rc = SCAN_4X8[eob] as usize;
let (ex, ey) = (rc >> 3, rc & 7);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[1][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][0][bc]);
}
levels[ex * 8 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_4X8[i] as usize;
let (x, y) = (rc_i >> 3, rc_i & 7);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WLH, 8);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[1][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][0][bc as usize]);
}
levels[x * 8 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[1][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[8] as u32 + levels[9] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[1][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_4X8[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_8x4_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 32],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_8X4) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[1][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[1][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_32_c,
&mut cdfs.eob_base[1][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[1][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_32_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[1][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 4) as usize + (eob > 8) as usize;
let rc = SCAN_8X4[eob] as usize;
let (ex, ey) = (rc >> 2, rc & 3);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[1][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][1][bc]);
}
levels[ex * 4 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_8X4[i] as usize;
let (x, y) = (rc_i >> 2, rc_i & 3);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WGH, 4);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[1][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][1][bc as usize]);
}
levels[x * 4 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[1][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[4] as u32 + levels[5] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[1][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_8X4[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_8x4_luma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 32],
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_8X4) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[1][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[1][skip_ctx]); enc.encode_symbol(txtp, &mut cdfs.txtp4[y_mode]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_32_l,
&mut cdfs.eob_base[1][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[1][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_32_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[1][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 4) as usize + (eob > 8) as usize;
let rc = SCAN_8X4[eob] as usize;
let (ex, ey) = (rc >> 2, rc & 3);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[1][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][0][bc]);
}
levels[ex * 4 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_8X4[i] as usize;
let (x, y) = (rc_i >> 2, rc_i & 3);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WGH, 4);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[1][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[1][0][bc as usize]);
}
levels[x * 4 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[1][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[4] as u32 + levels[5] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[1][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_8X4[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn encode_16x8_luma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 128],
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_16X8) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[2][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[2][skip_ctx]); enc.encode_symbol(txtp, &mut cdfs.txtp[y_mode]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_128_l,
&mut cdfs.eob_base[2][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[2][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_128_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[2][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 200];
let ctx_e = 1 + (eob > 16) as usize + (eob > 32) as usize;
let rc = SCAN_16X8[eob] as usize;
let (ex, ey) = (rc >> 3, rc & 7); let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[2][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][0][bc]);
}
levels[ex * 8 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_16X8[i] as usize;
let (x, y) = (rc_i >> 3, rc_i & 7);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WGH, 8);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[2][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][0][bc as usize]);
}
levels[x * 8 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[2][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[8] as u32 + levels[9] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[2][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_16X8[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_16x8_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 128],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_16X8) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[2][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[2][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_128_c,
&mut cdfs.eob_base[2][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[2][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_128_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[2][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 200];
let ctx_e = 1 + (eob > 16) as usize + (eob > 32) as usize;
let rc = SCAN_16X8[eob] as usize;
let (ex, ey) = (rc >> 3, rc & 7);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[2][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][1][bc]);
}
levels[ex * 8 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_16X8[i] as usize;
let (x, y) = (rc_i >> 3, rc_i & 7);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WGH, 8);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[2][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][1][bc as usize]);
}
levels[x * 8 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[2][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[8] as u32 + levels[9] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[2][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_16X8[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_8x16_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 128],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_8X16) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[2][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[2][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_128_c,
&mut cdfs.eob_base[2][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[2][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_128_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[2][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 200];
let ctx_e = 1 + (eob > 16) as usize + (eob > 32) as usize;
let rc = SCAN_8X16[eob] as usize;
let (ex, ey) = (rc >> 4, rc & 15);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[2][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][1][bc]);
}
levels[ex * 16 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_8X16[i] as usize;
let (x, y) = (rc_i >> 4, rc_i & 15);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WLH, 16);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[2][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][1][bc as usize]);
}
levels[x * 16 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[2][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[16] as u32 + levels[17] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[2][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_8X16[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_8x16_luma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 128],
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_8X16) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[2][skip_ctx]); return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[2][skip_ctx]); enc.encode_symbol(txtp, &mut cdfs.txtp[y_mode]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_128_l,
&mut cdfs.eob_base[2][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[2][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_128_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[2][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 200];
let ctx_e = 1 + (eob > 16) as usize + (eob > 32) as usize;
let rc = SCAN_8X16[eob] as usize;
let (ex, ey) = (rc >> 4, rc & 15);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[2][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][0][bc]);
}
levels[ex * 16 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_8X16[i] as usize;
let (x, y) = (rc_i >> 4, rc_i & 15);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WLH, 16);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[2][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[2][0][bc as usize]);
}
levels[x * 16 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[2][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[16] as u32 + levels[17] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[2][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_8X16[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_4x4_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 16],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_4X4) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[0][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[0][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_16_c,
&mut cdfs.eob_base[0][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[0][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_16_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[0][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 2) as usize + (eob > 4) as usize;
let rc = SCAN_4X4[eob] as usize;
let (ex, ey) = (rc >> 2, rc & 3);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[0][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[0][1][bc]);
}
levels[ex * 4 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_4X4[i] as usize;
let (x, y) = (rc_i >> 2, rc_i & 3);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF, 4);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[0][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[0][1][bc as usize]);
}
levels[x * 4 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[0][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[4] as u32 + levels[5] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[0][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_4X4[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_tx4_luma_coeffs_adapt(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 16],
skip_ctx: usize,
dcs_ctx: usize,
y_mode: usize,
txtp: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_4X4) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[0][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[0][skip_ctx]);
enc.encode_symbol(txtp, &mut cdfs.txtp4[y_mode]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_16_l,
&mut cdfs.eob_base[0][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[0][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_16_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[0][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 80];
let ctx_e = 1 + (eob > 2) as usize + (eob > 4) as usize;
let rc = SCAN_4X4[eob] as usize;
let (ex, ey) = (rc >> 2, rc & 3);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[0][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[0][0][bc]);
}
levels[ex * 4 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_4X4[i] as usize;
let (x, y) = (rc_i >> 2, rc_i & 3);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF, 4);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[0][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[0][0][bc as usize]);
}
levels[x * 4 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[0][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[4] as u32 + levels[5] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[0][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_4X4[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_16x32_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 512],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_16X32) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[3][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[3][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_512_c,
&mut cdfs.eob_base[3][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[3][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_512_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[3][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 640]; let ctx_e = 1 + (eob > 64) as usize + (eob > 128) as usize;
let rc = SCAN_16X32[eob] as usize;
let (ex, ey) = (rc >> 5, rc & 31);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[3][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][1][bc]);
}
levels[ex * 32 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_16X32[i] as usize;
let (x, y) = (rc_i >> 5, rc_i & 31);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WLH, 32);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[3][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][1][bc as usize]);
}
levels[x * 32 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[3][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[32] as u32 + levels[33] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[3][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_16X32[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_16x32_luma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 512],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_16X32) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[3][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[3][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_512_l,
&mut cdfs.eob_base[3][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[3][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_512_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[3][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 640]; let ctx_e = 1 + (eob > 64) as usize + (eob > 128) as usize;
let rc = SCAN_16X32[eob] as usize;
let (ex, ey) = (rc >> 5, rc & 31);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[3][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][0][bc]);
}
levels[ex * 32 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_16X32[i] as usize;
let (x, y) = (rc_i >> 5, rc_i & 31);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WLH, 32);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[3][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][0][bc as usize]);
}
levels[x * 32 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[3][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[32] as u32 + levels[33] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[3][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_16X32[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_32x16_luma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 512],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_32X16) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[3][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[3][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_512_l,
&mut cdfs.eob_base[3][0][0],
&mut cdfs.dc_sign[0][dcs_ctx],
&mut cdfs.br_tok[3][0][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_512_l);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[3][0][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 640]; let ctx_e = 1 + (eob > 64) as usize + (eob > 128) as usize;
let rc = SCAN_32X16[eob] as usize;
let (ex, ey) = (rc >> 4, rc & 15);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[3][0][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][0][bc]);
}
levels[ex * 16 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_32X16[i] as usize;
let (x, y) = (rc_i >> 4, rc_i & 15);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WGH, 16);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[3][0][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][0][bc as usize]);
}
levels[x * 16 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[3][0][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[16] as u32 + levels[17] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[3][0][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[0][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_32X16[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn encode_32x16_chroma_coeffs(
enc: &mut OdEcEncoder,
cdfs: &mut Cdfs,
cf: &[i32; 512],
skip_ctx: usize,
dcs_ctx: usize,
) -> u8 {
let Some((eob, cul)) = eob_and_cul(cf, &SCAN_32X16) else {
enc.encode_symbol(1, &mut cdfs.txb_skip[3][skip_ctx]);
return 0x40;
};
enc.encode_symbol(0, &mut cdfs.txb_skip[3][skip_ctx]);
let dc_sign_bits: u8 = if cf[0] == 0 {
1 << 6
} else if cf[0] < 0 {
0
} else {
2 << 6
};
let res_ctx = (cul.min(63) as u8) | dc_sign_bits;
if eob == 0 {
encode_dc_tail(
enc,
cf[0],
&mut cdfs.eob_bin_512_c,
&mut cdfs.eob_base[3][1][0],
&mut cdfs.dc_sign[1][dcs_ctx],
&mut cdfs.br_tok[3][1][0],
);
return res_ctx;
}
let eob_bin = if eob < 2 {
eob
} else {
32 - (eob as u32).leading_zeros() as usize
};
enc.encode_symbol(eob_bin, &mut cdfs.eob_bin_512_c);
if eob_bin > 1 {
let nbits = eob_bin - 2;
let hi = (eob >> nbits) & 1;
enc.encode_symbol(hi, &mut cdfs.eob_hi[3][1][eob_bin]);
for b in (0..nbits).rev() {
enc.encode_bool((eob >> b) & 1 == 1, 16384);
}
}
let mut levels = [0u8; 640]; let ctx_e = 1 + (eob > 64) as usize + (eob > 128) as usize;
let rc = SCAN_32X16[eob] as usize;
let (ex, ey) = (rc >> 4, rc & 15);
let m = cf[rc].unsigned_abs();
let eob_tok = m.min(3) - 1;
enc.encode_symbol(eob_tok as usize, &mut cdfs.eob_base[3][1][ctx_e]);
if eob_tok == 2 {
let bc = if (ex | ey) > 1 { 14 } else { 7 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][1][bc]);
}
levels[ex * 16 + ey] = level_byte(m);
for i in (1..eob).rev() {
let rc_i = SCAN_32X16[i] as usize;
let (x, y) = (rc_i >> 4, rc_i & 15);
let (ctx, hi_mag) = get_lo_ctx_2d(&levels, x, y, &LO_CTX_OFF_WGH, 16);
let m = cf[rc_i].unsigned_abs();
let tok = m.min(3);
enc.encode_symbol(tok as usize, &mut cdfs.base_tok[3][1][ctx]);
if tok == 3 {
let mag = hi_mag & 63;
let bc = (if (y | x) > 1 { 14 } else { 7 }) + if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, m, &mut cdfs.br_tok[3][1][bc as usize]);
}
levels[x * 16 + y] = level_byte(m);
}
let dm = cf[0].unsigned_abs();
let dc_tok = dm.min(3);
enc.encode_symbol(dc_tok as usize, &mut cdfs.base_tok[3][1][0]);
if dc_tok == 3 {
let mag = (levels[1] as u32 + levels[16] as u32 + levels[17] as u32) & 63;
let bc = if mag > 12 { 6 } else { (mag + 1) >> 1 };
encode_hi_tok(enc, dm, &mut cdfs.br_tok[3][1][bc as usize]);
}
if cf[0] != 0 {
enc.encode_symbol((cf[0] < 0) as usize, &mut cdfs.dc_sign[1][dcs_ctx]);
if dm >= 15 {
encode_golomb(enc, dm - 15);
}
}
for i in 1..=eob {
let c = cf[SCAN_32X16[i] as usize];
if c != 0 {
enc.encode_bool(c < 0, 16384);
if c.unsigned_abs() >= 15 {
encode_golomb(enc, c.unsigned_abs() - 15);
}
}
}
res_ctx
}
pub(crate) fn get_partition_ctx(a: &[u8], l: &[u8], bl: usize, x8: usize, y8: usize) -> usize {
let sh = 4 - bl;
((a[x8] >> sh) & 1) as usize + ((((l[y8] >> sh) & 1) as usize) << 1)
}
pub(crate) fn gather_split_prob_icdf(cdf: &[u16], top: bool) -> u16 {
let v = |s: usize| cdf[s] as i32; let out = if top {
(v(1) - v(4)) + v(5) + (v(8) - v(7))
} else {
(v(0) - v(1)) + (v(2) - v(6)) + (v(7) - v(8))
};
out.clamp(1, 32767) as u16
}