# vpxenc / libvpx

Canonical URL: https://encode.wiki/tools/software-encoders/vpxenc/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 08bbbcf5c8ba76a7cc808ec57baa3ae1b19bfb427290ab097b3d439656103098

> **Repository:** [webmproject/libvpx](https://github.com/webmproject/libvpx). Mirror only. Please do not send pull requests. Latest tag: [v1.17.0](https://github.com/webmproject/libvpx/tree/v1.17.0), Aug 20, 2026. Last commit: Oct 8, 2026. License: BSD-3-Clause. Stars: 975.

vpxenc is the command-line encoder in [libvpx](https://chromium.googlesource.com/webm/libvpx/), Google's implementation of [VP8](/codecs/video/vp8/) and [VP9](/codecs/video/vp9/). The same library is what [FFmpeg](/tools/utilities/ffmpeg/) uses for `libvpx` (VP8) and `libvpx-vp9`.

VP9 is still worth encoding when you need wide playback: every major browser decodes it, and many TVs, phones and streaming boxes have VP9 hardware decoding but no AV1. When the audience can decode [AV1](/codecs/video/av1/), a modern AV1 encoder such as [SVT-AV1](/tools/software-encoders/svt-av1/) gives better quality per bit. libvpx's defaults are not tuned for offline quality, so most of this page covers which options to set.

## Get vpxenc

Most Linux distributions and Homebrew package libvpx (on Debian and Ubuntu the command-line tools are in `vpx-tools`). To build the current release (v1.17.0) yourself, you need make, a C/C++ compiler and NASM or Yasm:

```sh
git clone --branch v1.17.0 https://chromium.googlesource.com/webm/libvpx
cd libvpx
./configure --enable-vp9-highbitdepth
make -j"$(nproc)"
```

`--enable-vp9-highbitdepth` is what makes 10- and 12-bit VP9 possible; many distribution builds already include it. WebM output and Y4M input work in a default build. The end of `vpxenc --help` lists the compiled-in encoders and the library version.

## Constant-quality VP9 with vpxenc

Give vpxenc a Y4M file, which carries the frame size, rate and bit depth:

```sh
ffmpeg -i input.mkv -pix_fmt yuv420p input.y4m
vpxenc --codec=vp9 --good --cpu-used=2 --end-usage=q --cq-level=30 \
  --kf-max-dist=240 --row-mt=1 -o output.webm input.y4m
```

For VP9 in `--good` mode, vpxenc runs **two passes by default**, which is what you want for offline encodes. `--end-usage=q` with `--cq-level` is libvpx's constant-quality mode, the closest thing it has to x264's CRF. Lower values give higher quality and bigger files. Values around 30 are a reasonable place to start at 1080p. Use lower values at higher resolutions: Google's VP9 VOD guidance uses 31 at 1080p, 24 at 1440p and 15 at 2160p.

`--cpu-used` is the speed preset. Lower is slower and more efficient. 0–2 suits final encodes, and 3–4 is for quicker turnaround. `--best` costs a lot of time for little gain over `--good --cpu-used=0`. `--rt` is for live and realtime use only.

The output contains only video. To add audio, mux it in afterwards. For example, copy the VP9 track and encode Opus audio from the source:

```sh
ffmpeg -i output.webm -i input.mkv -map 0:v -map 1:a:0 -c:v copy -c:a libopus -b:a 128k final.webm
```

### 10-bit VP9

10-bit encoding reduces banding, even from 8-bit sources. It requires VP9 profile 2 and a high-bit-depth build. Hardware decoders support profile 2 less often than 8-bit profile 0, especially on older devices.

```sh
ffmpeg -i input.mkv -pix_fmt yuv420p10le -strict -1 input10.y4m
vpxenc --codec=vp9 --profile=2 --bit-depth=10 --good --cpu-used=2 \
  --end-usage=q --cq-level=30 --kf-max-dist=240 --row-mt=1 -o output.webm input10.y4m
```

FFmpeg still needs `-strict -1` to write high-bit-depth Y4M. vpxenc reads the input depth from the Y4M header, so `--input-bit-depth` is unnecessary. If `--profile=2` is omitted, vpxenc refuses to start ("high bit-depth not supported in profile < 2"). For 4:4:4 or 4:2:2, use profile 1 (8-bit) or profile 3 (10/12-bit).

### Piping from FFmpeg

```sh
ffmpeg -i input.mkv -pix_fmt yuv420p -f yuv4mpegpipe - | \
  vpxenc --codec=vp9 --passes=1 --good --cpu-used=2 --end-usage=q --cq-level=30 \
  --kf-max-dist=240 --row-mt=1 -o output.webm -
```

> **Caution — Pipes need `--passes=1`.**
>
> Standard input cannot be rewound for a second pass. If you pipe into VP9 vpxenc without `--passes=1`, the first pass consumes the stream, and the second pass encodes nothing. You get a broken file and no error. For two-pass encoding, write a Y4M file first, or run `--pass=1` and `--pass=2` as separate commands with `--fpf=stats.log`, feeding identical frames to each.
### Target bitrate (two-pass VBR)

When a bitrate budget matters more than a fixed quality level:

```sh
vpxenc --codec=vp9 --good --cpu-used=2 --end-usage=vbr --target-bitrate=2000 \
  --kf-max-dist=240 --row-mt=1 -o output.webm input.y4m
```

`--target-bitrate` is in kbit/s. `--end-usage=cq` combines the two: `--cq-level` sets a quality floor and `--target-bitrate` caps the rate.

## VP9 with FFmpeg (`libvpx-vp9`)

FFmpeg handles decoding, audio and muxing in one step:

```sh
ffmpeg -i input.mkv -c:v libvpx-vp9 -crf 30 -b:v 0 -deadline good -cpu-used 2 \
  -row-mt 1 -g 240 -c:a libopus -b:a 128k output.webm
```

`-crf N -b:v 0` selects the same constant-quality (`q`) mode as `--end-usage=q`. If you give `-crf` together with a nonzero `-b:v`, it becomes constrained quality, with `-b:v` as the cap. Current FFmpeg defaults `-b:v` to 0 for libvpx, but writing it out is harmless and keeps the command working on older builds. FFmpeg's `-cpu-used` defaults to 1.

FFmpeg encodes **one pass** unless you ask for two, and some tools (multi-layer alt-refs, below) only work in the second pass of a two-pass encode. For the best results, run two passes:

```sh
ffmpeg -i input.mkv -c:v libvpx-vp9 -crf 30 -b:v 0 -deadline good -cpu-used 2 \
  -row-mt 1 -g 240 -pass 1 -an -f null /dev/null
ffmpeg -i input.mkv -c:v libvpx-vp9 -crf 30 -b:v 0 -deadline good -cpu-used 2 \
  -row-mt 1 -g 240 -pass 2 -c:a libopus -b:a 128k output.webm
```

On Windows, use `NUL` instead of `/dev/null`. For a bitrate target, replace `-crf 30 -b:v 0` with `-b:v 2M`.

FFmpeg's wrapper also turns alt-ref noise filtering off by default (it sends `arnr-maxframes 0`), where vpxenc uses 7 frames at strength 5. Add `-arnr-maxframes 7 -arnr-strength 5` to match vpxenc, or a lower strength on grainy sources.

For 10-bit, add `-pix_fmt yuv420p10le`; FFmpeg selects profile 2 automatically. `libvpx-vp9` also encodes alpha from `yuva420p` input into WebM.

## Options that matter

| vpxenc                       | FFmpeg                       | Default                                    | Notes                                                                                                                                                                               |
| ---------------------------- | ---------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--end-usage=q --cq-level=N` | `-crf N -b:v 0`              | vpxenc: VBR at 256 kbit/s                  | Constant quality, scale 0–63. Always set a rate-control mode; vpxenc's default is a low-bitrate VBR encode.                                                                         |
| `--good --cpu-used=N`        | `-deadline good -cpu-used N` | `--good`; cpu-used 0 (vpxenc), 1 (FFmpeg)  | Speed preset.                                                                                                                                                                       |
| `--passes=2`                 | `-pass 1` / `-pass 2`        | vpxenc 2 for VP9 (1 with `--rt`); FFmpeg 1 | Two passes improve rate allocation and enable multi-layer alt-refs.                                                                                                                 |
| `--kf-max-dist=N`            | `-g N`                       | 128 frames                                 | The default is short for VOD. 5–10 s of frames (240 at 24 fps) is typical. Scene cuts still get keyframes.                                                                          |
| `--row-mt=1`                 | `-row-mt 1`                  | off                                        | Row-based multithreading. A large speedup for a negligible efficiency cost; always enable it.                                                                                       |
| `--tile-columns=N`           | `-tile-columns N`            | 6 (log2), clamped to the width             | Tiles are at least 256 px wide, so 1080p allows at most 4 columns (`2`) and 2160p at most 8 (`3`). More tiles enable more encoder and decoder threads but cost a little efficiency. |
| `--lag-in-frames=N`          | `-lag-in-frames N`           | 25 (the maximum)                           | Lookahead. The default is already the maximum.                                                                                                                                      |
| `--auto-alt-ref=N`           | `-auto-alt-ref N`            | 1                                          | Alternate reference frames. 2–6 enable multi-layer alt-refs, which only take effect in two-pass mode. Community encoders commonly use 6.                                            |
| `--arnr-strength=N`          | `-arnr-strength N`           | vpxenc 5; FFmpeg 3 | Strength of the temporal filter applied to alt-ref frames (0–6). Lower values keep more grain and fine detail. Try 2–3 on grainy sources. |
| `--arnr-maxframes=N`         | `-arnr-maxframes N`          | vpxenc 7; FFmpeg 0 (filter off) | Number of frames the alt-ref filter averages. FFmpeg's wrapper sends 0 unless you set it, so pass `-arnr-maxframes 7` to match vpxenc. |
| `--tune-content=`            | `-tune-content`              | `default`                                  | `screen` for screen recordings and slides. `film` biases decisions toward keeping texture and noise.                                                                                |
| `--aq-mode=N`                | `-aq-mode N`                 | 0 (off)                                    | 1 variance, 2 complexity, 3 cyclic refresh (realtime).                                                                                                                              |
| `--profile=2 --bit-depth=10` | `-pix_fmt yuv420p10le`       | profile 0, 8-bit                           | 10-bit encoding; see above.                                                                                                                                                         |
| `--threads=N`                | `-threads N`                 | 8 (vpxenc)                                 | Worker limit. Useful parallelism depends on tiles and row-mt.                                                                                                                       |
| `--lossless=1`               | `-lossless 1`                | off                                        | Mathematically lossless relative to the YUV input.                                                                                                                                  |

## Pitfalls

- **Bare vpxenc is not constant quality.** Without `--end-usage`, VP9 vpxenc encodes VBR at 256 kbit/s, whatever the resolution.
- **FFmpeg `-crf` with a nonzero `-b:v` is not CRF.** It is constrained quality with a bitrate ceiling. Use `-b:v 0` for pure constant quality.
- **Piping without `--passes=1`** produces an empty or broken file, as described above.
- **Short default GOP.** Both vpxenc and FFmpeg default to a 128-frame maximum keyframe interval, which wastes bits on long-form content. Set `--kf-max-dist`/`-g`.
- **Tile rows add little.** They cost efficiency and add less parallelism than columns. Leave `--tile-rows` at 0 unless a decoder needs them.
- **High-bit-depth input validation.** Since v1.17.0, VP9 rejects high-bit-depth input samples outside the valid range. Fix the source conversion instead of disabling the check with `--validate-hbd-input=0`.

## VP8

VP8 is legacy. Use it only for devices or WebRTC endpoints that cannot decode VP9. It supports 8-bit 4:2:0 only (plus alpha in WebM via FFmpeg). In FFmpeg, VP8's `-crf` is always constrained quality, so give it a bitrate ceiling:

```sh
ffmpeg -i input.mkv -c:v libvpx -crf 10 -b:v 2M -deadline good -cpu-used 1 \
  -auto-alt-ref 1 -lag-in-frames 16 -c:a libopus output.webm
```

The vpxenc equivalent is:

```sh
vpxenc --codec=vp8 --good --cpu-used=1 --passes=2 --end-usage=cq --cq-level=10 \
  --target-bitrate=2000 -o output.webm input.y4m
```

VP8 uses the same 0–63 quality scale, a `--cpu-used` range of −16 to 16, and, unlike VP9, a single pass by default.

## Complete native VP9 parameter reference

Every `vpxenc` 1.17.0 option that applies to VP9, with its short form where one exists. The first five groups are generic vpxenc options that VP8 shares; the last two apply only to VP9. VP8's own group (`--token-parts`, `--screen-content-mode` and VP8 ranges for shared names) is not listed. The default is what vpxenc uses when you omit the option.

<details>
<summary>General options (VP8 and VP9)</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--help` | Off | Print the option list and exit. The end of the output lists the compiled-in encoders and the library version. |
| `-D`, `--debug` | Off | Deterministic output: leaves the application version out of the WebM tags so repeated encodes are byte-identical. |
| `-o`, `--output` | None (required) | Output file name. The container is WebM unless `--ivf` is given. |
| `--codec` | vp9 | `vp8` or `vp9`. The default is VP9 when the build includes it. |
| `-p`, `--passes` | 2 for VP9; 1 with `--rt` or for VP8 | 1 or 2. Two passes read the input twice, so use `--passes=1` when reading from a pipe. |
| `--pass` | Unset (run all passes) | Run only pass 1 or pass 2 of a two-pass encode; needs `--fpf`. `--pass=2` on its own implies `--passes=2`. |
| `--fpf` | Unset (stats kept in memory) | First-pass statistics file. Required when running the passes separately with `--pass`. |
| `--limit` | 0 (all frames) | Stop after this many input frames. |
| `--skip` | 0 | Discard this many frames from the start of the input. |
| `-d`, `--deadline` | 1000000 (good) | Per-frame time budget in µs: 0 selects best mode, 1 realtime, larger values good mode. The `--best`, `--good` and `--rt` shortcuts set it for you. |
| `--best` | Off | Best-quality mode (deadline 0). Far slower than `--good --cpu-used=0` for little gain. |
| `--good` | On | Good-quality mode (deadline 1000000), the normal choice for file encodes. Speed is set with `--cpu-used`. |
| `--rt` | Off | Realtime mode (deadline 1) for live and low-latency use. Forces one pass and a `--cpu-used` of at least 5. |
| `-q`, `--quiet` | Off | Do not print progress. |
| `-v`, `--verbose` | Off | Print the full encoder configuration before encoding. |
| `--psnr` | Off | Compute PSNR against the input and print it in the status line and summary. |
| `--webm` | On (WebM-enabled builds) | Write WebM. The file holds video only; mux audio in afterwards. |
| `--ivf` | Off | Write a bare IVF stream instead of WebM. |
| `-P`, `--output-partitions` | Off | VP8 only: output each token partition as a separate packet. Requires `--ivf`. |
| `--q-hist` | 0 (off) | Print a histogram of frame quantizers with N buckets at the end. |
| `--rate-hist` | 0 (off) | Print a histogram of per-frame bitrate with N buckets at the end. |
| `--disable-warnings` | Off | Parsed but unused in 1.17.0; warnings still print. Use `-y` to skip the prompt. |
| `-y`, `--disable-warning-prompt` | Off | Print configuration warnings (min-q and max-q less than 8 apart, non-zero lag in realtime CBR) without stopping to ask whether to continue. |
| `--test-decode` | off | Decode each frame and compare it with the encoder reconstruction: `off`, `fatal` (abort on mismatch) or `warn`. A debugging aid. |

</details>

<details>
<summary>Input and stream options (VP8 and VP9)</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--nv12` | Off | Raw input is NV12 (8-bit 4:2:0, interleaved U/V). |
| `--yv12` | Off | Raw input is YV12 (planar 4:2:0, V plane before U). |
| `--i420` | On (raw input) | Raw input is I420 (planar 4:2:0). Y4M input carries its own format. |
| `--i422` | Off | Raw input is planar 4:2:2 (VP9 profile 1 or 3). |
| `--i444` | Off | Raw input is planar 4:4:4 (VP9 profile 1 or 3). |
| `--i440` | Off | Raw input is planar 4:4:0 (VP9 profile 1 or 3). |
| `-u`, `--usage` | 0 | Encoder usage profile. VP9 defines only 0. |
| `-t`, `--threads` | 8 | Maximum worker threads (VP9 limit 64). Without `--row-mt=1`, VP9 uses at most one thread per tile column. |
| `--profile` | 0 | VP9 profile: 0 = 8-bit 4:2:0; 1 = 8-bit 4:2:2, 4:4:0 or 4:4:4; 2 = 10/12-bit 4:2:0; 3 = 10/12-bit 4:2:2, 4:4:0 or 4:4:4. Must match `--bit-depth`. |
| `-w`, `--width` | From the Y4M header | Frame width in pixels. Required for raw input. |
| `-h`, `--height` | From the Y4M header | Frame height in pixels. Required for raw input. `-h` is height, not help. |
| `--stereo-mode` | mono | WebM stereo-3D tag: `mono`, `left-right`, `bottom-top`, `top-bottom` or `right-left`. Signalling only. |
| `--timebase` | 1/frame rate; 1/1000 with `--fps` | Output timestamp unit as a fraction of a second. Only takes effect together with `--fps`; otherwise vpxenc uses the inverse of the input frame rate. |
| `--fps` | From the Y4M header; 30/1 for raw | Input frame rate as `num/den`, e.g. `24000/1001`. |
| `--error-resilient` | 0 (off) | Error-resilient coding for lossy real-time transports: frames stay decodable after losses, at an efficiency cost. Leave off for files. |
| `--test-16bit-internal` | Off | VP9, high-bit-depth builds only: use 16-bit internal buffers even for 8-bit input. A test option. |
| `--lag-in-frames` | 25 | Lookahead in frames, 0–25 (25 is the maximum). Alt-ref frames need a non-zero lag; use 0 for low-latency realtime CBR. |

</details>

<details>
<summary>Rate control (VP8 and VP9)</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--drop-frame` | 0 (off) | Drop frames when the decoder buffer falls below this percentage of its optimal level. For CBR streaming. |
| `--resize-allowed` | 0 (off) | 1 lets the encoder code frames at reduced resolution when bits run short (mainly one-pass CBR). |
| `--resize-width` | 0 (dynamic) | Coded width when resizing is allowed. With width and height both 0, VP9 chooses the size dynamically. |
| `--resize-height` | 0 (dynamic) | Coded height when resizing is allowed; see `--resize-width`. |
| `--resize-up` | 30% | VP8 only: buffer level above which a downscaled stream returns to full size. VP9 ignores it. |
| `--resize-down` | 60% | VP8 only: buffer level below which the encoder downscales. VP9 ignores it. |
| `--end-usage` | vbr | Rate control: `vbr`, `cbr`, `cq` (`--cq-level` with `--target-bitrate` as a cap) or `q` (constant quality from `--cq-level`). Use `q` for quality-targeted file encodes. |
| `--target-bitrate` | 256 kbit/s | Average bitrate in kbit/s for `vbr` and `cbr`, and the cap in `cq`. Not used by `q`. |
| `--min-q` | 0 | Best (lowest) quantizer rate control may use, 0–63. |
| `--max-q` | 63 | Worst (highest) quantizer rate control may use, 0–63. Lowering it limits quality drops in hard scenes. |
| `--undershoot-pct` | 25% | How far below the target rate control may run, 0–100 %. |
| `--overshoot-pct` | 25% | How far above the target rate control may run, 0–100 % for VP9. |
| `--buf-sz` | 6000 ms | Decoder buffer size, in milliseconds at the target bitrate. Matters for CBR. |
| `--buf-initial-sz` | 4000 ms | Buffer fullness at the start of the stream, in ms. |
| `--buf-optimal-sz` | 5000 ms | Buffer level rate control tries to maintain, in ms. |

</details>

<details>
<summary>Two-pass rate control (VP8 and VP9)</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--bias-pct` | 50% | Two-pass bit distribution: 0 spreads bits evenly (CBR-like), 100 lets hard scenes take far more (fully variable). |
| `--minsection-pct` | 0% | Two-pass floor: lowest bitrate any GOP may get, as a percentage of the target. |
| `--maxsection-pct` | 2000% | Two-pass ceiling: highest bitrate any GOP may get, as a percentage of the target. |
| `--corpus-complexity` | 0 (off) | Two-pass "corpus VBR": a non-zero value (up to 10000) fixes the complexity midpoint so bitrate allocation is comparable across many videos instead of normalised per clip. |

</details>

<details>
<summary>Keyframe placement (VP8 and VP9)</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--kf-min-dist` | 0 | Minimum keyframe interval in frames. VP9 accepts only 0 or the same value as `--kf-max-dist`, which gives a fixed interval. |
| `--kf-max-dist` | 128 | Maximum keyframe interval in frames. 5–10 seconds of frames is typical for files; scene cuts still get keyframes. |
| `--disable-kf` | Off | No automatic keyframes: only the first frame is a keyframe. |

</details>

<details>
<summary>VP9-specific options</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--cpu-used` | 0 | Speed: higher is faster and less efficient. VP9 uses the absolute value (−9–9). The useful range is 0–5 with `--good` and 5–9 with `--rt`. |
| `--auto-alt-ref` | 1 | Alt-ref frames (hidden, temporally filtered references): 0 off, 1 on, 2–6 allow that many alt-ref layers in the second pass of a two-pass encode. Needs a non-zero `--lag-in-frames`. |
| `--sharpness` | 0 | Loop-filter sharpness, 0–7. Higher values filter edges less, keeping detail at some cost in PSNR and blocking. |
| `--static-thresh` | 0 | Encode-breakout threshold: blocks whose residual falls below it are skipped. Used by the realtime mode decision; 0 is off. |
| `--tile-columns` | 6 | Tile columns as log2, 0–6, clamped so tiles are at least 256 px wide (1080p allows 2, i.e. 4 columns). More tiles allow more encoder and decoder threads but cost a little efficiency. |
| `--tile-rows` | 0 | Tile rows as log2, 0–2. VP9 forces 0 when using more than one thread with tile columns. |
| `--enable-tpl` | 1 | Temporal dependency model: spends more bits on blocks that later frames reference. 0 or 1. |
| `--enable-keyframe-filtering` | 0 (off) | Temporally filter keyframes with neighbouring frames, as alt-refs are. Only applies outside realtime mode with `--cpu-used` 0–1. |
| `--arnr-maxframes` | 7 | Frames the alt-ref temporal filter averages, 0–15; 0 disables the filter. |
| `--arnr-strength` | 5 | Alt-ref temporal filter strength, 0–6; 0 disables the filter. Lower values keep more grain and fine detail. |
| `--arnr-type` | None (ignored) | VP8 filter direction (1–3). VP9 accepts and ignores it. |
| `--tune` | psnr | `psnr` or `ssim`. `ssim` scales per-block rate–distortion weights by local SSIM. |
| `--cq-level` | 10 | Quality level for `--end-usage=q` and `cq`, 0–63; lower is higher quality. Has no effect in `vbr` or `cbr`. |
| `--max-intra-rate` | 0 (no cap) | Cap on keyframe size as a percentage of the average per-frame bitrate. |
| `--max-inter-rate` | 0 (no cap) | Cap on inter-frame size as a percentage of the average per-frame bitrate. |
| `--gf-cbr-boost` | 0 | Extra bits for golden frames in CBR, as a percentage. |
| `--lossless` | 0 (off) | 1 encodes losslessly relative to the YUV input; quantizer settings are ignored. |
| `--frame-parallel` | 1 | Frame-parallel decoding mode: 1 turns off backward probability adaptation so decoders can work on several frames at once. 0 compresses slightly better. |
| `--aq-mode` | 0 (off) | Adaptive quantization: 0 off, 1 variance, 2 complexity, 3 cyclic refresh (realtime), 4 equator360 (360° video). |
| `--alt-ref-aq` | 0 | Experimental separate adaptive quantization for alt-ref frames, 0 or 1. |
| `--frame-boost` | 0 (off) | Periodic quality boost on selected frames, 0 or 1. |
| `--noise-sensitivity` | 0 | Realtime temporal denoiser level, 0 (off) to 6. Needs a build with `--enable-vp9-temporal-denoising`; ignored above 8-bit. |
| `--tune-content` | default | `default`, `screen` (screen recordings and slides) or `film` (keeps more texture and grain). |
| `--color-space` | unknown | Colour space written to the bitstream: `unknown`, `bt601`, `bt709`, `smpte170`, `smpte240`, `bt2020`, `reserved` or `sRGB` (RGB, profile 1 or 3). Signalling only, no conversion. |
| `--min-gf-interval` | 0 (automatic) | Minimum distance between golden/alt-ref frames, 0–24. |
| `--max-gf-interval` | 0 (automatic) | Maximum distance between golden/alt-ref frames, 2–24 when set. `--lag-in-frames` must then be 0 or at least this plus 2. |
| `--target-level` | 255 (off) | VP9 level: 255 off, 0 only collect level statistics, 1 adapt alt-ref distance and tile columns to the picture size, or a level number such as 41 for level 4.1 (10–62). |
| `--row-mt` | 0 (off) | Row-based multithreading: lets VP9 use more threads than tile columns. A large speedup on multi-core machines. |
| `--disable-loopfilter` | 0 | Loop filter: 0 on for all frames, 1 off for non-reference frames, 2 off for all frames. |
| `--validate-hbd-input` | 1 (on) | Reject high-bit-depth input samples outside the valid range for the bit depth. Fix the source conversion rather than disabling it. |
| `-b`, `--bit-depth` | 8 | Coded bit depth: 8, 10 or 12. 10 and 12 need `--profile=2` or `3` and a high-bit-depth build. |
| `--input-bit-depth` | 8; from the Y4M header | Bit depth of the input samples. Raw input is read as 8-bit unless you set this; Y4M input sets it from the header. |

</details>

<details>
<summary>Vizier rate-control factors (VP9, experimental)</summary>

| Option | Default | What it does |
| --- | --- | --- |
| `--use-vizier-rc-params` | 0 (off) | 1 applies the factors below to two-pass rate control. Experimental tuning hooks. |
| `--active-wq-factor` | 1/1 | Active worst-quality factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--err-per-mb-factor` | 1/1 | Error-per-macroblock factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--sr-default-decay-limit` | 1/1 | Second-reference default decay limit. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--sr-diff-factor` | 1/1 | Second-reference difference factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--kf-err-per-mb-factor` | 1/1 | Keyframe error-per-macroblock factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--kf-frame-min-boost-factor` | 1/1 | Minimum keyframe boost factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--kf-frame-max-boost-first-factor` | 1/1 | Maximum boost factor for the first keyframe. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--kf-frame-max-boost-subs-factor` | 1/1 | Maximum boost factor for later keyframes. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--kf-max-total-boost-factor` | 1/1 | Keyframe maximum total boost factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--gf-max-total-boost-factor` | 1/1 | Golden-frame maximum total boost factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--gf-frame-max-boost-factor` | 1/1 | Golden-frame maximum per-frame boost factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--zm-factor` | 1/1 | Zero-motion power factor. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--rd-mult-inter-qp-fac` | 1/1 | RD multiplier adjustment for inter frames. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--rd-mult-arf-qp-fac` | 1/1 | RD multiplier adjustment for alt-ref frames. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |
| `--rd-mult-key-qp-fac` | 1/1 | RD multiplier adjustment for keyframes. Fraction `num/den`, denominator 1–1000. Only used with `--use-vizier-rc-params=1`. |

</details>

## Complete FFmpeg libvpx-vp9 private options

All 36 private options of FFmpeg 9.0.2's `libvpx-vp9` encoder. A default of `-1` or `auto` means FFmpeg leaves the libvpx default in place. Generic options such as `-b:v`, `-g` (`--kf-max-dist`), `-qmin`/`-qmax`, `-threads` and `-pass` are not listed.

> **Caution — Legacy aliases override the defaults.**
>
> The legacy spellings (`-speed`, `-quality`, `-rc_lookahead`, `-arnr_max_frames`, `-arnr_strength`, `-arnr_type`) write the same fields as the newer names, and their defaults are applied last. As a result FFmpeg sends `arnr-maxframes` 0 and `arnr-strength` 3, which turns alt-ref temporal filtering off. Set `-arnr-maxframes 7 -arnr-strength 5` (or your own values) to get vpxenc's behaviour, and set each option under one name only.
<details>
<summary>All libvpx-vp9 private options</summary>

| Option | Type | Default | Range / values | What it does |
| --- | --- | --- | --- | --- |
| `-lag-in-frames` | `int` | `-1` | `-1` to `INT_MAX` | Lookahead frames (libvpx maximum 25). Shares its field with `-rc_lookahead`, whose default of 25 is what is applied. |
| `-arnr-maxframes` | `int` | `-1` | `-1` to `INT_MAX` | Frames the alt-ref filter averages, 0–15. Shares its field with `-arnr_max_frames`, whose default of 0 is applied: alt-ref filtering is off unless you set this (libvpx default 7). |
| `-arnr-strength` | `int` | `-1` | `-1` to `INT_MAX` | Alt-ref filter strength, 0–6. Shares its field with `-arnr_strength`, whose default of 3 is applied (libvpx default 5). |
| `-arnr-type` | `int` | `-1` | `-1` to `INT_MAX`; `backward`=`1`, `forward`=`2`, `centered`=`3` | VP8 filter direction; VP9 ignores it. |
| `-tune` | `int` | `-1` | `-1` to `INT_MAX`; `psnr`=`0`, `ssim`=`1` | Rate–distortion tuning, `psnr` or `ssim`; libvpx default `psnr`. |
| `-deadline` | `int` | `good` | `INT_MIN` to `INT_MAX`; `best`=`0`, `good`=`1000000`, `realtime`=`1` | Encoding mode: `best`, `good` or `realtime` (or a µs value). `realtime` forces speed 5 or higher. |
| `-error-resilient` | `flags` | `0` | `default`=`1`, `partitions`=`2` | `default` turns on error-resilient coding for lossy transports; `partitions` is VP8 only. |
| `-max-intra-rate` | `int` | `-1` | `-1` to `INT_MAX` | Keyframe size cap as a percentage of the average frame bitrate; 0 means no cap. |
| `-crf` | `int` | `-1` | `-1` to `63` | Quality level 0–63 (`--cq-level`). With `-b:v 0` it is constant quality (`q`); with a non-zero `-b:v` it is constrained quality capped at `-b:v`. Without `-crf` or `-b:v`, FFmpeg uses `q` at 32. |
| `-static-thresh` | `int` | `0` | `0` to `INT_MAX` | Encode-breakout threshold, used by the realtime mode decision; 0 is off. |
| `-drop-threshold` | `int` | `0` | `INT_MIN` to `INT_MAX` | Frame-drop threshold as a percentage of the buffer level (`--drop-frame`). For CBR. |
| `-noise-sensitivity` | `int` | `0` | `0` to `4` | VP8 only: the wrapper does not pass it to VP9. |
| `-undershoot-pct` | `int` | `-1` | `-1` to `100` | How far below the target rate control may run, 0–100 %. |
| `-overshoot-pct` | `int` | `-1` | `-1` to `1000` | How far above the target rate control may run. VP9 rejects values above 100. |
| `-ts-parameters` | `dictionary` | `unset` | `key=value` list | Temporal-scalability layers for RTC as `key=value` pairs separated by `:`: `ts_number_layers`, `ts_target_bitrate`, `ts_rate_decimator`, `ts_periodicity`, `ts_layer_id`, `ts_layering_mode` (put it last). |
| `-auto-alt-ref` | `int` | `-1` | `-1` to `6` | 0 off, 1 on, 2–6 multi-layer alt-refs (second pass of a two-pass encode only); libvpx default 1. |
| `-cpu-used` | `int` | `1` | `-8` to `8` | Speed, −8 to 8; higher is faster. FFmpeg sends 1 by default (libvpx default 0). `-speed 9` reaches speed 9. |
| `-lossless` | `int` | `-1` | `-1` to `1` | 1 encodes losslessly; quantizer settings are ignored. |
| `-tile-columns` | `int` | `-1` | `-1` to `6` | Tile columns as log2, 0–6; libvpx default 6, clamped so tiles are at least 256 px wide. |
| `-tile-rows` | `int` | `-1` | `-1` to `2` | Tile rows as log2, 0–2; libvpx forces 0 when multi-threaded with tile columns. |
| `-frame-parallel` | `boolean` | `auto` | `-1` to `1` | Frame-parallel decoding mode; libvpx default on (no backward probability adaptation). `0` compresses slightly better. |
| `-aq-mode` | `int` | `-1` | `-1` to `4`; `none`=`0`, `variance`=`1`, `complexity`=`2`, `cyclic`=`3`, `equator360`=`4` | Adaptive quantization; libvpx default `none`. `cyclic` is for realtime, `equator360` for 360° video. |
| `-level` | `float` | `-1` | `-1` to `6.2` | Target VP9 level such as `4.1`; FFmpeg logs the achieved level at the end. Unset means no level target. |
| `-row-mt` | `boolean` | `auto` | `-1` to `1` | Row-based multithreading; libvpx default off. Set `1` on multi-core machines. |
| `-tune-content` | `int` | `-1` | `-1` to `2`; `default`=`0`, `screen`=`1`, `film`=`2` | `default`, `screen` (screen recordings) or `film` (keeps more grain). |
| `-corpus-complexity` | `int` | `-1` | `-1` to `10000` | Two-pass corpus-VBR complexity midpoint; 0 is off. |
| `-enable-tpl` | `boolean` | `auto` | `-1` to `1` | Temporal dependency model; libvpx default on. |
| `-min-gf-interval` | `int` | `-1` | `-1` to `INT_MAX` | Minimum golden/alt-ref interval; 0 lets the encoder choose. There is no FFmpeg option for the maximum. |
| `-speed` | `int` | `1` | `-16` to `16` | Legacy alias of `-cpu-used` with a ±16 range; libvpx-vp9 accepts −9 to 9. |
| `-quality` | `int` | `good` | `INT_MIN` to `INT_MAX`; `best`=`0`, `good`=`1000000`, `realtime`=`1` | Legacy alias of `-deadline`. |
| `-vp8flags` | `flags` | `0` | `error_resilient`=`1`, `altref`=`2` | Legacy flags: `error_resilient` (same as `-error-resilient default`) and `altref` (same as `-auto-alt-ref 1`). |
| `-arnr_max_frames` | `int` | `0` | `0` to `15` | Legacy alias of `-arnr-maxframes`. Its default of 0 is the value FFmpeg sends. |
| `-arnr_strength` | `int` | `3` | `0` to `6` | Legacy alias of `-arnr-strength`. Its default of 3 is the value FFmpeg sends. |
| `-arnr_type` | `int` | `3` | `1` to `3` | Legacy alias of `-arnr-type`; VP9 ignores it. |
| `-rc_lookahead` | `int` | `25` | `0` to `25` | Legacy alias of `-lag-in-frames`. Its default of 25 is the value FFmpeg sends. |
| `-sharpness` | `int` | `-1` | `-1` to `7` | Loop-filter sharpness, 0–7; libvpx default 0. |

</details>
