Skip to content

About

VA-API driver for V4L2 stateless decoders with Apple Video Decoder (AVD) fixes, used by omarchy-m1-video

Resources

Contributing

Security policy

Stars

10 stars

Watchers

1 watching

Forks

 
 

Repository files navigation

libva-v4l2_request-avd (unofficial fork)

An unofficial fork of the VA-API driver for V4L2 stateless decoders, carrying the Apple Video Decoder (AVD) support used by Asahi Linux. It lets VA-API applications (mpv, Chromium, FFmpeg) decode video on the AVD hardware in Apple Silicon Macs.

This fork is not affiliated with or endorsed by the authors of the projects it is based on. Please don't report problems with it to those projects; open an issue here instead.

To set up hardware video decoding on an Omarchy Mac with this driver and the matching kernel driver patches, use omarchy-m1-video.

The original documentation is in README.

Support contract

Codec, device and client claims are defined in docs/SUPPORT.md and the versioned support matrix. r11 evidence is M1 (T8103) only: HEVC 144/147, AVC 73/135, opt-in High 10 FRExt 27/69 and VP9 216/305, with exact pass sets pinned. Those fractions are raw suite totals, not eligible-subset percentages. No matrix row is currently supported. Compiled-in AV1/VP8/MPEG-2 backends and 12-bit/4:2:2/4:4:4 formats are untested or unsupported, not inferred from source files. Safe rejection is not decode support.

A separately qualified local FFmpeg n9.0.1 build with the pending-parameter-set client patch passes HEVC 145/147 on the same r11 driver, adding VPSSPSPPS_A_MainConcept_1 without losing a pass. The support matrix pins the exact client commit and patch hash. That client is not packaged or installed, so the shipped r11 baseline remains 144/147 and this is not a driver-only improvement.

Development roadmap

See the roadmap and ticket index for planned codec, reliability, client/display and release work across both repositories. Agents and contributors should read the claim and execution workflow before taking a ticket.

Contributing and reporting

Contributor priorities: choose an offline codec or AVD task. Humans and coding agents can contribute without owning an Apple Silicon test machine.

Start with CONTRIBUTING.md for repository ownership, offline checks and PR evidence. Use SECURITY.md for suspected vulnerabilities, and maintenance and handoff for triage, review and release decisions.

Upstream and credits

  • libva-v4l2_request by Ondřej Jirman (megi): the driver this all builds on.
  • sofus13/libva-v4l2_request, tag 1.3 (cfe6c2a): AVD support. This fork keeps that full history and its tags.
  • Chromium green-frame fix, from branch fix-avd-early-export of Ante042/libva-v4l2_request, kept as the original commits:
    • 201bc71 by Igor Ryzhkov: decode into surfaces the client exported before the first decode
    • 9e6d750 and 386956d by Ante042: keep exported dimensions, reserve codec tail storage, and a test

Changes carried by this fork

On top of sofus13's tag 1.3:

  • 201bc71, 9e6d750, 386956d (Igor Ryzhkov, Ante042): Chromium creates each VA surface, exports it as a dma-buf and imports it into the GPU before decoding into it. Version 1.3 decoded into different buffers, so Chromium showed solid green video. With these commits the decoder writes into the exported buffers.
  • H.264: drop trailing zero bytes from slice data. They made the AVD firmware hang on pictures with several CAVLC slices.
  • HEVC: fix the slice header parser that finds entry point offsets (VA-API does not carry them); tiled and wavefront streams hung on their first P picture.
  • P010: size the exported backing of 10-bit surfaces for the decoder's reference data; 10-bit HEVC decoded to blank frames.
  • Log why an exported surface backing does not fit the CAPTURE format.
  • HEVC: reject out-of-range reference counts, exp-Golomb codes and CTB sizes in untrusted slice headers; a crafted slice could overflow the stack.

Version 1.3.r6 also:

  • Reports failed CAPTURE buffers as VA_STATUS_ERROR_DECODING_ERROR and propagates flush, request, conversion and buffer-reuse wait failures.
  • Fixes FFmpeg hwdownload crashing when context destruction unmaps a frame during vaGetImage. Surface operations and context teardown are serialized; live surfaces keep their frame storage, and derived images own their mappings. Pending frames finish before teardown, with errors retained on the surviving surfaces.
  • Bounds image copies, preserves the last UV pair on odd-width NV12/P010 images, rejects invalid image dimensions, and avoids a dangling buffer after a zero-element resize.
  • Checks HEVC entry-point capacity and offset lengths, resets offsets between request batches, and rejects malformed headers before submission.
  • Includes offline regression tests, sanitizer CI, and hardware pixel-comparison scripts.

Version 1.3.r7 adds opt-in H.264 High 10, an explicit FFmpeg quantizer workaround, 10-bit capability checks, H.264 parser regressions, and a conformance runner that requires hardware frames and preserves resolution changes. See codec testing.

Version 1.3.r8 preserves short-term-only HEVC references in decode order on AVD and remaps all slice/RPS indices. This corrects all 300 pictures of RPS_B_qualcomm_5, raising the serial HEVC total to 144/147. The firmware's ordering sensitivity remains unexplained; RPS_E_qualcomm_5 still fails. Streams permitting long-term references and other V4L2 decoders retain the original reference order: the unrestricted experiment increased RPS_E corruption.

HEVC also rejects invalid active references and malformed slices before flushing a preceding batch. A failed RenderPicture blocks subsequent submission of the incomplete picture. Unused unavailable references around random-access points remain allowed.

Version 1.3.r9 rejects incomplete H.264 pictures, overflowing slice-parameter counts, and invalid active references before submitting a pending slice. Missing surface storage cannot match another missing reference through timestamp zero. Slice types must also agree with the parsed NAL header. Three new offline cases reproduce the earlier failures and verify valid submissions and recovery, bringing the sanitizer suite to 25 cases.

Version 1.3.r10 validates VP9 headers and submission completeness, preserves the colour-range flag on inter pictures, and commits loop-filter/segmentation/range changes only after successful submission. Missing reference storage, including references from an older decoder context, is rejected before hardware submission. Four VP9 cases bring the sanitizer suite to 29 cases, including 24,000 additional deterministic parser inputs.

Version 1.3.r11 protects the shared picture lifecycle and reference lookup:

  • Reserve fresh targets at BeginPicture and reject destruction while a picture still uses them; a malformed API sequence previously left EndPicture with a freed target pointer.
  • Keep the first RenderPicture failure through EndPicture, prevent nested BeginPicture calls from replacing staged work, and clean up after a failed codec begin.
  • Preserve a failed submission when an earlier slice finishes; a successful new submission resets the status on surface reuse.
  • Resolve reference timestamps only for valid buffers owned by the requesting decoder context. Missing, detached, mismatched and known-failed references cannot alias another context's buffer.
  • Validate context arguments and treat render-target lists as hints without changing ownership.

Six new offline cases bring the sanitizer suite to 35 cases. The lifetime bug is reproduced under ASan using an intercepted codec; it is an API misuse reproduction, not a demonstrated malicious-video exploit. Full VP9 inter-frame resize support still needs kernel-side work.

Tested on an M1 (T8103) with the kernel patches from omarchy-m1-video: JCT-VC-HEVC_V1 144/147 and JVT-AVC_V1 73/135 bit-exact through FFmpeg VA-API. Earlier Chrome 152 H.264 playback tests matched software rendering; this revision adds direct early-export pixel regressions.

Known problems

As of 2026-09-15:

  • Vulkan output in mpv (gpu-api=vulkan) shows a green/pink ghost picture: Mesa's Vulkan driver for Apple GPUs ignores the plane offsets of imported frames. Use gpu-api=opengl.
  • H.264 profiles: Constrained Baseline, Main and High are offered by default. High 10 requires the opt-in mode below. 4:2:2 uses software. Interlaced H.264 remains unsupported by AVD.
  • VP9: 8-bit and 10-bit 4:2:0 are tested. Sub-64-pixel dimensions, inter-frame resizing, and some scalable-video vectors remain incomplete. Two resize streams that caused firmware timeouts with r9 now fail in userspace when their references belong to an older context. This is safe rejection, not support for those streams. See VP9 testing.
  • Early export needs DMABUF import. Once a context decodes into client-exported surfaces, a later surface whose layout does not match fails instead of falling back to separate buffers.
  • Kernel driver bugs in AVD itself can hang or crash the system; the kernel patches in omarchy-m1-video fix several of them.

The remaining HEVC mismatches, boot-reset investigation, Chrome colour issue and Firefox validation are tracked in omarchy-m1-video's gap status. A successful decode call cannot detect a firmware-produced wrong picture without an error flag; the conformance failures remain open.

Building

meson setup build
meson compile -C build

To try the driver without installing it:

LIBVA_DRIVERS_PATH=$PWD/build/src LIBVA_DRIVER_NAME=v4l2_request mpv --hwdec=vaapi-copy video.mp4

Installing

meson install copies only the driver module, v4l2_request_drv_video.so, into libva's driver directory. It does not touch the kernel, install kernel patches, or reboot anything; hardware/kernel setup on Apple Silicon is a separate step handled by omarchy-m1-video.

meson setup build --prefix=/usr
meson compile -C build
sudo meson install -C build
  • Where it installs: by default the driver directory comes from libva's own pkg-config driverdir variable (pkg-config --variable=driverdir libva; typically /usr/lib/dri or an arch-tripled .../dri). Override it at meson setup time with -Ddriverdir=<path> when packaging for a nonstandard prefix.

  • Uninstalling: sudo ninja -C build uninstall removes exactly the files meson install put down, including now-empty parent directories it created; nothing else under the prefix is touched.

  • Disposable-root testing: verify a clean install/uninstall without touching the host using DESTDIR:

    meson setup build --prefix=/usr
    meson compile -C build
    root=$(mktemp -d)
    DESTDIR="$root" meson install -C build
    DESTDIR="$root" ninja -C build uninstall
    rmdir "$root"   # uninstall preserves this pre-existing DESTDIR directory

    tests/install-smoke.sh automates this for both the default and a custom -Ddriverdir, and additionally checks that the installed module is stripped, carries no build/worktree paths, and matches its libva ABI entrypoint (see Verifying an install below).

  • Installed artifacts: only the driver module has install: true in src/meson.build; test binaries and the build directory are never installed. The project defaults to -Dstrip=true, so the installed copy omits DWARF debug paths. The smoke test also checks for embedded source/build paths; stripping alone cannot remove arbitrary strings. Pass -Dstrip=false (e.g. for a -dbg package) to keep symbols. The unstripped build-tree copy under build/src/ is unaffected, so LIBVA_DRIVERS_PATH=$PWD/build/src development keeps full debug info.

Dependency bounds

The libva floor below is enforced at configure time: meson setup fails naming the version it found versus the floor when libva is too old. An explicitly -Dcodec_<name>=enabled codec fails configuration naming the missing kernel control instead of silently compiling out (see the codec_checks table in meson.build).

Dependency Floor Verified oldest combination Notes
libva (libva-dev) VA-API >= 1.7.0 (library release >= 2.7.0) Ubuntu 20.04, libva 2.7, gcc 9 dependency('libva', version: '>= 1.7.0'). DRM_PRIME_2 surface export needs 2.4; opt-in H.264 High 10 needs 2.18.
libdrm (libdrm-dev) any pkg-config libdrm — Presence only, no version floor enforced.
Linux UAPI headers (linux-libc-dev) Per-codec symbol checks: 5.11 (H.264) through 6.5 (AV1); 5.4 is the oldest verified header set, not a global configure-time floor Ubuntu 20.04, headers 5.4 (all stateless codecs compiled out) Auto-detected from the installed UAPI headers, not the running kernel; each codec's exact floor is documented in meson.build and meson_options.txt.
Meson, Ninja, a C11 compiler — GCC 9 and Clang, both exercised in CI c_std=gnu11.

These floors and the oldest-verified rows are exercised on every PR by the checks.yml CI matrix (its "current dependencies", "oldest verified dependencies (libva 2.14, kernel UAPI 5.15)" and "oldest kernel UAPI (5.4 headers, all stateless codecs compiled out)" jobs); that workflow is the authoritative source for pinned container identities and dependency tiers; package versions within those images are resolved from their archives and recorded in each run, not pinned individually.

Verifying an install

LIBVA_DRIVER_NAME=v4l2_request vainfo --display drm on a qualified decoder should report the vendor string v4l2-request (omarchy-m1-video 1.3.r11) (or the fork's current version). A different or missing string means LIBVA_DRIVERS_PATH/driverdir picked up a different module. If vainfo instead fails to find or load the driver, the two most likely causes are:

  • ABI entrypoint mismatch: libva looks up a version-specific symbol, __vaDriverInit_<VA_MAJOR>_<VA_MINOR>, generated from the libva headers this module was built against. Compare that to what the runtime libva expects:

    nm -D build/src/v4l2_request_drv_video.so | grep vaDriverInit   # symbol this build exports
    pkg-config --modversion libva                            # development metadata, not runtime proof

    The libva 2.24 loader tries its current VA minor and then older minors within the same major. An older driver minor can therefore be found by a newer runtime; exact minor equality is not required. A driver built for a newer minor than the runtime exports an entrypoint that runtime does not probe. Check the VA-API version and loader errors printed by the actual client (pkg-config can describe a different development installation), then rebuild against headers compatible with the deployed runtime if necessary. Symbol lookup alone does not establish working device initialization or decoding.

  • Wrong driver directory: confirm the installed path matches what libva actually searches, pkg-config --variable=driverdir libva (or the -Ddriverdir used at build time), and that LIBVA_DRIVER_NAME=v4l2_request is set so libva picks v4l2_request_drv_video.so there.

H.264 High 10 with FFmpeg or mpv

High 10 is disabled by default because FFmpeg 9.0.1 passes a bit-depth bias in its VA-API picture quantizers: a stream with QP 21 arrives as QP 33. The compatibility mode removes that bias. Both complete FREH10 conformance streams (718 frames) matched the reference checksums on the M1 with this mode:

LIBVA_DRIVERS_PATH=$PWD/build/src LIBVA_DRIVER_NAME=v4l2_request \
LIBVA_V4L2_H264_HIGH10=ffmpeg mpv --gpu-api=opengl --hwdec=vaapi-copy high10.mkv

LIBVA_V4L2_H264_HIGH10=native enables the profile for clients that already send the PPS syntax values. ffmpeg enables it and adjusts the biased quantizers; use it only with affected FFmpeg-based clients. Unset the variable (or use off) to disable High 10. Both enabled modes also require the decoder to accept a 10-bit SPS and offer usable 10-bit 4:2:0 output. Other hardware and all High 10 coding features are not yet validated.

The offset is visible in FFmpeg's PPS parser and VA parameter construction. This is a client compatibility setting, not a change to the VA-API or V4L2 parameter contract.

Diagnostics

Driver messages go to standard error as libva-v4l2request: ... lines. Set LIBVA_V4L2_DIAG=json to get one JSON record per line with a stable failure category (unsupported, client, bitstream, reference, allocation, timeout, kernel, decoder, device), the failed operation, errno, a per-context identifier and the driver's detected capabilities. Paths and URLs are redacted and output is rate limited. See docs/DIAGNOSTICS.md for the schema and what to include in a report.

Tests

See tests/README.md for the offline sanitizer suite and guarded hardware checks. vainfo --display drm identifies this build as v4l2-request (omarchy-m1-video 1.3.r11).

License

GPL-3.0-or-later, see COPYING.

About

VA-API driver for V4L2 stateless decoders with Apple Video Decoder (AVD) fixes, used by omarchy-m1-video

Resources

Contributing

Security policy

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages