# VAAPI

Canonical URL: https://encode.wiki/tools/hardware-encoders/vaapi/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 01c46a915c21bd2b82294cbee8b1f7bdf40ec4f2e794c3995f4277fdc0ea318b

VAAPI is the Linux API for GPU video encoding and decoding. Intel GPUs use the `intel-media-driver` (iHD) backend and AMD GPUs use Mesa's `radeonsi` backend. FFmpeg's wrappers are `h264_vaapi`, `hevc_vaapi`, `vp9_vaapi`, `av1_vaapi` and a few older codecs. Which of them work depends on the GPU, not on FFmpeg. NVIDIA GPUs have no VAAPI encoder; use [NVENC](/tools/hardware-encoders/nvenc/).

Unlike NVENC and AMF, VAAPI is a common API over different hardware, so the same command can behave differently on Intel and AMD. It is the usual Linux route for [Intel Quick Sync](/tools/hardware-encoders/qsv/) and for AMD, where [AMF](/tools/hardware-encoders/amf/) is awkward on Linux.

## Hardware or software encoder?

Hardware encoders are quick and cheap on power but lose to [x264](/tools/software-encoders/x264/), [x265](/tools/software-encoders/x265/) and [SVT-AV1](/tools/software-encoders/svt-av1/) at slow presets in quality per bit. Use VAAPI for fast transcodes, recording and streaming. Use a software encoder for archival work. More in [NVENC: hardware or software](/tools/hardware-encoders/nvenc/#hardware-or-software-encoder).

## Check what your GPU can encode

```sh
vainfo --display drm --device /dev/dri/renderD128
```

Look for the profile with `VAEntrypointEncSlice`, for example `VAProfileHEVCMain : VAEntrypointEncSlice`. `VAEntrypointEncSliceLP` is the low-power engine, which is what `-low_power 1` selects. A profile listed only as `VAEntrypointVLD` is decode-only. `vainfo` ships in `libva-utils`.

AV1 encode needs an Intel Arc or Meteor Lake-or-newer GPU, or an AMD RDNA 3 or newer GPU (or a Phoenix-or-newer APU). See [QSV](/tools/hardware-encoders/qsv/#which-hardware-supports-what) and [AMF](/tools/hardware-encoders/amf/#which-hardware-supports-what) for the generation lists.

## Quality-oriented encode

```sh
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mkv -vf 'format=nv12,hwupload' -c:v hevc_vaapi -global_quality 24 -c:a copy output.mkv
```

VAAPI only accepts frames in GPU memory, so `hwupload` after a `format=nv12` conversion is required with software-decoded input. `-global_quality` alone is enough for constant quality: FFmpeg tries ICQ and falls back to CQP when the driver has no ICQ, as with Mesa on AMD. Lower is better. Do not combine it with `-b:v`, which asks for QVBR instead. The numbers are not comparable to CRF.

For AV1:

```sh
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mkv -vf 'format=nv12,hwupload' -c:v av1_vaapi -rc_mode CQP -global_quality 100 -c:a copy output.mkv
```

AV1 uses the 0–255 quantizer, so values run higher than for HEVC, and the explicit `-rc_mode CQP` stops FFmpeg from picking ICQ, whose scale is 1–51. For 10-bit use `format=p010le,hwupload`.

### Bitrate-targeted

```sh
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mkv -vf 'format=nv12,hwupload' -c:v hevc_vaapi -b:v 6M -maxrate 9M -bufsize 12M -c:a copy output.mkv
```

`-b:v` with a larger `-maxrate` is VBR; equal values give CBR. A bare `-b:v` with no `-bufsize` tries AVBR first, which ignores buffer constraints. Force a mode with `-rc_mode CQP|CBR|VBR|ICQ|QVBR|AVBR` when the automatic choice is wrong. Drivers support only a subset, and FFmpeg errors out if you request an unsupported one.

## Full-GPU pipeline

```sh
ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device /dev/dri/renderD128 -i input.mkv -vf scale_vaapi=w=1920:h=1080 -c:v hevc_vaapi -global_quality 24 output.mkv
```

Decode, scale and encode stay on the GPU. Filters that are not VAAPI filters need `hwdownload,format=nv12` first. The decoder must support the input codec and profile, or the command fails at decode; fall back to the software-decode command above.

## Options that matter

| Option | What it does |
| --- | --- |
| `-global_quality` | Constant-quality target (ICQ or CQP). `h264_vaapi` and `hevc_vaapi` also have `-qp`, which forces CQP. |
| `-rc_mode` | Force `CQP`, `CBR`, `VBR`, `ICQ`, `QVBR` or `AVBR`. Default `auto`. |
| `-b:v`, `-maxrate`, `-bufsize` | Bitrate constraints. |
| `-compression_level` | Speed/quality trade-off passed to the driver as its quality level; higher is faster and worse. The range is driver-specific. |
| `-bf`, `-b_depth` | B-frames and B-pyramid depth. Some drivers ignore or reject them. |
| `-low_power 1` | Use the fixed-function low-power encoder. Fewer features; some other options may be rejected. |
| `-g`, `-idr_interval` | GOP length; `-idr_interval N` makes only every Nth I-frame an IDR (open GOP). |
| `-async_depth` | Frames in flight. |

## Pitfalls

- A profile with only a decode entry point cannot encode. Check `vainfo` before blaming FFmpeg.
- `hwupload` needs a device: use `-vaapi_device` (or `-init_hw_device`/`-filter_hw_device`) when decoding in software.
- Pick the right render node (`/dev/dri/renderD128`, `renderD129`, …) on systems with an iGPU and a discrete GPU.
- Behaviour differs across drivers. A command tuned on Intel may need `-rc_mode` or `-global_quality` changes on AMD.

## Full option reference

Every private option of `av1_vaapi` in FFmpeg 9.0.2. The driver may support fewer rate-control modes and profiles than FFmpeg can name; `vainfo` lists them. `INT_MAX` is 2147483647.

{/* ffmpeg-parameters:start */}

### Private options

| Parameter | Type | Default | Meaning | Range / named values |
| --- | --- | --- | --- | --- |
| `-idr_interval` | `int` | `0` | Number of non-key I-frames between key frames; 0 makes every I-frame a key frame. | `0` to `INT_MAX` |
| `-b_depth` | `int` | `1` | B-frame reference depth: 1 = flat B-frames, higher builds a hierarchy. Needs `-bf`. | `1` to `INT_MAX` |
| `-async_depth` | `int` | `2` | Frames in flight on the GPU; raise it for single-stream throughput. | `1` to `64` |
| `-low_power` | `boolean` | `false` | Use the low-power encode entrypoint (VDEnc on Intel). Some GPUs have only this one, and it can lack features. | `0` to `1` |
| `-max_frame_size` | `int` | `0` | Largest encoded frame, in bytes; 0 = no limit. | `0` to `2.68435e+08` |
| `-rc_mode` | `int` | `auto` | Rate control: `CQP`, `CBR`, `VBR`, `ICQ`, `QVBR`, `AVBR`. `auto` uses CQP with `-q:v`, ICQ with `-global_quality` (QVBR if `-b:v` is also set), CBR when `-b:v` equals `-maxrate`, otherwise AVBR or VBR; with no rate options, ICQ or CQP. | `0` to `6`; `auto`=`0`, `CQP`=`1`, `CBR`=`2`, `VBR`=`3`, `ICQ`=`4`, `QVBR`=`5`, `AVBR`=`6` |
| `-blbrc` | `boolean` | `false` | Block-level rate control (finer bit allocation within a frame) where the driver supports it. | `0` to `1` |
| `-profile` | `int` | `-99` | AV1 profile: `main`, `high`, `professional`. -99 chooses from the input format. | `-99` to `255`; `main`=`0`, `high`=`1`, `professional`=`2` |
| `-tier` | `int` | `main` | AV1 tier: `main` or `high`. | `0` to `1`; `main`=`0`, `high`=`1` |
| `-level` | `int` | `-99` | AV1 level (`seq_level_idx`); -99 chooses automatically. | `-99` to `31`; `2.0`=`0`, `2.1`=`1`, `3.0`=`4`, `3.1`=`5`, `4.0`=`8`, `4.1`=`9`, `5.0`=`12`, `5.1`=`13`, `5.2`=`14`, `5.3`=`15`, `6.0`=`16`, `6.1`=`17`, `6.2`=`18`, `6.3`=`19` |
| `-tiles` | `image_size` | `not exposed` | Tile layout as columns×rows, e.g. `2x2`; unset uses the minimum the resolution needs. | — |
| `-tile_groups` | `int` | `1` | Number of tile groups per frame. | `1` to `4096` |

### Codec-specific generic initialization overrides

The wrapper replaces these generic FFmpeg defaults for this encoder. `-b` is in bits/s; `-g` and
`-bf` count frames. `-1`, and `0` for `-b` and `-refs`, leave the value to the preset, driver or
rate-control logic.

| Generic parameter | Default |
| --- | --- |
| `-b` | `0` |
| `-bf` | `2` |
| `-g` | `120` |
| `-qmin` | `1` |
| `-qmax` | `255` |
| `-refs` | `0` |

{/* ffmpeg-parameters:end */}
