Files
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

109 lines
7.1 KiB
Markdown
Raw Permalink 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.
# 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:
```bash
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.