Architecture locked: implement H.265 SPS parser in backend by
vendoring GStreamer's gst-plugins-bad/codecparsers/gsth265parser.c
directly (B1 per operator decision 2026-05-16). Drop GLib deps,
preserve LGPL header + upstream function names (gst_h265_parser_*),
add README note pinning vendored revision.
Header strategy: runtime-optional V4L2 control probe (no #ifndef
shim, per GStreamer pattern). Compile-time CID + struct defs in a
new internal header src/hevc-ctrls/v4l2-hevc-ext-controls.h
mirroring fresnel iter25 precedent.
8 success criteria for iter2:
C1 — decode completes, 1440 frames
C2 — HW path engaged (ioctl trace shows new CID writes)
C3 — frame 0 byte-identical vs SW reference
C4 — frame 720 SSIM Y in H.264-drift territory, no fixed threshold
C5 — FPS N=3 with sigma, no fixed threshold
C6 — dmesg clean, no rkvdec_hevc_prepare_hw_st_rps OOPS
C7 — firefox-fourier vendor-default HEVC engagement (now possible
with SDDM auto-login configured; not iter2-blocking)
C8 — regression check: ampere-fourier iter1's 3-codec baseline
still passes C1-C6 per iter1 per-codec floors
4 falsifier branches with explicit loopback edges (F1: HEVC still
OOPSes -> re-open ka#11; F2: garbage output -> parser bisect;
F3: regression -> per-driver-kind gate; F4: license issue -> revisit).
Ready for iter2 Phase 2 situation analysis.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
7.3 KiB
Phase 1 — iter2 goal formulation (HEVC backend EXT_SPS_*_RPS extension)
Locked 2026-05-16, post-Phase-0-update with upstream-survey resolution.
Iter2 goal (one sentence)
Extend libva-v4l2-request-fourier to populate V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS and _LT_RPS for VDPU381/VDPU383 HEVC, by vendoring GStreamer's gst-plugins-bad/codecparsers/gsth265parser.c (dropping GLib deps), and using a runtime-optional control probe so the same backend binary works against both 7.0-and-later kernels (HEVC engages) and earlier kernels (HEVC falls back to whatever the pre-7.0 path did) — until ampere HEVC HW decode passes the ampere-fourier iter1 C1-C6 success criteria per the per-codec floors, with HEVC SSIM-Y-at-f720 expected in H.264-drift territory (~0.65 ± 0.05).
Resolved Phase 0 open questions
- Q1 (architecture): B — implement H.265 SPS parser in backend, mirroring GStreamer's
gst_v4l2_codec_h265_dec_fill_ext_sps_rps. - Q2 (UAPI shim vs bump): header strategy is runtime-optional control probe (no
#ifndefshim), per GStreamer's pattern. Compile-time CID + struct definitions: ship a minimal internal header atsrc/hevc-ctrls/v4l2-hevc-ext-controls.h(the new file matches the precedent of fresnel iter25's image_fmt shim approach — minimal, scope-tagged to what the new UAPI added in 7.0). The headers package on ampere stays at 6.19-1; nopacman -Syuneeded. - Parser source sub-question: B1 — vendor GStreamer's
gsth265parser.cdirectly. Operator-confirmed 2026-05-16.
Vendoring spec for the GStreamer parser
- Source:
gitlab.freedesktop.org/gstreamer/gstreamer→subprojects/gst-plugins-bad/codecparsers/gsth265parser.c+ companion header. Take the version that landed alongside or after MR !10820 (GStreamer 1.28). - Target location in backend:
src/h265_parser.{c,h}ORsrc/gsth265parser/{gsth265parser.c, gsth265parser.h}— TBD in Phase 4 (file-naming detail; the vendored content itself is licence-pinned by upstream's LGPL header which we preserve). - License: file keeps GStreamer's LGPL header (authorship + source URL preserved). Backend's existing COPYING.LGPL covers redistribution. MIT remains for the rest of the backend. Add a top-level note in
README.mdlisting the vendored file as an LGPL-licensed third-party component. - GLib dependency removal: replace
GArraywith plain dynamically-sized C arrays (size + pointer); replaceg_slice_*/g_mallocwith libcmalloc/free; replaceGstBitReaderwith the backend's ownbit_reader.{c,h}style (or a vendored copy if backend lacks one — check during Phase 2). - Function-name namespace: keep
gst_h265_parser_*for the vendored functions (don't rename — that breaks the upstream-bug-fix-sync we're paying for by vendoring). The backend's call sites use the GStreamer names directly. - Tracking upstream: README note pinning the vendored revision (sha + tag); when GStreamer ships a parser fix, the backend pulls it manually (no submodule machinery in this iteration).
Success criteria
For HEVC, mirroring ampere-fourier iter1's C1-C6 with per-codec-floor refinement:
| # | Criterion | Phase 3 instrument | Phase 7 anchor |
|---|---|---|---|
| C1 | HEVC libva HW decode runs to completion on bbb_60s_720p.hevc.mp4, exit 0, frame count = 1440 frames |
ffmpeg -benchmark -hwaccel vaapi -hwaccel_output_format vaapi -i $clip -vf hwdownload,format=nv12 -f null -; frame= count |
post-iter2 patch installed |
| C2 | HW path engaged via ioctl trace; new MEDIA_REQUEST_IOC_QUEUE count includes the EXT_SPS_*_RPS controls (i.e. higher per-frame ioctl count vs ampere-fourier iter1's H.264 baseline) |
strace -ff -e trace=ioctl -p $PID; count VIDIOC_S_EXT_CTRLS invocations involving the new CID values |
iter1 H.264 ioctl counts as reference history |
| C3 | HEVC frame 0 byte-identical vs ffmpeg SW reference (HEVC I-frame, no inter-prediction) | cmp of 1 382 400 bytes (one 720p yuv420p frame) |
iter1 all-codec sha 3214803d8be74416 |
| C4 | HEVC frame 720 (t=30 s) SSIM Y in H.264-drift territory (~0.65 ± 0.05); no fixed PASS threshold | ffmpeg -lavfi "[0:v][1:v]ssim" at frame 720 |
fresnel iter1 HEVC SSIM Y was 1.000 (byte-identical) on RK3399 — does NOT carry as anchor; ampere RK3588 may behave differently. Track and accept whatever drift territory shows up; if it's surprising (way better OR worse than ~0.65 ± 0.05), Phase 7 surfaces it for Phase 4 plan refinement |
| C5 | HEVC FPS reported at N=3 with σ; mean within an order of magnitude of iter1's H.264 461 FPS / VP8 217 FPS / MPEG-2 200 FPS (all 8x-20x realtime). No fixed threshold | wall-time around ffmpeg; mean + σ |
iter1 numbers as reference history only |
| C6 | dmesg clean across the full sweep — specifically no OOPS in rkvdec_hevc_prepare_hw_st_rps or related |
diff pre vs post dmesg --time-format=ctime |
iter1 empty diff |
| C7 | (carried over from iter1, was deferred) firefox-fourier vendor-default HEVC engagement — now testable since SDDM auto-login was set up post-iter1 | empty-profile sweep, count Got VA-API DMABufSurface for HEVC autoplay |
optional — capture if rig allows but not iter2-blocking |
| C8 | regression check — ampere-fourier iter1's 3-codec baseline (H.264, VP8, MPEG-2) still passes C1-C6 per iter1 per-codec floors | re-run ~/measurements/p3_*.sh post-patch |
iter1 numbers verbatim |
Hypothesis
With the vendored GStreamer parser + EXT_SPS_*_RPS control population:
- C1-C3, C5-C6, C8 pass
- C4 falls in H.264-drift territory (~0.65 ± 0.05) per fresnel + ampere iter1 convergent observations — RK3588 rkvdec is conformant within H.265 spec tolerance but not bit-identical to libavcodec SW
- C7 passes if rig (auto-login Wayland session) holds at test time
Hypothesis falsifiers (loopback edges)
- F1: HEVC decode still OOPSes despite the new controls being set with valid GStreamer-parser data → loopback Phase 0 with re-opened
kernel-agent#11. Mechanism is something other than UAPI-gap; needs deeper kernel-side debugging. - F2: HEVC decode succeeds (no OOPS) but produces garbage output (C3 fails — frame 0 not byte-identical) → loopback Phase 4. The parser is producing wrong field values; bisect against GStreamer's reference output or FFmpeg's WIP equivalent on the same clip.
- F3: HEVC decode succeeds and produces clean output but ampere-fourier iter1 regression (C8 fails) → loopback Phase 4. The patch is touching shared HEVC code in a way Phase 5 review didn't catch (e.g. unconditional control submission breaks RK3399 path). Per-driver gate via
driver_data->driver_kindperfeedback_per_driver_kludge_gating. - F4: Parser vendoring hits LGPL/MIT/license compatibility issues at distribution time → not a code falsifier; revisit at Phase 6 with the operator if it surfaces.
Out of iter2
- VP9 — that's iter3.
- AV1 — that's
libva-v4l2-request-fourier#2outside this meta-campaign. - Kernel-side defense-in-depth NULL/uninit guard for
rkvdec_hevc_prepare_hw_st_rps— upstream-defense work, optional follow-up issue against kernel-agent or directly upstream. - IOMMU restore patch verification (Phase 0 open Q4) — passive substrate check during iter2 Phase 2.
Phase 1 close
Goal, eight success criteria (C1-C8), four falsifier paths. Parser-source decision locked. Ready for iter2 Phase 2 (situation analysis + reset-context).