kernel: bind request controls to p_cur via v4l2_ctrl_request_setup #2

Merged
marfrit merged 1 commits from noether/kernel-ctrl-request-setup into main 2026-05-20 18:37:13 +00:00
Member

The other half of issue libva-v4l2-request-fourier#8 — actually fixes H.264 decode end-to-end on higgs

Bug

device_run was reading ctrl->p_cur.p_h264_* directly to populate struct daedalus_h264_meta for the wire protocol. But v4l2-m2m's request scheduler does NOT auto-bind the in-flight media_request's control values to p_cur — drivers have to call v4l2_ctrl_request_setup() explicitly. cedrus / rkvdec / hantro all do this from their device_run; daedalus didn't.

Result: daedalus_collect_h264_meta() read stale or default values (whatever the prior request had left, or v4l2_ctrl_new_custom initial state if no prior request had completed) instead of the S_EXT_CTRLS V4L2_CTRL_WHICH_REQUEST_VAL values libva-v4l2-request-fourier had just set for THIS frame.

Evidence

libva PR #9 / marfrit-packages PR #52 landed an instrumentation log line at h264_set_controls entry on higgs. Smoking gun side-by-side:

libva boundary (sent to kernel S_EXT_CTRLS):
  VAProfile=13 seq_fields=0x00032051 pic_fields=0x00000500 num_ref_frames=1

daedalus daemon (read from kernel p_cur via this commit's path):
  prof=100 level=41 ref_frames=0 flags=0x10 pps_flags=0x0

Libva sent num_ref_frames=1, ctrl handler returned 0. Libva sent rich pic_fields, ctrl handler returned all-zero flags. That's the missing setup.

Fix

One new call in daedalus_device_run, right after vb2_plane_vaddr and before daedalus_collect_h264_meta:

if (src_buf->vb2_buf.req_obj.req)
    v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, &ctx->hdl);

Pairs with the v4l2_ctrl_request_complete call already present in daedalus_complete_resp_frame (the completion-path half).

After-fix on higgs (Pi CM5, kernel 6.18.29+rpt-rpi-2712)

Daemon journal, same test stream as before (libx264 baseline 320x240 testsrc):

decoder: h264 SPS prof=66 level=11 ref_frames=1 w_mbs=19 h_units=14 poc_type=2 flags=0x50
decoder: h264 PPS spsid=0 ppsid=0 qp-26=-3 flags=0x88
decoder: OK 320x240 fmt=0 (yuv420p) fnv1a=0xf1c515aa luma=76800 chroma=38400
decoder: h264 SPS prof=66 level=11 ref_frames=1 ... flags=0x50
decoder: OK 320x240 fmt=0 (yuv420p) fnv1a=0x16e915e8 ...
decoder: OK 320x240 fmt=0 (yuv420p) fnv1a=0x16bd16cc ...
  • Per-frame fnv1a hashes are unique — libavcodec is actually decoding real pixel content from each P-frame (vs. the previous constant 0x6a6a05c5 "give-up-and-zero" hash).
  • Zero error while decoding MB lines.
  • Zero reference frames exceeds max lines.
  • ffmpeg exits rc=0 with valid output.

Daemon-side change

Small log-level promotion: the per-frame h264 SPS/PPS prepended ... trace went from log_debug to log_info so the journal shows what's being shipped into libavcodec without needing a daemon rebuild with --debug. Matches the libva-side h264_set_controls instrumentation already in libva PR #9.

Scope of remaining issue #8 work

Profile_idc / level_idc still come from libva's session-derived hardcoded values (h264_profile_to_idc + h264_derive_level_idc). For this test stream they happen to match (Constrained Baseline session profile → profile_idc=66 matching the bitstream). In general, a stream-accurate profile/level would need SPS-NAL parsing in libva — separate operator-design call, deferred per the libva PR #9 description.

Generated with Claude Code

## The other half of issue libva-v4l2-request-fourier#8 — actually fixes H.264 decode end-to-end on higgs ### Bug device_run was reading `ctrl->p_cur.p_h264_*` directly to populate `struct daedalus_h264_meta` for the wire protocol. But v4l2-m2m's request scheduler does NOT auto-bind the in-flight media_request's control values to p_cur — drivers have to call `v4l2_ctrl_request_setup()` explicitly. cedrus / rkvdec / hantro all do this from their device_run; daedalus didn't. Result: `daedalus_collect_h264_meta()` read stale or default values (whatever the prior request had left, or `v4l2_ctrl_new_custom` initial state if no prior request had completed) instead of the `S_EXT_CTRLS V4L2_CTRL_WHICH_REQUEST_VAL` values libva-v4l2-request-fourier had just set for THIS frame. ### Evidence libva PR #9 / marfrit-packages PR #52 landed an instrumentation log line at `h264_set_controls` entry on higgs. Smoking gun side-by-side: ``` libva boundary (sent to kernel S_EXT_CTRLS): VAProfile=13 seq_fields=0x00032051 pic_fields=0x00000500 num_ref_frames=1 daedalus daemon (read from kernel p_cur via this commit's path): prof=100 level=41 ref_frames=0 flags=0x10 pps_flags=0x0 ``` Libva sent num_ref_frames=1, ctrl handler returned 0. Libva sent rich pic_fields, ctrl handler returned all-zero flags. That's the missing setup. ### Fix One new call in `daedalus_device_run`, right after `vb2_plane_vaddr` and before `daedalus_collect_h264_meta`: ```c if (src_buf->vb2_buf.req_obj.req) v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, &ctx->hdl); ``` Pairs with the `v4l2_ctrl_request_complete` call already present in `daedalus_complete_resp_frame` (the completion-path half). ### After-fix on higgs (Pi CM5, kernel 6.18.29+rpt-rpi-2712) Daemon journal, same test stream as before (libx264 baseline 320x240 testsrc): ``` decoder: h264 SPS prof=66 level=11 ref_frames=1 w_mbs=19 h_units=14 poc_type=2 flags=0x50 decoder: h264 PPS spsid=0 ppsid=0 qp-26=-3 flags=0x88 decoder: OK 320x240 fmt=0 (yuv420p) fnv1a=0xf1c515aa luma=76800 chroma=38400 decoder: h264 SPS prof=66 level=11 ref_frames=1 ... flags=0x50 decoder: OK 320x240 fmt=0 (yuv420p) fnv1a=0x16e915e8 ... decoder: OK 320x240 fmt=0 (yuv420p) fnv1a=0x16bd16cc ... ``` - Per-frame fnv1a hashes are unique — libavcodec is actually decoding real pixel content from each P-frame (vs. the previous constant 0x6a6a05c5 "give-up-and-zero" hash). - Zero `error while decoding MB` lines. - Zero `reference frames exceeds max` lines. - ffmpeg exits rc=0 with valid output. ### Daemon-side change Small log-level promotion: the per-frame `h264 SPS/PPS prepended ...` trace went from `log_debug` to `log_info` so the journal shows what's being shipped into libavcodec without needing a daemon rebuild with --debug. Matches the libva-side h264_set_controls instrumentation already in libva PR #9. ### Scope of remaining issue #8 work Profile_idc / level_idc still come from libva's session-derived hardcoded values (`h264_profile_to_idc` + `h264_derive_level_idc`). For this test stream they happen to match (Constrained Baseline session profile → profile_idc=66 matching the bitstream). In general, a stream-accurate profile/level would need SPS-NAL parsing in libva — separate operator-design call, deferred per the libva PR #9 description. Generated with Claude Code
claude-noether added 1 commit 2026-05-20 18:35:43 +00:00
device_run was reading ctrl->p_cur.p_h264_* directly, but v4l2-m2m's
request scheduler does NOT auto-bind the in-flight media_request's
control values to the ctrl handler's p_cur slots — drivers have to
call v4l2_ctrl_request_setup() explicitly.  cedrus / rkvdec / hantro
all do this in their device_run; daedalus didn't.

Result: daedalus_collect_h264_meta() read stale or default values
(whatever the prior request had left in p_cur, or v4l2_ctrl_new_custom
initial state if no prior request had completed) instead of the
S_EXT_CTRLS V4L2_CTRL_WHICH_REQUEST_VAL values libva-v4l2-request-
fourier had just sent for THIS frame.

The mismatch was a smoking gun on higgs after libva PR #9 / packages
PR #52 landed an instrumentation log at h264_set_controls entry:

  libva boundary (sent to kernel):
    VAProfile=13 seq_fields=0x00032051 pic_fields=0x00000500 num_ref_frames=1
  daedalus daemon (read from kernel p_cur):
    prof=100 level=41 ref_frames=0 flags=0x10 pps_flags=0x0

After calling v4l2_ctrl_request_setup() at the top of device_run:

  daedalus daemon (read from kernel p_cur):
    prof=66 level=11 ref_frames=1 poc_type=2 flags=0x50 pps_flags=0x88

— matches what libva sent, matches the bitstream's actual SPS.

End-to-end test on higgs with libva-v4l2-request-fourier 1.0.0+r382
+gc1bb444 (after-fix-3-and-fix-4-instrumentation) + this kernel
patch:

  $ LIBVA_DRIVER_NAME=v4l2_request ffmpeg -hwaccel vaapi \
      -hwaccel_device /dev/dri/renderD128 -i h264_test.mp4 \
      -frames:v 1 -f null - ...
  rc=0
  daemon journal: zero "error while decoding MB" lines, zero
  "reference frames exceeds max" lines.  Per-frame fnv1a hashes
  differ (0xf1c515aa, 0x16e915e8, 0x16bd16cc, ...) instead of
  the constant 0x6a6a05c5 "give-up-and-zero" hash from before —
  libavcodec is actually decoding real pixel content from each
  P-frame.

Pair note: the daemon side already calls v4l2_ctrl_request_complete
in daedalus_complete_resp_frame (line 834) — this commit pairs the
setup half with that completion half.

The daemon side change (decoder.c) is a small log-level promotion:
the per-frame "h264 SPS/PPS prepended ..." trace went from log_debug
to log_info so the journal shows what's being shipped into libavcodec
without needing a daemon rebuild with --debug.  Matches the libva-
side h264_set_controls instrumentation that landed in libva PR #9.

Closes part of issue libva-v4l2-request-fourier#8 — the SPS/PPS
field-value gap.  Profile/level still come from libva's session-
derived hardcoded values (h264_profile_to_idc + h264_derive_level_
idc) which is sufficient for libavcodec to accept the synthesised
NAL unit; a true stream-parsed profile/level would need SPS-NAL
parsing in libva — separate operator-design call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
marfrit merged commit 462aa4b480 into main 2026-05-20 18:37:13 +00:00
marfrit deleted branch noether/kernel-ctrl-request-setup 2026-05-20 18:37:13 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: reauktion/daedalus-v4l2#2