Files
daedalus-v4l2/daemon
marfrit 29f16ece13 kernel: bind request controls to p_cur before reading them
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>
2026-05-20 20:35:06 +02:00
..

daemon/ — daedalus-v4l2 userspace decoder daemon

Userspace daemon that:

  1. Connects to the kernel module's chardev
  2. Receives bitstream + V4L2 control blobs
  3. Parses bitstream via dlopen'd FFmpeg
  4. Dispatches per-block work via daedalus_dispatch_* from sibling daedalus-fourier
  5. Returns decoded frames to kernel

Status

Scaffold only. Phase 8.3 not yet started.

Build dependencies (planned)

  • libdaedalus_core.a from sibling daedalus-fourier (static link)
  • FFmpeg dev headers (for AVPacket/AVCodec interface types) + runtime FFmpeg .so (loaded via dlopen)
  • libv4l2 (for V4L2 control struct definitions)
  • pthread

Build (when implemented)

mkdir build && cd build
cmake .. -DDAEDALUS_FOURIER_DIR=/path/to/daedalus-fourier
make

Layout (planned)

  • CMakeLists.txt
  • src/main.c — event loop, chardev connection
  • src/parser.c — FFmpeg dlopen wrapper + per-codec dispatch
  • src/decode_vp9.c, src/decode_av1.c, src/decode_h264.c — per-codec block walkers
  • src/frame_io.c — frame allocation, return to kernel

License

BSD-2-Clause (matches daedalus-fourier sibling).

Phase 8.3 starting point

A standalone program that:

  1. Opens a .ivf or .mp4
  2. Pulls codec packets via dlopen'd avformat
  3. Calls dlopen'd avcodec to parse (without decoding)
  4. Walks the block-level metadata
  5. Validates output structure

No kernel involvement yet — just confirm the parse path works.