# ab-av1: finding the CRF that actually lands on your VMAF target

> ab-av1 is a Rust command line wrapper that puts a quality target, rather than a CRF number, at the centre of an AV1 encode. It samples VMAF quickly, searches for the CRF that hits your target, and hands the final job to ffmpeg, with libsvtav1 and libvmaf as hard prerequisites.

**alexheretic/ab-av1** — AV1 re-encoding using ffmpeg, svt-av1 & vmaf.

- Repository: https://github.com/alexheretic/ab-av1
- Stars: 1,022 · Forks: 71
- Language: Rust
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/alexheretic-ab-av1

## A quality target replaces a CRF guess

Every video encoder exposes a rate control knob, and CRF is the one most people reach for. The trouble is that CRF is not portable. The same CRF value produces different quality and wildly different file sizes depending on the source, the preset, the encoder and the resolution.

ab-av1 inverts the question. Its description calls it an AV1 encoding tool with fast VMAF sampling and automatic encoder crf calculation, and the auto-encode command exists to "determine the best crf to deliver the --min-vmaf". You state the quality you want and let the tool work backwards to the bitrate.

That is a meaningful change in who makes the decision. Someone choosing a CRF by hand is guessing at a number that encodes poorly. Someone choosing a VMAF target is stating an acceptance criterion, and the README even shows the goal in its own diagram, finding the best crf encoding setting for VMAF 95 quality. The target audience is therefore a team with a quality bar and a library of source footage, not a person wanting the smallest possible file.

## Two phase auto-encode: search first, then ffmpeg

The auto-encode command is built from two phases, and the README states them plainly: a crf-search phase to determine the best --crf value, and then ffmpeg to encode using the settings.

```bash
ab-av1 auto-encode [OPTIONS] -i <INPUT> --preset <PRESET> --min-vmaf <MIN_VMAF>
```

The ordering is the point. The expensive measurement is done on short samples, the CRF is chosen from those measurements, and the full encode runs once with the result. The README describes sample-encode as much quicker than a full encode or VMAF run, which is what makes the search affordable on a large batch.

Underneath, sample-encode encodes short segments of the input at a given crf and preset, and reports a mean sample VMAF score along with predicted full encode size and predicted full encode time. Those predictions are what let the caller choose a CRF without ever running a full encode, and the same outputs are surfaced by the crf-search command once the search converges.

## Interpolated binary search over crf

The crf-search command is described as an interpolated binary search that uses sample-encode to find the best crf value delivering the requested --min-vmaf and the --max-encoded-percent. The second constraint matters as much as the first: a CRF that meets the quality bar but produces a file larger than a stated percentage of the original is not accepted.

```bash
ab-av1 crf-search [OPTIONS] -i <INPUT> --preset <PRESET> --min-vmaf <MIN_VMAF>
```

Binary search plus interpolation is a sensible choice here, because the relationship between CRF and measured VMAF is monotonic but not linear. A plain binary search would converge on the boundary, while interpolating between the two nearest samples lets the tool propose a CRF that sits closer to the target rather than just on the acceptable side of it. That produces a smaller file for the same quality, and a smaller file is the whole point of caring about CRF in the first place.

The search reuses sample-encode, so the same sampling machinery that produces a quick score also drives the convergence.

## XPSNR as an alternative metric to VMAF

VMAF is not the only quality metric in the tool, and the alternatives are not decorative. The crf-search command takes a --min-xpsnr option that may be used as an alternative to VMAF, and sample-encode has a matching --xpsnr option that specifies calculation of the XPSNR score instead of VMAF.

Both metrics are also available as standalone commands that compare a distorted file against a reference file, and both work with videos and images.

```bash
ab-av1 vmaf --reference <REFERENCE> --distorted <DISTORTED>
```

```bash
ab-av1 xpsnr --reference <REFERENCE> --distorted <DISTORTED>
```

The vmaf command also automates three things that are easy to get wrong by hand: it selects the model version, 4k or 1k, according to the resolution, sets n_threads to the system thread count, and upscales lower resolution videos to the model. That last behaviour is worth knowing about, since a score computed on an upscaled clip is not directly comparable to a native one.

For a workflow that already measures quality with something other than VMAF, the XPSNR path means ab-av1 can drive the CRF search from an existing metric instead of forcing a metric change.

## Verification flags that catch a damaged encode

The encode command hands the work to ffmpeg, and the README is unusually candid about a failure mode: the encoder can otherwise exit successfully having written a damaged or cut short result, for example from a truncated input. A batch job that trusts the exit code will happily move a broken file into place.

Two flags address this. The --verify option checks the finished encode before it is moved into place, decoding it in full and failing on decode errors under --verify-decode, and failing if the duration does not match the input within 2s under --verify-duration. Each check can be enabled on its own, so a job that only cares about truncation can skip the full decode pass.

```bash
ab-av1 encode [OPTIONS] -i <INPUT> --crf <CRF> --preset <PRESET>
```

The second is --fail-fast, which stops the encode at the first ffmpeg reported error instead of writing a damaged result. These are the flags that make the tool safe to run unattended, and the README notes that they also apply to auto-encode, so a quality-targeted run gets the same protections.

## Installing the binary and the ffmpeg it demands

There are several documented install routes, and the ffmpeg requirement is stricter than it first looks. The README requires ffmpeg newer than git-2022-02-24 with libsvtav1, libvmaf and libopus enabled, and that ffmpeg should be in $PATH.

On Arch Linux the package is in the AUR. On Linux generally, a pre-built statically linked x86_64-unknown-linux-musl binary ships with the latest release. On Windows, a pre-built ab-av1.exe ships with the release. For Rust users there are two cargo routes, one for the latest release and one for the latest code straight from git.

```sh
cargo install ab-av1
```

```sh
cargo install --git https://github.com/alexheretic/ab-av1
```

The repository also carries a Dockerfile that shows the intended container shape. The builder stage uses a Rust base image, downloads an ffmpeg and ffprobe build for amd64 or arm64, and compiles the release binary. The runtime stage is a Debian slim image with ffmpeg and ffprobe copied into /usr/local/bin, the binary at /app, a working directory of /videos, and the ab-av1 binary as the entrypoint. That file is the most useful thing in the repo for a CI system, since it packages the ffmpeg dependency with the tool instead of assuming a particular base image already has it.

Debugging is handled through the standard Rust logging facade, with RUST_LOG=ab_av1=debug enabling debug logs that include all ffmpeg calls.

## Rust dependencies, JSON output and a release cadence

The project is written in Rust on edition 2024, with version 0.11.7 recorded in Cargo.toml, and the README says it is maintained with the latest stable Rust. The dependency list gives a clear picture of the architecture: clap for the command line interface with derive, env and wrap_help features, plus clap_complete and clap-verbosity-flag, tokio for the async runtime with process and filesystem features, and tokio-process-stream for streaming ffmpeg output.

The heavier dependencies explain the approach. ffprobe is used to interrogate media, infer detects input types from content, shell-escape handles quoting for external commands, blake3 and sled point to a local cache and hash store for the sample and measurement data, and indicatif renders progress bars. Release profile settings favour small binaries: lto enabled, opt-level set to s, and strip on.

Output can be captured as JSON via --stdout-format json, documented in the repository's stdout-format-json.md, which matters when the tool sits inside a pipeline that needs machine readable scores rather than a progress display.

Release history shows v0.11.7 on 2026-08-21, v0.11.6 on 2026-08-16 and v0.11.5 on 2026-08-01, and the last push was on 2026-09-07. Licence is MIT, and the repository includes a CHANGELOG.md and a deploy directory alongside src/.

## Conclusion

ab-av1 fits anyone who has to hit a measured quality target on a batch of videos and would rather not guess CRF values by hand, and it earns its place for stills and shorter clips where a full encode with VMAF measurement is affordable. It is the wrong tool for a quick one-off re-encode of a single file with a known-good CRF, where the search machinery is pure overhead, and it will not run at all without an ffmpeg build that has libsvtav1, libvmaf and libopus enabled. Before the first run, check that ffmpeg on your PATH is newer than git-2022-02-24 and has those three libraries, because the binary refuses to be useful without them.

## FAQ

### What does ab-av1 need installed before it will work?

An ffmpeg newer than git-2022-02-24 with libsvtav1, libvmaf and libopus enabled, available on your PATH. The ab-av1 binary itself can come from the AUR, a release binary for Linux or Windows, or cargo install.

### How do I get ab-av1 to encode at a specific quality target?

Use the auto-encode command with --min-vmaf, which runs a crf-search phase to find the best crf value and then encodes with ffmpeg using that setting.

### Can ab-av1 use XPSNR instead of VMAF?

Yes. The crf-search command accepts --min-xpsnr as an alternative to VMAF, sample-encode accepts --xpsnr to score with XPSNR instead, and standalone xpsnr and vmaf commands compare a distorted file against a reference file.

### How does ab-av1 avoid writing a broken output file?

The --verify flag checks the finished encode before it is moved into place, decoding it fully with --verify-decode and failing if the duration is more than 2s off the input with --verify-duration, while --fail-fast stops at the first ffmpeg error.

### Does ab-av1 work with encoders other than SVT-AV1?

The README states that it also supports other ffmpeg compatible encoders like libx265 and libx264, while the default and documented path is AV1 through svt-av1.

## Sources

- [alexheretic/ab-av1 on GitHub](https://github.com/alexheretic/ab-av1)
- [Issues](https://github.com/alexheretic/ab-av1/issues)
- [License: MIT](https://github.com/alexheretic/ab-av1/blob/main/LICENSE)
- [README](https://github.com/alexheretic/ab-av1/blob/main/README.md)
- [Releases](https://github.com/alexheretic/ab-av1/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/alexheretic-ab-av1
