Files
fresnel-fourier/phase0_findings_iter2.md
claude-noether 6e8c970c1d iter2 Phase 0 + Phase 1 lock: HEVC Main on rkvdec
Iteration 2 of the campaign 8(+1)-phase loop opens following iter1
close (dc69378). Per phase0_evidence/2026-05-07/cross_validator_
traces.md suggested ordering, iter2 attacks HEVC Main on rkvdec —
the kernel + driver path is verified working (cross-validator sweep
exit 0); broken link is the libva backend at five distinct sites:

  src/config.c HEVCMain case fall-through (analogous to iter1 Bug 1)
  src/picture.c HEVCMain explicit UNSUPPORTED_PROFILE reject (NEW)
  src/h265.c uncompiled in build (presumably staging-era CIDs;
              Phase 2 source-read decides scope of rewrite)
  include/hevc-ctrls.h staging-era local header (deferred from
              iter1 Phase 5 Nit 6; iter2 closes the loop)
  src/meson.build h265.c commented out (re-enable)

Plus possible novel issues vs iter1's MPEG-2 work:
  - HEVC has 10 stateless control IDs vs MPEG-2's 3 (much larger
    rewrite if h265.c uses staging-era API)
  - HEVC slice_params is dynamic-array (kernel rkvdec accepts up
    to 600 entries) — different submission shape vs MPEG-2 single-
    struct or H.264 fixed-shape
  - HEVC SCALING_MATRIX is conditional (only when scaling_list_
    enabled in SPS); mapping VAIQMatrixBufferHEVC to V4L2 control
  - HEVC ENTRY_POINT_OFFSETS is in kernel surface (tile/slice
    resync) but campaign fixture doesn't use tiles — defer

Locked research question:

  Make HEVC Main the third codec to pass boolean-correctness on
  fresnel via libva-v4l2-request-fourier — mpv --hwdec=vaapi
  bbb_720p10s_hevc.mp4 engages backend cleanly and DMA-BUF GL
  import yields HW pixels byte-identical to SW reference for the
  same frames.

Phase 1 success criterion (5 boolean checks, all must pass):

  1. vainfo enumerates VAProfileHEVCMain on rkvdec env binding
     (regression check; already passes today).
  2. vaCreateConfig(VAProfileHEVCMain, VLD) returns VA_STATUS_
     SUCCESS. (Pre-iter2: VA_STATUS_ERROR_UNSUPPORTED_PROFILE.)
  3. ffmpeg -hwaccel vaapi -i bbb_720p10s_hevc.mp4 -frames:v 5
     -f null - exits 0 cleanly with no Failed-to-create-decode-
     configuration lines and no S_EXT_CTRLS EINVAL on HEVC
     controls. (Phase 1 criterion 3 anchored on ffmpeg-direct,
     mirroring iter1 Phase 5 Q4 amendment for codecs mpv may
     filter out.)
  4. mpv --hwdec=vaapi --vo=image at +02s seek: 2 distinct frames
     hash-equal to SW reference, hash-differ from each other (real
     motion). DMA-BUF GL import path per memory feedback_rockchip_
     pixel_verify_path.md (NOT ffmpeg-vaapi+hwdownload, which is
     cache-stale on RK3399 for both H.264 and MPEG-2 per iter1
     Phase 6/7 findings).
  5. iter1 MPEG-2 + T4 H.264 reference hashes BOTH still match
     (regression check on prior-iteration cells):
       MPEG-2 +02s: HW1=6e7873030dbf...   HW2=ccc7ce08810d...
       H.264 +30s:  HW1=f623d5f7a416...   HW2=7d7bc6f2146d...

Substrate carry-over:

  - libva-v4l2-request-fourier master tip post-iter1-close
    (commits e7dad7a..229d6d1 stack on iter8 65969da).
  - bbb_720p10s_hevc.mp4 fixture (620 KB, HEVC Main, 1280x720,
    24fps, 10s, yuv420p; provenance phase0_evidence/2026-05-07/
    test_fixtures.md).
  - Cross-validator anchor: phase0_evidence/2026-05-07/
    cross_validator/hevc/ — 14 S_EXT_CTRLS + 5 QUERY_EXT_CTRL
    (HEVC slice_params dynamic-array introspection unique among
    the 5 codecs) + 4 REQUEST_ALLOC.
  - Memory carries forward: feedback_gitea_as_claude_noether,
    feedback_no_session_termination_attempts, feedback_header_
    deletion_check (iter1 lesson L1 — apply to hevc-ctrls.h
    deletion), feedback_review_empirical_over_theoretical
    (iter1 lesson L2 — apply to Phase 5 review responses),
    feedback_rockchip_pixel_verify_path (iter1 lesson L3 —
    DMA-BUF GL is the verifier, NOT cached-mmap).

Out-of-scope (LOCKED): VP9/VP8 (later iterations); HEVC Main 10
(silicon support unverified); HEVC Main Still Picture; performance
metrics; long-duration HEVC stress; tile / wavefront parallel
processing (ENTRY_POINT_OFFSETS); Phase 4 cross-cutting backlog
(B1 device-discovery, B3 BeginPicture profile-aware reset, B4
context.c log suppression, B5 vbv_buffer_size negotiation, L3
vaDeriveImage cache-stale fix); chromium-fourier 149 install;
src/context.c changes; upstream engagement.

Predecessor open questions:
  - iter1 B3 latent surface-reuse bug (picture.c:287
    h264.matrix_set=false hits union byte 240) — for HEVC, the
    union member is params.h265.{picture,slice,iqmatrix,
    iqmatrix_set}. params.h265 layout differs from params.mpeg2.
    Phase 2 source-read action item: verify whether byte 240 lands
    in a meaningful HEVC field. If so, iter2 may need to address
    even though MPEG-2 didn't.

Phase 2 source-read targets (queued for next phase):
  - src/h265.c (~267 lines) — current state, target API
  - src/picture.c:204-206 (the explicit HEVC reject)
  - src/config.c:55-69 (confirm HEVCMain fall-through)
  - src/surface.h:103-108 (params.h265 struct)
  - include/hevc-ctrls.h (staging-era; identify CID/struct refs)
  - src/meson.build (commented-out h265.c)
  - linux/v4l2-controls.h:2110+ (modern HEVC stateless UAPI)
  - drivers/staging/media/rkvdec/rkvdec_hevc.c (rkvdec contract)
  - libavcodec/v4l2_request_hevc.c (FFmpeg reference impl)
  - va/va_dec_hevc.h (VAAPI HEVC buffer structs)

Predicted iter2 close shape: similar pattern to iter1 (config
break + h265.c new-API rewrite + header delete + meson re-enable
+ picture.c reject removal). Larger code change than iter1
(predicting 250-400 lines for h265.c rewrite vs iter1's ~120 lines
for mpeg2.c). One novel construct (slice_params dynamic-array)
worth Phase 4 contract-clause-level attention. Expect Phase 6
takes longer than iter1; Phase 7 harness re-uses iter1's pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:44:30 +00:00

20 KiB
Raw Permalink Blame History

Iteration 2 — Phase 0 (substrate / motivation / inventory) → Phase 1 lock

Opens 2026-05-08 immediately after iter1 close (phase8_iteration1_close.md, commit dc69378). Per feedback_dev_process.md Phase 0, this document captures iter2's locked research question + substrate + scope, ending with the Phase 1 measurable success criterion.

Locked research question (iteration 2)

"Make HEVC Main the third codec to pass boolean-correctness on fresnel via the libva-v4l2-request-fourier path — mpv --hwdec=vaapi bbb_720p10s_hevc.mp4 engages the backend cleanly and DMA-BUF GL import yields HW pixels byte-identical to a software-decoded reference for the same frames."

Pass/fail (boolean):

  1. Profile enumeration regression check. vainfo with the rkvdec env binding (LIBVA_V4L2_REQUEST_VIDEO_PATH=/dev/video<N>, LIBVA_V4L2_REQUEST_MEDIA_PATH=/dev/media<M> where N/M are this-boot's rkvdec node numbers — see device-numbering caveat below) continues to list VAProfileHEVCMain. (The enumerator already advertises HEVCMain unconditionally on rkvdec, gated only by the V4L2 V4L2_PIX_FMT_HEVC_SLICE format probe; this exists to confirm iter2 work doesn't strip the enumeration.)
  2. Config creation succeeds. vaCreateConfig(VAProfileHEVCMain, VAEntrypointVLD) returns VA_STATUS_SUCCESS. (Today returns 12 = VA_STATUS_ERROR_UNSUPPORTED_PROFILE per phase0_evidence/2026-05-07/cross_validator_traces.md — same fall-through bug iter1 fixed for MPEG-2.)
  3. End-to-end decode engages the backend. ffmpeg -hwaccel vaapi -i ~/fourier-test/bbb_720p10s_hevc.mp4 -frames:v 5 -f null - (with rkvdec env binding) shows the libva chain in stderr, libva trace shows vaCreateConfig SUCCESS, no Failed to create decode configuration, no EINVAL from VIDIOC_S_EXT_CTRLS, exits 0. (Phase 1 criterion #3 wording is ffmpeg-direct, mirroring iter1 Phase 5 Q4 amendment — mpv --hwdec=vaapi-copy may also silently filter HEVC out before libva is loaded; ffmpeg-direct exercises the path. mpv-driven testing follows in criterion #4 via DMA-BUF GL.)
  4. Cache-safe pixel verification matches SW reference. mpv --hwdec=vaapi --vo=image --frames=2 --start=00:00:02 against bbb_720p10s_hevc.mp4 and the equivalent --hwdec=no SW run produce JPEGs whose sha256sum outputs match for both frame 1 and frame 2. Frames 1 and 2 must hash-differ between each other (real motion content, not solid color) AND hash-equal across HW vs SW. Per memory/feedback_rockchip_pixel_verify_path.md: DMA-BUF GL is the cache-coherency-safe verifier; do NOT use ffmpeg-vaapi+hwdownload (vaDeriveImage cache-stale class returns all-zero on RK3399).
  5. Regression check on iter1 MPEG-2 AND T4 H.264. Both prior-iteration boolean cells continue to pass:
    • MPEG-2 hashes at +02s seek still 6e7873030dbf... and ccc7ce08810d... (iter1 Phase 7 reference).
    • T4 H.264 hashes at +30s seek still f623d5f7... and 7d7bc6f2... (iter1 Phase 7 + T4 reference). Iter2 must not regress either codec.

A clean iter2 close has all five checks green. Anything less loops back to Phase 4 per feedback_dev_process.md Phase 7 → Phase 4 edge.

Mechanism the question targets

Phase 0 cross-validator sweep (phase0_evidence/2026-05-07/cross_validator_traces.md) established the kernel + rkvdec driver path works for HEVC: ffmpeg -hwaccel v4l2request -i bbb_720p10s_hevc.mp4 -frames:v 2 -f null - = exit 0. So the broken link is the libva backend. From iter1 Phase 2 source-read of the master tip:

  • src/config.c:55-69 RequestCreateConfigcase VAProfileHEVCMain: falls through to default: returning VA_STATUS_ERROR_UNSUPPORTED_PROFILE. iter1 added a break; for the MPEG-2 cases; HEVC stays in the fall-through bucket.
  • src/picture.c:204-206 codec_set_controlscase VAProfileHEVCMain: explicitly returns VA_STATUS_ERROR_UNSUPPORTED_PROFILE with the comment /* Fourier-local: HEVC stripped, no HW support on RK3566. */. The "no HW support on RK3566" rationale was for ohm (PineTab2 RK3566/RK3568) at libva-multiplanar iter5 close; on RK3399 fresnel rkvdec, HEVC IS supported in silicon (cross-validator confirms).
  • src/meson.build# 'h265.c' is commented out in the sources list. Re-enable.
  • src/h265.c — uncompiled today; likely uses staging-era control IDs from include/hevc-ctrls.h (analogous to mpeg2.c using staging-era mpeg2-ctrls.h before iter1). The new mainline kernel UAPI for HEVC stateless controls lives at include/uapi/linux/v4l2-controls.h:2110+ with control IDs V4L2_CID_STATELESS_HEVC_{SPS,PPS,SLICE_PARAMS,SCALING_MATRIX,DECODE_PARAMS,DECODE_MODE,START_CODE,ENTRY_POINT_OFFSETS,EXT_SPS_ST_RPS,EXT_SPS_LT_RPS} (10 control IDs total — substantially more than MPEG-2's 3).
  • include/hevc-ctrls.h — local fork header, staging-era. iter1 Phase 5 Nit 6 deferred this deletion; iter2 closes that loop.

iter2 likely encounters four bugs structurally analogous to iter1, plus possibly more:

  • B1 (analogous to iter1 Bug 1): config.c HEVCMain case fall-through. Fix shape: 3-line break; addition.
  • B2 (analogous to iter1 Bug 2): src/h265.c using staging-era CIDs. Fix shape: rewrite against the new V4L2_CID_STATELESS_HEVC_* split API. Larger than iter1's mpeg2.c rewrite because HEVC has 10 control IDs vs MPEG-2's 3.
  • B3 (analogous to iter1 Bug 3): include/hevc-ctrls.h is the staging-era local header. Fix shape: delete the file; verify no remaining includes via clean rebuild after include-removal patches (per memory/feedback_header_deletion_check.md — grep alone is insufficient).
  • B4 (NEW): picture.c::codec_set_controls explicitly returns UNSUPPORTED_PROFILE for HEVCMain. Fix shape: replace the explicit reject with a dispatch to h265_set_controls.
  • B5 (meson): src/meson.build comments out h265.c. Fix shape: uncomment.

Plus possibly:

  • B6: VAAPI VAPicture/VASlice/VAIQMatrix HEVC structs may not map 1:1 to the new V4L2 control structs. Phase 2 source-read of <va/va_dec_hevc.h> + the kernel UAPI HEVC structs will identify any mismatches.
  • B7: HEVC slice_params is a dynamic-array control (kernel UAPI v4l2-controls.h:2117 V4L2_CID_STATELESS_HEVC_SLICE_PARAMS is per-slice; rkvdec accepts up to 600 entries per Phase 0 v4l2-ctl inventory). The libva backend must accumulate per-slice params and submit them as a dynamic-array. Different shape from H.264 (which uses single VASliceParameter per RenderPicture call) and MPEG-2 (which doesn't have slice params at all in the new API).

Phase 4 plan must cite the contract before patching (feedback_dev_process.md Phase 6 contract-before-code): read kernel drivers/staging/media/rkvdec/rkvdec_hevc.c (the rkvdec HEVC driver source), read FFmpeg downstream libavcodec/v4l2_request_hevc.c, read mainline include/uapi/linux/v4l2-controls.h:2110+, state the HEVC control-submission contract explicitly before any code lands.

Predecessor carry-over (iter1 → iter2)

State that carries forward (re-verified at iter2 open)

  • Hardware: fresnel RK3399, kernel 6.19.9-99-eos-arm. ftrace + tracing enabled. mpv 0.41.0 stock, ffmpeg n8.1-13 (Kwiboo branch), libva 1.23.0.
  • rkvdec node: Phase 7 verified /dev/video1 + /dev/media0 on the boot of 2026-05-08 morning. Caveat: V4L2 /dev/videoN numbering shuffles across reboots (per iter1 Phase 8 backlog B1). iter2 binding cells should re-verify v4l2-ctl --info at session start. Long-term fix candidate: backend-side device-discovery probe (Phase 4 cross-cutting, not iter2).
  • Decoder formats (rkvdec, from phase0_evidence/2026-05-07/v4l2_inventory.txt): OUTPUT_MPLANE = S265 (HEVC Parsed Slice Data) + S264 (H.264) + VP9F (VP9). CAPTURE_MPLANE = NV12.
  • Stateless control payloads kernel exposes (rkvdec, HEVC): hevc_sequence_parameter_set (0x00a40a90), hevc_picture_parameter_set (0x00a40a91), hevc_slice_parameters (0x00a40a92, dynamic-array max 600 elems), hevc_scaling_matrix (0x00a40a93), hevc_decode_parameters (0x00a40a94), hevc_decode_mode (0x00a40a95, menu, FRAME_BASED only), hevc_start_code (0x00a40a96, menu, ANNEX_B only).
  • HEVC profile menu (rkvdec): Main, Main Still Picture, Main 10. RK3399 silicon support for Main 10 (10-bit) is unverified; iter2 fixture is 8-bit Main only.
  • Backend build state: libva-v4l2-request-fourier master tip post-iter1-close, including:
    • iter1 commits: e7dad7a (config.c break) + 5fe873c (mpeg2.c rewrite) + 3aab187 (delete include/mpeg2-ctrls.h) + 229d6d1 (commit D fix-forward).
    • iter1's MPEG-2 path is a working reference for the patch shape (config.c break + new-API rewrite + header delete + grep-audit incompleteness fix).
    • src/h265.c is already in the source tree (267 lines per Phase 0 inventory) — Phase 2 will audit whether it uses staging-era or modern API. If staging-era, rewrite is the bulk of iter2 work. If somehow already on modern API, the work is much smaller.
  • Test fixture: ~/fourier-test/bbb_720p10s_hevc.mp4 on fresnel (620 KB, HEVC Main, 1280×720@24fps, yuv420p, 10s, generated 2026-05-07 23:34 from H.264 master via libx265 ultrafast). Provenance: phase0_evidence/2026-05-07/test_fixtures.md.
  • Reference fixtures for regression: ~/fourier-test/bbb_1080p30_h264.mp4 (T4 reference) and ~/fourier-test/bbb_720p10s_mpeg2.ts (iter1 reference).
  • iter1 + T4 reference hashes for regression criterion 5:
    • H.264 (T4) at +30s: HW frame 1 f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9, frame 2 7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8.
    • MPEG-2 (iter1) at +02s: HW frame 1 6e7873030dbf0403c67f35dd106ebef3c7909a0fd12433b82ad758e7fee9f092, frame 2 ccc7ce08810d4a96e9ba7a19f4f95bbf6cc861bda9337604b5c668ad52bef7de.
  • Cross-validator anchor: ffmpeg-v4l2request HEVC contract from phase0_evidence/2026-05-07/cross_validator/hevc/. 14 S_EXT_CTRLS, 5 QUERY_EXT_CTRL (HEVC slice_params dynamic-array introspection — unique among the 5 codecs), 4 MEDIA_IOC_REQUEST_ALLOC. 60 ftrace v4l2 events for 2 frames.
  • Cache-safe verify path: mpv --hwdec=vaapi --vo=image (DMA-BUF GL import). Confirmed for H.264 (T4) and MPEG-2 (iter1 Phase 7); iter2 expects the same path to work for HEVC.

Data that does NOT carry forward (re-acquire if needed)

  • ohm/RK3568 hantro HEVC behavior — there is none; RK3568 hantro doesn't decode HEVC. RK3399 rkvdec is the first time the libva-v4l2-request-fourier fork sees HEVC on real hardware. Reference history: zero.
  • libva-multiplanar iter1-iter5 close docs' "HEVC stripped" disposition — that was an ohm-side build-cleanly decision, not an empirical "HEVC doesn't work" finding. iter2 reverses the strip.

Open questions inherited from iter1 close

  • B3 latent surface-reuse bug (phase8_iteration1_close.md backlog): picture.c:287 params.h264.matrix_set = false writes union byte 240, lands inside mpeg2.iqmatrix.chroma_intra_quantiser_matrix[20]. For HEVC, the union member is params.h265.{picture, slice, iqmatrix, iqmatrix_set}. The params.h265 struct layout differs from params.mpeg2 (per src/surface.h:90-109). iter2 should verify whether byte 240 lands inside h265.iqmatrix or elsewhere; if it lands in a meaningful HEVC field, the latent bug becomes acute for iter2's binding cells. Phase 2 source-read action item.
  • Phase 4 cross-cutting work items (vaDeriveImage fix, V4L2 device-discovery, BeginPicture profile-aware reset, context.c log suppression): not iter2 scope; iter2 works around them via DMA-BUF GL verify path and re-checked device numbers.

Tooling and measurement-instrument inventory (live verification)

Re-verified at iter2 open (carries forward from iter1, all proven working):

  • strace -ff -tt -y -v -e trace=ioctl,openat,close — captures V4L2 + media-request ioctl sequence per thread.
  • LIBVA_TRACE environment variable — captures vaCreate/vaQuery/vaInitialize call traces with status return codes.
  • sudo sh -c "echo 1 > /sys/kernel/tracing/events/v4l2/enable" — captures kernel v4l2 tracepoints (qbuf/dqbuf events).
  • mpv --hwdec=vaapi --vo=image — cache-coherency-safe pixel verifier (DMA-BUF GL import).
  • ffmpeg -hwaccel v4l2request — independent V4L2 client cross-validator (different code path than libva).
  • Backend build harness on fresnel: ninja -C ~/src/libva-v4l2-request-fourier/build && sudo ninja -C build install.
  • Empirical HEVC decode of bbb_720p10s_hevc.mp4 via ffmpeg-v4l2request DRM_PRIME path — proven works in cross-validator sweep.

iter2 will likely add per-source debug printf/fprintf(stderr, ...) instrumentation in src/h265.c during Phase 6. That instrumentation is iter2-internal scratch; clean sweep at iter2 close per Phase 5 review precedent.

In-scope (LOCKED 2026-05-08 for iteration 2)

  • libva-v4l2-request-fourier backend HEVC Main path on rkvdec.
  • src/config.c::RequestCreateConfig — add break; for VAProfileHEVCMain case (analogous to iter1 Commit A pattern for MPEG-2).
  • src/picture.c::codec_set_controls — replace the explicit case VAProfileHEVCMain: return UNSUPPORTED_PROFILE with a dispatch to h265_set_controls.
  • src/h265.c — Phase 2 source-read decides the scope: if it uses staging-era CIDs, full rewrite against new split API. If somehow already modern, the audit produces a delta. Plus any fixes needed for VAAPI ↔ V4L2 control struct mapping (slice_params dynamic-array semantics, scaling_matrix conditional, decode_params per-frame).
  • include/hevc-ctrls.h — DELETE (iter1 Phase 5 Nit 6 deferred this; iter2 closes the loop). Apply memory/feedback_header_deletion_check.md discipline: drop #include from all callsites + clean rebuild + then git rm.
  • src/meson.build — uncomment 'h265.c' in the sources list.
  • iter2 binding-cell test harness: re-run iter1's Phase 7 5-criterion harness substituting HEVC fixture, plus iter1's MPEG-2 + T4 H.264 regression checks.
  • Cache-safe pixel verify must use DMA-BUF GL import (not vaDeriveImage), per memory feedback_rockchip_pixel_verify_path.md.

Out-of-scope (LOCKED 2026-05-08 for iteration 2)

  • VP9, VP8 work (iter3/iter4).
  • HEVC Main 10 (10-bit). Silicon support unverified; campaign codec scope is 8-bit yuv420p.
  • HEVC Main Still Picture profile (rkvdec advertises it via the menu, but the campaign fixture is Main, not Main Still Picture; defer).
  • Performance metrics (Phase 1+ separate iteration).
  • Long-duration HEVC stress (>10s).
  • HEVC tile / wavefront parallel processing (ENTRY_POINT_OFFSETS is in the kernel surface but the campaign fixture doesn't use tiles; defer).
  • Phase 4 cross-cutting backlog items B1 (V4L2 device-discovery), B3 (BeginPicture profile-aware reset), B4 (context.c log suppression), B5 (vbv_buffer_size negotiation), L3 (vaDeriveImage cache-stale fix). All carry forward from iter1; not iter2 scope.
  • chromium-fourier 149 install on fresnel (carry-over from iter1 deferred).
  • src/context.c — no changes (the H.264 device-init unconditional-EINVAL is auxiliary noise per iter1 Phase 7; benign for HEVC binding cells).
  • Upstream Linux engagement (per feedback_no_upstream.md). Kernel-side works; nothing to file.

Phase 1 success criterion (LOCKED 2026-05-08)

The five Pass/fail bullets at the top of this document are the iter2 success criterion. Phase 3 baseline measurements feed Phase 4 plan; Phase 7 verification re-runs all five against the patched backend.

If Phase 3 baseline reveals the chosen criterion is the wrong target (Phase 3 → Phase 1 loopback per feedback_dev_process.md), the criterion will be rewritten and re-locked. Plausible reasons that would trigger the loopback:

  • The HEVC fixture is malformed in a way that exposes a fixture-side bug rather than a backend-side bug. (Mitigation: ffmpeg-v4l2request decodes the same fixture cleanly per Phase 0 cross-validator sweep, so this is unlikely.)
  • HEVC slice_params dynamic-array semantics on rkvdec require a different submission shape than expected (e.g., per-slice S_EXT_CTRLS vs single batched submission with a slice_params array). Phase 3 baseline of ffmpeg-v4l2request HEVC trace will resolve.
  • mpv --hwdec=vaapi (DMA-BUF) ALSO filters HEVC out (Phase 5 Q4 amendment for iter1 ended up being non-blocking because mpv-vaapi engages MPEG-2; we'll see if HEVC behaves the same). Mitigation: fall-forward to ffmpeg-v4l2request DRM_PRIME + hwdownload pixel verify (we know that works; criterion holds, harness adapts).
  • VAAPI HEVC consumer pattern requires VAEncSliceParameterBufferType to be sent in some specific order; iter1 didn't have to handle this. Phase 2 source-read will identify.

The other four Phase 1 criteria (vainfo enumeration, vaCreateConfig success, ffmpeg-direct exit 0, MPEG-2+T4 regression) hold as locked — no adjustment expected.

Phase 2 source-read targets

For the upcoming Phase 2 situation analysis:

  • src/h265.c (entire file, ~267 lines) — current state, what API it targets, what VAAPI buffers it reads, what V4L2 controls it submits.
  • src/picture.c:204-206 — the explicit HEVC reject; verify the surrounding context.
  • src/config.c:55-69 — confirm HEVC fall-through (already inspected during iter1 Phase 2; nothing should have changed).
  • src/surface.h:103-108 (params.h265 struct) — VAAPI HEVC buffers in the surface union.
  • include/hevc-ctrls.h (entire file) — staging-era definitions; identify which CIDs and structs are referenced from src/h265.c.
  • src/meson.build — confirm h265.c commented out; identify any conditional compile flags.
  • Kernel UAPI <linux/v4l2-controls.h> lines 2110+ — modern HEVC stateless control IDs and struct layouts.
  • Linux mainline kernel drivers/staging/media/rkvdec/rkvdec_hevc.c — the rkvdec HEVC driver source. Specifically: which controls are mandatory, which are optional, what's the slice_params dynamic-array contract, what's the decode_params contract.
  • FFmpeg downstream libavcodec/v4l2_request_hevc.c — independent V4L2 client implementation. Submission shape, per-slice params batching, scaling_matrix conditionality.
  • VAAPI <va/va_dec_hevc.h> — VAAPI HEVC buffer struct definitions (especially VAPictureParameterBufferHEVC, VASliceParameterBufferHEVC (and any 422/444 ext variants), VAIQMatrixBufferHEVC).

What "iteration 2 close" looks like

A clean iter2 close per feedback_dev_process.md Phase 8:

  • All 5 Phase 1 criteria green.
  • phase8_iteration2_close.md summarizing the bug, contract, fix, binding-cell numbers.
  • Third-codec passing on the campaign-level scoreboard: 2/5 → 3/5.
  • Memory entries distilled for any new lessons (iter1 produced 3; iter2 may produce 0 if the work mirrors iter1's MPEG-2 pattern cleanly, or more if HEVC surfaces novel issues).
  • Debug-instrumentation sweep at close.
  • Phase 5 sonnet-architect review pass signed off.
  • Commits all authored as claude-noether per memory/feedback_gitea_as_claude_noether.md.
  • include/hevc-ctrls.h deleted (closing iter1 Phase 5 Nit 6).
  • src/h265.c re-enabled in src/meson.build, modernized against new V4L2 stateless API, dispatched correctly from picture.c.

Predicted iter2 difficulty vs iter1: similar shape (config break + new-API rewrite + header delete + grep-audit completeness), larger scope (10 control IDs vs 3), one novel construct (slice_params dynamic-array). Expect Phase 6 to take longer than iter1 (~120 lines mpeg2.c rewrite vs probably 250-400 lines for h265.c). Phase 7 verification harness re-uses iter1's pattern verbatim.