impl<'a> LossyTile<'a> {
fn skip_ctx_422(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let ca = (a[bx4c] != 0x40) as usize;
let cl = (l[by4c] != 0x40 || l[by4c + 1] != 0x40) as usize;
7 + ca + cl
}
fn dc_sign_ctx_422(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let s = (a[bx4c] >> 6) as i32 + (l[by4c] >> 6) as i32 + (l[by4c + 1] >> 6) as i32 - 3;
(s != 0) as usize + (s > 0) as usize
}
fn skip_ctx_8x16_422(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let ca = (a[bx4c] != 0x40 || a[bx4c + 1] != 0x40) as usize;
let cl =
(l[by4c] != 0x40 || l[by4c + 1] != 0x40 || l[by4c + 2] != 0x40 || l[by4c + 3] != 0x40)
as usize;
7 + ca + cl
}
fn dc_sign_ctx_8x16_422(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let s = (a[bx4c] >> 6) as i32
+ (a[bx4c + 1] >> 6) as i32
+ (l[by4c] >> 6) as i32
+ (l[by4c + 1] >> 6) as i32
+ (l[by4c + 2] >> 6) as i32
+ (l[by4c + 3] >> 6) as i32
- 6;
(s != 0) as usize + (s > 0) as usize
}
fn skip_ctx_16x32_422(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let ca = a[bx4c..bx4c + 4].iter().any(|&x| x != 0x40) as usize;
let cl = l[by4c..by4c + 8].iter().any(|&x| x != 0x40) as usize;
7 + ca + cl
}
fn dc_sign_ctx_16x32_422(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let suma: i32 = a[bx4c..bx4c + 4].iter().map(|x| (x >> 6) as i32).sum();
let suml: i32 = l[by4c..by4c + 8].iter().map(|x| (x >> 6) as i32).sum();
let s = suma + suml - 12;
(s != 0) as usize + (s > 0) as usize
}
fn skip_ctx_420(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
7 + (a[bx4c] != 0x40) as usize + (l[by4c] != 0x40) as usize
}
fn dc_sign_ctx_420(&self, plane: usize, bx4c: usize, by4c: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let s = (a[bx4c] >> 6) as i32 + (l[by4c] >> 6) as i32 - 2;
(s != 0) as usize + (s > 0) as usize
}
fn dc_sign_ctx_32(&self, plane: usize, bx4: usize, by4: usize) -> usize {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let suma: i32 = (0..8).map(|k| (a[bx4 + k] >> 6) as i32).sum();
let suml: i32 = (0..8).map(|k| (l[by4 + k] >> 6) as i32).sum();
let s = suma + suml - 16;
(s != 0) as usize + (s > 0) as usize
}
fn skip_ctx_32(&self, plane: usize, bx4: usize, by4: usize, chroma: bool) -> usize {
if !chroma {
0
} else {
let a = &self.a_coef[plane];
let l = &self.l_coef[plane];
let ca = (0..8).any(|k| a[bx4 + k] != 0x40) as usize;
let cl = (0..8).any(|k| l[by4 + k] != 0x40) as usize;
7 + ca + cl
}
}
fn choose_rect8(&self, _x8: usize, _y8: usize) -> Part16 {
Part16::None
}
fn rd_cost_rect32(&self, px: usize, py: usize, vert: bool, prdo: f32) -> f32 {
let (acq, dcq) = (self.quant.ac_q() as f32, self.quant.dc_q() as f32);
let lam = trellis_lambda();
let (lam, mlam) = (lam * prdo, self.mlam() * prdo);
let (lw, lh) = if vert { (16usize, 32usize) } else { (32, 16) };
let mut total = rate_cost(mlam, SPLIT_SIGNAL_BITS);
for half in 0..2 {
let (sx, sy) = if vert {
(px + half * 16, py)
} else {
(px, py + half * 16)
};
let dc = if vert {
dc_pred_16x32(&self.recon[0], self.w, sx, sy, self.bd as i32)
} else {
dc_pred_32x16(&self.recon[0], self.w, sx, sy, self.bd as i32)
};
let mut resid = [0i32; 512];
for ry in 0..lh {
let srow = &self.src[0][(sy + ry) * self.w + sx..];
for cx in 0..lw {
resid[ry * lw + cx] = srow[cx] - dc;
}
}
let (mut cf, tf) = if vert {
dct16x32_t(&resid, &self.quant)
} else {
dct32x16_t(&resid, &self.quant)
};
let scan: &[u32] = if vert { &SCAN_16X32 } else { &SCAN_32X16 };
trellis_optimize(&mut cf, &tf, dcq, acq, scan, lam);
let rr = if vert {
idct_dequant_16x32(&cf, &self.quant)
} else {
idct_dequant_32x16(&cf, &self.quant)
};
let distortion =
self.luma_partition_distortion(sx, sy, lw, lh, self.quant.ac_q() as f32, |i| {
dc + rr[i]
});
total += crate::partition_rd::rd_cost(distortion, mlam, block_rate_bits(&cf, scan));
}
total
}
fn choose_rect32(&self, x8: usize, y8: usize, prefer_none: bool) -> Part16 {
let unpruned_rect32 = self.base_q_idx >= UNPRUNED_RECT32_MIN_QINDEX;
if self.mono || (!unpruned_rect32 && self.quant.ac_q() < AC_Q_HORZ_MIN) {
return if prefer_none {
Part16::None
} else {
Part16::Split
};
}
let (px, py) = (x8 * 8, y8 * 8);
let prdo = self.perceptual_rd_scale(px, py, 32);
let block_var = self.luma_variance(px, py, 32, 32);
let base_part = if prefer_none {
Part16::None
} else {
Part16::Split
};
let rd_base = (if prefer_none {
self.rd_cost_none32(px, py, prdo)
} else {
self.rd_cost_split32(px, py, prdo)
} + self.rd_cost_chroma_partition(px, py, 32, base_part, prdo))
* if prefer_none { 0.97 } else { 1.03 };
let horz_on = HORZ_ENABLED.load(std::sync::atomic::Ordering::Relaxed);
let vert_on = !self.ss422 && VERT_ENABLED.load(std::sync::atomic::Ordering::Relaxed);
let mut rd_h = f32::INFINITY;
if horz_on {
let v0 = self.luma_variance(px, py, 32, 16);
let v1 = self.luma_variance(px, py + 16, 32, 16);
if unpruned_rect32 || (block_var > 1.0 && 0.5 * (v0 + v1) < 0.85 * block_var) {
rd_h = self.rd_cost_rect32(px, py, false, prdo)
+ self.rd_cost_chroma_partition(px, py, 32, Part16::Horz, prdo);
}
}
let mut rd_v = f32::INFINITY;
if vert_on {
let v0 = self.luma_variance(px, py, 16, 32);
let v1 = self.luma_variance(px + 16, py, 16, 32);
if unpruned_rect32 || (block_var > 1.0 && 0.5 * (v0 + v1) < 0.85 * block_var) {
rd_v = self.rd_cost_rect32(px, py, true, prdo)
+ self.rd_cost_chroma_partition(px, py, 32, Part16::Vert, prdo);
}
}
let cands = [
(rd_base, base_part),
(rd_h, Part16::Horz),
(rd_v, Part16::Vert),
];
cands
.into_iter()
.fold((f32::INFINITY, Part16::Split), |b, c| {
if c.0 < b.0 { c } else { b }
})
.1
}
fn rd_cost_none32(&self, px: usize, py: usize, prdo: f32) -> f32 {
let (acq, dcq) = (self.quant.ac_q() as f32, self.quant.dc_q() as f32);
let lam = trellis_lambda() * prdo;
let mlam = self.mlam() * prdo;
let dc = dc_pred_32x32(&self.recon[0], self.w, px, py, self.bd as i32);
let mut resid = [0i32; 1024];
for ry in 0..32 {
let srow = &self.src[0][(py + ry) * self.w + px..];
for cx in 0..32 {
resid[ry * 32 + cx] = srow[cx] - dc;
}
}
let (mut cf, tf) = forward_dct_quant_32x32_t(&resid, &self.quant);
trellis_optimize(&mut cf, &tf, dcq, acq, &SCAN_32X32, lam);
let rr = idct_dequant_32x32(&cf, &self.quant);
let distortion =
self.luma_partition_distortion(px, py, 32, 32, self.quant.ac_q() as f32, |i| {
dc + rr[i]
});
crate::partition_rd::rd_cost(distortion, mlam, block_rate_bits(&cf, &SCAN_32X32))
}
fn rd_cost_split32(&self, px: usize, py: usize, prdo: f32) -> f32 {
let (acq, dcq) = (self.quant.ac_q() as f32, self.quant.dc_q() as f32);
let lam = trellis_lambda() * prdo;
let mlam = self.mlam() * prdo;
let mut total = rate_cost(mlam, SPLIT_SIGNAL_BITS * 4.0f32);
for (sx, sy) in [(0usize, 0usize), (16, 0), (0, 16), (16, 16)] {
let dc = dc_pred_16x16(&self.recon[0], self.w, px + sx, py + sy, self.bd as i32);
let mut resid = [0i32; 256];
for ry in 0..16 {
let srow = &self.src[0][(py + sy + ry) * self.w + px + sx..];
for cx in 0..16 {
resid[ry * 16 + cx] = srow[cx] - dc;
}
}
let (mut cf, tf) = forward_dct_quant_16x16_t(&resid, &self.quant);
trellis_optimize(&mut cf, &tf, dcq, acq, &SCAN_16X16, lam);
let rr = idct_dequant_16x16(&cf, &self.quant);
let distortion = self.luma_partition_distortion(
px + sx,
py + sy,
16,
16,
self.quant.ac_q() as f32,
|i| dc + rr[i],
);
total +=
crate::partition_rd::rd_cost(distortion, mlam, block_rate_bits(&cf, &SCAN_16X16));
}
total
}
fn prefer_32x32(&self, _x8: usize, _y8: usize) -> bool {
let policy = tx32_policy();
if policy == 0 || self.mono {
return false;
}
if policy == 1 && self.block_luma_range(_x8, _y8, 32) < tx32_smooth_gate() {
return false;
}
let (px, py) = (_x8 * 8, _y8 * 8);
let lpred = dc_pred_32x32(&self.recon[0], self.w, px, py, self.bd as i32);
let mut r32 = [0i32; 1024];
for (ry, drow) in r32.as_chunks_mut::<32>().0.iter_mut().enumerate() {
let srow = &self.src[0][(py + ry) * self.w + px..];
for (dv, &s) in drow.iter_mut().zip(srow.iter()) {
*dv = s - lpred;
}
}
forward_dct_quant_32x32(&mut r32, &self.quant);
let cost32: u32 = est_block_bits(&r32, &SCAN_32X32) + OVERHEAD_16;
let mut cost16 = 0u32;
for (sx, sy) in [(0usize, 0usize), (16, 0), (0, 16), (16, 16)] {
let pred = dc_pred_16x16(&self.recon[0], self.w, px + sx, py + sy, self.bd as i32);
let mut r16 = [0i32; 256];
for (ry, drow) in r16.as_chunks_mut::<16>().0.iter_mut().enumerate() {
let srow = &self.src[0][(py + sy + ry) * self.w + px + sx..];
for (dv, &s) in drow.iter_mut().zip(srow.iter()) {
*dv = s - pred;
}
}
forward_dct_quant_16x16(&mut r16, &self.quant);
cost16 += est_block_bits(&r16, &SCAN_16X16) + OVERHEAD_16;
}
cost32 + (cost16 >> 4) <= cost16
}
fn code_block32(&mut self, x8: usize, y8: usize, have_tr: bool, have_bl: bool) {
self.record_blk(x8, y8, 8);
let (px, py) = (x8 * 8, y8 * 8);
let (dcq, acq, lam) = (
self.quant.dc_q() as f32,
self.quant.ac_q() as f32,
trellis_lambda(),
);
let mlam = self.mlam();
let prdo = self.perceptual_rd_scale(px, py, 32);
let (lam, mlam) = (lam * prdo, mlam * prdo);
let mut best_mode = DC_PRED;
let mut lpred = [0i32; 1024];
let mut lcf = [0i32; 1024];
let mut best_eff = f32::INFINITY;
let mut ltf = [0f32; 1024]; let modes = if self.speed.reduced_modes() {
fast_nd_modes()
} else {
nd_modes()
};
let directional_top =
self.rank_luma_directionals::<1024>(modes, px, py, 32, 32, have_tr, have_bl);
for &m in modes {
if is_directional_mode(m) && !directional_top.contains(m) {
continue;
}
let mut pred = [0i32; 1024];
if m == DC_PRED {
let d = dc_pred_32x32(&self.recon[0], self.w, px, py, self.bd as i32);
pred = [d; 1024];
} else {
intra_predict_nd(
m,
&self.recon[0],
self.w,
px,
py,
32,
32,
have_tr,
have_bl,
self.w,
self.h,
self.luma_filter_type(px, py),
&mut pred,
self.bd,
);
}
let mut resid = [0i32; 1024];
for (ry, (rrow, prow)) in resid
.as_chunks_mut::<32>()
.0
.iter_mut()
.zip(pred.as_chunks::<32>().0.iter())
.enumerate()
{
let srow = &self.src[0][(py + ry) * self.w + px..];
for (r, (&p, &s)) in rrow.iter_mut().zip(prow.iter().zip(srow.iter())) {
*r = s - p;
}
}
let (mut cf, tf) = forward_dct_quant_32x32_t(&resid, &self.quant);
if self.speed.per_candidate_rdoq() {
trellis_optimize_ctx(
&mut cf,
&tf,
dcq,
acq,
&SCAN_32X32,
lam,
32,
&self.cdfs,
3,
0,
&self.cdfs.eob_bin_1024_l,
self.dc_sign_ctx_32(0, px / 4, py / 4),
);
}
let rr = idct_dequant_32x32(&cf, &self.quant);
let mut sse = 0i64;
for (ry, (prow, rrow)) in pred
.as_chunks::<32>()
.0
.iter()
.zip(rr.as_chunks::<32>().0.iter())
.enumerate()
{
let srow = &self.src[0][(py + ry) * self.w + px..];
for ((&p, &rv), &s) in prow.iter().zip(rrow.iter()).zip(srow.iter()) {
let r = (p + rv).clamp(0, (1 << self.bd) - 1);
let d = s - r;
sse += (d * d) as i64;
}
}
let bits = block_rate_bits(&cf, &SCAN_32X32) + mode_signal_bits(m);
let cost = rd_cost_i64(sse, mlam, bits);
if cost < best_eff {
best_eff = cost;
best_mode = m;
lpred = pred;
lcf = cf;
ltf = tf;
}
}
let mut best_delta: i32 = 0;
if angle_delta_enabled()
&& self.speed.try_angle_deltas()
&& (D45_PRED..=VERT_LEFT_PRED).contains(&best_mode)
&& best_mode != V_PRED
&& best_mode != H_PRED
{
let mut ad_cdf = [0u16; 7];
ad_cdf.copy_from_slice(&self.cdfs.angle_delta[best_mode - V_PRED]);
let ds = self.dc_sign_ctx_32(0, px / 4, py / 4);
let wrr = idct_dequant_32x32(&lcf, &self.quant);
let mut wsse = 0i64;
for ry in 0..32 {
let srow = &self.src[0][(py + ry) * self.w + px..];
for rx in 0..32 {
let r = (lpred[ry * 32 + rx] + wrr[ry * 32 + rx]).clamp(0, (1 << self.bd) - 1);
let dd = srow[rx] - r;
wsse += (dd * dd) as i64;
}
}
let wbits = block_rate_bits(&lcf, &SCAN_32X32);
let mut best_ad_cost = rd_cost_i64(wsse, mlam, wbits + cdf_cost(&ad_cdf, 3));
for d in [-3i32, -2, -1, 1, 2, 3] {
let mut pred = [0i32; 1024];
intra_predict_nd_ad(
best_mode,
d,
&self.recon[0],
self.w,
px,
py,
32,
32,
have_tr,
have_bl,
self.w,
self.h,
self.luma_filter_type(px, py),
&mut pred,
self.bd,
);
let mut resid = [0i32; 1024];
for ry in 0..32 {
let srow = &self.src[0][(py + ry) * self.w + px..];
for rx in 0..32 {
resid[ry * 32 + rx] = srow[rx] - pred[ry * 32 + rx];
}
}
let (mut cf, tf) = forward_dct_quant_32x32_t(&resid, &self.quant);
if self.speed.per_candidate_rdoq() {
trellis_optimize_ctx(
&mut cf,
&tf,
dcq,
acq,
&SCAN_32X32,
lam,
32,
&self.cdfs,
3,
0,
&self.cdfs.eob_bin_1024_l,
ds,
);
}
let rr = idct_dequant_32x32(&cf, &self.quant);
let mut sse = 0i64;
for ry in 0..32 {
let srow = &self.src[0][(py + ry) * self.w + px..];
for rx in 0..32 {
let r =
(pred[ry * 32 + rx] + rr[ry * 32 + rx]).clamp(0, (1 << self.bd) - 1);
let dd = srow[rx] - r;
sse += (dd * dd) as i64;
}
}
let bits = block_rate_bits(&cf, &SCAN_32X32);
let cost = rd_cost_i64(sse, mlam, bits + cdf_cost(&ad_cdf, (d + 3) as usize));
if cost < best_ad_cost {
best_ad_cost = cost;
best_delta = d;
lpred = pred;
lcf = cf;
ltf = tf;
}
}
}
if !self.speed.per_candidate_rdoq() {
trellis_optimize_ctx(
&mut lcf,
<f,
dcq,
acq,
&SCAN_32X32,
lam,
32,
&self.cdfs,
3,
0,
&self.cdfs.eob_bin_1024_l,
self.dc_sign_ctx_32(0, px / 4, py / 4),
);
}
let luma_zero = lcf.iter().all(|&c| c == 0);
if self.ss420 {
self.code_block32_420(x8, y8, &lcf, &lpred, best_mode, luma_zero, best_delta);
} else if self.ss422 {
self.code_block32_422(x8, y8, &lcf, &lpred, best_mode, luma_zero, best_delta);
} else {
self.code_block32_444(x8, y8, &lcf, &lpred, best_mode, luma_zero, best_delta);
}
}
#[allow(clippy::too_many_arguments)]
fn code_header_luma32(
&mut self,
x8: usize,
y8: usize,
lcf: &[i32; 1024],
lpred: &[i32; 1024],
y_mode: usize,
block_skip: bool,
uv_mode: usize,
cfl: Option<[i32; 2]>,
angle_delta: i32,
) {
let (px, py) = (x8 * 8, y8 * 8);
let (bx4, by4) = (px / 4, py / 4);
let sctx = (self.a_skip[bx4] + self.l_skip[by4]) as usize;
self.code_skip_and_sb_tokens(block_skip, sctx);
self.mark_skip8(x8, y8, 4, block_skip);
let yctx = INTRA_MODE_CTX[self.a_mode[bx4] as usize] * 5
+ INTRA_MODE_CTX[self.l_mode[by4] as usize];
self.enc.encode_symbol(y_mode, &mut self.cdfs.kf_y[yctx]);
if (V_PRED..=VERT_LEFT_PRED).contains(&y_mode) {
self.enc.encode_symbol(
(angle_delta + 3) as usize,
&mut self.cdfs.angle_delta[y_mode - V_PRED],
);
}
self.emit_uv_mode(y_mode, uv_mode, cfl, px, py, 32, 32);
let sv = block_skip as u8;
let mv = y_mode as u8;
self.a_skip[bx4..bx4 + 8].fill(sv);
self.l_skip[by4..by4 + 8].fill(sv);
self.a_mode[bx4..bx4 + 8].fill(mv);
self.l_mode[by4..by4 + 8].fill(mv);
let lres = if block_skip {
0x40
} else {
let sk = self.skip_ctx_32(0, bx4, by4, false);
let ds = self.dc_sign_ctx_32(0, bx4, by4);
encode_tx32_coeffs_adapt(&mut self.enc, &mut self.cdfs, lcf, false, sk, ds)
};
self.a_coef[0][bx4..bx4 + 8].fill(lres);
self.l_coef[0][by4..by4 + 8].fill(lres);
let lrr = if block_skip {
[0i32; 1024]
} else {
idct_dequant_32x32(lcf, &self.quant)
};
for (ry, (prow, rrow)) in lpred
.as_chunks::<32>()
.0
.iter()
.zip(lrr.as_chunks::<32>().0.iter())
.enumerate()
{
let drow = &mut self.recon[0][(py + ry) * self.w + px..];
for ((dv, &p), &rv) in drow.iter_mut().zip(prow.iter()).zip(rrow.iter()) {
*dv = (p + rv).clamp(0, (1 << self.bd) - 1);
}
}
}
fn code_block8_rect(&mut self, x8: usize, y8: usize, vert: bool) {
let maxval = (1 << self.bd) - 1;
let lam = trellis_lambda();
let (dcq, acq) = (self.quant.dc_q() as f32, self.quant.ac_q() as f32);
let (cdcq, cacq) = (self.cquant.dc_q() as f32, self.cquant.ac_q() as f32);
let (lw, lh) = if vert { (4usize, 8usize) } else { (8, 4) };
for half in 0..2 {
let (px, py) = if vert {
(x8 * 8 + half * 4, y8 * 8)
} else {
(x8 * 8, y8 * 8 + half * 4)
};
let (bx4, by4) = (px / 4, py / 4);
let lpred = if vert {
dc_pred_4x8(&self.recon[0], self.w, px, py, self.bd as i32)
} else {
dc_pred_8x4(&self.recon[0], self.w, px, py, self.bd as i32)
};
let mut lresid = [0i32; 32];
for ry in 0..lh {
let srow = &self.src[0][(py + ry) * self.w + px..];
for cx in 0..lw {
lresid[ry * lw + cx] = srow[cx] - lpred;
}
}
let (mut lcf, ltf) = if vert {
dct4x8_t(&lresid, &self.quant)
} else {
dct8x4_t(&lresid, &self.quant)
};
let lscan: &[u32] = if vert { &SCAN_4X8 } else { &SCAN_8X4 };
trellis_optimize(&mut lcf, <f, dcq, acq, lscan, lam);
let mean_l = lresid[..lw * lh].iter().sum::<i32>() / (lw * lh) as i32;
if lcf[0] == 0 && mean_l.abs() >= 8 {
lcf[0] = if mean_l > 0 { 1 } else { -1 };
}
let luma_zero = lcf.iter().all(|&v| v == 0);
let has_chroma = if self.ss420 {
if vert { px % 8 != 0 } else { py % 8 != 0 } } else {
true
};
let (cx, cy, cw, ch) = if self.ss420 {
(x8 * 4, y8 * 4, 4usize, 4usize) } else if self.ss422 {
(px / 2, py, lw / 2, lh)
} else {
(px, py, lw, lh)
};
let (cbx4, cby4) = (cx / 4, cy / 4);
let cn = cw * ch;
let mut ccf = [[0i32; 64]; 2];
let mut cpred = [0i32; 2];
if has_chroma {
for ci in 0..2 {
let plane = ci + 1;
let dc = chroma_dc_rect8(
&self.recon[plane],
self.cw,
cx,
cy,
cw,
ch,
self.bd as i32,
);
cpred[ci] = dc;
let mut resid = [0i32; 64];
for ry in 0..ch {
let srow = &self.src[plane][(cy + ry) * self.cw + cx..];
for c in 0..cw {
resid[ry * cw + c] = srow[c] - dc;
}
}
let (mut q, qt) = fwd_chroma_rect8(cw, ch, &resid, &self.cquant);
let cscan = scan_rect8(cw, ch);
trellis_optimize(&mut q, &qt, cdcq, cacq, cscan, lam);
let mean_c = resid[..cn].iter().sum::<i32>() / cn as i32;
if q[0] == 0 && mean_c.abs() >= 8 {
q[0] = if mean_c > 0 { 1 } else { -1 };
}
ccf[ci] = q;
}
}
let chroma_zero =
!has_chroma || (ccf[0].iter().all(|&v| v == 0) && ccf[1].iter().all(|&v| v == 0));
let block_skip = luma_zero && chroma_zero;
let sctx = (self.a_skip[bx4] + self.l_skip[by4]) as usize;
self.code_skip_and_sb_tokens(block_skip, sctx);
self.record_blk_rect(px / 8, py / 8, (lw / 4).max(1) as u8, (lh / 4).max(1) as u8);
self.mark_skip8_rect(px / 8, py / 8, 1, 1, block_skip);
let yctx = INTRA_MODE_CTX[self.a_mode[bx4] as usize] * 5
+ INTRA_MODE_CTX[self.l_mode[by4] as usize];
self.enc.encode_symbol(DC_PRED, &mut self.cdfs.kf_y[yctx]);
if has_chroma {
self.emit_uv_mode(DC_PRED, DC_PRED, None, px, py, lw, lh);
}
let sv = block_skip as u8;
let (aw, ah) = ((lw / 4).max(1), (lh / 4).max(1));
self.a_skip[bx4..bx4 + aw].fill(sv);
self.l_skip[by4..by4 + ah].fill(sv);
self.a_mode[bx4..bx4 + aw].fill(DC_PRED as u8);
self.l_mode[by4..by4 + ah].fill(DC_PRED as u8);
let lres_ctx = if block_skip {
0x40
} else if vert {
let ds = self.dc_sign_ctx_4x8_luma(bx4, by4);
encode_4x8_luma_coeffs(&mut self.enc, &mut self.cdfs, &lcf, 0, ds, DC_PRED, 1)
} else {
let ds = self.dc_sign_ctx_8x4_luma(bx4, by4);
encode_8x4_luma_coeffs(&mut self.enc, &mut self.cdfs, &lcf, 0, ds, DC_PRED, 1)
};
self.a_coef[0][bx4..bx4 + aw].fill(lres_ctx);
self.l_coef[0][by4..by4 + ah].fill(lres_ctx);
let lrr = if block_skip {
[0i32; 32]
} else if vert {
idct_dequant_4x8(&lcf, &self.quant)
} else {
idct_dequant_8x4(&lcf, &self.quant)
};
for ry in 0..lh {
let drow = &mut self.recon[0][(py + ry) * self.w + px..];
for cx2 in 0..lw {
drow[cx2] = (lpred + lrr[ry * lw + cx2]).clamp(0, maxval);
}
}
if has_chroma {
let (caw, cah) = ((cw / 4).max(1), (ch / 4).max(1));
for ci in 0..2 {
let plane = ci + 1;
let cres_ctx = if block_skip {
0x40
} else {
self.emit_chroma_rect8(plane, cbx4, cby4, cw, ch, &ccf[ci])
};
self.a_coef[plane][cbx4..cbx4 + caw].fill(cres_ctx);
self.l_coef[plane][cby4..cby4 + cah].fill(cres_ctx);
let rr = if block_skip {
[0i32; 64]
} else {
inv_chroma_rect8(cw, ch, &ccf[ci], &self.cquant)
};
for ry in 0..ch {
let drow = &mut self.recon[plane][(cy + ry) * self.cw + cx..];
for c in 0..cw {
drow[c] = (cpred[ci] + rr[ry * cw + c]).clamp(0, maxval);
}
}
}
}
}
}
fn emit_chroma_rect8(
&mut self,
plane: usize,
cbx4: usize,
cby4: usize,
cw: usize,
ch: usize,
cf: &[i32; 64],
) -> u8 {
match (cw, ch) {
(8, 4) => {
let sk = self.skip_ctx_8x4_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_8x4_chroma(plane, cbx4, cby4);
let mut a = [0i32; 32];
a.copy_from_slice(&cf[..32]);
encode_8x4_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
(4, 8) => {
let sk = self.skip_ctx_4x8_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_4x8_chroma(plane, cbx4, cby4);
let mut a = [0i32; 32];
a.copy_from_slice(&cf[..32]);
encode_4x8_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
_ => {
let sk = self.skip_ctx_4x4_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_4x4_chroma(plane, cbx4, cby4);
let mut a = [0i32; 16];
a.copy_from_slice(&cf[..16]);
encode_4x4_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
}
}
fn code_block32_rect(&mut self, x8: usize, y8: usize, vert: bool) {
let maxval = (1 << self.bd) - 1;
let lam = trellis_lambda();
let (dcq, acq) = (self.quant.dc_q() as f32, self.quant.ac_q() as f32);
let (cdcq, cacq) = (self.cquant.dc_q() as f32, self.cquant.ac_q() as f32);
for half in 0..2 {
let (px, py) = if vert {
(x8 * 8 + half * 16, y8 * 8)
} else {
(x8 * 8, y8 * 8 + half * 16)
};
let (bx4, by4) = (px / 4, py / 4);
let (lw, lh) = if vert { (16usize, 32usize) } else { (32, 16) };
let lpred = if vert {
dc_pred_16x32(&self.recon[0], self.w, px, py, self.bd as i32)
} else {
dc_pred_32x16(&self.recon[0], self.w, px, py, self.bd as i32)
};
let mut lresid = [0i32; 512];
for ry in 0..lh {
let srow = &self.src[0][(py + ry) * self.w + px..];
for cx in 0..lw {
lresid[ry * lw + cx] = srow[cx] - lpred;
}
}
let (mut lcf, ltf) = if vert {
dct16x32_t(&lresid, &self.quant)
} else {
dct32x16_t(&lresid, &self.quant)
};
let lscan: &[u32] = if vert { &SCAN_16X32 } else { &SCAN_32X16 };
trellis_optimize(&mut lcf, <f, dcq, acq, lscan, lam);
let mean_l = lresid[..lw * lh].iter().sum::<i32>() / (lw * lh) as i32;
if lcf[0] == 0 && mean_l.abs() >= 8 {
lcf[0] = if mean_l > 0 { 1 } else { -1 };
}
let luma_zero = lcf.iter().all(|&v| v == 0);
let (cx, cy, cw, ch) = if self.ss420 {
(px / 2, py / 2, lw / 2, lh / 2)
} else if self.ss422 {
(px / 2, py, lw / 2, lh)
} else {
(px, py, lw, lh)
};
let (cbx4, cby4) = (cx / 4, cy / 4);
let cn = cw * ch;
let mut ccf = [[0i32; 512]; 2];
let mut cpred = [0i32; 2];
for ci in 0..2 {
let plane = ci + 1;
let dc =
chroma_dc_rect(&self.recon[plane], self.cw, cx, cy, cw, ch, self.bd as i32);
cpred[ci] = dc;
let mut resid = [0i32; 512];
for ry in 0..ch {
let srow = &self.src[plane][(cy + ry) * self.cw + cx..];
for c in 0..cw {
resid[ry * cw + c] = srow[c] - dc;
}
}
let (mut q, qt) = fwd_chroma_rect(cw, ch, &resid, &self.cquant);
let cscan = scan_rect(cw, ch);
trellis_optimize(&mut q, &qt, cdcq, cacq, cscan, lam);
let mean_c = resid[..cn].iter().sum::<i32>() / cn as i32;
if q[0] == 0 && mean_c.abs() >= 8 {
q[0] = if mean_c > 0 { 1 } else { -1 };
}
ccf[ci] = q;
}
let chroma_zero = ccf[0].iter().all(|&v| v == 0) && ccf[1].iter().all(|&v| v == 0);
let block_skip = luma_zero && chroma_zero;
let sctx = (self.a_skip[bx4] + self.l_skip[by4]) as usize;
self.code_skip_and_sb_tokens(block_skip, sctx);
self.record_blk_rect(px / 8, py / 8, (lw / 4) as u8, (lh / 4) as u8);
self.mark_skip8_rect(px / 8, py / 8, lw / 8, lh / 8, block_skip);
let yctx = INTRA_MODE_CTX[self.a_mode[bx4] as usize] * 5
+ INTRA_MODE_CTX[self.l_mode[by4] as usize];
self.enc.encode_symbol(DC_PRED, &mut self.cdfs.kf_y[yctx]);
self.emit_uv_mode(DC_PRED, DC_PRED, None, px, py, lw, lh);
let sv = block_skip as u8;
let (aw, ah) = (lw / 4, lh / 4);
self.a_skip[bx4..bx4 + aw].fill(sv);
self.l_skip[by4..by4 + ah].fill(sv);
self.a_mode[bx4..bx4 + aw].fill(DC_PRED as u8);
self.l_mode[by4..by4 + ah].fill(DC_PRED as u8);
let lres_ctx = if block_skip {
0x40
} else if vert {
let ds = self.dc_sign_ctx_16x32_luma(bx4, by4);
encode_16x32_luma_coeffs(&mut self.enc, &mut self.cdfs, &lcf, 0, ds)
} else {
let ds = self.dc_sign_ctx_32x16_luma(bx4, by4);
encode_32x16_luma_coeffs(&mut self.enc, &mut self.cdfs, &lcf, 0, ds)
};
self.a_coef[0][bx4..bx4 + aw].fill(lres_ctx);
self.l_coef[0][by4..by4 + ah].fill(lres_ctx);
let lrr = if block_skip {
[0i32; 512]
} else if vert {
idct_dequant_16x32(&lcf, &self.quant)
} else {
idct_dequant_32x16(&lcf, &self.quant)
};
for ry in 0..lh {
let drow = &mut self.recon[0][(py + ry) * self.w + px..];
for cx2 in 0..lw {
drow[cx2] = (lpred + lrr[ry * lw + cx2]).clamp(0, maxval);
}
}
let (caw, cah) = (cw / 4, ch / 4);
for ci in 0..2 {
let plane = ci + 1;
let cres_ctx = if block_skip {
0x40
} else {
self.emit_chroma_rect(plane, cbx4, cby4, cw, ch, &ccf[ci])
};
self.a_coef[plane][cbx4..cbx4 + caw].fill(cres_ctx);
self.l_coef[plane][cby4..cby4 + cah].fill(cres_ctx);
let rr = if block_skip {
[0i32; 512]
} else {
inv_chroma_rect(cw, ch, &ccf[ci], &self.cquant)
};
for ry in 0..ch {
let drow = &mut self.recon[plane][(cy + ry) * self.cw + cx..];
for c in 0..cw {
drow[c] = (cpred[ci] + rr[ry * cw + c]).clamp(0, maxval);
}
}
}
}
}
fn emit_chroma_rect(
&mut self,
plane: usize,
cbx4: usize,
cby4: usize,
cw: usize,
ch: usize,
cf: &[i32; 512],
) -> u8 {
match (cw, ch) {
(32, 16) => {
let sk = self.skip_ctx_32x16_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_32x16_chroma(plane, cbx4, cby4);
let mut a = [0i32; 512];
a.copy_from_slice(cf);
encode_32x16_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
(16, 32) => {
let sk = self.skip_ctx_16x32_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_16x32_chroma(plane, cbx4, cby4);
let mut a = [0i32; 512];
a.copy_from_slice(cf);
encode_16x32_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
(16, 8) => {
let sk = self.skip_ctx_16x8_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_16x8_chroma(plane, cbx4, cby4);
let mut a = [0i32; 128];
a.copy_from_slice(&cf[..128]);
encode_16x8_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
(8, 16) => {
let sk = self.skip_ctx_8x16_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_8x16_chroma(plane, cbx4, cby4);
let mut a = [0i32; 128];
a.copy_from_slice(&cf[..128]);
encode_8x16_chroma_coeffs(&mut self.enc, &mut self.cdfs, &a, sk, ds)
}
_ => {
let sk = self.skip_ctx_16x16_chroma(plane, cbx4, cby4);
let ds = self.dc_sign_ctx_16x16_chroma(plane, cbx4, cby4);
let mut a = [0i32; 256];
a.copy_from_slice(&cf[..256]);
encode_tx16_coeffs_adapt(
&mut self.enc,
&mut self.cdfs,
&a,
true,
sk,
ds,
DC_PRED,
0,
)
}
}
}
#[allow(clippy::too_many_arguments)]
fn code_block32_444(
&mut self,
x8: usize,
y8: usize,
lcf: &[i32; 1024],
lpred: &[i32; 1024],
y_mode: usize,
luma_zero: bool,
angle_delta: i32,
) {
let (px, py) = (x8 * 8, y8 * 8);
let (bx4, by4) = (px / 4, py / 4);
let (dcq, acq, lam) = (
self.cquant.dc_q() as f32,
self.cquant.ac_q() as f32,
trellis_lambda(),
);
let mut ccf = [[0i32; 1024]; 2];
let mut cdc = [0i32; 2];
for ci in 0..2 {
let plane = ci + 1;
let dc = dc_pred_32x32(&self.recon[plane], self.w, px, py, self.bd as i32);
cdc[ci] = dc;
let mut cresid = [0i32; 1024];
for (ry, drow) in cresid.as_chunks_mut::<32>().0.iter_mut().enumerate() {
let srow = &self.src[plane][(py + ry) * self.w + px..];
for (dv, &s) in drow.iter_mut().zip(srow.iter()) {
*dv = s - dc;
}
}
let (q, qt) = forward_dct_quant_32x32_t(&cresid, &self.cquant);
ccf[ci] = q;
trellis_optimize(&mut ccf[ci], &qt, dcq, acq, &SCAN_32X32, lam);
let mean_resid_dc = cresid.iter().sum::<i32>() / 1024;
if ccf[ci][0] == 0 && mean_resid_dc.abs() >= 8 {
ccf[ci][0] = if mean_resid_dc > 0 { 1 } else { -1 };
}
}
let mut cfl_ccf = [[0i32; 1024]; 2];
let mut cfl_pred = [[0i32; 1024]; 2];
let mut cfl_a = [0i32; 2];
let (mut dc_cost, mut cfl_cost) = ([0f32; 2], [0f32; 2]);
let mlam = self.mlam();
{
let lrr_cfl = idct_dequant_32x32(lcf, &self.quant);
let mut luma_rec = [0i32; 1024];
for i in 0..1024 {
luma_rec[i] = (lpred[i] + lrr_cfl[i]).clamp(0, (1 << self.bd) - 1);
}
let mut ac = [0i32; 1024];
cfl_ac_444(&luma_rec, 32, 32, &mut ac);
for ci in 0..2 {
let plane = ci + 1;
let dc = cdc[ci];
let mut src = [0i32; 1024];
for (ry, drow) in src.as_chunks_mut::<32>().0.iter_mut().enumerate() {
drow.copy_from_slice(&self.src[plane][(py + ry) * self.w + px..][..32]);
}
let dcrr = idct_dequant_32x32(&ccf[ci], &self.cquant);
let mut s = 0i64;
for i in 0..1024 {
let d = src[i] - (dc + dcrr[i]).clamp(0, (1 << self.bd) - 1);
s += (d * d) as i64;
}
dc_cost[ci] = rd_cost_i64(s, mlam, block_rate_bits(&ccf[ci], &SCAN_32X32));
let a = cfl_best_alpha(&ac, &src, dc, 1024, self.bd);
cfl_a[ci] = a;
let mut cpr = [0i32; 1024];
let mut resid = [0i32; 1024];
for i in 0..1024 {
cpr[i] = cfl_pred_pixel(dc, ac[i], a, self.bd);
resid[i] = src[i] - cpr[i];
}
let (mut q, qt) = forward_dct_quant_32x32_t(&resid, &self.cquant);
trellis_optimize(&mut q, &qt, dcq, acq, &SCAN_32X32, lam);
let rr = idct_dequant_32x32(&q, &self.cquant);
let mut s2 = 0i64;
for i in 0..1024 {
let d = src[i] - (cpr[i] + rr[i]).clamp(0, (1 << self.bd) - 1);
s2 += (d * d) as i64;
}
cfl_ccf[ci] = q;
cfl_pred[ci] = cpr;
cfl_cost[ci] = rd_cost_i64(s2, mlam, block_rate_bits(&q, &SCAN_32X32));
}
}
let cfl_sig = 4.0f32
+ if cfl_a[0] != 0 { 4.0f32 } else { 0.0f32 }
+ if cfl_a[1] != 0 { 4.0f32 } else { 0.0f32 };
let use_cfl = acq > 300.0
&& (cfl_a[0] != 0 || cfl_a[1] != 0)
&& cfl_cost[0] + cfl_cost[1] + rate_cost(mlam, cfl_sig) < dc_cost[0] + dc_cost[1];
#[allow(unused_mut)] let (cf_use, pred_dc, mut cfl_opt): (
&[[i32; 1024]; 2],
[i32; 2],
Option<[i32; 2]>,
) = if use_cfl {
(&cfl_ccf, cdc, Some(cfl_a))
} else {
(&ccf, cdc, None)
};
#[allow(unused_mut)] let mut cf_use_owned: [[i32; 1024]; 2];
let mut sv_preds32 = [[0i32; 1024]; 2];
let (final_cf, chosen_uv_32) = 'sv: {
let dcq2 = self.cquant.dc_q() as f32;
let acq2 = self.cquant.ac_q() as f32;
let lam2 = trellis_lambda();
let mlam = self.mlam_c();
let maxv = (1 << self.bd) - 1;
let mut cur_total = 0f32;
if use_cfl {
let a = cfl_a;
cur_total += rate_cost(
mlam,
4.0f32
+ if a[0] != 0 { 4.0f32 } else { 0.0f32 }
+ if a[1] != 0 { 4.0f32 } else { 0.0f32 },
);
}
for ci in 0..2 {
let plane = ci + 1;
let rr = idct_dequant_32x32(&cf_use[ci], &self.cquant);
let mut sse = 0i64;
for (ry, rrow) in rr.as_chunks::<32>().0.iter().enumerate() {
let srow = &self.src[plane][(py + ry) * self.w + px..];
for (j, (&s, &r)) in srow[..32].iter().zip(rrow.iter()).enumerate() {
let p = if use_cfl {
cfl_pred[ci][ry * 32 + j]
} else {
pred_dc[ci]
};
let d = s - (p + r).clamp(0, maxv);
sse += (d * d) as i64;
}
}
cur_total += rd_cost_i64(sse, mlam, block_rate_bits(&cf_use[ci], &SCAN_32X32));
}
let mut best_total = cur_total;
let mut best_mode = DC_PRED;
let mut best_ccf = [[0i32; 1024]; 2];
let mut best_pred = [[0i32; 1024]; 2];
let candidates = &[
SMOOTH_V_PRED,
PAETH_PRED,
SMOOTH_PRED,
SMOOTH_H_PRED,
V_PRED,
H_PRED,
D135_PRED,
D113_PRED,
D157_PRED,
];
let directional_top =
self.rank_chroma_directionals::<1024>(candidates, px, py, px, py, 32, 32);
for &cand in candidates {
if cand != V_PRED
&& cand != H_PRED
&& (V_PRED..=VERT_LEFT_PRED).contains(&cand)
&& !self.speed.chroma_angle_directional()
{
continue;
}
if is_directional_mode(cand) && !directional_top.contains(cand) {
continue;
}
let mut cand_ccf = [[0i32; 1024]; 2];
let mut cand_pred = [[0i32; 1024]; 2];
let sig_bits = if (V_PRED..=VERT_LEFT_PRED).contains(&cand) {
7.0f32
} else {
4.0f32
};
let mut cand_total = rate_cost(mlam, sig_bits);
for ci in 0..2 {
let plane = ci + 1;
intra_predict_nd(
cand,
&self.recon[plane],
self.w,
px,
py,
32,
32,
false,
false,
self.w,
self.h,
self.chroma_filter_type(px, py),
&mut cand_pred[ci],
self.bd,
);
let mut resid = [0i32; 1024];
for (ry, drow) in resid.as_chunks_mut::<32>().0.iter_mut().enumerate() {
let srow = &self.src[plane][(py + ry) * self.w + px..];
let prow = &cand_pred[ci][ry * 32..];
for (dv, (&s, &p)) in drow.iter_mut().zip(srow.iter().zip(prow.iter())) {
*dv = s - p;
}
}
let (mut q, qt) = forward_dct_quant_32x32_t(&resid, &self.cquant);
trellis_optimize(&mut q, &qt, dcq2, acq2, &SCAN_32X32, lam2);
let mean_resid = resid.iter().sum::<i32>() / 1024;
if q[0] == 0 && mean_resid.abs() >= 8 {
q[0] = if mean_resid > 0 { 1 } else { -1 };
}
cand_ccf[ci] = q;
let rr = idct_dequant_32x32(&q, &self.cquant);
let mut sse = 0i64;
for (ry, rrow) in rr.as_chunks::<32>().0.iter().enumerate() {
let srow = &self.src[plane][(py + ry) * self.w + px..];
let prow = &cand_pred[ci][ry * 32..];
for ((&s, &p), &r) in srow[..32].iter().zip(prow.iter()).zip(rrow.iter()) {
let d = s - (p + r).clamp(0, maxv);
sse += (d * d) as i64;
}
}
cand_total += rd_cost_i64(sse, mlam, block_rate_bits(&q, &SCAN_32X32));
}
if cand_total < best_total {
best_total = cand_total;
best_mode = cand;
best_ccf = cand_ccf;
best_pred = cand_pred;
}
}
if best_mode != DC_PRED {
cfl_opt = None; cf_use_owned = best_ccf;
sv_preds32 = best_pred;
break 'sv (&cf_use_owned, best_mode);
}
(cf_use, DC_PRED)
};
let block_skip =
luma_zero && final_cf[0].iter().all(|&c| c == 0) && final_cf[1].iter().all(|&c| c == 0);
self.code_header_luma32(
x8,
y8,
lcf,
lpred,
y_mode,
block_skip,
chosen_uv_32,
cfl_opt,
angle_delta,
);
for ci in 0..2 {
let plane = ci + 1;
let cres = if block_skip {
0x40
} else {
let sk = self.skip_ctx_32(plane, bx4, by4, true);
let ds = self.dc_sign_ctx_32(plane, bx4, by4);
encode_tx32_coeffs_adapt(&mut self.enc, &mut self.cdfs, &final_cf[ci], true, sk, ds)
};
self.a_coef[plane][bx4..bx4 + 8].fill(cres);
self.l_coef[plane][by4..by4 + 8].fill(cres);
let crr = if block_skip {
[0i32; 1024]
} else {
idct_dequant_32x32(&final_cf[ci], &self.cquant)
};
for (ry, rrow) in crr.as_chunks::<32>().0.iter().enumerate() {
let drow = &mut self.recon[plane][(py + ry) * self.w + px..];
if chosen_uv_32 != DC_PRED {
let prow = &sv_preds32[ci][ry * 32..];
for (j, (dv, &rv)) in drow[..32].iter_mut().zip(rrow.iter()).enumerate() {
*dv = (prow[j] + rv).clamp(0, (1 << self.bd) - 1);
}
} else {
let base = if use_cfl {
cfl_pred[ci][ry * 32..][0]
} else {
pred_dc[ci]
};
for (dv, (&cp, &rv)) in drow[..32]
.iter_mut()
.zip(cfl_pred[ci][ry * 32..].iter().zip(rrow.iter()))
{
let b = if use_cfl { cp } else { base };
*dv = (b + rv).clamp(0, (1 << self.bd) - 1);
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
fn code_block32_420(
&mut self,
x8: usize,
y8: usize,
lcf: &[i32; 1024],
lpred: &[i32; 1024],
y_mode: usize,
luma_zero: bool,
angle_delta: i32,
) {
let (px, py) = (x8 * 8, y8 * 8);
let (cx, cy) = (px / 2, py / 2);
let (bx4c, by4c) = (cx / 4, cy / 4);
let (dcq, acq, lam) = (
self.cquant.dc_q() as f32,
self.cquant.ac_q() as f32,
trellis_lambda(),
);
let maxval = (1 << self.bd) - 1;
let mut ccf_dc = [[0i32; 256]; 2];
let mut dc_preds = [0i32; 2];
for ci in 0..2 {
let plane = ci + 1;
let dc = dc_pred_16x16(&self.recon[plane], self.cw, cx, cy, self.bd as i32);
dc_preds[ci] = dc;
let mut resid = [0i32; 256];
for (ry, drow) in resid.as_chunks_mut::<16>().0.iter_mut().enumerate() {
let srow = &self.src[plane][(cy + ry) * self.cw + cx..];
for (dv, &s) in drow.iter_mut().zip(srow.iter()) {
*dv = s - dc;
}
}
let (q, qt) = forward_dct_quant_16x16_t(&resid, &self.cquant);
ccf_dc[ci] = q;
trellis_optimize(&mut ccf_dc[ci], &qt, dcq, acq, &SCAN_16X16, lam);
let mean_resid_dc = resid.iter().sum::<i32>() / 256;
if ccf_dc[ci][0] == 0 && mean_resid_dc.abs() >= 8 {
ccf_dc[ci][0] = if mean_resid_dc > 0 { 1 } else { -1 };
}
}
let mlam = self.mlam();
let mut rr_dc = [[0i32; 256]; 2];
let mut dc_total = 0f32;
for ci in 0..2 {
let plane = ci + 1;
rr_dc[ci] = idct_dequant_16x16(&ccf_dc[ci], &self.cquant);
let dc = dc_preds[ci];
let mut sse = 0i64;
for (ry, rrow) in rr_dc[ci].as_chunks::<16>().0.iter().enumerate() {
let srow = &self.src[plane][(cy + ry) * self.cw + cx..];
for (&s, &r) in srow[..16].iter().zip(rrow.iter()) {
let d = s - (dc + r).clamp(0, maxval);
sse += (d * d) as i64;
}
}
dc_total += rd_cost_i64(sse, mlam, block_rate_bits(&ccf_dc[ci], &SCAN_16X16));
}
let mut best_total = dc_total;
let mut chosen_uv = DC_PRED;
let mut best_ccf = ccf_dc;
let mut best_rr = rr_dc;
let mut sv_preds = [[0i32; 256]; 2];
let candidates = &[
SMOOTH_V_PRED,
PAETH_PRED,
SMOOTH_PRED,
SMOOTH_H_PRED,
V_PRED,
H_PRED,
D135_PRED,
D113_PRED,
D157_PRED,
];
let directional_top =
self.rank_chroma_directionals::<256>(candidates, px, py, cx, cy, 16, 16);
for &cand in candidates {
if cand != V_PRED
&& cand != H_PRED
&& (V_PRED..=VERT_LEFT_PRED).contains(&cand)
&& !self.speed.chroma_angle_directional()
{
continue;
}
if is_directional_mode(cand) && !directional_top.contains(cand) {
continue;
}
let tx = chroma_tx_for_mode(cand);
let mut cand_ccf = [[0i32; 256]; 2];
let mut cand_rr = [[0i32; 256]; 2];
let mut cand_pred = [[0i32; 256]; 2];
let sig_bits = if (V_PRED..=VERT_LEFT_PRED).contains(&cand) {
7.0f32
} else {
4.0f32
};
let mut cand_total = rate_cost(mlam, sig_bits);
for ci in 0..2 {
let plane = ci + 1;
intra_predict_nd(
cand,
&self.recon[plane],
self.cw,
cx,
cy,
16,
16,
false,
false,
self.cw,
self.h,
self.chroma_filter_type(px, py),
&mut cand_pred[ci],
self.bd,
);
let mut resid = [0i32; 256];
for (ry, drow) in resid.as_chunks_mut::<16>().0.iter_mut().enumerate() {
let srow = &self.src[plane][(cy + ry) * self.cw + cx..];
let prow = &cand_pred[ci][ry * 16..];
for (dv, (&s, &p)) in drow.iter_mut().zip(srow.iter().zip(prow.iter())) {
*dv = s - p;
}
}
let (mut q, qt) = fwd_chroma_16x16(tx, &resid, &self.cquant);
trellis_optimize(&mut q, &qt, dcq, acq, &SCAN_16X16, lam);
let mean_resid = resid.iter().sum::<i32>() / 256;
if q[0] == 0 && mean_resid.abs() >= 8 {
q[0] = if mean_resid > 0 { 1 } else { -1 };
}
cand_ccf[ci] = q;
cand_rr[ci] = inv_chroma_16x16(tx, &q, &self.cquant);
let mut sse = 0i64;
for (ry, rrow) in cand_rr[ci].as_chunks::<16>().0.iter().enumerate() {
let srow = &self.src[plane][(cy + ry) * self.cw + cx..];
let prow = &cand_pred[ci][ry * 16..];
for ((&s, &p), &r) in srow[..16].iter().zip(prow.iter()).zip(rrow.iter()) {
let d = s - (p + r).clamp(0, maxval);
sse += (d * d) as i64;
}
}
cand_total += rd_cost_i64(sse, mlam, block_rate_bits(&q, &SCAN_16X16));
}
if cand_total < best_total {
best_total = cand_total;
chosen_uv = cand;
best_ccf = cand_ccf;
best_rr = cand_rr;
sv_preds = cand_pred;
}
}
let use_sv = chosen_uv != DC_PRED;
let (ccf, rr_cache) = (best_ccf, best_rr);
let block_skip =
luma_zero && ccf[0].iter().all(|&c| c == 0) && ccf[1].iter().all(|&c| c == 0);
self.code_header_luma32(
x8,
y8,
lcf,
lpred,
y_mode,
block_skip,
chosen_uv,
None,
angle_delta,
);
for ci in 0..2 {
let plane = ci + 1;
let res_ctx = if block_skip {
0x40
} else {
let sk = self.skip_ctx_16(plane, bx4c, by4c, true);
let ds = self.dc_sign_ctx_16(plane, bx4c, by4c);
encode_tx16_coeffs_adapt(
&mut self.enc,
&mut self.cdfs,
&ccf[ci],
true,
sk,
ds,
0,
1,
)
};
self.a_coef[plane][bx4c..bx4c + 4].fill(res_ctx);
self.l_coef[plane][by4c..by4c + 4].fill(res_ctx);
let rr = if block_skip {
[0i32; 256]
} else {
rr_cache[ci]
};
for (ry, rrow) in rr.as_chunks::<16>().0.iter().enumerate() {
let drow = &mut self.recon[plane][(cy + ry) * self.cw + cx..];
if use_sv {
let prow = &sv_preds[ci][ry * 16..];
for ((dv, &rv), &prow) in drow[..16]
.iter_mut()
.zip(rrow[..16].iter())
.zip(prow[..16].iter())
{
*dv = (prow + rv).clamp(0, maxval);
}
} else {
let dc = dc_preds[ci];
for (dv, &rv) in drow[..16].iter_mut().zip(rrow.iter()) {
*dv = (dc + rv).clamp(0, maxval);
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
fn code_block32_422(
&mut self,
x8: usize,
y8: usize,
lcf: &[i32; 1024],
lpred: &[i32; 1024],
y_mode: usize,
luma_zero: bool,
angle_delta: i32,
) {
let (px, py) = (x8 * 8, y8 * 8);
let cx = px / 2;
let (bx4c, by4c) = (cx / 4, py / 4);
let maxv = (1 << self.bd) - 1;
let (dcq, acq, lam) = (
self.cquant.dc_q() as f32,
self.cquant.ac_q() as f32,
trellis_lambda(),
);
let mlam = self.mlam();
let mut ccf = [[0i32; 512]; 2];
let mut cpred = [0i32; 2];
let mut cpred_px = [[0i32; 512]; 2];
let mut src_planes = [[0i32; 512]; 2];
let mut dc_ccf = [[0i32; 512]; 2];
let mut dc_sse = [0i64; 2];
let mut dc_bits = [0f32; 2];
for ci in 0..2 {
let plane = ci + 1;
let pred = dc_pred_16x32(&self.recon[plane], self.cw, cx, py, self.bd as i32);
cpred[ci] = pred;
let mut src = [0i32; 512];
let mut resid = [0i32; 512];
for (ry, (drow, srow_dst)) in resid
.as_chunks_mut::<16>()
.0
.iter_mut()
.zip(src.as_chunks_mut::<16>().0.iter_mut())
.enumerate()
{
let srow = &self.src[plane][(py + ry) * self.cw + cx..];
for ((dv, sd), &s) in drow.iter_mut().zip(srow_dst.iter_mut()).zip(srow.iter()) {
*dv = s - pred;
*sd = s;
}
}
src_planes[ci] = src;
let (mut q, qt) = forward_dct_quant_16x32_t(&resid, &self.cquant);
trellis_optimize(&mut q, &qt, dcq, acq, &SCAN_16X32, lam);
let rr = idct_dequant_16x32(&q, &self.cquant);
let mut sse = 0i64;
for i in 0..512 {
let r = (pred + rr[i]).clamp(0, maxv);
let d = src[i] - r;
sse += (d * d) as i64;
}
dc_ccf[ci] = q;
dc_sse[ci] = sse;
dc_bits[ci] = block_rate_bits(&q, &SCAN_16X32);
}
let mut use_cfl = false;
let mut cfl_alpha_uv = [0i32; 2];
{
let lrr_cfl = idct_dequant_32x32(lcf, &self.quant);
let mut luma_rec = [0i32; 1024];
for i in 0..1024 {
luma_rec[i] = (lpred[i] + lrr_cfl[i]).clamp(0, maxv);
}
let mut ac = [0i32; 512];
cfl_ac_sub(&luma_rec, 32, 16, 32, true, false, &mut ac);
let mut cfl_ccf = [[0i32; 512]; 2];
let mut cfl_a = [0i32; 2];
let mut cfl_sse = [0i64; 2];
let mut cfl_bits = [0f32; 2];
for ci in 0..2 {
let dc = cpred[ci];
let src = src_planes[ci];
let a = cfl_best_alpha(&ac, &src, dc, 512, self.bd);
cfl_a[ci] = a;
let mut cpr = [0i32; 512];
let mut resid = [0i32; 512];
for i in 0..512 {
cpr[i] = cfl_pred_pixel(dc, ac[i], a, self.bd);
resid[i] = src[i] - cpr[i];
}
let (mut q, qt) = forward_dct_quant_16x32_t(&resid, &self.cquant);
trellis_optimize(&mut q, &qt, dcq, acq, &SCAN_16X32, lam);
let rr = idct_dequant_16x32(&q, &self.cquant);
let mut sse = 0i64;
for i in 0..512 {
let r = (cpr[i] + rr[i]).clamp(0, maxv);
let d = src[i] - r;
sse += (d * d) as i64;
}
cfl_ccf[ci] = q;
cfl_sse[ci] = sse;
cfl_bits[ci] = block_rate_bits(&q, &SCAN_16X32);
cpred_px[ci] = cpr;
}
let sig = 4.0f32
+ if cfl_a[0] != 0 { 4.0f32 } else { 0.0f32 }
+ if cfl_a[1] != 0 { 4.0f32 } else { 0.0f32 };
let dc_total = rd_cost_i64(dc_sse[0] + dc_sse[1], mlam, dc_bits[0] + dc_bits[1]);
let cfl_total = rd_cost_i64(
cfl_sse[0] + cfl_sse[1],
mlam,
cfl_bits[0] + cfl_bits[1] + sig,
);
if cfl_total < dc_total && (cfl_a[0] != 0 || cfl_a[1] != 0) {
use_cfl = true;
cfl_alpha_uv = cfl_a;
ccf[..2].copy_from_slice(&cfl_ccf[..2]);
}
}
let mut chosen_uv = if use_cfl { CFL_PRED } else { DC_PRED };
{
let mut best_total = 0f32;
if use_cfl {
let a = cfl_alpha_uv;
best_total += rate_cost(
mlam,
4.0f32
+ if a[0] != 0 { 4.0f32 } else { 0.0f32 }
+ if a[1] != 0 { 4.0f32 } else { 0.0f32 },
);
}
for ci in 0..2 {
let cur_ccf = if use_cfl { ccf[ci] } else { dc_ccf[ci] };
let rr = idct_dequant_16x32(&cur_ccf, &self.cquant);
let mut sse = 0i64;
for i in 0..512 {
let p = if use_cfl { cpred_px[ci][i] } else { cpred[ci] };
let d = src_planes[ci][i] - (p + rr[i]).clamp(0, maxv);
sse += (d * d) as i64;
}
best_total += rd_cost_i64(sse, mlam, block_rate_bits(&cur_ccf, &SCAN_16X32));
}
let candidates = &[
SMOOTH_V_PRED,
PAETH_PRED,
SMOOTH_PRED,
SMOOTH_H_PRED,
V_PRED,
H_PRED,
D135_PRED,
D113_PRED,
D157_PRED,
];
let directional_top =
self.rank_chroma_directionals::<512>(candidates, px, py, cx, py, 16, 32);
for &cand in candidates {
if cand != V_PRED
&& cand != H_PRED
&& (V_PRED..=VERT_LEFT_PRED).contains(&cand)
&& !self.speed.chroma_angle_directional()
{
continue;
}
if is_directional_mode(cand) && !directional_top.contains(cand) {
continue;
}
let mut cand_ccf = [[0i32; 512]; 2];
let mut cand_pred = [[0i32; 512]; 2];
let sig_bits = if (V_PRED..=VERT_LEFT_PRED).contains(&cand) {
7.0f32
} else {
4.0f32
};
let mut cand_total = rate_cost(mlam, sig_bits);
for ci in 0..2 {
let plane = ci + 1;
intra_predict_nd(
cand,
&self.recon[plane],
self.cw,
cx,
py,
16,
32,
false,
false,
self.cw,
self.h,
self.chroma_filter_type(px, py),
&mut cand_pred[ci],
self.bd,
);
let src = src_planes[ci];
let mut resid = [0i32; 512];
for i in 0..512 {
resid[i] = src[i] - cand_pred[ci][i];
}
let (mut q, qt) = forward_dct_quant_16x32_t(&resid, &self.cquant);
trellis_optimize(&mut q, &qt, dcq, acq, &SCAN_16X32, lam);
let mean_resid = resid.iter().sum::<i32>() / 512;
if q[0] == 0 && mean_resid.abs() >= 8 {
q[0] = if mean_resid > 0 { 1 } else { -1 };
}
cand_ccf[ci] = q;
let rr = idct_dequant_16x32(&q, &self.cquant);
let mut sse = 0i64;
for i in 0..512 {
let r = (cand_pred[ci][i] + rr[i]).clamp(0, maxv);
let d = src[i] - r;
sse += (d * d) as i64;
}
cand_total += rd_cost_i64(sse, mlam, block_rate_bits(&q, &SCAN_16X32));
}
if cand_total < best_total {
best_total = cand_total;
chosen_uv = cand;
use_cfl = false;
ccf[..2].copy_from_slice(&cand_ccf[..2]);
cpred_px[..2].copy_from_slice(&cand_pred[..2]);
}
}
}
if chosen_uv == DC_PRED {
for ci in 0..2 {
ccf[ci] = dc_ccf[ci];
cpred_px[ci] = [cpred[ci]; 512];
}
}
let block_skip =
luma_zero && ccf[0].iter().all(|&c| c == 0) && ccf[1].iter().all(|&c| c == 0);
self.code_header_luma32(
x8,
y8,
lcf,
lpred,
y_mode,
block_skip,
chosen_uv,
if use_cfl { Some(cfl_alpha_uv) } else { None },
angle_delta,
);
for ci in 0..2 {
let plane = ci + 1;
let res_ctx = if block_skip {
0x40
} else {
let sk = self.skip_ctx_16x32_422(plane, bx4c, by4c);
let ds = self.dc_sign_ctx_16x32_422(plane, bx4c, by4c);
encode_16x32_chroma_coeffs(&mut self.enc, &mut self.cdfs, &ccf[ci], sk, ds)
};
self.a_coef[plane][bx4c..bx4c + 4].fill(res_ctx);
self.l_coef[plane][by4c..by4c + 8].fill(res_ctx);
let rr = if block_skip {
[0i32; 512]
} else {
idct_dequant_16x32(&ccf[ci], &self.cquant)
};
for (ry, rrow) in rr.as_chunks::<16>().0.iter().enumerate() {
let drow = &mut self.recon[plane][(py + ry) * self.cw + cx..];
let prow = &cpred_px[ci][ry * 16..];
for ((dv, &rv), &p) in drow.iter_mut().zip(rrow.iter()).zip(prow.iter()) {
*dv = (p + rv).clamp(0, maxv);
}
}
}
}
}