marfrit 1ae9528e76 Phase 8.8: throughput baseline + multi-codec streams + HDR
Per the correctness-before-speed principle: measure before
optimising. Roadmap going in said "QPU dispatch substitution
to hit 30fps@1080p". Measurement on hertz shows the FFmpeg
software path already hits 65-88 fps@1080p across all three
codecs — QPU substitution would be premature optimisation.

So 8.8 ships what's actually useful:
1. Per-frame timing in test_m2m_stream.
2. Multi-frame AV1 + H.264 streams verified byte-exact at
   1080p (closes the "VP9-only stream tests" gap from 8.7).
3. HDR / 10-bit via V4L2_PIX_FMT_P010 + daemon
   pack_p010_to_plane.

Test harness (tools/test_m2m_stream.c):
- Per-frame µs timing via CLOCK_MONOTONIC; reports mean/p50/
  p99/min/max + wall ms + fps.
- Annex-B H.264 parser: split on 3-/4-byte start codes,
  accumulate NALs into access units (push on VCL NAL types
  1 or 5). Without AU grouping FFmpeg rejects SPS/PPS-only
  buffers as "no frame!".
- Format auto-detect (DKIF magic → IVF; else Annex-B).
- Optional 6th arg `[capture]`: nv12m | p010.
- CAPTURE mmap path generalised for num_planes==1 (P010).

Kernel (kernel/daedalus_v4l2_main.c):
- CAPTURE formats array {NV12M, P010}; enum_fmt walks it.
- daedalus_fill_capture_fmt takes a fourcc:
    NV12M: 2 planes, W*H + W*H/2 bytes, bpl=W
    P010:  1 plane,  W*H*2 + W*H bytes, bpl=W*2
- try_fmt preserves caller fourcc when supported.
- daedalus_complete_resp_frame's dmabuf path now sets each
  plane's payload to vb2_plane_size(vb,p) — generalises
  cleanly across 1-plane (P010) and 2-plane (NV12M) layouts;
  the daemon fully populates the plane so payload =
  sizeimage.

Daemon (daemon/src/decoder.c):
- pack_p010_to_plane: YUV420P10LE → P010 single-plane.
  10-bit samples shifted left by 6 to MSB-align in 16-bit
  words per V4L2 ABI. Y at base+0, interleaved CbCr right
  after Y plane (per format spec for single-plane P010).
  Strips source stride padding; respects destination stride.
- daedalus_decoder_run_request dispatches on
  req->capture_pix_fmt (NV12M → pack_nv12_to_planes; P010
  → pack_p010_to_plane; else warn + skip).
- Includes <linux/videodev2.h> for fourcc constants.

Verification on hertz (Pi 5, 6.12.75+rpt-rpi-2712):

1080p throughput baseline (30 frames testsrc, dmabuf path):

  VP9   1080p:  mean 12.0 ms,  p99 15.9 ms,  fps **83.1**, byte-exact ✓
  AV1   1080p:  mean 15.4 ms,  p99 41.0 ms,  fps **65.0**, byte-exact ✓
  H.264 1080p:  mean 11.3 ms,  p99 21.5 ms,  fps **88.3**, byte-exact ✓

All 2-3× over the 30fps-floor-is-fine criterion.

HDR / 10-bit 1080p P010:
  10 frames, 62 MB output, fps **48.8**, byte-exact vs
  `ffmpeg -pix_fmt p010le -f rawvideo`.

Small-frame P010 (320×240): fps 966 — fixed daemon overhead
dominates at low resolutions.

v4l2-compliance unchanged from 8.7: 49/49 passing.
Format enumeration confirms NM12 + P010 on CAPTURE.

Clean SIGTERM + rmmod; no kernel oops/WARN.

Roadmap update (docs/roadmap.md):
- 8.8 marked closed with closure-doc reference, including
  the explicit "QPU substitution not needed" rationale.
- 8.9 reshaped: libva-v4l2-request consumer integration
  (per project_consumer_target memory) — the actual
  user-facing endpoint.

Per correctness-before-speed:
- Measured first; QPU work explicitly justified-out via data.
- Byte-exact pixel comparison for every codec/format combo
  (NV12: VP9, AV1, H.264; P010: VP9 10-bit at 320×240 and
  1080p).
- AU grouping in the Annex-B parser is the correct
  semantic boundary, not just a workaround.
- vb2_plane_size for payload generalises to any plane
  count, not hardcoded to 2.

Phase 8.9 next: libva-v4l2-request integration — close
the loop from YouTube/Firefox to /dev/video0 + daemon
playback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 16:34:05 +00:00

daedalus-v4l2

V4L2 stateless decoder for the Raspberry Pi 5 / CM5, backed by the daedalus-fourier kernel library (VP9 + AV1 CDEF + H.264 video decode kernels on VideoCore VII compute + ARM NEON).

Status: scaffold (2026-05-18). Architecture locked per daedalus-fourier session memory; implementation not yet begun.

What this is

Sibling repo to daedalus-fourier (the kernel library; cycles 1-9 closed).

A two-piece userspace + kernel-module stack that exposes a V4L2 stateless decoder interface (/dev/videoNN) so that libva-v4l2-request-fourierfirefox-fourier / chromium-fourier can drive it the same way they drive existing hardware-decode pipelines on Pi 5 / RK3588.

+-----------------------------------------------------------+
| firefox-fourier / chromium-fourier  (existing)            |
+-----------------------------------------------------------+
| VA-API                                                    |
+-----------------------------------------------------------+
| libva-v4l2-request-fourier  (existing, sibling project)   |
+-----------------------------------------------------------+
| V4L2 stateless ioctl uAPI                                 |
+-----------------------------------------------------------+
| daedalus-v4l2 kernel module  (`kernel/`)                  |
|   - registers /dev/videoNN                                |
|   - parses V4L2 stateless ioctls (VP9/AV1/H.264 controls) |
|   - forwards bitstream + controls to userspace daemon     |
|     via chardev or netlink                                |
+-----------------------------------------------------------+
| daedalus-v4l2 userspace daemon  (`daemon/`)               |
|   - takes bitstream blobs + per-slice controls            |
|   - drives FFmpeg parsers via dlopen (Option γ)           |
|   - dispatches per-block ops via daedalus-fourier         |
|     public API (daedalus_dispatch_*)                      |
|   - posts decoded frames back to kernel module            |
+-----------------------------------------------------------+
| daedalus-fourier kernel library  (sibling project)        |
|   - exports include/daedalus.h public API                 |
|   - per-kernel CPU NEON + opportunistic V3D QPU dispatch  |
|   - 9 closed cycles across VP9, AV1 CDEF, H.264           |
+-----------------------------------------------------------+
| V3D 7.1 (Mesa userspace v3dv) + ARM NEON (BCM2712)        |
+-----------------------------------------------------------+

Why this architecture (Option B + γ + sibling)

Locked by user 2026-05-18 from 3 options in daedalus-fourier/docs/phase8_scoping.md:

  • Option B over A (userspace v4l2loopback): real /dev/videoNN, proper DRM PRIME / dmabuf for browser zero-copy.
  • Option γ: dlopen FFmpeg as parser at runtime. No vendoring, fastest to v1.
  • Sibling repo: per project_consumer_target convention, V4L2-side work lives outside daedalus-fourier so the kernel-library has a clean API boundary.

Status

Initial scaffold only. See docs/architecture.md for the deeper design and docs/roadmap.md for the sub-phase breakdown.

Repo layout

  • kernel/ — Linux kernel module (V4L2 device registration + ioctl handling + userspace chardev bridge). Out-of-tree.
  • daemon/ — userspace decoder daemon (links libdaedalus_core.a from sibling daedalus-fourier; uses dlopen for FFmpeg parser).
  • include/ — shared headers between kernel and daemon.
  • docs/ — architecture + roadmap.

License

Kernel module: GPLv2 (required for kernel-tree compatibility). Userspace daemon: BSD-2-Clause (matches daedalus-fourier).

S
Description
No description provided
Readme 686 KiB
Languages
C 97.8%
CMake 1.5%
Makefile 0.7%