firefox-fourier patch 3: probe v4l2_request via codec name first

Diagnostic on fresnel (RK3399 / Mali-T860 / mainline) showed
InitV4L2RequestDecoder running at runtime but failing the
hw_configs sanity check:

  FFMPEG: Initialising V4L2 stateless (request API) FFmpeg decoder
  FFMPEG:   codec h264 has no DRM hwaccel —
            libavcodec built without --enable-v4l2-request?
  FFMPEG: Initialising V4L2-DRM FFmpeg decoder      ← falls through to stateful
  FFMPEG:   V4L2 codec h264_v4l2m2m : V4L2 mem2mem H.264 decoder wrapper
  FFMPEG:   Couldn't initialise V4L2 decoder        ← stateful also fails

…despite the system libavcodec.so being built with
--enable-v4l2-request and exposing h264_v4l2request, vp8_v4l2request,
etc. as named AVCodec entries.

Root cause: libavcodec exposes v4l2_request through one of two
mechanisms depending on the build:
  (a) Named AVCodec entry (legacy, distro-portable): looked up via
      avcodec_find_decoder_by_name("h264_v4l2request"). ALARM,
      Debian, most distros use this.
  (b) hw_configs entry on the generic codec (modern, upstream): the
      generic codec's AVCodecHWConfig array advertises
      AV_HWDEVICE_TYPE_DRM. Setting hw_device_ctx binds the hwaccel.

Patch 3 originally only probed (b). On builds that ship (a) — the
common case — the check failed even though v4l2_request was fully
functional.

Fix: probe (a) first via the codec-name lookup table, fall back to
(b) walking hw_configs. Both shapes work; the decoder is opened with
whichever AVCodec the probe selected. The DRM hwdevice ctx
attachment is unchanged (both mechanisms need it for surface
allocation).

Patch description and the in-code comment block updated to document
the dual mechanism. Behaviour on stateful-only boards (Pi4 / vendor
MPP) preserved: neither named codec nor hw_configs DRM is registered,
the function bails out, the existing InitV4L2Decoder runs as before.
This commit is contained in:
2026-04-28 21:59:01 +00:00
parent a1dc662c39
commit e0af915788
@@ -15,12 +15,16 @@ fails to open, Firefox falls all the way through to software.
This patch adds a sibling init path, `InitV4L2RequestDecoder`, that:
* uses the **generic** codec (e.g. plain `h264`, returned by
`avcodec_find_decoder(AV_CODEC_ID_H264)`) rather than the stateful
wrapper;
* sanity-checks the codec's `hw_configs` for an `AV_HWDEVICE_TYPE_DRM`
entry — that's how libavcodec surfaces the v4l2_request hwaccel
upstream (no dedicated `_V4L2REQUEST` device type exists);
* looks up the codec via two complementary mechanisms libavcodec
uses for v4l2_request:
- **named codec** (`h264_v4l2request`, `vp8_v4l2request`, etc.):
the legacy AVCodec-per-hwaccel registration, used by ALARM /
Debian / most distros that build with --enable-v4l2-request;
- **generic codec + AV_HWDEVICE_TYPE_DRM** in `hw_configs`:
the modern hwaccel registration, used by some upstream-only
builds.
Probes named-codec first (explicit, portable) and falls back to
walking the generic codec's hw_configs.
* creates an `AV_HWDEVICE_TYPE_DRM` hwdevice context bound to
`/dev/dri/renderD128` via the new `av_hwdevice_ctx_create` wrapper
(patch 2/4) and attaches it to the codec context;
@@ -104,30 +108,55 @@ diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platf
+
+ StaticMutexAutoLock mon(sMutex);
+
+ // Use the GENERIC codec (not the _v4l2m2m wrapper). libavcodec picks
+ // the v4l2_request hwaccel internally by walking the codec's
+ // hw_configs once an AV_HWDEVICE_TYPE_DRM ctx is attached.
+ AVCodec* codec = mLib->avcodec_find_decoder(mCodecID);
+ if (!codec) {
+ FFMPEG_LOG(" generic codec for ID %d not found", mCodecID);
+ return NS_ERROR_NOT_AVAILABLE;
+ // libavcodec exposes V4L2 stateless decoders through one of two
+ // mechanisms depending on the build:
+ // (a) Named AVCodec entry (h264_v4l2request, vp8_v4l2request,
+ // etc.) — the legacy mechanism. Each hwaccel is a standalone
+ // 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
+ // AV_HWDEVICE_TYPE_DRM in its hw_configs array, and setting
+ // hw_device_ctx on the codec context binds v4l2_request
+ // internally. Some upstream-only builds expose this.
+ // Probe (a) first — it's the explicit, distro-portable lookup.
+ // Fall back to (b) when the named entry isn't registered.
+ const char* requestName = nullptr;
+ switch (mCodecID) {
+ case AV_CODEC_ID_H264: requestName = "h264_v4l2request"; break;
+ case AV_CODEC_ID_HEVC: requestName = "hevc_v4l2request"; break;
+ case AV_CODEC_ID_VP8: requestName = "vp8_v4l2request"; break;
+ case AV_CODEC_ID_VP9: requestName = "vp9_v4l2request"; break;
+ case AV_CODEC_ID_AV1: requestName = "av1_v4l2request"; break;
+ case AV_CODEC_ID_MPEG2VIDEO: requestName = "mpeg2_v4l2request"; break;
+ default:
+ FFMPEG_LOG(" no v4l2_request mapping for codec ID %d", mCodecID);
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ // Sanity-check: refuse when libavcodec was built without the
+ // v4l2_request hwaccel (no DRM hwaccel registered against this
+ // codec). Distro packagers occasionally drop --enable-v4l2-request.
+ bool hasDrmHwaccel = false;
+ for (int i = 0;; i++) {
+ const AVCodecHWConfig* cfg = mLib->avcodec_get_hw_config(codec, i);
+ if (!cfg) break;
+ if (cfg->device_type == AV_HWDEVICE_TYPE_DRM) {
+ hasDrmHwaccel = true;
+ break;
+ AVCodec* codec = mLib->avcodec_find_decoder_by_name(requestName);
+ if (codec) {
+ FFMPEG_LOG(" using named v4l2_request codec %s", requestName);
+ } else {
+ // Fallback path (b): generic codec + DRM hwaccel.
+ AVCodec* generic = mLib->avcodec_find_decoder(mCodecID);
+ if (generic) {
+ for (int i = 0;; i++) {
+ const AVCodecHWConfig* cfg = mLib->avcodec_get_hw_config(generic, i);
+ if (!cfg) break;
+ if (cfg->device_type == AV_HWDEVICE_TYPE_DRM) {
+ codec = generic;
+ FFMPEG_LOG(" using generic codec %s with DRM hwaccel", codec->name);
+ break;
+ }
+ }
+ }
+ }
+ if (!hasDrmHwaccel) {
+ FFMPEG_LOG(" codec %s has no DRM hwaccel — libavcodec built "
+ "without --enable-v4l2-request?", codec->name);
+
+ if (!codec) {
+ FFMPEG_LOG(" no v4l2_request path for codec ID %d — neither named "
+ "codec %s nor generic codec with DRM hwaccel available "
+ "(libavcodec built without --enable-v4l2-request?)",
+ mCodecID, requestName);
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ FFMPEG_LOG(" V4L2 stateless: codec %s : %s", codec->name, codec->long_name);