# moq-vaapi
> **⚠️ AI GENERATED.** This crate was written by an AI agent (Claude), using the
> repositories below as references. How closely individual files track upstream
> varies, so treat the whole thing as derived work and review before relying on
> it. The encoder and the decoder have both been checked against ffmpeg's
> software codecs on Intel hardware (see below).
A small, self-contained **VA-API H.264 hardware codec** for Linux (Intel / AMD),
derived from
[discord/cros-libva @ discord-0.0.13](https://github.com/discord/cros-libva/tree/discord-0.0.13)
and
[discord/cros-codecs @ discord-0.0.5](https://github.com/discord/cros-codecs/tree/discord-0.0.5)
— both BSD-3-Clause, themselves forks of Intel's
[cros-libva](https://github.com/intel/cros-libva) (ChromiumOS).
It exists to give [moq](https://github.com/moq-dev/moq)'s `moq-video` a thin,
crates.io-publishable VA-API codec brick instead of a multi-backend framework
pulled in as a git dependency.
## What it does
- **H.264 encode** over VA-API: an Annex-B elementary stream out (packed
SPS/PPS + slice headers, low-latency IPPP, CBR rate control whose bitrate can
change between frames, the color space labelled in the VUI). Three inputs:
tightly-packed NV12 from the CPU, an NV12 DMA-BUF at the encoder's size
encoded in place, and any other importable DMA-BUF (packed RGB, YUYV, NV12
at another size or in another color space) converted and scaled into the
encoder's surface on the GPU. NV12 and BGRX input are tested; the other
formats go through the same video processor call untested.
Checked on Intel Meteor Lake (iHD 26.1.5) by decoding with ffmpeg: luma
above 35 dB PSNR against the source, and RGB converted to BT.601 and BT.709
to within a few code values. These run as tests wherever ffmpeg and a VA-API
device are both present.
- **DMA-BUF import and video post-processing.** `dmabuf` wraps a DRM PRIME
buffer as a surface without copying it; `vpp` blits one surface into another
through `VAEntrypointVideoProc`, scaling, converting, and re-tiling on the
way.
- **H.264 decode** over VA-API: one Annex-B access unit in, tightly-packed NV12
out, with in-stream parameter sets, a conformant DPB (reference marking,
reordering, frame_num gaps), and mid-stream resolution changes. Progressive
8-bit 4:2:0 only, with right/bottom cropping supported and left/top cropping
rejected. Verified bit-exact against ffmpeg's software decoder on Intel
Meteor Lake (iHD 26.1.5) for constrained baseline, main with B-frames, high at
720p, and a cropped non-macroblock-aligned size. The main-with-B-frames case
runs as a test wherever ffmpeg and a VA-API device are both present.
- **Pinned, vendored headers.** libva's headers are vendored into
[`libva/`](./libva) (see `just vendor`) and fed to bindgen, so generating the
bindings needs **no system libva-dev** — only `libclang` — and the pinned
version means a system libva bump can't drift the bindings.
- **Links system libva on Linux.** The generated `va*` symbols are resolved by
linking the system `libva` / `libva-drm` (via pkg-config), so a `vaapi`-enabled
binary requires `libva.so` present at runtime — fine for a build that targets
VA-API hardware. VA-API's ABI is stable, so a newer system libva links against
the pinned bindings. (On non-Linux hosts the crate only builds as an rlib, which
leaves the symbols for the final binary, so it stays compilable for development.)
## Layout
- `src/` — libva bindings (`bindings`, `display`, `surface`, `buffer`, ...), the
H.264 bitstream layer (`bitstream_utils`, `codec::h264`), the thin encode
and decode drivers (`encode`, `decode`), DMA-BUF import (`dmabuf`), video
post-processing (`vpp`), and the color space both share (`color`).
- `libva/` — vendored libva headers (checked in; refreshed by `just vendor`).
- `build.rs` + `bindgen_gen.rs` + `libva-wrapper.h` — bindgen setup.
## Development
Recipes run inside the nix devShell:
```sh
nix develop --command just check # clippy + fmt
nix develop --command just ci # check + cargo-deny
nix develop --command just vendor # refresh libva/ headers from upstream
```
The crate compiles on any OS (macOS included) — the rlib build is header-only and
defers the libva link to the final binary, which is Linux-only.
## Licensing
BSD-3-Clause (see [`LICENSE`](./LICENSE)). Vendored upstreams keep their notices:
[`LICENSE.cros-codecs`](./LICENSE.cros-codecs) and the vendored libva headers
under [`LICENSE.libva`](./LICENSE.libva) (MIT).