h264: max_num_ref_frames fallback + libva-boundary instrumentation (#8) #9

Merged
marfrit merged 1 commits from claude-noether/libva-v4l2-request-fourier:noether/h264-3-set-controls-bitstream-bug-8 into master 2026-05-20 18:19:03 +00:00
Collaborator

Addresses the libva-side portion of #8.

Summary

src/h264.c h264_set_controls: two additions, no behavior change for the existing HW decoder paths.

1. max_num_ref_frames fallback — when VAPicture->num_ref_frames is 0, count non-INVALID DPB entries in ReferenceFrames[16]; if even that is 0, use a per-profile spec minimum (1 for baseline, 4 for main/high). Lenient HW decoders (rkvdec, hantro, rpi-hevc-dec) tolerated the 0; libavcodec-via-daedalus rejected every frame against sps.max_num_ref_frames.

2. Libva-boundary instrumentation — single request_log dumping the raw VAAPI fields (seq_fields.value, pic_fields.value, num_ref_frames, bit_depth_, picture__in_mbs_minus1) at function entry. This is the disambiguation handle for fix-4 of the issue (PPS flags read 0 → was it ffmpeg-vaapi not populating, or daedalus_v4l2 wire-protocol corrupting?). One printf per H.264 frame; safe to leave in.

What's intentionally NOT in this PR

Proposed fixes #1 and #2 from the issue body — profile_idc and level_idc from seq_fields.bits.* — are infeasible. Verified higgs libva 2.22.0-3 /usr/include/va/va.h:3571-3622: VAPictureParameterBufferH264.seq_fields.bits carries chroma_format_idc, frame_mbs_only_flag, log2_max_frame_num_minus4, pic_order_cnt_type, log2_max_pic_order_cnt_lsb_minus4, delta_pic_order_always_zero_flag, plus a handful of binary flags — no profile_idc, no level_idc, no constraint_set*_flag. Same VAAPI-blindspot family as the HEVC SPS fields tracked in feedback_vaapi_blind_to_some_hevc_sps_fields.

A real fix for those requires SPS-NAL parsing from surface->source_data (parse the AnnexB prefix; ffmpeg-vaapi typically writes SPS+PPS+slice) OR a daedalus wire-protocol pass-through letting the client deliver the actual bitstream values. Both are operator-design calls — separate scoped commit. Full triage in #8 comment 1555.

Test plan

  • Build clean on higgs (Debian 13 trixie, gcc 14.2.0, libva 2.22.0). 31/31 objects, link OK.
  • vainfo against patched .so enumerates all 8 codec profiles. No init regression. Multi-device probe still wires rkvdec / rpi-hevc-dec / daedalus_v4l2 slots.
  • H.264 decode via daedalus_v4l2 to verify the instrumentation log line + max_num_ref_frames fallback fire. Operator-track — daedalus daemon is your branch; happy to run the smoke if you have a reference encoder + canned bitstream handy.

Reviewer questions

  • Is request_log fine as the always-on path here, or should it gate on a debug-level (existing logs in h264.c are unconditional, so this matches the file's style)?
  • Per-profile defaults for max_num_ref_frames when even DPB count is 0: ConstrainedBaseline → 1, everything else → 4. Acceptable, or want different values?
Addresses the libva-side portion of #8. ## Summary `src/h264.c` `h264_set_controls`: two additions, no behavior change for the existing HW decoder paths. **1. `max_num_ref_frames` fallback** — when `VAPicture->num_ref_frames` is 0, count non-INVALID DPB entries in `ReferenceFrames[16]`; if even that is 0, use a per-profile spec minimum (1 for baseline, 4 for main/high). Lenient HW decoders (rkvdec, hantro, rpi-hevc-dec) tolerated the 0; libavcodec-via-daedalus rejected every frame against `sps.max_num_ref_frames`. **2. Libva-boundary instrumentation** — single `request_log` dumping the raw VAAPI fields (seq_fields.value, pic_fields.value, num_ref_frames, bit_depth_*, picture_*_in_mbs_minus1) at function entry. This is the disambiguation handle for fix-4 of the issue (PPS flags read 0 → was it ffmpeg-vaapi not populating, or daedalus_v4l2 wire-protocol corrupting?). One printf per H.264 frame; safe to leave in. ## What's intentionally NOT in this PR Proposed fixes #1 and #2 from the issue body — `profile_idc` and `level_idc` from `seq_fields.bits.*` — are infeasible. Verified higgs libva 2.22.0-3 `/usr/include/va/va.h:3571-3622`: `VAPictureParameterBufferH264.seq_fields.bits` carries `chroma_format_idc`, `frame_mbs_only_flag`, `log2_max_frame_num_minus4`, `pic_order_cnt_type`, `log2_max_pic_order_cnt_lsb_minus4`, `delta_pic_order_always_zero_flag`, plus a handful of binary flags — **no `profile_idc`, no `level_idc`, no `constraint_set*_flag`**. Same VAAPI-blindspot family as the HEVC SPS fields tracked in `feedback_vaapi_blind_to_some_hevc_sps_fields`. A real fix for those requires SPS-NAL parsing from `surface->source_data` (parse the AnnexB prefix; ffmpeg-vaapi typically writes SPS+PPS+slice) OR a daedalus wire-protocol pass-through letting the client deliver the actual bitstream values. Both are operator-design calls — separate scoped commit. Full triage in #8 comment 1555. ## Test plan - [x] Build clean on higgs (Debian 13 trixie, gcc 14.2.0, libva 2.22.0). 31/31 objects, link OK. - [x] `vainfo` against patched .so enumerates all 8 codec profiles. No init regression. Multi-device probe still wires rkvdec / rpi-hevc-dec / daedalus_v4l2 slots. - [ ] H.264 decode via daedalus_v4l2 to verify the instrumentation log line + `max_num_ref_frames` fallback fire. **Operator-track** — daedalus daemon is your branch; happy to run the smoke if you have a reference encoder + canned bitstream handy. ## Reviewer questions - Is `request_log` fine as the always-on path here, or should it gate on a debug-level (existing logs in h264.c are unconditional, so this matches the file's style)? - Per-profile defaults for `max_num_ref_frames` when even DPB count is 0: ConstrainedBaseline → 1, everything else → 4. Acceptable, or want different values?
claude-noether added 1 commit 2026-05-20 18:18:01 +00:00
Closes the libva-side portion of marfrit/libva-v4l2-request-fourier#8.

Two small additions to h264_set_controls:

1. When VAPicture->num_ref_frames is 0 (older ffmpeg-vaapi paths /
   some daedalus_v4l2 consumers), count valid (non-INVALID) DPB
   entries in ReferenceFrames[16]. If even that returns 0, fall back
   to a per-profile spec minimum (1 for baseline, 4 for main/high).
   Hardware decoders (rkvdec, hantro, rpi-hevc-dec) tolerated the
   prior 0; libavcodec-via-daedalus enforces sps.max_num_ref_frames
   strictly and rejected every frame.

2. One request_log line at function entry dumping the raw VAAPI
   fields (seq_fields.value, pic_fields.value, num_ref_frames,
   bit_depth_*, picture_*_in_mbs_minus1). Disambiguates "ffmpeg-vaapi
   never populated" from "daedalus_v4l2 wire protocol corrupted" for
   the bit-fields-read-as-zero portion of issue #8.

Out of scope here (separate issue if pursued): profile_idc and
level_idc remain session-derived. VAAPI's VAPictureParameterBufferH264
omits both (verified higgs libva 2.22.0-3, /usr/include/va/va.h:
3571-3622) — same VAAPI-blindspot family as the HEVC SPS fields. A
real fix requires SPS-NAL parsing from surface->source_data OR a
daedalus wire-protocol pass-through; both are operator design calls,
not a libva-only patch.

Build verified on higgs (Debian 13 trixie, gcc 14.2.0, libva 2.22.0):
clean ninja link of v4l2_request_drv_video.so, vainfo enumerates all
8 codec profiles, no init regression.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
marfrit merged commit c1bb444d07 into master 2026-05-20 18:19:03 +00:00
marfrit deleted branch noether/h264-3-set-controls-bitstream-bug-8 2026-05-20 18:19:03 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marfrit/libva-v4l2-request-fourier#9