Files
daedalus-fourier/tests/test_intra_pred_16x16.c
T
claude-noether c43ee84d8e h264: Intra_16x16 luma prediction — 4-mode C reference + spec gates
Second piece of the intra-prediction primitive set after PR #12
(Intra_4x4 luma 9 modes).  Covers the Intra_16x16 luma MB type
per H.264 §8.3.2: 4 modes (Vertical, Horizontal, DC, Plane).

Scope:
  - tests/h264_intra_pred_16x16_ref.c — 4 spec-derived modes.
    Same FFmpeg-style interface as the 4x4 sibling:
      void daedalus_h264_pred_16x16_<name>_ref(uint8_t *dst, ptrdiff_t stride);
    Assumes all neighbours valid (interior-MB case).

    The Plane mode is the algorithmically heaviest of the four —
    spec §8.3.2.4 has two slope sums (H, V) over the asymmetric
    top/left contexts, a clipped quadratic evaluation per cell,
    and a top-left-corner participant at i=7 / j=7.  Implementation
    follows the spec straightforwardly with `clip_u8` on the final
    saturating cast.

  - tests/test_intra_pred_16x16.c — 5 test cases:
      * V, H, DC: standard contexts (gradient top / gradient left /
        small uniform pair).
      * Plane (uniform): all neighbours = 100 → H = V = 0 →
        output = (16*200 + 16) >> 5 = 100.  Verifies the
        orientation-free portion of the formula.
      * Plane (gradient): top + left both 0..15, spec-derived
        corner expectations pred[0][0] = 1 and pred[15][15] = 31.
        The arithmetic chain (H = V = 400 → b = c = 31, a = 480)
        is fully hand-traced in the test comment so the expected
        values are auditable.

  - CMakeLists.txt — new test_intra_pred_16x16 binary; pure-CPU
    library, no daedalus_core dependency (same separation as the
    4x4 ref).

Verified on hertz:

  $ ./build/test_intra_pred_16x16
    Vertical (mode 0)              PASS
    Horizontal (mode 1)            PASS
    DC (mode 2)                    PASS
    Plane (mode 3, uniform)        PASS
    Plane (mode 3, gradient)       PASS (corners 1, 31)

  ALL Intra_16x16 mode references PASS

Plane mode being right first try is meaningful — H/V sums, b/c
slope shifts, and the a-baseline arithmetic have many sign / index
error opportunities.  The asymmetric gradient test would have caught
any of them; it didn't.

What this does NOT cover (still in the intra-pred backlog):
  - Intra_8x8 chroma (4 modes per H.264 §8.3.3).
  - Intra_8x8 luma (High profile, 9 modes per §8.3.2.1 + the 1-2-1
    smoothing pre-filter — distinct algorithm from Intra_4x4).
  - Neighbour-availability fallback for boundary MBs.
  - Dispatch wrappers (same architectural question as before — wait
    for decoder Stage 2a strategy decision).
2026-05-25 00:35:24 +02:00

168 lines
6.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Tests the 4 H.264 Intra_16x16 luma prediction modes against
* spec-derived expected patterns. Same layout as the 4x4 test:
* a buffer that holds the 16x16 output plus 1-pixel top/left
* context and 1-pixel top-left corner.
*
* row 0: [tl][t0..t15]
* row 1: [l0][output row 0]
* row 2: [l1][output row 1]
* ...
* row 16: [l15][output row 15]
*
* Buffer dimensions: 17 rows × 17 cols, total 289 bytes.
* dst (passed to the pred fns) points at row 1 col 1.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
extern void daedalus_h264_pred_16x16_vertical_ref(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_16x16_horizontal_ref(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_16x16_dc_ref(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_16x16_plane_ref(uint8_t *dst, ptrdiff_t stride);
#define STRIDE 17
#define ROWS 17
static void set_ctx(uint8_t buf[ROWS][STRIDE], int tl,
const int t[16], const int l[16])
{
for (int r = 0; r < ROWS; r++)
for (int c = 0; c < STRIDE; c++) buf[r][c] = 0xff;
buf[0][0] = (uint8_t) tl;
for (int c = 0; c < 16; c++) buf[0][1 + c] = (uint8_t) t[c];
for (int r = 0; r < 16; r++) buf[1 + r][0] = (uint8_t) l[r];
}
static int check(const uint8_t buf[ROWS][STRIDE], const char *name,
uint8_t (*expect_at)(int r, int c, void *), void *cookie)
{
int diff = 0;
int first_r = 0, first_c = 0, first_got = 0, first_exp = 0;
for (int r = 0; r < 16; r++) {
for (int c = 0; c < 16; c++) {
uint8_t got = buf[1 + r][1 + c];
uint8_t exp = expect_at(r, c, cookie);
if (got != exp) {
if (diff == 0) {
first_r = r; first_c = c;
first_got = got; first_exp = exp;
}
diff++;
}
}
}
if (diff == 0)
printf(" %-30s PASS\n", name);
else
printf(" %-30s FAIL (%d/256 wrong, first r=%d c=%d got=%u exp=%u)\n",
name, diff, first_r, first_c, first_got, first_exp);
return diff == 0 ? 0 : 1;
}
/* Expectation helpers for each mode. */
static uint8_t expect_uniform(int r, int c, void *cookie)
{ (void)r; (void)c; return *(uint8_t *)cookie; }
struct vertical_ctx { const int *t; };
static uint8_t expect_vertical(int r, int c, void *cookie)
{ (void)r; return (uint8_t) ((struct vertical_ctx *)cookie)->t[c]; }
struct horizontal_ctx { const int *l; };
static uint8_t expect_horizontal(int r, int c, void *cookie)
{ (void)c; return (uint8_t) ((struct horizontal_ctx *)cookie)->l[r]; }
int main(void)
{
int fail = 0;
/* --- Mode 0 Vertical: each col = top[col] --- */
{
uint8_t buf[ROWS][STRIDE];
int t[16], l[16];
for (int i = 0; i < 16; i++) { t[i] = 10 + i; l[i] = 0; }
set_ctx(buf, 0, t, l);
daedalus_h264_pred_16x16_vertical_ref(&buf[1][1], STRIDE);
struct vertical_ctx vc = { t };
fail |= check(buf, "Vertical (mode 0)", expect_vertical, &vc);
}
/* --- Mode 1 Horizontal: each row = left[row] --- */
{
uint8_t buf[ROWS][STRIDE];
int t[16] = {0}, l[16];
for (int i = 0; i < 16; i++) l[i] = 50 + i;
set_ctx(buf, 0, t, l);
daedalus_h264_pred_16x16_horizontal_ref(&buf[1][1], STRIDE);
struct horizontal_ctx hc = { l };
fail |= check(buf, "Horizontal (mode 1)", expect_horizontal, &hc);
}
/* --- Mode 2 DC: ((sum + 16) >> 5) --- */
/* All top = 2, all left = 6: sum = 32 + 96 = 128, +16 = 144,
* >>5 = 144/32 = 4. */
{
uint8_t buf[ROWS][STRIDE];
int t[16], l[16];
for (int i = 0; i < 16; i++) { t[i] = 2; l[i] = 6; }
set_ctx(buf, 99, t, l);
daedalus_h264_pred_16x16_dc_ref(&buf[1][1], STRIDE);
uint8_t exp_val = 4;
fail |= check(buf, "DC (mode 2)", expect_uniform, &exp_val);
}
/* --- Mode 3 Plane: uniform neighbours → uniform output --- */
/* H=V=0 when neighbours are uniform. a = 16*(p+p) = 32p.
* pred[y][x] = (32p + 0 + 0 + 16) >> 5 = (32p + 16) >> 5 = p
* (exact integer for any p, since 32p/32 = p and +16/32 = 0).
* Verifies the orientation-free portion of the formula. */
{
uint8_t buf[ROWS][STRIDE];
int t[16], l[16];
for (int i = 0; i < 16; i++) { t[i] = 100; l[i] = 100; }
set_ctx(buf, 100, t, l); /* uniform tl too — H/V sums actually zero */
daedalus_h264_pred_16x16_plane_ref(&buf[1][1], STRIDE);
uint8_t exp_val = 100;
fail |= check(buf, "Plane (mode 3, uniform)", expect_uniform, &exp_val);
}
/* --- Mode 3 Plane: gradient sanity ---
* Top row = 0..15 (gradient), left col = 0..15, tl = 0.
* H = sum_{i=0..7} (i+1) * (t[8+i] - t[6-i] for i<7; or t[15]-tl=15 for i=7)
* = 1*(8-6) + 2*(9-5) + 3*(10-4) + 4*(11-3) + 5*(12-2) + 6*(13-1)
* + 7*(14-0) + 8*(15-0)
* = 2 + 8 + 18 + 32 + 50 + 72 + 98 + 120 = 400
* V = same shape on left col = 400
* b = (5*400 + 32) >> 6 = 2032 >> 6 = 31
* c = (5*400 + 32) >> 6 = 31
* a = 16 * (l[15] + t[15]) = 16 * (15 + 15) = 480
* pred[0][0] = (480 + 31*(-7) + 31*(-7) + 16) >> 5
* = (480 - 217 - 217 + 16) >> 5
* = 62 >> 5 = 1
* pred[15][15] = (480 + 31*8 + 31*8 + 16) >> 5
* = (480 + 248 + 248 + 16) >> 5
* = 992 >> 5 = 31
* Just spot-check those two corners. */
{
uint8_t buf[ROWS][STRIDE];
int t[16], l[16];
for (int i = 0; i < 16; i++) { t[i] = i; l[i] = i; }
set_ctx(buf, 0, t, l);
daedalus_h264_pred_16x16_plane_ref(&buf[1][1], STRIDE);
uint8_t tl_actual = buf[1 + 0][1 + 0];
uint8_t br_actual = buf[1 + 15][1 + 15];
int spot_fail = 0;
if (tl_actual != 1) { fprintf(stderr, "Plane gradient pred[0][0] = %u, expected 1\n", tl_actual); spot_fail = 1; }
if (br_actual != 31) { fprintf(stderr, "Plane gradient pred[15][15] = %u, expected 31\n", br_actual); spot_fail = 1; }
if (!spot_fail) printf(" %-30s PASS (corners 1, 31)\n", "Plane (mode 3, gradient)");
else printf(" %-30s FAIL\n", "Plane (mode 3, gradient)");
fail |= spot_fail;
}
if (fail == 0) printf("\nALL Intra_16x16 mode references PASS\n");
else fprintf(stderr, "\n%d test(s) FAILED\n", fail);
return fail ? 1 : 0;
}