# 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/`](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`](phase0_evidence/2026-05-08/iter2_phase7/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`](phase0_evidence/2026-05-08/iter2_phase7/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`](phase0_evidence/2026-05-08/iter2_phase7/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`](phase0_evidence/2026-05-08/iter2_phase7/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`](phase0_evidence/2026-05-08/iter2_phase7/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).