proto: bump PROTO_MAX_PAYLOAD 64 KiB → 1 MiB (closes #19) #20

Merged
marfrit merged 1 commits from noether/issue-19-bump-proto-payload-1mib into main 2026-05-22 18:47:47 +00:00
Owner

Fixes #19.

Bug

Real H.264 access units routinely exceed the previous 64 KiB wire-protocol cap (720p worst-case I-frame ~200 KiB; 1080p ~500 KiB). libva-v4l2-request-fourier detects the under-sized OUTPUT_MPLANE buffer and asks for sizeimage=147456 via VIDIOC_S_FMT, but daedalus_fill_output_fmt unconditionally pins it to DAEDALUS_MAX_BITSTREAM (65484) — Firefox loses the slice and falls back to libmozavcodec SW. Trace:

v4l2-request: codec_store_buffer: OUTPUT-pool resize (need 72921 > cap 65484 → new_sizeimage 147456)
v4l2-request: codec_store_buffer_ensure_capacity: kernel returned sizeimage 65484 < required 72921

Fix

Bump DAEDALUS_PROTO_MAX_PAYLOAD in include/daedalus_v4l2_proto.h from 64 KiB to 1 MiB. DAEDALUS_MAX_BITSTREAM is derived from the same #define, so the kernel's reported sizeimage lifts with it.

Allocations (kmemdup, kmalloc, daemon malloc of read buffer, vb2 plane backing) are sized per-payload at runtime; the only growth is the daemon's startup read buffer (one ~1 MiB allocation per daemon process) and V4L2 OUTPUT_MPLANE per-buffer size. KMALLOC_MAX_SIZE on aarch64 SLUB is several MiB; 1 MiB is well within bounds. Other V4L2 stateless decoders (cedrus, rkvdec, hantro) report 1-4 MiB sizeimage — this puts daedalus at the conservative end of normal.

Compatibility

#define-only change; struct layout unchanged. But the effective cap is the smaller of (kernel cap, daemon cap):

  • new daemon + stale kernel: still capped at 64 KiB until the kernel rebuilds.
  • new kernel + stale daemon: same.

Lock-step install of daedalus-v4l2 + daedalus-v4l2-dkms is required. Mirrors the PR-#7/#8 cadence.

NOT covered (deferred)

  • daedalus_fill_output_fmt still hardcodes sizeimage = DAEDALUS_MAX_BITSTREAM regardless of userspace request. Acceptable for now: vb2 allocates up to that, and libva's resize-test now sees the kernel report a sizeimage at-least-as-large as what it asked for. A future cleanup could respect userspace's S_FMT.sizeimage clamped to the cap, to save memory on small-bitrate streams.
  • chardev kmallockvmalloc swap. Only matters above KMALLOC_MAX_SIZE, not at 1 MiB.

Verify post-merge

  1. Bump marfrit/marfrit-packages/{debian,arch}/daedalus-v4l2{,-dkms} to this tip — both packages atomically.
  2. Deploy on higgs.
  3. Open YouTube avc1 720p in Firefox; play.
  4. Confirm no codec_store_buffer_ensure_capacity: kernel returned sizeimage 65484 < required N in libva trace.
  5. Confirm decoder: OK lines in daemon journal while playing.

Refs

  • Issue #19: #19
  • Earlier failure mode (tiny pause sentinel): #17 / PR #18.
  • Same OUTPUT-pool sizing story, opposite end of the size range.
Fixes #19. ## Bug Real H.264 access units routinely exceed the previous 64 KiB wire-protocol cap (720p worst-case I-frame ~200 KiB; 1080p ~500 KiB). libva-v4l2-request-fourier detects the under-sized OUTPUT_MPLANE buffer and asks for `sizeimage=147456` via `VIDIOC_S_FMT`, but `daedalus_fill_output_fmt` unconditionally pins it to `DAEDALUS_MAX_BITSTREAM` (65484) — Firefox loses the slice and falls back to libmozavcodec SW. Trace: ``` v4l2-request: codec_store_buffer: OUTPUT-pool resize (need 72921 > cap 65484 → new_sizeimage 147456) v4l2-request: codec_store_buffer_ensure_capacity: kernel returned sizeimage 65484 < required 72921 ``` ## Fix Bump `DAEDALUS_PROTO_MAX_PAYLOAD` in `include/daedalus_v4l2_proto.h` from 64 KiB to 1 MiB. `DAEDALUS_MAX_BITSTREAM` is derived from the same #define, so the kernel's reported `sizeimage` lifts with it. Allocations (`kmemdup`, `kmalloc`, daemon `malloc` of read buffer, vb2 plane backing) are sized per-payload at runtime; the only growth is the daemon's startup read buffer (one ~1 MiB allocation per daemon process) and V4L2 OUTPUT_MPLANE per-buffer size. `KMALLOC_MAX_SIZE` on aarch64 SLUB is several MiB; 1 MiB is well within bounds. Other V4L2 stateless decoders (cedrus, rkvdec, hantro) report 1-4 MiB sizeimage — this puts daedalus at the conservative end of normal. ## Compatibility `#define`-only change; struct layout unchanged. But the *effective* cap is the smaller of (kernel cap, daemon cap): - new daemon + stale kernel: still capped at 64 KiB until the kernel rebuilds. - new kernel + stale daemon: same. **Lock-step install of `daedalus-v4l2` + `daedalus-v4l2-dkms` is required.** Mirrors the PR-#7/#8 cadence. ## NOT covered (deferred) - `daedalus_fill_output_fmt` still hardcodes `sizeimage = DAEDALUS_MAX_BITSTREAM` regardless of userspace request. Acceptable for now: vb2 allocates up to that, and libva's resize-test now sees the kernel report a sizeimage at-least-as-large as what it asked for. A future cleanup could respect userspace's `S_FMT.sizeimage` clamped to the cap, to save memory on small-bitrate streams. - chardev `kmalloc` → `kvmalloc` swap. Only matters above `KMALLOC_MAX_SIZE`, not at 1 MiB. ## Verify post-merge 1. Bump `marfrit/marfrit-packages/{debian,arch}/daedalus-v4l2{,-dkms}` to this tip — both packages atomically. 2. Deploy on higgs. 3. Open YouTube avc1 720p in Firefox; play. 4. Confirm no `codec_store_buffer_ensure_capacity: kernel returned sizeimage 65484 < required N` in libva trace. 5. Confirm `decoder: OK` lines in daemon journal while playing. ## Refs - Issue #19: https://git.reauktion.de/reauktion/daedalus-v4l2/issues/19 - Earlier failure mode (tiny pause sentinel): #17 / PR #18. - Same OUTPUT-pool sizing story, opposite end of the size range.
marfrit added 1 commit 2026-05-22 18:46:55 +00:00
Real H.264 access units routinely exceed the previous 64 KiB cap
on the chardev wire protocol:

  720p worst-case I-frame  ~200 KiB
  1080p worst-case I-frame ~500 KiB

libva-v4l2-request-fourier detects the under-sized OUTPUT-MPLANE
buffer and tries to grow it via VIDIOC_S_FMT to 147456 B, but
daedalus_fill_output_fmt unconditionally pins sizeimage to
DAEDALUS_MAX_BITSTREAM (= 65484) regardless of userspace's
request.  Firefox loses the slice, falls back to libmozavcodec
SW for the rest of the session.

Bumping the wire-protocol cap to 1 MiB lifts the kernel
OUTPUT_MPLANE sizeimage with it (DAEDALUS_MAX_BITSTREAM is derived
from the same #define).  All allocations (kernel kmalloc /
kmemdup, daemon read buffer, vb2 plane backing) are dynamic and
sized per-payload at runtime, so the only growth is the daemon's
startup read buffer (one ~1 MiB allocation per daemon process)
and the V4L2 OUTPUT_MPLANE per-buffer size.  KMALLOC_MAX_SIZE on
aarch64 SLUB is several MiB; 1 MiB is well within bounds.  Other
V4L2 stateless decoders (cedrus, rkvdec, hantro) report 1-4 MiB
OUTPUT_MPLANE sizeimage — this puts daedalus at the conservative
end of normal.

## Compatibility

#define-only change; struct layout unchanged.  But the
effective cap is the smaller of (kernel cap, daemon cap), so:
- new daemon + stale kernel: still capped at 64 KiB until the
  kernel module rebuilds.
- new kernel + stale daemon: same.
Lock-step install of daedalus-v4l2 + daedalus-v4l2-dkms is
therefore required for the fix to take effect; mirrors the
PR-#7/#8 cadence.

## NOT changed in this commit

- daedalus_fill_output_fmt still hardcodes sizeimage =
  DAEDALUS_MAX_BITSTREAM regardless of userspace request.
  Acceptable: vb2 will allocate up to that, and libva's resize-
  test now sees the kernel report a sizeimage at-least-as-large
  as what it asked for (147456 < 1048524).  A future cleanup
  could respect userspace's S_FMT.sizeimage clamped to the cap,
  to save memory on tiny streams.
- chardev kmalloc → kvmalloc swap (only matters above
  KMALLOC_MAX_SIZE, not here).

Refs #19.
marfrit merged commit 872eec505e into main 2026-05-22 18:47:47 +00:00
marfrit deleted branch noether/issue-19-bump-proto-payload-1mib 2026-05-22 18:47:47 +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#20