/* * Standalone bit-exact C reference for VP9 8-tap inner loop filter * (wd=8, horizontal, 8-pixel edge). Transcribed from FFmpeg's * libavcodec/vp9dsp_template.c loop_filter() function with wd=8 * (vendored at external/ffmpeg-snapshot/). 8-bit pixels only. * * Differs from cycle 2's vp9_lpf_ref.c (wd=4) in: * - Adds flat8in test (6 abs comparisons) per row * - If flat8in passes, writes 6 pixels (p2 p1 p0 q0 q1 q2) per row * using 8-pixel-input flat filter * - Otherwise falls through to wd=4 hev/no-hev paths * * License: LGPL-2.1-or-later (matches upstream). * Spec: VP9 specification ยง8.8.1. */ #include #include static inline int abs_i(int x) { return x < 0 ? -x : x; } static inline int clip_intp2_7(int x) { return x > 127 ? 127 : x < -128 ? -128 : x; } static inline uint8_t clip_u8(int x) { return (uint8_t)(x > 255 ? 255 : x < 0 ? 0 : x); } static inline int min_i(int a, int b) { return a < b ? a : b; } /* wd=8 inner-edge horizontal LPF. 8 rows, neighborhood [-4..+3] cols. */ void daedalus_vp9_loop_filter_h_8_8_ref(uint8_t *dst, ptrdiff_t stride, int E, int I, int H) { const int F = 1; /* 1 << (BIT_DEPTH - 8) for BIT_DEPTH=8 */ for (int i = 0; i < 8; i++, dst += stride) { int p3 = dst[-4], p2 = dst[-3], p1 = dst[-2], p0 = dst[-1]; int q0 = dst[ 0], q1 = dst[+1], q2 = dst[+2], q3 = dst[+3]; int fm = abs_i(p3 - p2) <= I && abs_i(p2 - p1) <= I && abs_i(p1 - p0) <= I && abs_i(q1 - q0) <= I && abs_i(q2 - q1) <= I && abs_i(q3 - q2) <= I && abs_i(p0 - q0) * 2 + (abs_i(p1 - q1) >> 1) <= E; if (!fm) continue; int flat8in = abs_i(p3 - p0) <= F && abs_i(p2 - p0) <= F && abs_i(p1 - p0) <= F && abs_i(q1 - q0) <= F && abs_i(q2 - q0) <= F && abs_i(q3 - q0) <= F; if (flat8in) { /* 8-pixel-input "inner flat" filter, 6 outputs. */ dst[-3] = (uint8_t)((p3 + p3 + p3 + 2 * p2 + p1 + p0 + q0 + 4) >> 3); dst[-2] = (uint8_t)((p3 + p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4) >> 3); dst[-1] = (uint8_t)((p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3); dst[ 0] = (uint8_t)((p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3); dst[+1] = (uint8_t)((p1 + p0 + q0 + 2 * q1 + q2 + q3 + q3 + 4) >> 3); dst[+2] = (uint8_t)((p0 + q0 + q1 + 2 * q2 + q3 + q3 + q3 + 4) >> 3); } else { /* Fall-through: same wd=4 hev/no-hev paths as cycle 2. */ int hev = abs_i(p1 - p0) > H || abs_i(q1 - q0) > H; if (hev) { int f = clip_intp2_7(p1 - q1); f = clip_intp2_7(3 * (q0 - p0) + f); int f1 = min_i(f + 4, 127) >> 3; int f2 = min_i(f + 3, 127) >> 3; dst[-1] = clip_u8(p0 + f2); dst[ 0] = clip_u8(q0 - f1); } else { int f = clip_intp2_7(3 * (q0 - p0)); int f1 = min_i(f + 4, 127) >> 3; int f2 = min_i(f + 3, 127) >> 3; dst[-1] = clip_u8(p0 + f2); dst[ 0] = clip_u8(q0 - f1); int fp = (f1 + 1) >> 1; dst[-2] = clip_u8(p1 + fp); dst[+1] = clip_u8(q1 - fp); } } } }