diff --git a/tests/h264_intra_pred_8x8_luma_ref.c b/tests/h264_intra_pred_8x8_luma_ref.c index 3bf0524..14d7b06 100644 --- a/tests/h264_intra_pred_8x8_luma_ref.c +++ b/tests/h264_intra_pred_8x8_luma_ref.c @@ -121,3 +121,185 @@ void daedalus_h264_pred_8x8l_dc_ref(uint8_t *dst, ptrdiff_t stride) for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) dst[r * stride + c] = v; } + +/* --- 6 directional modes for Intra_8x8 (H.264 §8.3.2.1.5..§8.3.2.1.10). + * Transcribed from FFmpeg libavcodec/h264pred_template.c + * pred8x8l_{down_left, down_right, vertical_right, horizontal_down, + * vertical_left, horizontal_up} (LGPL-2.1+ in the original; algorithm + * reproduced here for test purposes). + * + * All 6 use the same FILTERED reference samples produced by + * filter_refs() above. Mapping from FFmpeg's t0..t15 / l0..l7 / lt + * notation: + * tN = FT(N) for N in 0..15 + * lN = FL(N) for N in 0..7 + * lt = FTL + * + * SRC(x,y) maps to dst[y*stride + x] (col x, row y). + */ +#define SRC(x, y) dst[(y) * stride + (x)] +#define T(i) FT(i) +#define L(j) FL(j) +#define LT FTL + +/* Mode 3 DDL (Diagonal_Down_Left) — uses TOP + TOP_RIGHT, no LEFT. */ +void daedalus_h264_pred_8x8l_ddl_ref(uint8_t *dst, ptrdiff_t stride) +{ + uint8_t filt[25]; + filter_refs(dst, stride, filt); + SRC(0,0)= (T(0) + 2*T(1) + T(2) + 2) >> 2; + SRC(0,1)=SRC(1,0)= (T(1) + 2*T(2) + T(3) + 2) >> 2; + SRC(0,2)=SRC(1,1)=SRC(2,0)= (T(2) + 2*T(3) + T(4) + 2) >> 2; + SRC(0,3)=SRC(1,2)=SRC(2,1)=SRC(3,0)= (T(3) + 2*T(4) + T(5) + 2) >> 2; + SRC(0,4)=SRC(1,3)=SRC(2,2)=SRC(3,1)=SRC(4,0)= (T(4) + 2*T(5) + T(6) + 2) >> 2; + SRC(0,5)=SRC(1,4)=SRC(2,3)=SRC(3,2)=SRC(4,1)=SRC(5,0)= (T(5) + 2*T(6) + T(7) + 2) >> 2; + SRC(0,6)=SRC(1,5)=SRC(2,4)=SRC(3,3)=SRC(4,2)=SRC(5,1)=SRC(6,0)= (T(6) + 2*T(7) + T(8) + 2) >> 2; + SRC(0,7)=SRC(1,6)=SRC(2,5)=SRC(3,4)=SRC(4,3)=SRC(5,2)=SRC(6,1)=SRC(7,0)= (T(7) + 2*T(8) + T(9) + 2) >> 2; + SRC(1,7)=SRC(2,6)=SRC(3,5)=SRC(4,4)=SRC(5,3)=SRC(6,2)=SRC(7,1)= (T(8) + 2*T(9) + T(10) + 2) >> 2; + SRC(2,7)=SRC(3,6)=SRC(4,5)=SRC(5,4)=SRC(6,3)=SRC(7,2)= (T(9) + 2*T(10) + T(11) + 2) >> 2; + SRC(3,7)=SRC(4,6)=SRC(5,5)=SRC(6,4)=SRC(7,3)= (T(10) + 2*T(11) + T(12) + 2) >> 2; + SRC(4,7)=SRC(5,6)=SRC(6,5)=SRC(7,4)= (T(11) + 2*T(12) + T(13) + 2) >> 2; + SRC(5,7)=SRC(6,6)=SRC(7,5)= (T(12) + 2*T(13) + T(14) + 2) >> 2; + SRC(6,7)=SRC(7,6)= (T(13) + 2*T(14) + T(15) + 2) >> 2; + SRC(7,7)= (T(14) + 3*T(15) + 2) >> 2; +} + +/* Mode 4 DDR (Diagonal_Down_Right). */ +void daedalus_h264_pred_8x8l_ddr_ref(uint8_t *dst, ptrdiff_t stride) +{ + uint8_t filt[25]; + filter_refs(dst, stride, filt); + SRC(0,7)= (L(7) + 2*L(6) + L(5) + 2) >> 2; + SRC(0,6)=SRC(1,7)= (L(6) + 2*L(5) + L(4) + 2) >> 2; + SRC(0,5)=SRC(1,6)=SRC(2,7)= (L(5) + 2*L(4) + L(3) + 2) >> 2; + SRC(0,4)=SRC(1,5)=SRC(2,6)=SRC(3,7)= (L(4) + 2*L(3) + L(2) + 2) >> 2; + SRC(0,3)=SRC(1,4)=SRC(2,5)=SRC(3,6)=SRC(4,7)= (L(3) + 2*L(2) + L(1) + 2) >> 2; + SRC(0,2)=SRC(1,3)=SRC(2,4)=SRC(3,5)=SRC(4,6)=SRC(5,7)= (L(2) + 2*L(1) + L(0) + 2) >> 2; + SRC(0,1)=SRC(1,2)=SRC(2,3)=SRC(3,4)=SRC(4,5)=SRC(5,6)=SRC(6,7)= (L(1) + 2*L(0) + LT + 2) >> 2; + SRC(0,0)=SRC(1,1)=SRC(2,2)=SRC(3,3)=SRC(4,4)=SRC(5,5)=SRC(6,6)=SRC(7,7)= (L(0) + 2*LT + T(0) + 2) >> 2; + SRC(1,0)=SRC(2,1)=SRC(3,2)=SRC(4,3)=SRC(5,4)=SRC(6,5)=SRC(7,6)= (LT + 2*T(0) + T(1) + 2) >> 2; + SRC(2,0)=SRC(3,1)=SRC(4,2)=SRC(5,3)=SRC(6,4)=SRC(7,5)= (T(0) + 2*T(1) + T(2) + 2) >> 2; + SRC(3,0)=SRC(4,1)=SRC(5,2)=SRC(6,3)=SRC(7,4)= (T(1) + 2*T(2) + T(3) + 2) >> 2; + SRC(4,0)=SRC(5,1)=SRC(6,2)=SRC(7,3)= (T(2) + 2*T(3) + T(4) + 2) >> 2; + SRC(5,0)=SRC(6,1)=SRC(7,2)= (T(3) + 2*T(4) + T(5) + 2) >> 2; + SRC(6,0)=SRC(7,1)= (T(4) + 2*T(5) + T(6) + 2) >> 2; + SRC(7,0)= (T(5) + 2*T(6) + T(7) + 2) >> 2; +} + +/* Mode 5 VR (Vertical_Right). */ +void daedalus_h264_pred_8x8l_vr_ref(uint8_t *dst, ptrdiff_t stride) +{ + uint8_t filt[25]; + filter_refs(dst, stride, filt); + SRC(0,6)= (L(5) + 2*L(4) + L(3) + 2) >> 2; + SRC(0,7)= (L(6) + 2*L(5) + L(4) + 2) >> 2; + SRC(0,4)=SRC(1,6)= (L(3) + 2*L(2) + L(1) + 2) >> 2; + SRC(0,5)=SRC(1,7)= (L(4) + 2*L(3) + L(2) + 2) >> 2; + SRC(0,2)=SRC(1,4)=SRC(2,6)= (L(1) + 2*L(0) + LT + 2) >> 2; + SRC(0,3)=SRC(1,5)=SRC(2,7)= (L(2) + 2*L(1) + L(0) + 2) >> 2; + SRC(0,1)=SRC(1,3)=SRC(2,5)=SRC(3,7)= (L(0) + 2*LT + T(0) + 2) >> 2; + SRC(0,0)=SRC(1,2)=SRC(2,4)=SRC(3,6)= (LT + T(0) + 1) >> 1; + SRC(1,1)=SRC(2,3)=SRC(3,5)=SRC(4,7)= (LT + 2*T(0) + T(1) + 2) >> 2; + SRC(1,0)=SRC(2,2)=SRC(3,4)=SRC(4,6)= (T(0) + T(1) + 1) >> 1; + SRC(2,1)=SRC(3,3)=SRC(4,5)=SRC(5,7)= (T(0) + 2*T(1) + T(2) + 2) >> 2; + SRC(2,0)=SRC(3,2)=SRC(4,4)=SRC(5,6)= (T(1) + T(2) + 1) >> 1; + SRC(3,1)=SRC(4,3)=SRC(5,5)=SRC(6,7)= (T(1) + 2*T(2) + T(3) + 2) >> 2; + SRC(3,0)=SRC(4,2)=SRC(5,4)=SRC(6,6)= (T(2) + T(3) + 1) >> 1; + SRC(4,1)=SRC(5,3)=SRC(6,5)=SRC(7,7)= (T(2) + 2*T(3) + T(4) + 2) >> 2; + SRC(4,0)=SRC(5,2)=SRC(6,4)=SRC(7,6)= (T(3) + T(4) + 1) >> 1; + SRC(5,1)=SRC(6,3)=SRC(7,5)= (T(3) + 2*T(4) + T(5) + 2) >> 2; + SRC(5,0)=SRC(6,2)=SRC(7,4)= (T(4) + T(5) + 1) >> 1; + SRC(6,1)=SRC(7,3)= (T(4) + 2*T(5) + T(6) + 2) >> 2; + SRC(6,0)=SRC(7,2)= (T(5) + T(6) + 1) >> 1; + SRC(7,1)= (T(5) + 2*T(6) + T(7) + 2) >> 2; + SRC(7,0)= (T(6) + T(7) + 1) >> 1; +} + +/* Mode 6 HD (Horizontal_Down). */ +void daedalus_h264_pred_8x8l_hd_ref(uint8_t *dst, ptrdiff_t stride) +{ + uint8_t filt[25]; + filter_refs(dst, stride, filt); + SRC(0,7)= (L(6) + L(7) + 1) >> 1; + SRC(1,7)= (L(5) + 2*L(6) + L(7) + 2) >> 2; + SRC(0,6)=SRC(2,7)= (L(5) + L(6) + 1) >> 1; + SRC(1,6)=SRC(3,7)= (L(4) + 2*L(5) + L(6) + 2) >> 2; + SRC(0,5)=SRC(2,6)=SRC(4,7)= (L(4) + L(5) + 1) >> 1; + SRC(1,5)=SRC(3,6)=SRC(5,7)= (L(3) + 2*L(4) + L(5) + 2) >> 2; + SRC(0,4)=SRC(2,5)=SRC(4,6)=SRC(6,7)= (L(3) + L(4) + 1) >> 1; + SRC(1,4)=SRC(3,5)=SRC(5,6)=SRC(7,7)= (L(2) + 2*L(3) + L(4) + 2) >> 2; + SRC(0,3)=SRC(2,4)=SRC(4,5)=SRC(6,6)= (L(2) + L(3) + 1) >> 1; + SRC(1,3)=SRC(3,4)=SRC(5,5)=SRC(7,6)= (L(1) + 2*L(2) + L(3) + 2) >> 2; + SRC(0,2)=SRC(2,3)=SRC(4,4)=SRC(6,5)= (L(1) + L(2) + 1) >> 1; + SRC(1,2)=SRC(3,3)=SRC(5,4)=SRC(7,5)= (L(0) + 2*L(1) + L(2) + 2) >> 2; + SRC(0,1)=SRC(2,2)=SRC(4,3)=SRC(6,4)= (L(0) + L(1) + 1) >> 1; + SRC(1,1)=SRC(3,2)=SRC(5,3)=SRC(7,4)= (LT + 2*L(0) + L(1) + 2) >> 2; + SRC(0,0)=SRC(2,1)=SRC(4,2)=SRC(6,3)= (LT + L(0) + 1) >> 1; + SRC(1,0)=SRC(3,1)=SRC(5,2)=SRC(7,3)= (L(0) + 2*LT + T(0) + 2) >> 2; + SRC(2,0)=SRC(4,1)=SRC(6,2)= (T(1) + 2*T(0) + LT + 2) >> 2; + SRC(3,0)=SRC(5,1)=SRC(7,2)= (T(2) + 2*T(1) + T(0) + 2) >> 2; + SRC(4,0)=SRC(6,1)= (T(3) + 2*T(2) + T(1) + 2) >> 2; + SRC(5,0)=SRC(7,1)= (T(4) + 2*T(3) + T(2) + 2) >> 2; + SRC(6,0)= (T(5) + 2*T(4) + T(3) + 2) >> 2; + SRC(7,0)= (T(6) + 2*T(5) + T(4) + 2) >> 2; +} + +/* Mode 7 VL (Vertical_Left) — uses TOP + TOP_RIGHT only. */ +void daedalus_h264_pred_8x8l_vl_ref(uint8_t *dst, ptrdiff_t stride) +{ + uint8_t filt[25]; + filter_refs(dst, stride, filt); + SRC(0,0)= (T(0) + T(1) + 1) >> 1; + SRC(0,1)= (T(0) + 2*T(1) + T(2) + 2) >> 2; + SRC(0,2)=SRC(1,0)= (T(1) + T(2) + 1) >> 1; + SRC(0,3)=SRC(1,1)= (T(1) + 2*T(2) + T(3) + 2) >> 2; + SRC(0,4)=SRC(1,2)=SRC(2,0)= (T(2) + T(3) + 1) >> 1; + SRC(0,5)=SRC(1,3)=SRC(2,1)= (T(2) + 2*T(3) + T(4) + 2) >> 2; + SRC(0,6)=SRC(1,4)=SRC(2,2)=SRC(3,0)= (T(3) + T(4) + 1) >> 1; + SRC(0,7)=SRC(1,5)=SRC(2,3)=SRC(3,1)= (T(3) + 2*T(4) + T(5) + 2) >> 2; + SRC(1,6)=SRC(2,4)=SRC(3,2)=SRC(4,0)= (T(4) + T(5) + 1) >> 1; + SRC(1,7)=SRC(2,5)=SRC(3,3)=SRC(4,1)= (T(4) + 2*T(5) + T(6) + 2) >> 2; + SRC(2,6)=SRC(3,4)=SRC(4,2)=SRC(5,0)= (T(5) + T(6) + 1) >> 1; + SRC(2,7)=SRC(3,5)=SRC(4,3)=SRC(5,1)= (T(5) + 2*T(6) + T(7) + 2) >> 2; + SRC(3,6)=SRC(4,4)=SRC(5,2)=SRC(6,0)= (T(6) + T(7) + 1) >> 1; + SRC(3,7)=SRC(4,5)=SRC(5,3)=SRC(6,1)= (T(6) + 2*T(7) + T(8) + 2) >> 2; + SRC(4,6)=SRC(5,4)=SRC(6,2)=SRC(7,0)= (T(7) + T(8) + 1) >> 1; + SRC(4,7)=SRC(5,5)=SRC(6,3)=SRC(7,1)= (T(7) + 2*T(8) + T(9) + 2) >> 2; + SRC(5,6)=SRC(6,4)=SRC(7,2)= (T(8) + T(9) + 1) >> 1; + SRC(5,7)=SRC(6,5)=SRC(7,3)= (T(8) + 2*T(9) + T(10) + 2) >> 2; + SRC(6,6)=SRC(7,4)= (T(9) + T(10) + 1) >> 1; + SRC(6,7)=SRC(7,5)= (T(9) + 2*T(10) + T(11) + 2) >> 2; + SRC(7,6)= (T(10) + T(11) + 1) >> 1; + SRC(7,7)= (T(10) + 2*T(11) + T(12) + 2) >> 2; +} + +/* Mode 8 HU (Horizontal_Up) — uses LEFT only. */ +void daedalus_h264_pred_8x8l_hu_ref(uint8_t *dst, ptrdiff_t stride) +{ + uint8_t filt[25]; + filter_refs(dst, stride, filt); + SRC(0,0)= (L(0) + L(1) + 1) >> 1; + SRC(1,0)= (L(0) + 2*L(1) + L(2) + 2) >> 2; + SRC(0,1)=SRC(2,0)= (L(1) + L(2) + 1) >> 1; + SRC(1,1)=SRC(3,0)= (L(1) + 2*L(2) + L(3) + 2) >> 2; + SRC(0,2)=SRC(2,1)=SRC(4,0)= (L(2) + L(3) + 1) >> 1; + SRC(1,2)=SRC(3,1)=SRC(5,0)= (L(2) + 2*L(3) + L(4) + 2) >> 2; + SRC(0,3)=SRC(2,2)=SRC(4,1)=SRC(6,0)= (L(3) + L(4) + 1) >> 1; + SRC(1,3)=SRC(3,2)=SRC(5,1)=SRC(7,0)= (L(3) + 2*L(4) + L(5) + 2) >> 2; + SRC(0,4)=SRC(2,3)=SRC(4,2)=SRC(6,1)= (L(4) + L(5) + 1) >> 1; + SRC(1,4)=SRC(3,3)=SRC(5,2)=SRC(7,1)= (L(4) + 2*L(5) + L(6) + 2) >> 2; + SRC(0,5)=SRC(2,4)=SRC(4,3)=SRC(6,2)= (L(5) + L(6) + 1) >> 1; + SRC(1,5)=SRC(3,4)=SRC(5,3)=SRC(7,2)= (L(5) + 2*L(6) + L(7) + 2) >> 2; + SRC(0,6)=SRC(2,5)=SRC(4,4)=SRC(6,3)= (L(6) + L(7) + 1) >> 1; + SRC(1,6)=SRC(3,5)=SRC(5,4)=SRC(7,3)= (L(6) + 3*L(7) + 2) >> 2; + /* 20 positions all = L(7) per FFmpeg lines 1097-1100. */ + SRC(0,7)=SRC(1,7)=SRC(2,6)=SRC(2,7)=SRC(3,6)= + SRC(3,7)=SRC(4,5)=SRC(4,6)=SRC(4,7)=SRC(5,5)= + SRC(5,6)=SRC(5,7)=SRC(6,4)=SRC(6,5)=SRC(6,6)= + SRC(6,7)=SRC(7,4)=SRC(7,5)=SRC(7,6)=SRC(7,7)= L(7); +} + +#undef SRC +#undef T +#undef L +#undef LT diff --git a/tests/test_intra_pred_8x8_luma.c b/tests/test_intra_pred_8x8_luma.c index ac8b03c..5beffda 100644 --- a/tests/test_intra_pred_8x8_luma.c +++ b/tests/test_intra_pred_8x8_luma.c @@ -17,6 +17,12 @@ extern void daedalus_h264_pred_8x8l_vertical_ref(uint8_t *dst, ptrdiff_t stride); extern void daedalus_h264_pred_8x8l_horizontal_ref(uint8_t *dst, ptrdiff_t stride); extern void daedalus_h264_pred_8x8l_dc_ref(uint8_t *dst, ptrdiff_t stride); +extern void daedalus_h264_pred_8x8l_ddl_ref(uint8_t *dst, ptrdiff_t stride); +extern void daedalus_h264_pred_8x8l_ddr_ref(uint8_t *dst, ptrdiff_t stride); +extern void daedalus_h264_pred_8x8l_vr_ref(uint8_t *dst, ptrdiff_t stride); +extern void daedalus_h264_pred_8x8l_hd_ref(uint8_t *dst, ptrdiff_t stride); +extern void daedalus_h264_pred_8x8l_vl_ref(uint8_t *dst, ptrdiff_t stride); +extern void daedalus_h264_pred_8x8l_hu_ref(uint8_t *dst, ptrdiff_t stride); #define STRIDE 17 #define ROWS 9 @@ -133,7 +139,32 @@ int main(void) fail |= (diff == 0) ? 0 : 1; } - if (fail == 0) printf("\nALL Intra_8x8 luma PASS (3 modes — V, H, DC)\n"); + /* Directional modes — uniform-context sanity tests. With all + * neighbours = N, the 1-2-1 filter produces uniform N, and any + * 3-tap / 2-tap on uniform N produces N. So every directional + * mode should output uniform N on uniform input. */ + { + typedef void (*pred_fn_t)(uint8_t *dst, ptrdiff_t stride); + struct { const char *name; pred_fn_t fn; } modes[] = { + { "DDL (mode 3, uniform)", daedalus_h264_pred_8x8l_ddl_ref }, + { "DDR (mode 4, uniform)", daedalus_h264_pred_8x8l_ddr_ref }, + { "VR (mode 5, uniform)", daedalus_h264_pred_8x8l_vr_ref }, + { "HD (mode 6, uniform)", daedalus_h264_pred_8x8l_hd_ref }, + { "VL (mode 7, uniform)", daedalus_h264_pred_8x8l_vl_ref }, + { "HU (mode 8, uniform)", daedalus_h264_pred_8x8l_hu_ref }, + }; + for (size_t i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) { + uint8_t buf[ROWS][STRIDE]; + int t[16], l[8]; + for (int k = 0; k < 16; k++) t[k] = 120; + for (int k = 0; k < 8; k++) l[k] = 120; + set_ctx(buf, 120, t, l); + modes[i].fn(&buf[1][1], STRIDE); + fail |= check_uniform(buf, modes[i].name, 120); + } + } + + if (fail == 0) printf("\nALL Intra_8x8 luma PASS (9 modes — V, H, DC, DDL, DDR, VR, HD, VL, HU)\n"); else fprintf(stderr, "\n%d test(s) FAILED\n", fail); return fail ? 1 : 0; }