static BETA_TABLE: [i32; 52] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64,
];
static TC_TABLE: [i32; 54] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3,
3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 24,
];
#[inline]
fn clip3(lo: i32, hi: i32, v: i32) -> i32 {
v.max(lo).min(hi)
}
#[inline]
fn clip_sample(v: i32, max_val: i32) -> u16 {
v.max(0).min(max_val) as u16
}
fn table8_22(qpi: i32) -> i32 {
static TAB: [i32; 13] = [29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37];
if qpi < 30 {
qpi
} else if qpi >= 43 {
qpi - 6
} else {
TAB[(qpi - 30) as usize]
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn deblock(
y: &mut [u16],
w: usize,
h: usize,
cb: &mut [u16],
cr: &mut [u16],
cw: usize,
ch: usize,
qp: u8,
bit_depth: crate::fmt::BitDepth,
) {
for &vertical in &[true, false] {
deblock_luma(y, w, h, qp, vertical, bit_depth.bits());
deblock_chroma(cb, cw, ch, qp, vertical, bit_depth.bits());
deblock_chroma(cr, cw, ch, qp, vertical, bit_depth.bits());
}
}
pub(crate) fn deblock_luma_only(
y: &mut [u16],
w: usize,
h: usize,
qp: u8,
bit_depth: crate::fmt::BitDepth,
) {
for &vertical in &[true, false] {
deblock_luma(y, w, h, qp, vertical, bit_depth.bits());
}
}
fn deblock_luma(y: &mut [u16], w: usize, h: usize, qp: u8, vertical: bool, bit_depth: u8) {
let qp_l = qp as i32;
let bdshift = (bit_depth - 8) as i32;
let beta = BETA_TABLE[clip3(0, 51, qp_l) as usize] << bdshift;
let tc = TC_TABLE[clip3(0, 53, qp_l + 2) as usize] << bdshift;
let max_val = (1i32 << bit_depth) - 1;
if vertical {
let mut x = 8;
while x < w {
let mut yk = 0;
while yk + 4 <= h {
filter_luma_segment(y, w, x, yk, true, beta, tc, max_val);
yk += 4;
}
x += 8;
}
} else {
let mut yy = 8;
while yy < h {
let mut xk = 0;
while xk + 4 <= w {
filter_luma_segment(y, w, xk, yy, false, beta, tc, max_val);
xk += 4;
}
yy += 8;
}
}
}
#[allow(clippy::too_many_arguments)]
fn filter_luma_segment(
y: &mut [u16],
stride: usize,
ex: usize,
ey: usize,
vertical: bool,
beta: i32,
tc: i32,
max_val: i32,
) {
let at = |yref: &[u16], r: usize, c: usize| yref[r * stride + c] as i32;
let mut p = [[0i32; 4]; 4];
let mut q = [[0i32; 4]; 4];
for k in 0..4 {
for i in 0..4 {
if vertical {
let r = ey + k;
q[k][i] = at(y, r, ex + i);
p[k][i] = at(y, r, ex - 1 - i);
} else {
let c = ex + k;
q[k][i] = at(y, ey + i, c);
p[k][i] = at(y, ey.wrapping_sub(i + 1), c);
}
}
}
let dp0 = (p[0][2] - 2 * p[0][1] + p[0][0]).abs();
let dp3 = (p[3][2] - 2 * p[3][1] + p[3][0]).abs();
let dq0 = (q[0][2] - 2 * q[0][1] + q[0][0]).abs();
let dq3 = (q[3][2] - 2 * q[3][1] + q[3][0]).abs();
let dpq0 = dp0 + dq0;
let dpq3 = dp3 + dq3;
let dp = dp0 + dp3;
let dq = dq0 + dq3;
let d = dpq0 + dpq3;
if d >= beta {
return;
}
let d_sam0 = 2 * dpq0 < (beta >> 2)
&& (p[0][3] - p[0][0]).abs() + (q[0][0] - q[0][3]).abs() < (beta >> 3)
&& (p[0][0] - q[0][0]).abs() < ((5 * tc + 1) >> 1);
let d_sam3 = 2 * dpq3 < (beta >> 2)
&& (p[3][3] - p[3][0]).abs() + (q[3][0] - q[3][3]).abs() < (beta >> 3)
&& (p[3][0] - q[3][0]).abs() < ((5 * tc + 1) >> 1);
let de = if d_sam0 && d_sam3 { 2 } else { 1 };
let dep = if dp < ((beta + (beta >> 1)) >> 3) {
1
} else {
0
};
let deq = if dq < ((beta + (beta >> 1)) >> 3) {
1
} else {
0
};
let set = |y: &mut [u16], r: usize, c: usize, v: u16| {
y[r * stride + c] = v;
};
for k in 0..4 {
let (p0, p1, p2, p3) = (p[k][0], p[k][1], p[k][2], p[k][3]);
let (q0, q1, q2, q3) = (q[k][0], q[k][1], q[k][2], q[k][3]);
if de == 2 {
let pn0 = clip3(
p0 - 2 * tc,
p0 + 2 * tc,
(p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3,
);
let pn1 = clip3(p1 - 2 * tc, p1 + 2 * tc, (p2 + p1 + p0 + q0 + 2) >> 2);
let pn2 = clip3(
p2 - 2 * tc,
p2 + 2 * tc,
(2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3,
);
let qn0 = clip3(
q0 - 2 * tc,
q0 + 2 * tc,
(p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3,
);
let qn1 = clip3(q1 - 2 * tc, q1 + 2 * tc, (p0 + q0 + q1 + q2 + 2) >> 2);
let qn2 = clip3(
q2 - 2 * tc,
q2 + 2 * tc,
(p0 + q0 + q1 + 3 * q2 + 2 * q3 + 4) >> 3,
);
let pn = [pn0, pn1, pn2];
let qn = [qn0, qn1, qn2];
for i in 0..3 {
if vertical {
set(y, ey + k, ex - 1 - i, clip_sample(pn[i], max_val));
set(y, ey + k, ex + i, clip_sample(qn[i], max_val));
} else {
set(y, ey - 1 - i, ex + k, clip_sample(pn[i], max_val));
set(y, ey + i, ex + k, clip_sample(qn[i], max_val));
}
}
} else {
let delta = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4;
if delta.abs() < tc * 10 {
let delta = clip3(-tc, tc, delta);
if vertical {
set(y, ey + k, ex - 1, clip_sample(p0 + delta, max_val));
set(y, ey + k, ex, clip_sample(q0 - delta, max_val));
} else {
set(y, ey - 1, ex + k, clip_sample(p0 + delta, max_val));
set(y, ey, ex + k, clip_sample(q0 - delta, max_val));
}
if dep == 1 {
let dpv = clip3(
-(tc >> 1),
tc >> 1,
(((p2 + p0 + 1) >> 1) - p1 + delta) >> 1,
);
if vertical {
set(y, ey + k, ex - 2, clip_sample(p1 + dpv, max_val));
} else {
set(y, ey - 2, ex + k, clip_sample(p1 + dpv, max_val));
}
}
if deq == 1 {
let dqv = clip3(
-(tc >> 1),
tc >> 1,
(((q2 + q0 + 1) >> 1) - q1 - delta) >> 1,
);
if vertical {
set(y, ey + k, ex + 1, clip_sample(q1 + dqv, max_val));
} else {
set(y, ey + 1, ex + k, clip_sample(q1 + dqv, max_val));
}
}
}
}
}
}
fn deblock_chroma(c: &mut [u16], cw: usize, chh: usize, qp: u8, vertical: bool, bit_depth: u8) {
let qpi = qp as i32;
let qp_c = table8_22(qpi);
let bdshift = (bit_depth - 8) as i32;
let tc = TC_TABLE[clip3(0, 53, qp_c + 2) as usize] << bdshift;
let max_val = (1i32 << bit_depth) - 1;
if tc == 0 { }
if vertical {
let mut x = 8;
while x < cw {
let mut yk = 0;
while yk + 4 <= chh {
filter_chroma_segment(c, cw, x, yk, true, tc, max_val);
yk += 4;
}
x += 8;
}
} else {
let mut yy = 8;
while yy < chh {
let mut xk = 0;
while xk + 4 <= cw {
filter_chroma_segment(c, cw, xk, yy, false, tc, max_val);
xk += 4;
}
yy += 8;
}
}
}
fn filter_chroma_segment(
c: &mut [u16],
stride: usize,
ex: usize,
ey: usize,
vertical: bool,
tc: i32,
max_val: i32,
) {
let at = |cref: &[u16], r: usize, col: usize| cref[r * stride + col] as i32;
for k in 0..4 {
let (p0, p1, q0, q1);
if vertical {
let r = ey + k;
q0 = at(c, r, ex);
q1 = at(c, r, ex + 1);
p0 = at(c, r, ex - 1);
p1 = at(c, r, ex - 2);
} else {
let col = ex + k;
q0 = at(c, ey, col);
q1 = at(c, ey + 1, col);
p0 = at(c, ey - 1, col);
p1 = at(c, ey - 2, col);
}
let delta = clip3(-tc, tc, (((q0 - p0) * 4) + p1 - q1 + 4) >> 3);
if vertical {
c[(ey + k) * stride + (ex - 1)] = clip_sample(p0 + delta, max_val);
c[(ey + k) * stride + ex] = clip_sample(q0 - delta, max_val);
} else {
c[(ey - 1) * stride + (ex + k)] = clip_sample(p0 + delta, max_val);
c[ey * stride + (ex + k)] = clip_sample(q0 - delta, max_val);
}
}
}