Files
fresnel-fourier/phase7_iter2_verification.md
T
claude-noether 05b4bd56ec iter2 Phase 7: verification — all 5 criteria GREEN, third codec PASS
Phase 7 verification of iter2 HEVC fix executed against fork tip
8d71e20 (libva-v4l2-request-fourier master = post-iter2-Commit-B).
Verbatim raw output captured to phase0_evidence/2026-05-08/
iter2_phase7/. All five Phase 1 criteria green; bonus byte-compare
confirms structural match against Baseline B with two minor field-
value divergences (informational SPS fields VAAPI doesn't expose;
non-blocking per Criterion 4 byte-identical pixel pass).

Phase 1 → Phase 7 scoreboard:

  Criterion 1 (vainfo VAProfileHEVCMain enum):                  PASS
    rkvdec bind: H.264 (5 profiles) + HEVCMain — same as Baseline.

  Criterion 2 (vaCreateConfig SUCCESS for HEVCMain):            PASS
    Pre-iter2: VA_STATUS_ERROR_UNSUPPORTED_PROFILE (12)
    Post-iter2: VA_STATUS_SUCCESS (verified verbatim libva trace)

  Criterion 3 (ffmpeg-direct HEVC engages backend, exit 0):     PASS
    5 frames decoded clean, cap_pool_init: 24 slots ready,
    no Failed-to-create lines, no S_EXT_CTRLS EINVAL.

  Criterion 4 (DMA-BUF GL HEVC HW=SW byte-identical at +02s):   PASS
    HW frame 1: 47a5f3850df5d8c732767a227830c2272ff78402a7b6adeea329e29838808be5
    SW frame 1: 47a5f3850df5d8c732767a227830c2272ff78402a7b6adeea329e29838808be5
    HW frame 2: a467b3bc9d7b6374b6786ecfac46932d6c7bb932ab11d311edaa233d7863e656
    SW frame 2: a467b3bc9d7b6374b6786ecfac46932d6c7bb932ab11d311edaa233d7863e656
    Frames 1 vs 2 hash-differ (real motion).

  Criterion 5 (iter1 MPEG-2 + T4 H.264 reference hashes):       PASS
    H.264 +30s HW1: f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9 (T4 ref MATCH)
    H.264 +30s HW2: 7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8 (T4 ref MATCH)
    MPEG-2 +02s HW1: 6e7873030dbf0403c67f35dd106ebef3c7909a0fd12433b82ad758e7fee9f092 (iter1 ref MATCH)
    MPEG-2 +02s HW2: ccc7ce08810d4a96e9ba7a19f4f95bbf6cc861bda9337604b5c668ad52bef7de (iter1 ref MATCH)

Bonus byte-compare against Phase 3 Baseline B verbatim:

  count=5, ctrl_class=V4L2_CTRL_CLASS_CODEC_STATELESS=0xf010000:
    SPS            id=0xa40a90 size=40   (matches Baseline B)
    PPS            id=0xa40a91 size=64   (matches)
    SLICE_PARAMS   id=0xa40a92 size=280  (1 slice × sizeof(slice_params))
    SCALING_MATRIX id=0xa40a93 size=1000 (matches sizeof(scaling_matrix);
                                          Phase 4 plan typo'\''d 1296 — actual
                                          struct sums to 1000 = 96+384+384+
                                          128+6+2)
    DECODE_PARAMS  id=0xa40a94 size=328  (matches)
    All return = 0 (kernel accepts every batched call).

  SPS field-value divergences vs Baseline B (FFmpeg-v4l2request):
    sps_max_num_reorder_pics:    post-fix=0  baseline=2   DIVERGE
    sps_max_latency_increase_plus1: post-fix=0  baseline=4 DIVERGE
    All other SPS fields match (pic_width=1280, pic_height=720,
    bit_depth=0, flags=0x180=SAO|STRONG_INTRA_SMOOTHING).

  PPS flags also diverge slightly (bit 12 ENTROPY_CODING_SYNC_ENABLED:
  post-fix unset, baseline set). Other PPS fields match.

  Cause: VAAPI'\''s VAPictureParameterBufferHEVC doesn'\''t expose
  sps_max_num_reorder_pics, sps_max_latency_increase_plus1, or
  always-truthful entropy_coding_sync. FFmpeg parses these from
  bitstream directly. Operational impact NIL (Criterion 4 byte-
  identical pixel pass — kernel decoded correctly with these fields
  defaulted to 0). Phase 8 polish backlog candidate (low priority):
  add SPS bitstream parsing to extract these fields when VAAPI
  doesn'\''t supply them.

Phase 7 → Phase 8: clean transition, no loopback.

Notable Phase 7 observations for Phase 8 memory:

  1. Phase 5 review value confirmed: 3 Critical findings (C1
     data_byte_offset rename, C2 dpb.rps→index-arrays semantics,
     C3 pic_order_cnt_val rename) caught at Phase 5 — prevented
     Phase 6 compile failures + at least 1-2 Phase 7→Phase 4
     loopback cycles. Per memory feedback_review_empirical_over_
     theoretical.md: every Critical/Should-fix verified
     empirically before responding. Lesson held.

  2. One Phase 5 amendment was empirically wrong: S1 suggested
     uniform_spacing_flag exists in VAAPI; gcc test-compile rejected.
     Both PPS bits 19+20 left zero (VAAPI exposes neither).
     Documented inline. Lesson: even reviewer-cited field mappings
     warrant empirical verification.

  3. Phase 4 plan typo: claimed sizeof(scaling_matrix) = 1296;
     empirical size is 1000. Code uses sizeof() so produces correct
     bytes. Plan body amendment-by-side-channel; not blocking.

  4. VAAPI↔V4L2 field-fidelity gaps surfaced: 2 SPS fields +
     possibly 1 PPS bit not exposed by VAAPI. Operational nil;
     Phase 8 polish-backlog candidate.

  5. mpv --hwdec=vaapi engages HEVC cleanly (no MPEG-2-style
     filtering). Confirms Phase 5 Q3 — VAPictureParameterBufferType
     sent per-frame for HEVC; latent B3 bug masked same as MPEG-2.

  6. BBB HEVC fixture is 1 slice per frame (slice_params size=280
     = 1 × sizeof). Multi-slice path in iter2 is coded but
     untested by binding cell.

Campaign scoreboard: 2/5 → 3/5 codecs passing
(H.264 in T4, MPEG-2 in iter1, HEVC in iter2). iter2 advances
to Phase 8.

Refs:
  ../libva-v4l2-request-fourier@8d71e20 (the fork tip verified)
  phase4_iter2_plan.md (10 contract clauses; SCALING_MATRIX size
                        typo noted)
  phase5_iter2_review.md (3 Critical + 4 Should-fix amendments
                          all incorporated; S1 partially empirically
                          incorrect — VAAPI doesn'\''t expose
                          uniform_spacing_flag)

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

15 KiB
Raw Blame History

Iteration 2 — Phase 7 (verification measurements)

Phase 7 verification of the iter2 HEVC fix, executed 2026-05-08 against fork tip 8d71e20 on git.reauktion.de/marfrit/libva-v4l2-request-fourier. All five Phase 1 criteria green. Bonus byte-compare confirms structural match against Baseline B with two field-value divergences in informational bitstream parameters that don't affect decode correctness (Criterion 4's byte-identical HW=SW pixel verification proves it).

Per feedback_dev_process.md Phase 7: verbatim raw output is the artifact; this document is the index. Raw captures in phase0_evidence/2026-05-08/iter2_phase7/.

Pre-flight: rig state

$ ssh fresnel 'git -C ~/src/libva-v4l2-request-fourier log --oneline -3'
8d71e20 fresnel-fourier iter2 Phase 6 commit B: rewrite h265.c against new V4L2 stateless HEVC API
cca539d fresnel-fourier iter2 Phase 6 commit A: config.c break for HEVCMain case
229d6d1 fresnel-fourier iter1 Phase 6 commit D: drop missed mpeg2-ctrls.h include from context.c

$ sha256sum /usr/lib/dri/v4l2_request_drv_video.so build/src/v4l2_request_drv_video.so
9e27043847998c197a46a1a26b2f77f22880bb7b3a62aa4d60d8fcaec0ae6258  /usr/lib/dri/v4l2_request_drv_video.so
9e27043847998c197a46a1a26b2f77f22880bb7b3a62aa4d60d8fcaec0ae6258  build/src/v4l2_request_drv_video.so

device map (this boot):
  /dev/video0  rockchip-rga
  /dev/video1  rkvdec                       (HEVC + H.264 + VP9)
  /dev/video2  rockchip,rk3399-vpu-enc
  /dev/video3  rockchip,rk3399-vpu-dec      (MPEG-2 + VP8)
  /dev/video4  Camera (USB)
  /dev/video5  Camera (USB)

Same device numbering as iter1 Phase 7 boot. Substrate matches iter1 close + pacman -Syu userland refresh + iter2 Phase 6 commits A + B. eos-reboot-recommended marker still present from the userland upgrade; mfritsche Plasma session active throughout (no SDDM regression).

Criterion 1 — vainfo lists VAProfileHEVCMain on rkvdec bind

Verbatim (criterion1_vainfo.txt):

$ LIBVA_DRIVER_NAME=v4l2_request \
  LIBVA_V4L2_REQUEST_VIDEO_PATH=/dev/video1 \
  LIBVA_V4L2_REQUEST_MEDIA_PATH=/dev/media0 \
  vainfo --display drm --device /dev/dri/renderD128

vainfo: VA-API version: 1.23 (libva 2.22.0)
vainfo: Driver version: v4l2-request
vainfo: Supported profile and entrypoints
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264MultiviewHigh      :	VAEntrypointVLD
      VAProfileH264StereoHigh         :	VAEntrypointVLD
      VAProfileHEVCMain               :	VAEntrypointVLD

Result: PASS. VAProfileHEVCMain enumerated; H.264 family unchanged; no regression.

Criterion 2 — vaCreateConfig succeeds for VAProfileHEVCMain

Verbatim libva trace (criterion2_3/libva.trace.135940.thd-0x000052f4):

[60492.576649] vaQueryConfigProfiles ret = VA_STATUS_SUCCESS
[60492.576680] va_TraceCreateConfig
[60492.576684]   profile = 17, VAProfileHEVCMain
[60492.576687]   entrypoint = 1, VAEntrypointVLD
[60492.576690]   num_attribs = 0
[60492.576730] vaCreateConfig ret = VA_STATUS_SUCCESS, success (no error)

Result: PASS. vaCreateConfig(VAProfileHEVCMain, VAEntrypointVLD) returns VA_STATUS_SUCCESS (was VA_STATUS_ERROR_UNSUPPORTED_PROFILE = 12 pre-iter2).

Criterion 3 — ffmpeg-direct HEVC decode engages backend, exits 0

Verbatim (criterion2_3/ffmpeg.stdout):

$ ffmpeg -hide_banner -loglevel info -hwaccel vaapi \
    -i ~/fourier-test/bbb_720p10s_hevc.mp4 -frames:v 5 -f null -

Press [q] to stop, [?] for help
v4l2-request: cap_pool_init: 24 slots ready (v4l2_index=0..23, 1 plane(s) per slot)
Output #0, null, to 'pipe:':
  Stream #0:0(eng): Video: wrapped_avframe, nv12(tv, bt709, progressive), 1280x720,
                   q=2-31, 200 kb/s, 24 fps, 24 tbn (default)
frame=    5 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.20 bitrate=N/A speed=0.253x
[ffmpeg exit 0]

Greps:

  • Failed to create decode configuration: 0 hits.
  • S_EXT_CTRLS.*EINVAL in libva trace: 0 hits.
  • EINVAL in ffmpeg stdout: 0 hits.

Notably no auxiliary "Unable to set control(s)" line for HEVC (vs MPEG-2/H.264 cases where it appears from the H.264 device-init falling on hantro). On rkvdec both H.264 and HEVC device-init batches succeed; both batches set DECODE_MODE + START_CODE without EINVAL.

Result: PASS. ffmpeg processed 5 HEVC frames cleanly via the libva backend; cap_pool_init confirms our backend was engaged.

Criterion 4 — DMA-BUF GL HEVC HW=SW byte-identical at +02s

Verbatim hashes (criterion4/hashes.txt):

47a5f3850df5d8c732767a227830c2272ff78402a7b6adeea329e29838808be5  /tmp/iter2_phase7/criterion4/image_hw/00000001.jpg
a467b3bc9d7b6374b6786ecfac46932d6c7bb932ab11d311edaa233d7863e656  /tmp/iter2_phase7/criterion4/image_hw/00000002.jpg
47a5f3850df5d8c732767a227830c2272ff78402a7b6adeea329e29838808be5  /tmp/iter2_phase7/criterion4/image_sw/00000001.jpg
a467b3bc9d7b6374b6786ecfac46932d6c7bb932ab11d311edaa233d7863e656  /tmp/iter2_phase7/criterion4/image_sw/00000002.jpg
Check Result
HW frame 1 == SW frame 1 (47a5f3850df5...) PASS
HW frame 2 == SW frame 2 (a467b3bc9d7b...) PASS
frame 1 != frame 2 (real motion) PASS

Result: PASS. HEVC hardware decode on RK3399 / rkvdec / libva-v4l2-request-fourier @ iter2 produces pixels bit-exact identical to software reference, when read via the cache-coherency-safe DMA-BUF GL import path.

Criterion 5 — iter1 MPEG-2 + T4 H.264 references both still match

Verbatim hashes (criterion5/hashes.txt):

f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9  /tmp/iter2_phase7/criterion5/h264_hw/00000001.jpg
7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8  /tmp/iter2_phase7/criterion5/h264_hw/00000002.jpg
6e7873030dbf0403c67f35dd106ebef3c7909a0fd12433b82ad758e7fee9f092  /tmp/iter2_phase7/criterion5/mpeg2_hw/00000001.jpg
ccc7ce08810d4a96e9ba7a19f4f95bbf6cc861bda9337604b5c668ad52bef7de  /tmp/iter2_phase7/criterion5/mpeg2_hw/00000002.jpg
Cell Reference Match
H.264 +30s frame 1 T4 f623d5f7...
H.264 +30s frame 2 T4 7d7bc6f2...
MPEG-2 +02s frame 1 iter1 6e7873030dbf...
MPEG-2 +02s frame 2 iter1 ccc7ce08810d...

Result: PASS. Iter2's HEVC fix doesn't regress H.264 or MPEG-2. All four reference hashes hold byte-identical.

Bonus — byte-compare post-fix VIDIOC_S_EXT_CTRLS payload vs Baseline B

Verbatim post-fix call (frame 1, from bonus/postfix_frame1.txt):

ioctl(/dev/video1, VIDIOC_S_EXT_CTRLS,
  {ctrl_class=0xf010000 /* V4L2_CTRL_CLASS_CODEC_STATELESS */,
   count=5,
   controls=[
     {id=0xa40a90 /* SPS */,            size=40,   ...},
     {id=0xa40a91 /* PPS */,            size=64,   ...},
     {id=0xa40a92 /* SLICE_PARAMS */,   size=280,  ...},  /* 1 slice × sizeof(struct v4l2_ctrl_hevc_slice_params)=280 */
     {id=0xa40a93 /* SCALING_MATRIX */, size=1000, ...},  /* sizeof(struct v4l2_ctrl_hevc_scaling_matrix) = 1000 */
     {id=0xa40a94 /* DECODE_PARAMS */,  size=328,  ...}
   ]}) = 0

Structural match: same shape as Phase 3 Baseline B verbatim — count=5, ctrl_class=V4L2_CTRL_CLASS_CODEC_STATELESS, three CIDs in order (90, 91, 92, 93, 94), all sizes correct.

(Note: my Phase 4 plan body claimed sizeof(struct v4l2_ctrl_hevc_scaling_matrix) = 1296 but empirical sizeof is 1000 bytes = 96 (4×4) + 384 (8×8) + 384 (16×16) + 128 (32×32) + 6 (DC 16×16) + 2 (DC 32×32). Plan's 1296 was a typo from earlier draft; actual struct is 1000.)

Field-decoded SPS (40 bytes, BBB I-frame frame 1):

post-fix:    00000005d002000004040000010100030000fffffd00000001000000000000008001000000000000
Baseline B:  00000005d00200000404020401010003 0000fffffd00000001000000000000008001000000000000

(Bytes 8-11 highlighted: 00 00 00 00 post-fix vs 02 04 00 00 Baseline B.)

Byte offset Field Post-fix Baseline B Match
0 video_parameter_set_id 0 0
1 seq_parameter_set_id 0 0
2-3 pic_width_in_luma_samples 1280 1280
4-5 pic_height_in_luma_samples 720 720
6 bit_depth_luma_minus8 0 0
7 bit_depth_chroma_minus8 0 0
8 log2_max_pic_order_cnt_lsb_minus4 4 4
9 sps_max_dec_pic_buffering_minus1 4 4
10 sps_max_num_reorder_pics 0 2 DIVERGE
11 sps_max_latency_increase_plus1 0 4 DIVERGE
12+ (rest matches) ... ...
32-39 flags 0x180 (SAO|STRONG_INTRA_SMOOTHING) 0x180

Two field divergences in SPS bytes 10-11. Per Phase 4 plan Clause 2: "VAAPI doesn't expose sps_max_num_reorder_pics or sps_max_latency_increase_plus1; iter2 hardcodes 0." FFmpeg parses these from the bitstream's SPS header directly. The libva backend reads them via VAAPI's VAPictureParameterBufferHEVC which doesn't expose them, so they default to 0.

Operational impact: nil. Criterion 4 confirms HW=SW byte-identical pixels — kernel decoded correctly with these fields zero. The kernel HEVC handler may use them for DPB sizing hints, but the rkvdec driver tolerated 0 values for the BBB fixture.

PPS field divergence (informational)

PPS bytes also show a small divergence in the flags u64:

  • Post-fix: bits set are 6 (CU_QP_DELTA_ENABLED) + 14 (PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED) → flags = 0x4040.
  • Baseline B (per Phase 3 raw): includes one additional bit, possibly bit 12 (ENTROPY_CODING_SYNC_ENABLED) → flags = 0x5040.

VAAPI source for bit 12 is picture->pic_fields.bits.entropy_coding_sync_enabled_flag. The post-fix code DOES check that field and set the flag. Either:

(a) BBB doesn't actually have entropy_coding_sync_enabled (field is 0 in VAAPI's struct on libva path; FFmpeg may have parsed something different from bitstream), OR (b) Two distinct VAAPI consumers (mpv-vaapi vs ffmpeg-v4l2request) feed different data to the libva backend.

Operational impact: nil. Criterion 4 byte-identical pass.

Net byte-compare verdict

The libva backend's V4L2 control payload differs from the cross-validator on a small number of informational bitstream-parsed fields that VAAPI doesn't expose to the libva backend. Pixel correctness verified independently via Criterion 4 byte-identical HW=SW — kernel HEVC decoder accepts the libva-supplied controls and produces correct output regardless of these field divergences.

No Phase 7 → Phase 4 loopback triggered. Field divergences logged for Phase 8 backlog (low-priority polish — improve VAAPI-to-V4L2 fidelity by parsing additional SPS fields from slice bitstream, similar to the existing NAL-unit-type extraction).

Phase 1 → Phase 7 scoreboard

Criterion Pre-iter2 (Phase 3 baseline) Post-iter2 (Phase 7 verification) Verdict
1: vainfo VAProfileHEVCMain ✓ already ✓ unchanged PASS
2: vaCreateConfig SUCCESS ✗ ret = 12 UNSUPPORTED_PROFILE ✓ ret = VA_STATUS_SUCCESS PASS
3: ffmpeg-direct exit 0 ✗ Failed setup for format vaapi ✓ frame=5, exit 0, cap_pool engaged PASS
4: DMA-BUF GL HW=SW byte-identical at +02s n/a (decode never reached) ✓ HW1=SW1=47a5f3850df5..., HW2=SW2=a467b3bc9d7b..., frames differ PASS
5: iter1 MPEG-2 + T4 H.264 reference hashes ✓ baseline ✓ all 4 reference hashes hold byte-identical PASS

All five criteria green. Phase 7 → Phase 8: proceed (no Phase 7 → Phase 4 loopback needed).

Notable Phase 7 observations for Phase 8 memory

  1. Phase 5 review value: 3 Critical findings (data_byte_offset rename, dpb.rps→index-arrays semantics, pic_order_cnt_val rename) caught at Phase 5 — prevented Phase 6 compile failures + at least 1-2 Phase 7 → Phase 4 loopback cycles. Per feedback_review_empirical_over_theoretical.md: every Critical and Should-fix verified against fresnel kernel UAPI before responding; no source-read rebuttals attempted. Lesson held throughout iter2.

  2. One Phase 5 reviewer suggestion was empirically wrong: S1 mapping suggested picture->pic_fields.bits.uniform_spacing_flag exists in VAAPI; gcc test-compile rejected it. Both PPS bits 19 (DEBLOCKING_FILTER_CONTROL_PRESENT) and 20 (UNIFORM_SPACING) stay zero — VAAPI doesn't expose either. Documented inline in src/h265.c::h265_fill_pps. Functionally fine for BBB (no tiles, no explicit deblocking control). Lesson: even reviewer-cited mappings can be wrong on subtle field availability; the rule "verify empirically" applies to amendment proposals too, not just original-author claims.

  3. Phase 4 plan body had a typo on sizeof(struct v4l2_ctrl_hevc_scaling_matrix): claimed 1296 bytes, actual is 1000. Reviewer didn't catch this (focused on field-name correctness, not size arithmetic). Phase 7 byte-compare caught it — the structural-shape check confirmed 1000 was right. Phase 4 amendment-by-side-channel: the value in Phase 4 plan body is wrong; the actual code uses sizeof() so produces correct bytes.

  4. VAAPI ↔ V4L2 field-fidelity gaps: the bonus byte-compare surfaced 2 field divergences (sps_max_num_reorder_pics, sps_max_latency_increase_plus1, possibly PPS bit 12) where the libva backend's output differs from FFmpeg's because VAAPI's VAPictureParameterBufferHEVC doesn't expose all SPS-parsed fields. Operational impact nil (Criterion 4 byte-identical pixel pass). Phase 8 polish-backlog candidate: add SPS bitstream parsing to extract these fields when VAAPI doesn't supply them.

  5. No mpv-vaapi-MPEG-2-style filter for HEVC: mpv --hwdec=vaapi engages HEVC cleanly (unlike its silent fallback for MPEG-2 vaapi-copy in iter1). Confirms Phase 5 Q3: mpv-vaapi DOES send VAPictureParameterBufferType per frame for HEVC — the per-frame iqmatrix-set-true reset masks the latent B3 bug for HEVC same as it does for iter1 MPEG-2.

  6. Slice count for BBB HEVC fixture: 1 slice per frame (size=280 = 1 × sizeof(slice_params)), confirming Phase 4 prediction. Multi-slice support in iter2 is untested but coded.

Phase 7 close

Phase 7 → Phase 8 transition. iter2 advances to memory-update phase. Third-codec passing on the campaign-level scoreboard: 2/5 → 3/5 (H.264 in T4, MPEG-2 in iter1, HEVC in iter2).