11 Commits

Author SHA1 Message Date
marfrit ce2fff1a4f libva-v4l2-request-fourier: bump pin to c454618 (#15 transparent resize)
Bumps both Arch PKGBUILD and Debian build-deb.sh pins to PR #16 —
codec_store_buffer + request_pool_resize transparent OUTPUT-pool grow
on a mid-session resolution upshift overrun.  Picks up the frame-
survival path that supersedes #13's drop-and-recreate fallback.

Dual-pin per feedback_marfrit_packages_dual_pin so both Arch and
Debian repos see check-already-published.sh report a new version.
2026-05-21 13:24:21 +02:00
marfrit 9301894997 Merge pull request 'daedalus-v4l2{,-dkms}: f0d4186 -> 79256dc — H.264 B-frame reorder fix + menu ctrls' (#67) from claude-noether/marfrit-packages:noether/daedalus-bump-79256dc into main
Reviewed-on: marfrit/marfrit-packages#67
2026-05-21 10:51:14 +00:00
claude-noether f21c1ff80a daedalus-v4l2{,-dkms}: f0d4186 -> 79256dc — H.264 B-frame reorder + menu ctrls
Lock-step bump of both packages to daedalus-v4l2#7 + #4.  PROTO_VERSION
bumps 0 → 1 at the daemon ↔ kernel chardev wire: REQ_DECODE adds
__u64 src_pts (the OUTPUT vb2 timestamp); RESP_FRAME adds __u32 flags
(HAS_PIXELS / SRC_CONSUMED) + __u64 output_src_pts (= frame->pts on
drain).  Both .debs must be installed atomically or the chardev
handshake rejects the version mismatch.

  * daedalus-v4l2: daemon's send_packet → receive_frame loop now
    stamps pkt->pts = req->src_pts and looks up the cookie for each
    drained frame via frame->pts.  chardev_client emits multiple
    RESP_FRAME messages per REQ_DECODE when libavcodec's display-
    order DPB releases an earlier frame on receipt of a later
    bitstream — fixes the "2 1 4 3 6 5" pair-swap on H.264 streams
    with B-frames.

  * daedalus-v4l2-dkms: kernel device_run mirrors src_buf timestamp
    into REQ_DECODE.src_pts.  Completion path splits HAS_PIXELS /
    SRC_CONSUMED: src is released as soon as send_packet succeeds
    (so the m2m scheduler moves on), dst stays parked until the
    matching frame is drained later.  TIMESTAMP_COPY's auto src→dst
    pairing no longer applies once lifecycles decouple — dst is
    stamped explicitly from inflight->src_pts at HAS_PIXELS time.

  * daedalus-v4l2-dkms also carries forward the -2 multi-kernel
    postinst fix (#64) from the prior PKGREL.  PKGREL resets to 1 on
    the new upstream pin.

The daedalus-v4l2#4 H.264 DECODE_MODE + START_CODE menu controls (a
cosmetic warning fix that PR landed alongside #7) is also subsumed —
"Unable to set control(s) error_idx=2/2" no longer fires.

Refs:
  * reauktion/daedalus-v4l2#7
  * reauktion/daedalus-v4l2#4
  * reauktion/daedalus-v4l2#6
2026-05-21 12:41:12 +02:00
marfrit e15b887d8d Merge pull request 'libva-v4l2-request-fourier: bump pin to 2860d75 (#13 bounds-check fix)' (#66) from claude-noether/marfrit-packages:bump-libva-fourier-2860d75-issue-13 into main
Reviewed-on: marfrit/marfrit-packages#66
2026-05-21 10:38:03 +00:00
marfrit b69db65037 libva-v4l2-request-fourier: bump pin to 2860d75 (#13 bounds-check fix)
Bumps both the Arch PKGBUILD and the Debian build-deb.sh pins to PR
#14 merge — codec_store_buffer bounds-checks for VASliceDataBufferType.
Picks up the SIGSEGV fix for mpv --hwdec=vaapi-copy on resolution
upshift mid-stream (issue #13).

Dual-pin so check-already-published.sh detects both pool ABIs as
needing a fresh build.
2026-05-21 12:19:04 +02:00
marfrit adcc824bf7 Merge pull request 'daedalus-v4l2-dkms: postinst — autoinstall for all installed kernels (#64)' (#65) from claude-noether/marfrit-packages:fix/daedalus-dkms-multi-kernel-64 into main
Reviewed-on: marfrit/marfrit-packages#65
2026-05-21 09:28:47 +00:00
claude-noether 7213b23861 daedalus-v4l2-dkms: postinst — autoinstall for all installed kernels (#64)
Previously dkms autoinstall ran only against $(uname -r), so installing
the package on kernel A and rebooting into separately-installed kernel B
left /lib/modules/B/updates/dkms/ empty.  /dev/daedalus-v4l2 absent,
daedalus daemon nothing to talk to, browser/VAAPI silently falling back
to software with no obvious diagnostic for the user.

Now we enumerate every /lib/modules/*/build that resolves to a real
directory (i.e. headers are actually installed for that kernel) and run
'dkms autoinstall -k <kver>' for each.  Per-kernel verify; aggregated
warning only for the kernels that didn't build.

Tested locally: enumeration filters dangling /build symlinks correctly
(2 kernels installed, 1 has headers → only that one is built against).

Bumps PKGREL 1 → 2.  Closes #64.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 11:07:35 +02:00
marfrit 2cd3acd680 Merge pull request 'firefox-fourier 0003: proper V4L2REQUEST type acceptance patch (closes #60)' (#63) from firefox-0003-v4l2request-proper-2026-05-21 into main
Reviewed-on: marfrit/marfrit-packages#63
2026-05-21 05:10:27 +00:00
marfrit 22ac3c9845 firefox-fourier 0003: V4L2REQUEST type acceptance (proper patch, regenerated from real source)
Closes #60.

Resolves the malformed-patch issue from #61 (since reverted in #62)
by regenerating the 0003 patch via actual application against firefox
150.0.3 Pi-OS source.

Functional change vs prior 0003: walking hw_configs accepts
AV_HWDEVICE_TYPE_DRM (legacy) OR integer device_type values 13/14
(AV_HWDEVICE_TYPE_V4L2REQUEST in Kwibos no-AMF / upstream-AMF trees).
CreateV4L2RequestDeviceContext passes integer 13 (Kwibos value) cast
to enum AVHWDeviceType for the av_hwdevice_ctx_create call.

Tested: applied cleanly via patch -p1 against firefox-150.0.3 source
post-Pi-OS-quilt-patches. Test build follow-up in firefox-rpios EC2
script (drops the in-source sed hack from v7-v8).
2026-05-21 06:59:20 +02:00
marfrit 3275d06728 Merge pull request 'Revert #61: malformed firefox-fourier 0003 patch' (#62) from revert-pr-61-malformed-patch into main
Reviewed-on: marfrit/marfrit-packages#62
2026-05-21 04:33:35 +00:00
marfrit 33b91cf7dc Revert "Merge pull request 'firefox-fourier patch #3: accept AV_HWDEVICE_TYPE_V4L2REQUEST too' (#61) from fix/firefox-v4l2request-type-accept-2026-05-21 into main"
This reverts commit a640633ea7, reversing
changes made to de3c2c6744.
2026-05-21 06:32:39 +02:00
9 changed files with 226 additions and 156 deletions
+5 -3
View File
@@ -18,10 +18,12 @@ _module=daedalus_v4l2
# Same pin as arch/daedalus-v4l2 — keep kernel module + daemon # Same pin as arch/daedalus-v4l2 — keep kernel module + daemon
# bit-versioned together so the chardev wire protocol stays in sync. # bit-versioned together so the chardev wire protocol stays in sync.
_commit=f0d41867f60f5bf8dbfcc6cc16404d7d7eb90014 # PROTO_VERSION 0 → 1 at this pin (H.264 B-frame reorder fix); must
# install both packages atomically.
_commit=79256dc7ef41f83873ca9c23db20f5888858e65d
pkgver=0.1.0.r24.f0d4186 pkgver=0.1.0.r28.79256dc
pkgrel=1 # reset for new upstream pin (3dd0eb0 — DAEMON-PPS H.264 SPS/PPS NAL synth) pkgrel=1 # reset for new upstream pin (79256dc — H.264 B-frame reorder fix)
pkgdesc="V4L2 stateless decoder shim kernel module (DKMS) — Pi 5 / CM5" pkgdesc="V4L2 stateless decoder shim kernel module (DKMS) — Pi 5 / CM5"
arch=('any') arch=('any')
url="https://git.reauktion.de/reauktion/daedalus-v4l2" url="https://git.reauktion.de/reauktion/daedalus-v4l2"
+9 -8
View File
@@ -16,17 +16,18 @@
pkgname=daedalus-v4l2 pkgname=daedalus-v4l2
_upstreampkg=daedalus-v4l2 _upstreampkg=daedalus-v4l2
# Pin the daedalus-v4l2 tip. 481279c = "Phase 8.13: byte-exact end-to- # Pin the daedalus-v4l2 tip. 79256dc = "kernel + daemon: H.264 B-frame
# end via libva (consumer target hit)" — first commit where the full # display reorder fix (closes #6)" — adds the wire-protocol src_pts /
# ffmpeg -hwaccel vaapi → libva → /dev/video0 → daemon path lands a # output_src_pts / RESP_FRAME flags split that lets H.264 streams with
# pixel-correct decoded frame back in ffmpeg. Promote to a later pin # B-frames preserve display order through libva → kernel → daemon.
# only after a future phase closes cleanly. # PROTO_VERSION bumps 0 → 1; lock-step userspace + kernel rebuild
_commit=f0d41867f60f5bf8dbfcc6cc16404d7d7eb90014 # REQUIRED (daedalus-v4l2-dkms PKGBUILD pinned to the same commit).
_commit=79256dc7ef41f83873ca9c23db20f5888858e65d
# 0.1.0 (pre-1.0) + commit count + short sha. Bump the .Y on each # 0.1.0 (pre-1.0) + commit count + short sha. Bump the .Y on each
# Phase 8.x close. pkgver() recomputes at build time. # Phase 8.x close. pkgver() recomputes at build time.
pkgver=0.1.0.r24.f0d4186 pkgver=0.1.0.r28.79256dc
pkgrel=1 # reset for new upstream pin (3dd0eb0 — DAEMON-PPS H.264 SPS/PPS NAL synth) pkgrel=1 # reset for new upstream pin (79256dc — H.264 B-frame reorder fix)
pkgdesc="Userspace daemon for the daedalus-v4l2 V4L2 stateless decoder shim (VP9/AV1/H.264 on Pi 5 / CM5)" pkgdesc="Userspace daemon for the daedalus-v4l2 V4L2 stateless decoder shim (VP9/AV1/H.264 on Pi 5 / CM5)"
arch=('aarch64') arch=('aarch64')
url="https://git.reauktion.de/reauktion/daedalus-v4l2" url="https://git.reauktion.de/reauktion/daedalus-v4l2"
@@ -18,94 +18,86 @@ This patch adds a sibling init path, `InitV4L2RequestDecoder`, that:
* looks up the codec via two complementary mechanisms libavcodec * looks up the codec via two complementary mechanisms libavcodec
uses for v4l2_request: uses for v4l2_request:
- **named codec** (`h264_v4l2request`, `vp8_v4l2request`, etc.): - **named codec** (`h264_v4l2request`, `vp8_v4l2request`, etc.):
the legacy AVCodec-per-hwaccel registration. ALARM, Debian, the legacy AVCodec-per-hwaccel registration.
and most distros building with --enable-v4l2-request expose
this (avcodec_find_decoder_by_name lookup).
- **generic codec + hw_configs walk**: the modern hwaccel - **generic codec + hw_configs walk**: the modern hwaccel
registration. Accepts EITHER AV_HWDEVICE_TYPE_DRM (legacy registration. Accepts EITHER AV_HWDEVICE_TYPE_DRM (legacy
ffmpeg-v4l2-request-fork output prior to FFmpeg 7.1) OR ffmpeg-v4l2-request-fork output prior to FFmpeg 7.1) OR
AV_HWDEVICE_TYPE_V4L2REQUEST (FFmpeg 7.1+ dedicated enum, AV_HWDEVICE_TYPE_V4L2REQUEST (FFmpeg 7.1+ dedicated enum,
value 13 on Kwiboo's no-AMF tree, 14 on upstream-AMF tree). value 13 on Kwiboo's no-AMF tree, 14 on upstream-AMF tree).
Mozilla's bundled libavutil headers may not have the V4L2REQUEST
enumerator, so the test is on the integer value via `(int)cast`.
Probes named-codec first (explicit, portable) and falls back to Probes named-codec first (explicit, portable) and falls back to
walking the generic codec's `hw_configs` for either device type; walking the generic codec's `hw_configs` for either device type;
* creates an hwdevice context of the matched type bound to * creates an hwdevice context bound to `/dev/dri/renderD128`. Uses
`/dev/dri/renderD128` via the `av_hwdevice_ctx_create` wrapper integer 13 (V4L2REQUEST as defined by Kwiboo's v4l2-request-n7.1.3
(patch 2/4) and attaches it to the codec context; tree, what our libavcodec61-fourier emits) cast to enum
AVHWDeviceType for the av_hwdevice_ctx_create call;
* reuses the existing `ChooseV4L2PixelFormat` get-format callback * reuses the existing `ChooseV4L2PixelFormat` get-format callback
(already returns `AV_PIX_FMT_DRM_PRIME`) and the existing (already returns `AV_PIX_FMT_DRM_PRIME`) and the existing
`apply_cropping = 0` constraint. `apply_cropping = 0` constraint.
`InitV4L2RequestDecoder` is invoked **before** `InitV4L2Decoder` in `InitV4L2RequestDecoder` is invoked **before** `InitV4L2Decoder` in
`InitHWDecoderIfAllowed`. On Rockchip mainline it succeeds via either `InitHWDecoderIfAllowed`. On Rockchip mainline it succeeds via either
mechanism (ALARM uses the named codec). On Pi4 / Mediatek / mechanism. On Pi4 / Mediatek / vendor-MPP-stateful boards neither
vendor-MPP-stateful boards neither mechanism is registered for the mechanism is registered for the codec, the function bails out, and the
codec, the function bails out, and the existing stateful existing stateful `InitV4L2Decoder` runs as before. No regression of
`InitV4L2Decoder` runs as before. No regression of stateful boards. stateful boards.
`mV4L2RequestDeviceContext` is unconditionally `av_buffer_unref`'d in `mDRMDeviceContext` is unconditionally `av_buffer_unref`'d in
`ProcessShutdown` (no-op when null). Gated behind `ProcessShutdown` (no-op when null). Gated behind
`media.ffmpeg.v4l2-request.enabled` from patch 4/4. `media.ffmpeg.v4l2-request.enabled` from patch 4/4.
Bug 1969297. Bug 1969297.
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h 2026-05-21 04:57:59.570946601 +0000
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h 2026-03-18 19:22:14.000000000 +0000 +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h 2026-05-21 04:57:59.876488776 +0000
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h 2026-04-27 20:43:39.347992674 +0000 @@ -225,7 +225,12 @@
@@ -225,7 +225,13 @@
bool IsLinuxHDR() const; bool IsLinuxHDR() const;
MediaResult InitVAAPIDecoder(); MediaResult InitVAAPIDecoder();
MediaResult InitV4L2Decoder(); MediaResult InitV4L2Decoder();
+ // firefox-fourier: V4L2 stateless (request API) decode path. Uses + // firefox-fourier: V4L2 stateless (request API) decode path. Uses
+ // libavcodec's v4l2_request hwaccel, which it surfaces via either + // libavcodec's v4l2_request hwaccel, which it surfaces via
+ // AV_HWDEVICE_TYPE_DRM (legacy) or AV_HWDEVICE_TYPE_V4L2REQUEST + // AV_HWDEVICE_TYPE_DRM rather than a dedicated _V4L2REQUEST type.
+ // (FFmpeg 7.1+ dedicated enum).
+ MediaResult InitV4L2RequestDecoder(); + MediaResult InitV4L2RequestDecoder();
bool CreateVAAPIDeviceContext(); bool CreateVAAPIDeviceContext();
+ bool CreateV4L2RequestDeviceContext(int aDeviceType); + bool CreateV4L2RequestDeviceContext();
bool GetVAAPISurfaceDescriptor(VADRMPRIMESurfaceDescriptor* aVaDesc); bool GetVAAPISurfaceDescriptor(VADRMPRIMESurfaceDescriptor* aVaDesc);
void AddAcceleratedFormats(nsTArray<AVCodecID>& aCodecList, void AddAcceleratedFormats(nsTArray<AVCodecID>& aCodecList,
AVCodecID aCodecID, AVVAAPIHWConfig* hwconfig); AVCodecID aCodecID, AVVAAPIHWConfig* hwconfig);
@@ -239,7 +245,10 @@ @@ -239,7 +244,10 @@
void AdjustHWDecodeLogging(); void AdjustHWDecodeLogging();
AVBufferRef* mVAAPIDeviceContext = nullptr; AVBufferRef* mVAAPIDeviceContext = nullptr;
+ // firefox-fourier: hwdevice ctx for the v4l2_request hwaccel. + // firefox-fourier: DRM hwdevice ctx for the v4l2_request hwaccel.
+ AVBufferRef* mV4L2RequestDeviceContext = nullptr; + AVBufferRef* mDRMDeviceContext = nullptr;
bool mUsingV4L2 = false; bool mUsingV4L2 = false;
+ bool mUsingV4L2Request = false; + bool mUsingV4L2Request = false;
// If video overlay is used we want to upload SW decoded frames to // If video overlay is used we want to upload SW decoded frames to
// DMABuf and present it as a external texture to rendering pipeline. // DMABuf and present it as a external texture to rendering pipeline.
bool mUploadSWDecodeToDMABuf = false; bool mUploadSWDecodeToDMABuf = false;
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp 2026-05-21 04:57:59.566685221 +0000
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp 2026-04-27 16:09:10.000000000 +0200 +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp 2026-05-21 04:58:00.136004159 +0000
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp 2026-04-29 00:10:00.098884335 +0200 @@ -403,6 +403,129 @@
@@ -403,6 +403,148 @@
return NS_OK; return NS_OK;
} }
+// firefox-fourier: V4L2 stateless (request API) hwdevice context. +// firefox-fourier: V4L2 stateless (request API) DRM hwdevice context.
+// libavcodec's v4l2_request hwaccel binds via either AV_HWDEVICE_TYPE_DRM +// libavcodec's v4l2_request hwaccel binds via AV_HWDEVICE_TYPE_DRM
+// (legacy) or AV_HWDEVICE_TYPE_V4L2REQUEST (FFmpeg 7.1+, enum value 13 +// no dedicated _V4L2REQUEST type exists upstream.
+// on Kwiboo's no-AMF tree, 14 on upstream-AMF tree). Caller passes the +bool FFmpegVideoDecoder<LIBAV_VER>::CreateV4L2RequestDeviceContext() {
+// matched type as an int (Mozilla's bundled libavutil headers may not
+// have the V4L2REQUEST enumerator).
+bool FFmpegVideoDecoder<LIBAV_VER>::CreateV4L2RequestDeviceContext(
+ int aDeviceType) {
+ if (!mLib->av_hwdevice_ctx_create) { + if (!mLib->av_hwdevice_ctx_create) {
+ FFMPEG_LOG(" av_hwdevice_ctx_create not available (libavutil too old)"); + FFMPEG_LOG(" av_hwdevice_ctx_create not available (libavutil too old)");
+ return false; + return false;
+ } + }
+ const char* drmDevice = "/dev/dri/renderD128"; + const char* drmDevice = "/dev/dri/renderD128";
+ if (mLib->av_hwdevice_ctx_create(&mV4L2RequestDeviceContext, + if (mLib->av_hwdevice_ctx_create(&mDRMDeviceContext,
+ (enum AVHWDeviceType)aDeviceType, + (enum AVHWDeviceType)13, drmDevice,
+ drmDevice, nullptr, 0) < 0) { + nullptr, 0) < 0) {
+ FFMPEG_LOG(" av_hwdevice_ctx_create(type=%d, %s) failed", + FFMPEG_LOG(" av_hwdevice_ctx_create(DRM, %s) failed", drmDevice);
+ aDeviceType, drmDevice);
+ return false; + return false;
+ } + }
+ mCodecContext->hw_device_ctx = mLib->av_buffer_ref(mV4L2RequestDeviceContext); + mCodecContext->hw_device_ctx = mLib->av_buffer_ref(mDRMDeviceContext);
+ FFMPEG_LOG(" v4l2_request hwdevice ctx created (type=%d) on %s", + FFMPEG_LOG(" DRM hwdevice ctx created on %s", drmDevice);
+ aDeviceType, drmDevice);
+ return true; + return true;
+} +}
+ +
@@ -122,14 +114,13 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
+ // mechanisms depending on the build: + // mechanisms depending on the build:
+ // (a) Named AVCodec entry (h264_v4l2request, vp8_v4l2request, + // (a) Named AVCodec entry (h264_v4l2request, vp8_v4l2request,
+ // etc.) — the legacy mechanism. Each hwaccel is a standalone + // etc.) — the legacy mechanism. Each hwaccel is a standalone
+ // AVCodec, looked up by name. Some forks expose this. + // AVCodec, looked up by name. ALARM, Debian, and most distros
+ // building with --enable-v4l2-request expose this.
+ // (b) Modern hwaccel registration: the generic codec advertises + // (b) Modern hwaccel registration: the generic codec advertises
+ // AV_HWDEVICE_TYPE_DRM (legacy) or AV_HWDEVICE_TYPE_V4L2REQUEST + // AV_HWDEVICE_TYPE_DRM in its hw_configs array, and setting
+ // (FFmpeg 7.1+ dedicated type, enum value 13 or 14 depending + // hw_device_ctx on the codec context binds v4l2_request
+ // on whether AMF is in the enum) in its hw_configs array, and + // internally. Some upstream-only builds expose this.
+ // setting hw_device_ctx on the codec context binds v4l2_request + // Probe (a) first — it is the explicit, distro-portable lookup.
+ // internally.
+ // Probe (a) first — explicit, distro-portable lookup.
+ // Fall back to (b) when the named entry isn't registered. + // Fall back to (b) when the named entry isn't registered.
+ const char* requestName = nullptr; + const char* requestName = nullptr;
+ switch (mCodecID) { + switch (mCodecID) {
@@ -144,18 +135,8 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
+ return NS_ERROR_NOT_AVAILABLE; + return NS_ERROR_NOT_AVAILABLE;
+ } + }
+ +
+ // AV_HWDEVICE_TYPE_V4L2REQUEST integer values across known builds. + AVCodec* codec = mLib->avcodec_find_decoder_by_name(requestName);
+ // Kwiboo's v4l2-request-n7.1.3 tree (no AMF) puts it at 13; + if (codec) {
+ // upstream FFmpeg 8.x with AMF puts it at 14.
+ const int V4L2REQUEST_KWIBOO = 13;
+ const int V4L2REQUEST_UPSTREAM = 14;
+
+ AVCodec* codec = nullptr;
+ int matchedType = AV_HWDEVICE_TYPE_DRM;
+
+ AVCodec* named = mLib->avcodec_find_decoder_by_name(requestName);
+ if (named) {
+ codec = named;
+ FFMPEG_LOG(" using named v4l2_request codec %s", requestName); + FFMPEG_LOG(" using named v4l2_request codec %s", requestName);
+ } else { + } else {
+ AVCodec* generic = mLib->avcodec_find_decoder(mCodecID); + AVCodec* generic = mLib->avcodec_find_decoder(mCodecID);
@@ -163,16 +144,9 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
+ for (int i = 0;; i++) { + for (int i = 0;; i++) {
+ const AVCodecHWConfig* cfg = mLib->avcodec_get_hw_config(generic, i); + const AVCodecHWConfig* cfg = mLib->avcodec_get_hw_config(generic, i);
+ if (!cfg) break; + if (!cfg) break;
+ if (!(cfg->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) { + if (cfg->device_type == AV_HWDEVICE_TYPE_DRM || (int)cfg->device_type == 13 || (int)cfg->device_type == 14) {
+ continue;
+ }
+ if (cfg->device_type == AV_HWDEVICE_TYPE_DRM ||
+ (int)cfg->device_type == V4L2REQUEST_KWIBOO ||
+ (int)cfg->device_type == V4L2REQUEST_UPSTREAM) {
+ codec = generic; + codec = generic;
+ matchedType = (int)cfg->device_type; + FFMPEG_LOG(" using generic codec %s with DRM hwaccel", codec->name);
+ FFMPEG_LOG(" using generic codec %s with v4l2_request hwaccel "
+ "(device_type=%d)", codec->name, matchedType);
+ break; + break;
+ } + }
+ } + }
@@ -180,9 +154,9 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
+ } + }
+ +
+ if (!codec) { + if (!codec) {
+ FFMPEG_LOG(" no v4l2_request path for codec ID %d neither named " + FFMPEG_LOG(" no v4l2_request path for codec ID %d \u2014 neither named "
+ "codec %s nor generic codec with DRM/V4L2REQUEST hwaccel " + "codec %s nor generic codec with DRM hwaccel available "
+ "available (libavcodec built without --enable-v4l2-request?)", + "(libavcodec built without --enable-v4l2-request?)",
+ mCodecID, requestName); + mCodecID, requestName);
+ return NS_ERROR_NOT_AVAILABLE; + return NS_ERROR_NOT_AVAILABLE;
+ } + }
@@ -203,7 +177,7 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
+ auto releaseDecoder = MakeScopeExit( + auto releaseDecoder = MakeScopeExit(
+ [&]() MOZ_NO_THREAD_SAFETY_ANALYSIS { ReleaseCodecContext(); }); + [&]() MOZ_NO_THREAD_SAFETY_ANALYSIS { ReleaseCodecContext(); });
+ +
+ if (!CreateV4L2RequestDeviceContext(matchedType)) { + if (!CreateV4L2RequestDeviceContext()) {
+ return NS_ERROR_NOT_AVAILABLE; + return NS_ERROR_NOT_AVAILABLE;
+ } + }
+ +
@@ -233,7 +207,7 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
MediaResult FFmpegVideoDecoder<LIBAV_VER>::InitV4L2Decoder() { MediaResult FFmpegVideoDecoder<LIBAV_VER>::InitV4L2Decoder() {
FFMPEG_LOG("Initialising V4L2-DRM FFmpeg decoder"); FFMPEG_LOG("Initialising V4L2-DRM FFmpeg decoder");
@@ -656,6 +798,16 @@ @@ -656,6 +779,16 @@
# endif // MOZ_ENABLE_VAAPI # endif // MOZ_ENABLE_VAAPI
# ifdef MOZ_ENABLE_V4L2 # ifdef MOZ_ENABLE_V4L2
@@ -250,14 +224,14 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
// VAAPI didn't work or is disabled, so try V4L2 with DRM // VAAPI didn't work or is disabled, so try V4L2 with DRM
if (NS_SUCCEEDED(InitV4L2Decoder())) { if (NS_SUCCEEDED(InitV4L2Decoder())) {
return; return;
@@ -2046,6 +2198,11 @@ @@ -2046,6 +2179,11 @@
if (IsHardwareAccelerated()) { if (IsHardwareAccelerated()) {
mLib->av_buffer_unref(&mVAAPIDeviceContext); mLib->av_buffer_unref(&mVAAPIDeviceContext);
} }
+ // firefox-fourier: release the hwdevice ctx for the v4l2_request + // firefox-fourier: release the DRM hwdevice ctx for the v4l2_request
+ // hwaccel. Always safe — av_buffer_unref no-ops on a null pointer. + // hwaccel. Always safe — av_buffer_unref no-ops on a null pointer.
+ if (mV4L2RequestDeviceContext) { + if (mDRMDeviceContext) {
+ mLib->av_buffer_unref(&mV4L2RequestDeviceContext); + mLib->av_buffer_unref(&mDRMDeviceContext);
+ } + }
#endif #endif
#ifdef MOZ_ENABLE_D3D11VA #ifdef MOZ_ENABLE_D3D11VA
+17 -17
View File
@@ -24,29 +24,29 @@ pkgname=libva-v4l2-request-fourier
epoch=1 epoch=1
_upstreampkg=libva-v4l2-request _upstreampkg=libva-v4l2-request
# Pin the fork tip. 77f9236 = PR #12 merge "av1: populate # Pin the fork tip. c454618 = PR #16 merge "picture, request_pool:
# V4L2_CID_STATELESS_AV1_SEQUENCE in codec_set_controls (#11 libva side)" # transparent OUTPUT-pool resize on bitstream overrun (#15)" —
# — addresses the libva-side portion of marfrit/libva-v4l2-request-fourier#11. # follow-up root-cause fix to #13/#14. On a mid-stream bitstream-
# Adds src/av1.{c,h} with av1_set_controls that maps VAAPI's # budget overrun (typical cause: SPS-driven resolution upshift in an
# VAPictureParameterBufferAV1.seq_info_fields onto struct # adaptive-bitrate stream), codec_store_buffer now snapshots the in-
# v4l2_ctrl_av1_sequence and queues V4L2_CID_STATELESS_AV1_SEQUENCE via # flight surface's accumulated bytes, releases its OUTPUT pool slot,
# S_EXT_CTRLS. The daedalus_v4l2 daemon track is the consumer that turns # calls request_pool_resize (STREAMOFF → REQBUFS(0) → S_FMT with
# the ctrl into an OBU_SEQUENCE_HEADER and prepends it to the slice # 2×sizeimage hint, capped at 1 GiB, page-aligned → CREATE_BUFS →
# bitstream so libdav1d can parse the (sequence-header-stripped) OUTPUT # mmap → media_request_alloc → STREAMON), re-acquires a slot, re-
# buffer that ffmpeg-vaapi delivers. Until the daemon side lands the ctrl # mirrors the surface's source_{data,size,request_fd}, restores the
# is just sitting in the request unused — no-cost no-op for HW decoders # bytes, and continues. The frame survives instead of being dropped
# (vpu981 parses OBU bytes directly). # back to libavcodec for surface recreation. CAPTURE side untouched
# (per-queue V4L2 streaming independence).
# #
# Prior pin (c1bb444) = PR #9 merge — h264_set_controls # Prior pin (2860d75) = PR #14 merge — codec_store_buffer bounds-
# max_num_ref_frames fallback + libva-boundary instrumentation for the # check floor (#13).
# daedalus consumer-strict path (issue #8 libva side). _commit=c454618ae11addce2e17b560f4deeacbed067d98
_commit=77f92364661419f6e5a7bd827c1b845b4e426569
# Project version from meson.build (1.0.0) + commit count + short sha, # Project version from meson.build (1.0.0) + commit count + short sha,
# matching the ffmpeg-v4l2-request-fourier convention. Recomputed at # matching the ffmpeg-v4l2-request-fourier convention. Recomputed at
# build time by pkgver() below; the static value here is a placeholder # build time by pkgver() below; the static value here is a placeholder
# so AUR-style consumers see something coherent before src/ exists. # so AUR-style consumers see something coherent before src/ exists.
pkgver=1.0.0.r386.77f9236 pkgver=1.0.0.r390.c454618
pkgrel=1 pkgrel=1
pkgdesc="VA-API backend for V4L2 stateless decoders (multiplanar fork — fourier umbrella)" pkgdesc="VA-API backend for V4L2 stateless decoders (multiplanar fork — fourier umbrella)"
arch=('aarch64') arch=('aarch64')
+49 -23
View File
@@ -14,9 +14,9 @@
# Sibling userspace package: ../daedalus-v4l2/build-deb.sh # Sibling userspace package: ../daedalus-v4l2/build-deb.sh
set -euo pipefail set -euo pipefail
UPSTREAM_COMMIT=f0d41867f60f5bf8dbfcc6cc16404d7d7eb90014 UPSTREAM_COMMIT=79256dc7ef41f83873ca9c23db20f5888858e65d
PKGVER=0.1.0+r24+gf0d4186 PKGVER=0.1.0+r28+g79256dc
PKGREL=1 # reset for new upstream pin (3dd0eb0 — DAEMON-PPS H.264 SPS/PPS NAL synth) PKGREL=1 # reset for new upstream pin (79256dc — H.264 B-frame reorder fix); still carries the #64 multi-kernel postinst fix
MODULE_NAME=daedalus_v4l2 MODULE_NAME=daedalus_v4l2
HERE=$(dirname "$(readlink -f "$0")") HERE=$(dirname "$(readlink -f "$0")")
@@ -78,7 +78,6 @@ set -e
NAME=${MODULE_NAME} NAME=${MODULE_NAME}
VERSION=${PKGVER} VERSION=${PKGVER}
KERNELVER=\$(uname -r)
# Yellow + bold ANSI for the warning so it stands out in apt's # Yellow + bold ANSI for the warning so it stands out in apt's
# stream of "Setting up" lines. Disable colour on non-TTY. # stream of "Setting up" lines. Disable colour on non-TTY.
@@ -101,29 +100,56 @@ if [ "\$1" = "configure" ]; then
dkms add "\$NAME/\$VERSION" 2>/dev/null || true dkms add "\$NAME/\$VERSION" 2>/dev/null || true
# Don't let autoinstall failure mask the actual problem behind '|| true'. # Enumerate every kernel whose headers are actually present
# Run it, capture the result, then verify post-condition. # (/lib/modules/<kver>/build resolves to a directory). We iterate
autoinstall_rc=0 # all of them — not just \$(uname -r) — so that installing this
dkms autoinstall "\$NAME/\$VERSION" || autoinstall_rc=\$? # package after a kernel update covers the newly-installed kernel
# too, and so that a later kernel-headers install for a previously
# uncovered version gets picked up on dpkg-reconfigure. Without
# this, autoinstall (which targets only the running kernel) leaves
# /dev/daedalus-v4l2 absent after a kernel switch + reboot
# (marfrit/marfrit-packages#64).
kvers=''
for d in /lib/modules/*/build; do
[ -d "\$d" ] || continue
k=\$(basename "\$(dirname "\$d")")
kvers="\$kvers \$k"
done
# Verify the module actually built + installed for the running kernel. if [ -z "\$kvers" ]; then
status=\$(dkms status -m "\$NAME" -v "\$VERSION" -k "\$KERNELVER" 2>/dev/null || true)
if ! printf '%s\\n' "\$status" | grep -q -E 'installed|loaded'; then
warn "" warn ""
warn "DKMS build did NOT land for kernel \$KERNELVER." warn "No kernels with headers found under /lib/modules/*/build."
warn " dkms status -m \$NAME -v \$VERSION -k \$KERNELVER:" warn "Install kernel headers (e.g. linux-headers-rpi-2712 on Pi OS)"
warn " \$(printf '%s' "\$status" | head -1)" warn "then finish with:"
warn ""
warn "Most likely cause: kernel headers package is missing."
warn " Raspberry Pi OS / Pi 5: apt install linux-headers-rpi-2712"
warn " Debian generic: apt install linux-headers-\$KERNELVER"
warn ""
warn "After installing headers, finish the install with:"
warn " sudo dkms autoinstall \$NAME/\$VERSION" warn " sudo dkms autoinstall \$NAME/\$VERSION"
warn " sudo modprobe daedalus_v4l2" exit 0
fi
failed=''
for k in \$kvers; do
dkms autoinstall -k "\$k" "\$NAME/\$VERSION" >/dev/null 2>&1 || true
s=\$(dkms status -m "\$NAME" -v "\$VERSION" -k "\$k" 2>/dev/null || true)
if ! printf '%s\\n' "\$s" | grep -q -E 'installed|loaded'; then
failed="\$failed \$k"
fi
done
if [ -n "\$failed" ]; then
warn "" warn ""
warn "Until then daedalus_v4l2 will NOT be loadable and the" warn "DKMS build did NOT land for kernel(s):\$failed"
warn "userspace daedalus-v4l2 daemon will have nothing to talk to." warn ""
warn "Most likely cause: kernel headers missing for those versions."
warn " Raspberry Pi OS / Pi 5: apt install linux-headers-rpi-2712"
warn " Debian generic: apt install linux-headers-<version>"
warn ""
warn "After installing headers, finish with:"
for k in \$failed; do
warn " sudo dkms autoinstall -k \$k \$NAME/\$VERSION"
done
warn " sudo modprobe daedalus_v4l2 (after booting that kernel)"
warn ""
warn "Until then daedalus_v4l2 will NOT be loadable on those kernels"
warn "and the userspace daedalus-v4l2 daemon will have nothing to talk to."
fi fi
fi fi
+37
View File
@@ -1,3 +1,40 @@
daedalus-v4l2-dkms (0.1.0+r28+g79256dc-1) bookworm trixie; urgency=medium
* Bump to 79256dc — H.264 B-frame display reorder fix (closes
daedalus-v4l2#6). libavcodec's H.264 decoder reorders output to
display order before returning from avcodec_receive_frame; the
daemon was binding each REQ_DECODE's pixels to the cookie of the
bitstream that triggered the receive_frame call, not the cookie
of the bitstream that actually produced the picture. For B-frame
sequences this paired cookie N's CAPTURE buffer with cookie N-2's
pixels and silently lost intermediate frames — visible as
"2 1 4 3 6 5" frame pairing in mpv / Firefox on Pi CM5.
* Wire-protocol bump (DAEDALUS_PROTO_VERSION 0 → 1): REQ_DECODE
gains __u64 src_pts; RESP_FRAME gains __u32 flags +
__u64 output_src_pts. Kernel + daemon must install atomically
(this package + daedalus-v4l2 0.1.0+r28+g79256dc).
* Carries forward the #64 multi-kernel postinst fix from -2:
autoinstall for every /lib/modules/*/build that resolves to real
headers, not just $(uname -r).
* Closes #64.
-- Markus Fritsche <mfritsche@reauktion.de> Thu, 21 May 2026 12:00:00 +0000
daedalus-v4l2-dkms (0.1.0+r24+gf0d4186-2) bookworm trixie; urgency=medium
* postinst: autoinstall for every installed kernel with headers, not
just the running one. Previously `dkms autoinstall $NAME/$VERSION`
built only against `$(uname -r)`, so installing the package on
kernel A and then rebooting into a separately-installed kernel B
left /lib/modules/B/updates/dkms/ empty — /dev/daedalus-v4l2 absent,
daedalus daemon nothing to talk to, browser/VAAPI silently falling
back to software with no obvious diagnostic. Now we enumerate every
/lib/modules/*/build that resolves to a real directory and run
`dkms autoinstall -k <kver>` for each, reporting per-kernel failure
only when headers are missing. Closes #64.
-- Markus Fritsche <mfritsche@reauktion.de> Thu, 21 May 2026 09:30:00 +0000
daedalus-v4l2-dkms (0.1.0+r24+gf0d4186-1) bookworm trixie; urgency=medium daedalus-v4l2-dkms (0.1.0+r24+gf0d4186-1) bookworm trixie; urgency=medium
* Bump to f0d4186 — per-ctx vb2 lock fix. daedalus_queue_init now * Bump to f0d4186 — per-ctx vb2 lock fix. daedalus_queue_init now
+10 -7
View File
@@ -11,13 +11,16 @@
# Upstream repo: https://git.reauktion.de/reauktion/daedalus-v4l2 # Upstream repo: https://git.reauktion.de/reauktion/daedalus-v4l2
set -euo pipefail set -euo pipefail
# Same pin as the Arch PKGBUILD. 481279c = "Phase 8.13: byte-exact # Same pin as the Arch PKGBUILD. 79256dc = "kernel + daemon: H.264
# end-to-end via libva (consumer target hit)" — first commit where the # B-frame display reorder fix (closes #6)" — adds the wire-protocol
# full ffmpeg -hwaccel vaapi → libva → /dev/video0 → daemon path lands # src_pts / output_src_pts / RESP_FRAME flags split that lets H.264
# a pixel-correct decoded frame back in ffmpeg. # streams with B-frames preserve display order through libva → kernel
UPSTREAM_COMMIT=f0d41867f60f5bf8dbfcc6cc16404d7d7eb90014 # → daemon. PROTO_VERSION bumps 0 → 1; lock-step userspace + kernel
PKGVER=0.1.0+r24+gf0d4186 # rebuild REQUIRED (daedalus-v4l2-dkms build-deb.sh pinned to the same
PKGREL=1 # reset for new upstream pin (3dd0eb0 — DAEMON-PPS H.264 SPS/PPS NAL synth) # commit).
UPSTREAM_COMMIT=79256dc7ef41f83873ca9c23db20f5888858e65d
PKGVER=0.1.0+r28+g79256dc
PKGREL=1 # reset for new upstream pin (79256dc — H.264 B-frame reorder fix)
HERE=$(dirname "$(readlink -f "$0")") HERE=$(dirname "$(readlink -f "$0")")
+24
View File
@@ -1,3 +1,27 @@
daedalus-v4l2 (0.1.0+r28+g79256dc-1) bookworm trixie; urgency=medium
* Bump to 79256dc — H.264 B-frame display reorder fix (closes
daedalus-v4l2#6 + #4 menu controls). Daemon side: the
avcodec_send_packet → receive_frame loop now stamps pkt->pts =
req->src_pts so libavcodec's display-ordered frame->pts identifies
which OUTPUT bitstream's pixels each drained frame belongs to.
chardev_client maintains a (src_pts → cookie) lookup table so the
daemon can ship pixels to the cookie of the *originating*
bitstream, not the cookie of whatever REQ triggered the
receive_frame call. Multiple RESP_FRAME messages per REQ_DECODE
are now possible (one for the just-consumed src, one or more for
drained pixels).
* Wire-protocol bump (DAEDALUS_PROTO_VERSION 0 → 1): REQ_DECODE
gains __u64 src_pts; RESP_FRAME gains __u32 flags +
__u64 output_src_pts. Daemon + kernel must install atomically
(this package + daedalus-v4l2-dkms 0.1.0+r28+g79256dc).
* Also subsumes 79256dc's predecessor 7ff2d89 — H.264 DECODE_MODE +
START_CODE menu-control registration that retires the
"Unable to set control(s) error_idx=2/2" warning libva-v4l2-
request emitted on every context init.
-- Markus Fritsche <mfritsche@reauktion.de> Thu, 21 May 2026 12:00:00 +0000
daedalus-v4l2 (0.1.0+r24+gf0d4186-1) bookworm trixie; urgency=medium daedalus-v4l2 (0.1.0+r24+gf0d4186-1) bookworm trixie; urgency=medium
* Bump to f0d4186 — kernel per-ctx vb2 lock fix. daedalus_queue_init * Bump to f0d4186 — kernel per-ctx vb2 lock fix. daedalus_queue_init
+18 -15
View File
@@ -10,22 +10,25 @@
# Upstream fork: https://git.reauktion.de/marfrit/libva-v4l2-request-fourier # Upstream fork: https://git.reauktion.de/marfrit/libva-v4l2-request-fourier
set -euo pipefail set -euo pipefail
# Same pin as the Arch PKGBUILD. 77f9236 = PR #12 merge "av1: # Same pin as the Arch PKGBUILD. c454618 = PR #16 merge "picture,
# populate V4L2_CID_STATELESS_AV1_SEQUENCE in codec_set_controls # request_pool: transparent OUTPUT-pool resize on bitstream overrun
# (#11 libva side)" — adds src/av1.{c,h} with av1_set_controls that # (#15)" — follow-up root-cause fix to #13/#14. On a mid-stream
# maps VAAPI's VAPictureParameterBufferAV1.seq_info_fields onto # bitstream-budget overrun (typical cause: SPS-driven resolution
# struct v4l2_ctrl_av1_sequence and queues V4L2_CID_STATELESS_AV1_ # upshift in an adaptive-bitrate stream), codec_store_buffer now
# SEQUENCE via S_EXT_CTRLS. The daedalus_v4l2 daemon track is the # snapshots the in-flight surface's accumulated bytes, releases its
# consumer that turns the ctrl into an OBU_SEQUENCE_HEADER and # OUTPUT pool slot, calls request_pool_resize (STREAMOFF →
# prepends it to the slice bitstream so libdav1d can parse the # REQBUFS(0) → S_FMT with 2×sizeimage hint, capped at 1 GiB, page-
# (sequence-header-stripped) OUTPUT buffer that ffmpeg-vaapi # aligned → CREATE_BUFS → mmap → media_request_alloc → STREAMON),
# delivers. # re-acquires a slot, re-mirrors the surface's source_{data,size,
# request_fd}, restores the bytes, and continues. The frame
# survives instead of being dropped back to libavcodec for surface
# recreation. CAPTURE side untouched (per-queue V4L2 streaming
# independence).
# #
# Prior pin (c1bb444) = PR #9 merge — h264_set_controls # Prior pin (2860d75) = PR #14 merge — codec_store_buffer bounds-
# max_num_ref_frames fallback + libva-boundary instrumentation for # check floor (#13).
# the daedalus consumer-strict path (issue #8 libva side). UPSTREAM_COMMIT=c454618ae11addce2e17b560f4deeacbed067d98
UPSTREAM_COMMIT=77f92364661419f6e5a7bd827c1b845b4e426569 PKGVER=1.0.0+r390+gc454618
PKGVER=1.0.0+r386+g77f9236
PKGREL=1 PKGREL=1
HERE=$(dirname "$(readlink -f "$0")") HERE=$(dirname "$(readlink -f "$0")")