X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-realmedia%2Fsrc%2Fcodecs%2Frv40enc%2Fdsp%2Floopfilt.rs;fp=nihav-realmedia%2Fsrc%2Fcodecs%2Frv40enc%2Fdsp%2Floopfilt.rs;h=5fa25efe09ab85e8ce009c3b04eca5bb1a35ee9e;hp=0000000000000000000000000000000000000000;hb=4965a5e560c5e194c5b5163c591fcade5f56c3f0;hpb=6bd5b458d9889f092abe9b582bd531ed08a8dc51 diff --git a/nihav-realmedia/src/codecs/rv40enc/dsp/loopfilt.rs b/nihav-realmedia/src/codecs/rv40enc/dsp/loopfilt.rs new file mode 100644 index 0000000..5fa25ef --- /dev/null +++ b/nihav-realmedia/src/codecs/rv40enc/dsp/loopfilt.rs @@ -0,0 +1,643 @@ +use nihav_core::frame::NASimpleVideoFrame; +use super::super::types::DeblockInfo; +use super::clip8; + +const Y_TOP_ROW_MASK: u32 = 0x000F; +const Y_BOT_ROW_MASK: u32 = 0xF000; +const Y_LEFT_COL_MASK: u32 = 0x1111; +const Y_RIGHT_COL_MASK: u32 = 0x8888; +const C_TOP_ROW_MASK: u8 = 0x3; +const C_BOT_ROW_MASK: u8 = 0xC; +const C_LEFT_COL_MASK: u8 = 0x5; +const C_RIGHT_COL_MASK: u8 = 0xA; + +macro_rules! test_bit { + ($pat: expr, $x: expr) => ( (($pat >> $x) & 1) != 0 ) +} + +pub fn loop_filter_frame(dst: &mut NASimpleVideoFrame, dblk: &[DeblockInfo], mb_w: usize, mb_h: usize) { + let small_frame = dst.width[0] * dst.height[0] <= 176 * 144; + + let mut mb_pos = 0; + for mb_y in 0..mb_h { + let is_last_row = mb_y == mb_h - 1; + let mut left_q: usize = 0; + let mut left_cbp_y = 0; + let mut left_cbp_c = 0; + let mut left_dbk_y = 0; + + for mb_x in 0..mb_w { + let q = usize::from(dblk[mb_pos].q); + let alpha = RV40_ALPHA_TAB[q]; + let beta = RV40_BETA_TAB[q]; + let beta_y = if small_frame { beta * 4 } else { beta * 3 }; + let beta_c = beta * 3; + + let is_strong = dblk[mb_pos].is_strong; + let top_is_strong = mb_y > 0 && dblk[mb_pos - mb_w].is_strong; + let left_is_strong = mb_x > 0 && dblk[mb_pos - 1].is_strong; + let bot_is_strong = !is_last_row && dblk[mb_pos + mb_w].is_strong; + + let cur_dbk_y = dblk[mb_pos].deblock_y; + let cur_cbp_y = if is_strong { 0xFFFF } else { u32::from(dblk[mb_pos].cbp_y) }; + + let (top_cbp_y, top_dbk_y) = if mb_y > 0 { + (if top_is_strong { 0xFFFF } else { u32::from(dblk[mb_pos - mb_w].cbp_y) }, dblk[mb_pos - mb_w].deblock_y) + } else { + (0, 0) + }; + let bot_dbk_y = if !is_last_row { + dblk[mb_pos + mb_w].deblock_y + } else { + 0 + }; + + let y_to_deblock = (cur_dbk_y as u32) | ((bot_dbk_y as u32) << 16); + let mut y_h_deblock = y_to_deblock | ((cur_cbp_y << 4) & !Y_TOP_ROW_MASK) | ((top_cbp_y & Y_BOT_ROW_MASK) >> 12); + let mut y_v_deblock = y_to_deblock | ((cur_cbp_y << 1) & !Y_LEFT_COL_MASK) | ((left_cbp_y & Y_RIGHT_COL_MASK) >> 3); + + if mb_x == 0 { + y_v_deblock &= !Y_LEFT_COL_MASK; + } + if mb_y == 0 { + y_h_deblock &= !Y_TOP_ROW_MASK; + } + if is_last_row || is_strong || bot_is_strong { + y_h_deblock &= !(Y_TOP_ROW_MASK << 16); + } + + for y in 0..4 { + let yoff = dst.offset[0] + mb_x * 16 + (mb_y * 16 + y * 4) * dst.stride[0]; + for x in 0..4 { + let bpos = x + y * 4; + let ver_strong = (x == 0) && (mb_x > 0) && (is_strong || left_is_strong); + + let cur_strength: usize; + if is_strong { + cur_strength = 2; + } else if test_bit!(cur_dbk_y, bpos) { + cur_strength = 1; + } else { + cur_strength = 0; + } + + let left_strength: usize; + if x > 0 { + if is_strong { + left_strength = 2; + } else if test_bit!(cur_dbk_y, bpos - 1) { + left_strength = 1; + } else { + left_strength = 0; + } + } else if mb_x > 0 { + if left_is_strong { + left_strength = 2; + } else if test_bit!(left_dbk_y, bpos + 3) { + left_strength = 1; + } else { + left_strength = 0; + } + } else { + left_strength = 0; + } + + let bot_strength: usize; + if y < 3 { + if is_strong { + bot_strength = 2; + } else if test_bit!(cur_dbk_y, bpos + 4) { + bot_strength = 1; + } else { + bot_strength = 0; + } + } else if !is_last_row { + if dblk[mb_pos + mb_w].is_strong { + bot_strength = 2; + } else if test_bit!(bot_dbk_y, x) { + bot_strength = 1; + } else { + bot_strength = 0; + } + } else { + bot_strength = 0; + } + + let top_strength: usize; + if y > 0 { + if is_strong { + top_strength = 2; + } else if test_bit!(cur_dbk_y, bpos - 4) { + top_strength = 1; + } else { + top_strength = 0; + } + } else if mb_y > 0 { + if top_is_strong { + top_strength = 2; + } else if test_bit!(top_dbk_y, bpos + 12) { + top_strength = 1; + } else { + top_strength = 0; + } + } else { + top_strength = 0; + } + + let l_q = if x > 0 { q } else { left_q }; + let top_q = if mb_y > 0 { usize::from(dblk[mb_pos - mb_w].q) } else { 0 }; + + let lim_cur = RV40_FILTER_CLIP_TBL [cur_strength][q]; + let lim_top = RV40_FILTER_CLIP_TBL [top_strength][top_q]; + let lim_left = RV40_FILTER_CLIP_TBL[left_strength][l_q]; + let lim_bottom = RV40_FILTER_CLIP_TBL [bot_strength][q]; + + let dmode = if y > 0 { x + y * 4 } else { x * 4 }; + + if test_bit!(y_h_deblock, bpos + 4) { + rv40_loop_filter4_h(dst.data, yoff + 4 * dst.stride[0] + x * 4, dst.stride[0], + dmode, lim_cur, lim_bottom, alpha, beta, beta_y, false, false); + } + if test_bit!(y_v_deblock, bpos) && !ver_strong { + rv40_loop_filter4_v(dst.data, yoff + x * 4, dst.stride[0], + dmode, lim_left, lim_cur, alpha, beta, beta_y, false, false); + } + if (y == 0) && test_bit!(y_h_deblock, bpos) && (is_strong || top_is_strong) { + rv40_loop_filter4_h(dst.data, yoff + x * 4, dst.stride[0], + dmode, lim_top, lim_cur, alpha, beta, beta_y, false, true); + } + if test_bit!(y_v_deblock, bpos) && ver_strong { + rv40_loop_filter4_v(dst.data, yoff + x * 4, dst.stride[0], + dmode, lim_left, lim_cur, alpha, beta, beta_y, false, true); + } + } + } + + let cur_cbp_c = dblk[mb_pos].cbp_c; + let top_cbp_c = if mb_y > 0 { + if top_is_strong { 0xFF } else { dblk[mb_pos - mb_w].cbp_c } + } else { + 0 + }; + let bot_cbp_c = if !is_last_row { + dblk[mb_pos + mb_w].cbp_c + } else { + 0 + }; + for comp in 1..3 { + let cshift = (comp - 1) * 4; + let c_cur_cbp = (cur_cbp_c >> cshift) & 0xF; + let c_top_cbp = (top_cbp_c >> cshift) & 0xF; + let c_left_cbp = (left_cbp_c >> cshift) & 0xF; + let c_bot_cbp = (bot_cbp_c >> cshift) & 0xF; + + let c_deblock = c_cur_cbp | (c_bot_cbp << 4); + let mut c_v_deblock = c_deblock | ((c_cur_cbp << 1) & !C_LEFT_COL_MASK) | ((c_left_cbp & C_RIGHT_COL_MASK) >> 1); + let mut c_h_deblock = c_deblock | ((c_cur_cbp & C_TOP_ROW_MASK) << 2) | ((c_top_cbp & C_BOT_ROW_MASK) >> 2); + if mb_x == 0 { + c_v_deblock &= !C_LEFT_COL_MASK; + } + if mb_y == 0 { + c_h_deblock &= !C_TOP_ROW_MASK; + } + if is_last_row || is_strong || bot_is_strong { + c_h_deblock &= !(C_TOP_ROW_MASK << 4); + } + + for y in 0..2 { + let coff = dst.offset[comp] + mb_x * 8 + (mb_y * 8 + y * 4) * dst.stride[comp]; + for x in 0..2 { + let bpos = x + y * 2; + + let ver_strong = (x == 0) && (is_strong || left_is_strong); + + let cur_strength: usize; + if is_strong { + cur_strength = 2; + } else if test_bit!(c_cur_cbp, bpos) { + cur_strength = 1; + } else { + cur_strength = 0; + } + + let left_strength: usize; + if x > 0 { + if is_strong { + left_strength = 2; + } else if test_bit!(c_cur_cbp, bpos - 1) { + left_strength = 1; + } else { + left_strength = 0; + } + } else if mb_x > 0 { + if left_is_strong { + left_strength = 2; + } else if test_bit!(c_left_cbp, bpos + 1) { + left_strength = 1; + } else { + left_strength = 0; + } + } else { + left_strength = 0; + } + + let bot_strength: usize; + if y != 3 { + if is_strong { + bot_strength = 2; + } else if test_bit!(c_cur_cbp, bpos + 2) { + bot_strength = 1; + } else { + bot_strength = 0; + } + } else if !is_last_row { + if dblk[mb_pos + mb_w].is_strong { + bot_strength = 2; + } else if test_bit!(c_bot_cbp, x) { + bot_strength = 1; + } else { + bot_strength = 0; + } + } else { + bot_strength = 0; + } + + let top_strength: usize; + if y > 0 { + if is_strong { + top_strength = 2; + } else if test_bit!(c_cur_cbp, bpos - 2) { + top_strength = 1; + } else { + top_strength = 0; + } + } else if mb_y > 0 { + if top_is_strong { + top_strength = 2; + } else if test_bit!(c_top_cbp, bpos + 2) { + top_strength = 1; + } else { + top_strength = 0; + } + } else { + top_strength = 0; + } + + let l_q = if x > 0 { q } else { left_q }; + let top_q = if mb_y > 0 { usize::from(dblk[mb_pos - mb_w].q) } else { 0 }; + + let lim_cur = RV40_FILTER_CLIP_TBL [cur_strength][q]; + let lim_top = RV40_FILTER_CLIP_TBL [top_strength][top_q]; + let lim_left = RV40_FILTER_CLIP_TBL[left_strength][l_q]; + let lim_bottom = RV40_FILTER_CLIP_TBL [bot_strength][q]; + + if test_bit!(c_h_deblock, bpos + 2) { + rv40_loop_filter4_h(dst.data, coff + 4 * dst.stride[comp] + x * 4, dst.stride[comp], + x * 8, lim_cur, lim_bottom, alpha, beta, beta_c, true, false); + } + if test_bit!(c_v_deblock, bpos) && !ver_strong { + rv40_loop_filter4_v(dst.data, coff + x * 4, dst.stride[comp], + y * 8, lim_left, lim_cur, alpha, beta, beta_c, true, false); + } + if (y == 0) && test_bit!(c_h_deblock, bpos) && (is_strong || top_is_strong) { + rv40_loop_filter4_h(dst.data, coff + x * 4, dst.stride[comp], + x * 8, lim_top, lim_cur, alpha, beta, beta_c, true, true); + } + if test_bit!(c_v_deblock, bpos) && ver_strong { + rv40_loop_filter4_v(dst.data, coff + x * 4, dst.stride[comp], + y * 8, lim_left, lim_cur, alpha, beta, beta_c, true, true); + } + } + } + } + + left_q = q; + left_dbk_y = cur_dbk_y; + left_cbp_y = cur_cbp_y; + left_cbp_c = cur_cbp_c; + + mb_pos += 1; + } + } +} + +macro_rules! el { + ($src: ident, $o: expr) => ($src[$o] as i16); +} + +fn clip_symm(a: i16, lim: i16) -> i16 { + if a < -lim { + -lim + } else if a > lim { + lim + } else { + a + } +} + +fn rv40_weak_loop_filter4(pix: &mut [u8], mut off: usize, step: usize, stride: usize, + filter_p1: bool, filter_q1: bool, alpha: i16, beta: i16, + lim_p0q0: i16, lim_p1: i16, lim_q1: i16) { + for _ in 0..4 { + let p0 = el!(pix, off - step); + let q0 = el!(pix, off); + + let t = q0 - p0; + if t == 0 { + off += stride; + continue; + } + + let u = (alpha * t.wrapping_abs()) >> 7; + if u > (if filter_p1 && filter_q1 { 2 } else { 3 }) { + off += stride; + continue; + } + + let p2 = el!(pix, off - 3*step); + let p1 = el!(pix, off - 2*step); + let q1 = el!(pix, off + step); + let q2 = el!(pix, off + 2*step); + + let strength; + if filter_p1 && filter_q1 { + strength = (t << 2) + (p1 - q1); + } else { + strength = t << 2; + } + + let diff = clip_symm((strength + 4) >> 3, lim_p0q0); + pix[off - step] = clip8(p0 + diff); + pix[off ] = clip8(q0 - diff); + + if filter_p1 && ((p1 - p2).wrapping_abs() <= beta) { + let p1_diff = ((p1 - p0) + (p1 - p2) - diff) >> 1; + pix[off - 2*step] = clip8(p1 - clip_symm(p1_diff, lim_p1)); + } + + if filter_q1 && ((q1 - q2).wrapping_abs() <= beta) { + let q1_diff = ((q1 - q0) + (q1 - q2) + diff) >> 1; + pix[off + step] = clip8(q1 - clip_symm(q1_diff, lim_q1)); + } + + off += stride; + } +} + +fn rv40_weak_loop_filter4_h(pix: &mut [u8], off: usize, stride: usize, + filter_p1: bool, filter_q1: bool, alpha: i16, beta: i16, + lim_p0q0: i16, lim_p1: i16, lim_q1: i16) { + rv40_weak_loop_filter4(pix, off, stride, 1, filter_p1, filter_q1, alpha, beta, lim_p0q0, lim_p1, lim_q1); +} +#[allow(clippy::eq_op)] +fn rv40_weak_loop_filter4_v(pix: &mut [u8], off: usize, stride: usize, + filter_p1: bool, filter_q1: bool, alpha: i16, beta: i16, + lim_p0q0: i16, lim_p1: i16, lim_q1: i16) { + let src = &mut pix[off - 3..][..stride * 3 + 3 + 3]; + for ch in src.chunks_mut(stride).take(4) { + assert!(ch.len() >= 3 + 3); + let p0 = el!(ch, 3 - 1); + let q0 = el!(ch, 3); + + let t = q0 - p0; + if t == 0 { + continue; + } + + let u = (alpha * t.wrapping_abs()) >> 7; + if u > (if filter_p1 && filter_q1 { 2 } else { 3 }) { + continue; + } + + let p2 = el!(ch, 3 - 3); + let p1 = el!(ch, 3 - 2); + let q1 = el!(ch, 3 + 1); + let q2 = el!(ch, 3 + 2); + + let strength; + if filter_p1 && filter_q1 { + strength = (t << 2) + (p1 - q1); + } else { + strength = t << 2; + } + + let diff = clip_symm((strength + 4) >> 3, lim_p0q0); + ch[3 - 1] = clip8(p0 + diff); + ch[3 ] = clip8(q0 - diff); + + if filter_p1 && ((p1 - p2).wrapping_abs() <= beta) { + let p1_diff = ((p1 - p0) + (p1 - p2) - diff) >> 1; + ch[3 - 2] = clip8(p1 - clip_symm(p1_diff, lim_p1)); + } + + if filter_q1 && ((q1 - q2).wrapping_abs() <= beta) { + let q1_diff = ((q1 - q0) + (q1 - q2) + diff) >> 1; + ch[3 + 1] = clip8(q1 - clip_symm(q1_diff, lim_q1)); + } + } +} + +#[allow(clippy::many_single_char_names)] +fn sfilter(a: i16, b: i16, c: i16, d: i16, e: i16, dither: i16, clip: bool, lims: i16) -> i16 { + let val = (25 * (a + e) + 26 * (b + c + d) + dither) >> 7; + if clip { + if val < c - lims { + c - lims + } else if val > c + lims { + c + lims + } else { + val + } + } else { + val + } +} + +fn rv40_strong_loop_filter4(pix: &mut [u8], mut off: usize, step: usize, stride: usize, + alpha: i16, lims: i16, dmode: usize, chroma: bool) { + for i in 0..4 { + let p0 = el!(pix, off - step); + let q0 = el!(pix, off); + + let t = q0 - p0; + if t == 0 { + off += stride; + continue; + } + + let fmode = (alpha * t.wrapping_abs()) >> 7; + if fmode > 1 { + off += stride; + continue; + } + + let p3 = el!(pix, off - 4*step); + let p2 = el!(pix, off - 3*step); + let p1 = el!(pix, off - 2*step); + let q1 = el!(pix, off + step); + let q2 = el!(pix, off + 2*step); + let q3 = el!(pix, off + 3*step); + + let np0 = sfilter(p2, p1, p0, q0, q1, RV40_DITHER_L[dmode + i], fmode != 0, lims); + let nq0 = sfilter( p1, p0, q0, q1, q2, RV40_DITHER_R[dmode + i], fmode != 0, lims); + + let np1 = sfilter(p3, p2, p1, np0, q0, RV40_DITHER_L[dmode + i], fmode != 0, lims); + let nq1 = sfilter( p0, nq0, q1, q2, q3, RV40_DITHER_R[dmode + i], fmode != 0, lims); + + pix[off - 2*step] = np1 as u8; + pix[off - step] = np0 as u8; + pix[off] = nq0 as u8; + pix[off + step] = nq1 as u8; + + if !chroma { + let np2 = sfilter(np0, np1, p2, p3, p2, 64, false, 0); + let nq2 = sfilter(nq0, nq1, q2, q3, q2, 64, false, 0); + pix[off - 3*step] = np2 as u8; + pix[off + 2*step] = nq2 as u8; + } + + off += stride; + } +} + +fn rv40_loop_strength(pix: &[u8], off: usize, step: usize, stride: usize, + beta: i16, beta2: i16, edge: bool) -> (bool, bool, bool) { + let mut sum_p1p0 = 0; + let mut sum_q1q0 = 0; + + let mut off1 = off; + for _ in 0..4 { + sum_p1p0 += el!(pix, off1 - 2 * step) - el!(pix, off1 - step); + sum_q1q0 += el!(pix, off1 + step) - el!(pix, off1); + off1 += stride; + } + + let filter_p1 = sum_p1p0.wrapping_abs() < beta * 4; + let filter_q1 = sum_q1q0.wrapping_abs() < beta * 4; + + if (!filter_p1 || !filter_q1) || !edge { + return (false, filter_p1, filter_q1); + } + + let mut sum_p1p2 = 0; + let mut sum_q1q2 = 0; + + let mut off1 = off; + for _ in 0..4 { + sum_p1p2 += el!(pix, off1 - 2 * step) - el!(pix, off1 - 3 * step); + sum_q1q2 += el!(pix, off1 + step) - el!(pix, off1 + 2 * step); + off1 += stride; + } + + let strong = (sum_p1p2.wrapping_abs() < beta2) && (sum_q1q2.wrapping_abs() < beta2); + + (strong, filter_p1, filter_q1) +} + +fn rv40_loop_strength_h(pix: &[u8], off: usize, stride: usize, + beta: i16, beta2: i16, edge: bool) -> (bool, bool, bool) { + rv40_loop_strength(pix, off, stride, 1, beta, beta2, edge) +} + +#[allow(clippy::eq_op)] +fn rv40_loop_strength_v(pix: &[u8], off: usize, stride: usize, + beta: i16, beta2: i16, edge: bool) -> (bool, bool, bool) { + let src = &pix[off - 3..][..stride * 3 + 3 + 3]; + let mut sum_p1p0 = 0; + let mut sum_q1q0 = 0; + + for ch in src.chunks(stride).take(4) { + assert!(ch.len() >= 3 + 3); + sum_p1p0 += el!(ch, 3 - 2) - el!(ch, 3 - 1); + sum_q1q0 += el!(ch, 3 + 1) - el!(ch, 3); + } + + let filter_p1 = sum_p1p0.wrapping_abs() < beta * 4; + let filter_q1 = sum_q1q0.wrapping_abs() < beta * 4; + + if (!filter_p1 || !filter_q1) || !edge { + return (false, filter_p1, filter_q1); + } + + let mut sum_p1p2 = 0; + let mut sum_q1q2 = 0; + + for ch in src.chunks(stride).take(4) { + assert!(ch.len() >= 3 + 3); + sum_p1p2 += el!(ch, 3 - 2) - el!(ch, 3 - 3); + sum_q1q2 += el!(ch, 3 + 1) - el!(ch, 3 + 2); + } + + let strong = (sum_p1p2.wrapping_abs() < beta2) && (sum_q1q2.wrapping_abs() < beta2); + + (strong, filter_p1, filter_q1) +} + +fn rv40_loop_filter4_h(pix: &mut [u8], off: usize, stride: usize, + dmode: usize, lim_p1: i16, lim_q1: i16, alpha: i16, beta: i16, beta2: i16, + chroma: bool, edge: bool) { + let (strong, filter_p1, filter_q1) = rv40_loop_strength_h(pix, off, stride, beta, beta2, edge); + let lims = (filter_p1 as i16) + (filter_q1 as i16) + ((lim_p1 + lim_q1) >> 1) + 1; + + if strong { + rv40_strong_loop_filter4(pix, off, stride, 1, alpha, lims, dmode, chroma); + } else if filter_p1 && filter_q1 { + rv40_weak_loop_filter4_h(pix, off, stride, true, true, alpha, beta, + lims, lim_p1, lim_q1); + } else if filter_p1 || filter_q1 { + rv40_weak_loop_filter4_h(pix, off, stride, filter_p1, filter_q1, alpha, beta, + lims >> 1, lim_p1 >> 1, lim_q1 >> 1); + } +} + +fn rv40_loop_filter4_v(pix: &mut [u8], off: usize, stride: usize, + dmode: usize, lim_p1: i16, lim_q1: i16, alpha: i16, beta: i16, beta2: i16, + chroma: bool, edge: bool) { + let (strong, filter_p1, filter_q1) = rv40_loop_strength_v(pix, off, stride, beta, beta2, edge); + let lims = (filter_p1 as i16) + (filter_q1 as i16) + ((lim_p1 + lim_q1) >> 1) + 1; + + if strong { + rv40_strong_loop_filter4(pix, off, 1, stride, alpha, lims, dmode, chroma); + } else if filter_p1 && filter_q1 { + rv40_weak_loop_filter4_v(pix, off, stride, true, true, alpha, beta, + lims, lim_p1, lim_q1); + } else if filter_p1 || filter_q1 { + rv40_weak_loop_filter4_v(pix, off, stride, filter_p1, filter_q1, alpha, beta, + lims >> 1, lim_p1 >> 1, lim_q1 >> 1); + } +} + +const RV40_DITHER_L: [i16; 16] = [ + 0x40, 0x50, 0x20, 0x60, 0x30, 0x50, 0x40, 0x30, + 0x50, 0x40, 0x50, 0x30, 0x60, 0x20, 0x50, 0x40 +]; +const RV40_DITHER_R: [i16; 16] = [ + 0x40, 0x30, 0x60, 0x20, 0x50, 0x30, 0x30, 0x40, + 0x40, 0x40, 0x50, 0x30, 0x20, 0x60, 0x30, 0x40 +]; + +const RV40_ALPHA_TAB: [i16; 32] = [ + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 122, 96, 75, 59, 47, 37, + 29, 23, 18, 15, 13, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1 +]; + +const RV40_BETA_TAB: [i16; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 4, 4, 6, 6, + 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 14, 15, 16, 17 +]; + +const RV40_FILTER_CLIP_TBL: [[i16; 32]; 3] = [ + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 5, 5 + ], [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 7, 8, 9 + ] +]; +