Files
daedalus-fourier/tests/test_intra_pred_chroma8x8.c
T
claude-noether cb3aef3dac h264: promote remaining intra prediction modes (17) to public API
Follows PR #26 (Intra_4x4 luma) with the same promotion pattern for
the rest of the intra prediction primitive set:

  Intra_16x16 luma   (4 modes, PR #13) — V/H/DC/Plane
  Intra_8x8  chroma  (4 modes, PR #14) — DC/H/V/Plane (4:2:0)
  Intra_8x8  luma    (9 modes, PRs #21 + #22) — High profile,
                                                 with 1-2-1 pre-filter

3 file moves via `git mv`, ~17 function renames stripping the `_ref`
suffix.  Test binaries rewired to link daedalus_core instead of
compiling the (now moved) ref files directly.  No code change — pure
plumbing for substitution-arc consumers.

26 intra prediction modes total now in the public API after this PR.

Verified on hertz:

  test_intra_pred_16x16:    5/5  PASS
  test_intra_pred_chroma8x8: 5/5  PASS
  test_intra_pred_8x8_luma: 11/11 PASS

All via public symbols (test binaries linked against daedalus_core).

Unblocks marfrit-packages substitution arc patch 0014 — wires
H264PredContext.pred4x4[], pred16x16[], pred8x8[], pred8x8l[]
through daedalus alongside the existing IDCT / deblock / qpel / DC
Hadamard substitutions.

After 0014 lands, the libavcodec.so built by marfrit-packages will
have EVERY hot-path pixel-math kernel of an H.264 8-bit 4:2:0
decode routing through daedalus — the substitution arc is feature-
complete for the campaign target (Pi 5 Firefox YouTube playback).
2026-05-25 15:37:44 +02:00

171 lines
6.3 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_8x8 chroma prediction modes against
* spec-derived expected patterns. Same buffer layout idea as the
* other intra tests: a buffer that holds the 8x8 output + 1-pixel
* top/left context + 1-pixel top-left corner.
*
* row 0: [tl][t0..t7]
* row 1: [l0][output row 0]
* ...
* row 8: [l7][output row 7]
*
* Dimensions: 9 rows × 9 cols. dst (passed to pred fns) = &buf[1][1].
*/
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
extern void daedalus_h264_pred_chroma8x8_dc(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_chroma8x8_horizontal(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_chroma8x8_vertical(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_chroma8x8_plane(uint8_t *dst, ptrdiff_t stride);
#define STRIDE 9
#define ROWS 9
static void set_ctx(uint8_t buf[ROWS][STRIDE], int tl,
const int t[8], const int l[8])
{
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 < 8; c++) buf[0][1 + c] = (uint8_t) t[c];
for (int r = 0; r < 8; r++) buf[1 + r][0] = (uint8_t) l[r];
}
static int check_per_cell(const uint8_t buf[ROWS][STRIDE], const char *name,
const uint8_t expect[8][8])
{
int diff = 0;
int first_r = 0, first_c = 0, first_got = 0, first_exp = 0;
for (int r = 0; r < 8; r++) {
for (int c = 0; c < 8; c++) {
uint8_t got = buf[1 + r][1 + c];
uint8_t exp = expect[r][c];
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/64 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;
}
int main(void)
{
int fail = 0;
/* --- Mode 1 Horizontal --- */
{
uint8_t buf[ROWS][STRIDE];
int t[8] = {0}, l[8] = {10, 20, 30, 40, 50, 60, 70, 80};
set_ctx(buf, 0, t, l);
daedalus_h264_pred_chroma8x8_horizontal(&buf[1][1], STRIDE);
uint8_t exp[8][8];
for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) exp[r][c] = (uint8_t) l[r];
fail |= check_per_cell(buf, "Horizontal (mode 1)", exp);
}
/* --- Mode 2 Vertical --- */
{
uint8_t buf[ROWS][STRIDE];
int t[8] = {15, 25, 35, 45, 55, 65, 75, 85}, l[8] = {0};
set_ctx(buf, 0, t, l);
daedalus_h264_pred_chroma8x8_vertical(&buf[1][1], STRIDE);
uint8_t exp[8][8];
for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) exp[r][c] = (uint8_t) t[c];
fail |= check_per_cell(buf, "Vertical (mode 2)", exp);
}
/* --- Mode 0 DC: per-quadrant. Test with distinct halves so any
* quadrant mix-up surfaces immediately.
*
* top[0..3] = 4 × 8 → sum_top_lo = 32
* top[4..7] = 4 × 16 → sum_top_hi = 64
* left[0..3] = 4 × 24 → sum_left_lo = 96
* left[4..7] = 4 × 40 → sum_left_hi = 160
*
* dc00 = (32 + 96 + 4) >> 3 = 132/8 = 16
* dc01 = (64 + 2) >> 2 = 66/4 = 16
* dc10 = ( 160 + 2) >> 2 = 162/4 = 40
* dc11 = (64 + 160 + 4) >> 3 = 228/8 = 28
*/
{
uint8_t buf[ROWS][STRIDE];
int t[8] = { 8, 8, 8, 8, 16, 16, 16, 16 };
int l[8] = { 24, 24, 24, 24, 40, 40, 40, 40 };
set_ctx(buf, 99, t, l);
daedalus_h264_pred_chroma8x8_dc(&buf[1][1], STRIDE);
uint8_t exp[8][8] = {
{16,16,16,16, 16,16,16,16},
{16,16,16,16, 16,16,16,16},
{16,16,16,16, 16,16,16,16},
{16,16,16,16, 16,16,16,16},
{40,40,40,40, 28,28,28,28},
{40,40,40,40, 28,28,28,28},
{40,40,40,40, 28,28,28,28},
{40,40,40,40, 28,28,28,28},
};
fail |= check_per_cell(buf, "DC quadrants (mode 0)", exp);
}
/* --- Mode 3 Plane (uniform): H = V = 0; a = 16 * (100 + 100) = 3200.
* pred[y][x] = (3200 + 0 + 0 + 16) >> 5 = 3216 >> 5 = 100. */
{
uint8_t buf[ROWS][STRIDE];
int t[8], l[8];
for (int i = 0; i < 8; i++) { t[i] = 100; l[i] = 100; }
set_ctx(buf, 100, t, l);
daedalus_h264_pred_chroma8x8_plane(&buf[1][1], STRIDE);
uint8_t exp[8][8];
for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) exp[r][c] = 100;
fail |= check_per_cell(buf, "Plane uniform (mode 3)", exp);
}
/* --- Mode 3 Plane gradient sanity ---
* t = 0..7, l = 0..7, tl = 0.
* H = 1*(t[4]-t[2]) + 2*(t[5]-t[1]) + 3*(t[6]-t[0]) + 4*(t[7]-tl)
* = 1*(4-2) + 2*(5-1) + 3*(6-0) + 4*(7-0)
* = 2 + 8 + 18 + 28 = 56
* V = same shape on left = 56
* b = (34*56 + 32) >> 6 = 1936 >> 6 = 30
* c = 30
* a = 16 * (l[7] + t[7]) = 16 * (7 + 7) = 224
*
* pred[0][0] = (224 + 30*(-3) + 30*(-3) + 16) >> 5
* = (224 - 90 - 90 + 16) >> 5
* = 60 >> 5 = 1
* pred[7][7] = (224 + 30*4 + 30*4 + 16) >> 5
* = (224 + 120 + 120 + 16) >> 5
* = 480 >> 5 = 15
* Spot-check those two corners. */
{
uint8_t buf[ROWS][STRIDE];
int t[8], l[8];
for (int i = 0; i < 8; i++) { t[i] = i; l[i] = i; }
set_ctx(buf, 0, t, l);
daedalus_h264_pred_chroma8x8_plane(&buf[1][1], STRIDE);
uint8_t tl_actual = buf[1 + 0][1 + 0];
uint8_t br_actual = buf[1 + 7][1 + 7];
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 != 15) { fprintf(stderr, "Plane gradient pred[7][7] = %u, expected 15\n", br_actual); spot_fail = 1; }
if (!spot_fail) printf(" %-30s PASS (corners 1, 15)\n", "Plane gradient (mode 3)");
else printf(" %-30s FAIL\n", "Plane gradient (mode 3)");
fail |= spot_fail;
}
if (fail == 0) printf("\nALL Intra_8x8 chroma mode references PASS\n");
else fprintf(stderr, "\n%d test(s) FAILED\n", fail);
return fail ? 1 : 0;
}