Files
fresnel-fourier/phase0_evidence/2026-05-07/test_fixtures.md
T
claude-noether b74551bc56 phase 0 close: deliverables 5 + 6 — fixtures + cross-validator anchor
Closes Phase 0 for fresnel-fourier. Per-codec test fixtures and
cross-validator contract traces complete the campaign-locked
boolean-correctness baseline.

Deliverable #5 — per-codec test fixtures (test_fixtures.md):

Generated 4 new fixtures on fresnel from the bbb_1080p30_h264.mp4
master via stock ffmpeg (libx265 ultrafast, libvpx-vp9 speed 5,
mpeg2video, libvpx vp8). All 720p 10s 8-bit yuv420p — matching the
silicon-supported profile/pixfmt for each codec on RK3399:

  bbb_720p10s_hevc.mp4   620 KB  (HEVC Main, rkvdec target)
  bbb_720p10s_vp9.webm   3.4 MB  (VP9 Profile 0, rkvdec target)
  bbb_720p10s_mpeg2.ts   5.3 MB  (MPEG-2 Main, hantro-vpu-dec target)
  bbb_720p10s_vp8.webm   2.4 MB  (VP8, hantro-vpu-dec target)

Encode wall times on fresnel: HEVC 13s, VP9 93s, MPEG-2 6s, VP8 26s.
H.264 master is 725 MB carryover from libva-multiplanar / fourier_attribution.

Deliverable #6 — cross-validator anchor (cross_validator_traces.md):

phase0_findings.md named chromium-fourier 149 as the cross-validator;
that package isn't installed on fresnel and marfrit-packages isn't
configured (no auto-install path tonight). Substituted ffmpeg
-hwaccel v4l2request as a better-fit cross-validator: it's an
independent V4L2 client (uses no libva at all, lives in
libavcodec/v4l2_request*.c), already on the box (stock
ffmpeg n8.1-13-gb57fbbe50c, the Kwiboo v4l2-request-n8.1 branch),
and implements all 5 codecs the campaign locked.

Headline finding: ALL 5 CODECS WORK end-to-end via the kernel
direct path on RK3399.

  ffmpeg -hwaccel v4l2request -i bbb_<codec>.<ext> -frames:v 2 -f null -
  H.264:  exit 0
  HEVC:   exit 0
  VP9:    exit 0
  MPEG-2: exit 0
  VP8:    exit 0

The Linux kernel + rkvdec + hantro-vpu drivers are solid for the
entire campaign codec scope. Phase 6 work scope is purely libva-
backend code — no kernel patches, no upstream Linux engagement.

Per-codec libva (iter8) vs ffmpeg-v4l2request status sweep:

  H.264   libva: PASS (T4 PASS + bit-exact pixel verify) | ffmpeg-v4l2req: PASS
  HEVC    libva: vaCreateConfig=12 (UNSUPPORTED_PROFILE) | ffmpeg-v4l2req: PASS
          → src/h265.c is excluded in src/meson.build but src/config.c:151
            enumerates HEVCMain via V4L2_PIX_FMT_HEVC_SLICE probe;
            vaCreateConfig fails downstream of the case match.
  VP9     libva: profile not enumerated                  | ffmpeg-v4l2req: PASS
          → no vp9.c in fork
  MPEG-2  libva: vaCreateConfig=12 (UNSUPPORTED_PROFILE) | ffmpeg-v4l2req: PASS
          → mpeg2.c IS compiled, config.c:64-65 has the case statements,
            yet vaCreateConfig rejects. Phase 2 source-read needed.
  VP8     libva: profile not enumerated                  | ffmpeg-v4l2req: PASS
          → no vp8.c in fork

Suggested Phase 6 iteration order (subject to Phase 1 lock):
  iter1: MPEG-2 — likely cheapest (config.c-level path; mpeg2.c
                  already compiled)
  iter2: HEVC   — re-enable h265.c in build, audit against rkvdec
  iter3: VP8    — implement vp8.c on hantro
  iter4: VP9    — implement vp9.c on rkvdec (largest control surface)

Per-codec ioctl frequency anchor (2-frame ffmpeg -hwaccel v4l2request):

  ioctl                  H.264 HEVC  VP9  MPEG-2 VP8
  VIDIOC_DQBUF              45   49   40    26   49
  VIDIOC_QBUF               22   24   20    10   20
  VIDIOC_CREATE_BUFS        17   17   17    12   17
  VIDIOC_QUERYBUF           15   15   15    10   15
  VIDIOC_S_EXT_CTRLS        13   14   11     5   10
  VIDIOC_EXPBUF             11   11   11     6   11
  VIDIOC_QUERY_EXT_CTRL      0    5    0     0    0
  MEDIA_IOC_REQUEST_ALLOC    4    4    4     4    4
  DMA_BUF_IOCTL_SYNC         0    0    0     4    0
  MEDIA_REQUEST_IOC_REINIT   0    0    0     0    3

Architectural divergence ffmpeg-v4l2request vs libva-v4l2-request-fourier:

  - ffmpeg uses VIDIOC_EXPBUF + DMA-BUF for downstream readback.
    Our libva backend uses cached mmap via vaDeriveImage — the
    iter1 patch-0011 cache-stale bug class. Phase 4 work item
    consistent with T4's finding: adding VIDIOC_EXPBUF + DMA-BUF-
    backed image export to the libva backend would fix the
    cache-coherency issue identified in T4's H.264 readback.
  - ffmpeg uses 4 request_fds pooled. Our backend uses 16 (iter6
    per-OUTPUT-slot binding). Both valid; different pool depth.
  - HEVC alone needs VIDIOC_QUERY_EXT_CTRL for hevc_slice_params
    dynamic-array introspection — unique among the 5 codecs.

Substrate change deferred (not a Phase 0 blocker): chromium-fourier
149 install on fresnel is Phase 1+ work. When done, a follow-up
trace pass per codec will cross-check ffmpeg-v4l2request and
chromium contracts. For Phase 0 baseline, ffmpeg-v4l2request is
the anchor.

Phase 0 fully closed. Six deliverables landed. Phase 1 lock can proceed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:52:21 +00:00

7.1 KiB
Raw Blame History

Per-codec test fixtures — fresnel 2026-05-07

Phase 0 deliverable #5. Fixtures for the five locked codecs (H.264 + HEVC + VP9 + MPEG-2 + VP8), all derived from the same Big Buck Bunny H.264 master, generated on fresnel with stock ffmpeg n8.1-13.

Inventory

All fixtures live at ~/fourier-test/ on fresnel. Same path on ohm (carryover convention from libva-multiplanar). H.264 master mirrored on both hosts.

Codec File Size Profile/Level Resolution Pix fmt Duration Targets V4L2 device
H.264 bbb_1080p30_h264.mp4 (carryover) 725 MB High@4.0 1920×1080 yuv420p 596 s rkvdec /dev/video3 (S264)
HEVC bbb_720p10s_hevc.mp4 620 KB Main 8-bit 1280×720 yuv420p 10 s rkvdec /dev/video3 (S265)
VP9 bbb_720p10s_vp9.webm 3.4 MB Profile 0 (8-bit 4:2:0) 1280×720 yuv420p 10 s rkvdec /dev/video3 (VP9F)
MPEG-2 bbb_720p10s_mpeg2.ts 5.3 MB Main 1280×720 yuv420p 10 s hantro-vpu-dec /dev/video5 (MG2S)
VP8 bbb_720p10s_vp8.webm 2.4 MB Profile 0 1280×720 yuv420p 10 s hantro-vpu-dec /dev/video5 (VP8F)

Codec scope alignment (per phase0_findings.md LOCK + 2026-05-07 evening corrections):

  • rkvdec: 8-bit Main HEVC (silicon doesn't do 10-bit reliably; rkvdec advertises Main 10 in its menu but RK3399 hardware support is unverified — 8-bit fixture stays in the "expected to work" lane).
  • rkvdec: VP9 Profile 0 only (kernel menu shows vp9_profile min=0 max=0 default=0 — no other profile is enumerable).
  • hantro-vpu-dec: MPEG-2 Main (per kernel hantro_mpeg2.c).
  • hantro-vpu-dec: VP8 (single profile, no menu).

Generation provenance

All four non-H.264 fixtures generated on fresnel 2026-05-07 23:3423:36 CEST from the H.264 master via stock ffmpeg software encoders:

INPUT=~/fourier-test/bbb_1080p30_h264.mp4

# HEVC Main 8-bit, 720p, 10s seek-30s, x265 ultrafast
ffmpeg -y -ss 30 -t 10 -i "$INPUT" \
  -vf scale=1280:720 -c:v libx265 -preset ultrafast -crf 28 \
  -profile:v main -pix_fmt yuv420p -tag:v hvc1 -an \
  ~/fourier-test/bbb_720p10s_hevc.mp4

# VP9 Profile 0, 720p, 10s, libvpx-vp9 speed 5 with row-mt
ffmpeg -y -ss 30 -t 10 -i "$INPUT" \
  -vf scale=1280:720 -c:v libvpx-vp9 -speed 5 -row-mt 1 \
  -profile:v 0 -pix_fmt yuv420p -an -b:v 2M \
  ~/fourier-test/bbb_720p10s_vp9.webm

# MPEG-2 Main, 720p, 10s, transport stream container
ffmpeg -y -ss 30 -t 10 -i "$INPUT" \
  -vf scale=1280:720 -c:v mpeg2video -profile:v 4 -level:v 8 \
  -b:v 4M -pix_fmt yuv420p -an \
  ~/fourier-test/bbb_720p10s_mpeg2.ts

# VP8, 720p, 10s, libvpx
ffmpeg -y -ss 30 -t 10 -i "$INPUT" \
  -vf scale=1280:720 -c:v libvpx -deadline good -cpu-used 4 \
  -pix_fmt yuv420p -an -b:v 2M \
  ~/fourier-test/bbb_720p10s_vp8.webm

Wall-clock encode times on fresnel RK3399:

Codec Wall User CPU Notes
HEVC 13.4 s 66.6 s x265 ultrafast across 5 of 6 cores
VP9 93.4 s 278.3 s libvpx-vp9 -speed 5 -row-mt 1, 3-core utilization
MPEG-2 5.95 s 24.5 s mpeg2video, lightweight
VP8 26.4 s 108.4 s libvpx -cpu-used 4, 4-core utilization

Reproducible: re-run the four ffmpeg invocations above; outputs should hash-match modulo encoder-version non-determinism (libx265/libvpx don't always produce bit-exact identical encodes across runs even with identical flags).

Why 720p / 10s

  • 720p matches the second-most-common consumer playback resolution (mpv, Firefox YouTube embed, Chromium WebRTC) without exhausting the 1080p H.264 master's encoded resolution (downscale, never upscale). Keeps encode time ≪ 2 minutes per codec on RK3399 SW encoders.
  • 10s = 240 frames at 24 fps. Long enough to see DPB activity, B-frame ordering (where applicable), reference-frame pumping, and any transient bug like iter4's frame-11 EINVAL on libva-multiplanar. Short enough for a contract trace's grep'ability.
  • 8-bit yuv420p matches the kernel's silicon support reality for all five codecs on RK3399.

Encoder choice rationale

  • libx265 ultrafast preset for HEVC: trades file size for encode wall-time. We don't care about quality (decode-side test, not encode-side); we care about a valid, parseable HEVC bitstream that exercises the rkvdec HEVC path.
  • libvpx-vp9 speed 5 for VP9: balanced — speed 6+ hurts conformance, speed 4 doubles the encode time.
  • mpeg2video profile 4 level 8 (Main, ML): the most generic compatibility target. RK3399 hantro accepts Simple and Main; Main covers both and is what's commonly streamed.
  • libvpx (vp8): stock libvpx, no speed tuning needed — VP8 is fast enough.

Phase 1+ may add additional fixtures: longer durations (60s+ for run-stability), higher resolutions (1080p HEVC for rkvdec stress), or additional source content (e.g., a low-motion test pattern, a high-motion sports clip). Keeping Phase 0 at the smallest set that exercises each codec's request-API contract on its assigned V4L2 node.

Verification

Each fixture probed via ffprobe -v error -show_entries stream=codec_name,profile,pix_fmt,width,height,r_frame_rate,duration:

File codec_name profile pix_fmt width×height fps duration
bbb_720p10s_hevc.mp4 hevc Main yuv420p 1280×720 24/1 10.000000
bbb_720p10s_vp9.webm vp9 Profile 0 yuv420p 1280×720 24/1 N/A (live-stream container)
bbb_720p10s_mpeg2.ts mpeg2video Main yuv420p 1280×720 24/1 10.000000
bbb_720p10s_vp8.webm vp8 0 yuv420p 1280×720 24/1 N/A (live-stream container)

Profile/pix_fmt match the campaign codec scope. Phase 1 binding cells per codec can use these directly.

Open future-fixture items (not Phase 0 gating)

  • Test patterns for synthetic decode-correctness checks (constant-color frames, gradient ramps, single-pixel motion). Useful for bit-exact verification beyond JPEG-of-real-content. Not generated yet; Phase 1 work item.
  • Long-duration variants (60s, 5min) for run-stability / leak detection. iter7's slot-leak fix is in iter8 master so this should be clean, but a long-run trace would prove it on RK3399.
  • Stress fixtures: 1080p HEVC, 1080p VP9, complex motion. Defer until basic boolean-correctness lands per codec.
  • chromium-fourier 149 reference clips if the cross-validator engages a different fixture format (e.g., MSE/EME-encrypted clip for DRM-path validation). Not in Phase 0 scope.

Storage / mirroring

  • ~/fourier-test/ on fresnel is the working location.
  • Mirror to data:/moviedata/fourier-test/ for fleet-wide availability — pending; data is currently offline (no route to host as of 2026-05-07 22:34). Wake via the his cheatsheet (Fritz!DECT plug or WoL) when the next iteration needs cross-host fixtures.
  • ~/fourier-test/ on ohm holds the H.264 master; ohm doesn't yet have the new per-codec clips. Decision deferred — fresnel-fourier is the campaign that needs them; ohm is the libva-multiplanar testbed (already H.264-only-locked at iter5+).

The fixtures are gitignored as binary content (*.mp4, *.webm, *.ts are treated as raw data; not in phase*_evidence/ extension allow-list). They live on fresnel; this document is the canonical inventory.