Skip to content

Av1an

currentMigrated from docs/utilities/av1an.mdx at 37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0

Cross-platform command-line AV1 / VP9 / HEVC / H264 encoding framework with per scene quality encoding

Latest release
v0.5.2
Last commit
License
GPL-3.0
Stars
1,997

Av1an is a command-line encoding framework. It detects scene changes, cuts the video into chunks at those scenes, runs several encoder processes (“workers”) at once, and joins the results with the audio. Encoders scale poorly across many cores on their own, so running one instance per chunk is how most people keep a modern CPU fully busy with slow AV1 presets.

It can also run in target-quality mode, where it searches for the CRF/quantizer of each chunk that hits a metric score (VMAF, SSIMULACRA2, Butteraugli or XPSNR).

Av1an does not encode anything itself. It drives the encoder executables (aomenc, SvtAv1EncApp, rav1e, vpxenc, x264, x265), and uses FFmpeg and VapourSynth for decoding. The cost of parallelism is memory: every worker holds its own encoder instance and source decoder, so RAM use grows with the worker count.

  • Windows: download av1an.exe from the latest pre-release, a nightly build of master. The tagged releases carry no binaries.
  • Arch Linux: pacman -S av1an (release build) or av1an-git from the AUR (master).
  • Cargo: cargo install av1an for the release. For master, clone the repository and run cargo build --release. Building needs Rust, NASM, clang, FFmpeg and VapourSynth.
  • macOS: build with Cargo; MacPorts also has a port.
  • Docker: masterofzen/av1an:master contains every supported encoder and the optional plugins. Mount your working directory at /videos:
Terminal window
docker run --privileged -v "$(pwd):/videos" --user $(id -u):$(id -g) -it --rm masterofzen/av1an:master -i input.mkv -o output.mkv

Outside Docker you provide the dependencies yourself:

DependencyNeeded for
FFmpeg and VapourSynthAlways
At least one encoder executableAlways. A library package such as libSvtAv1Enc is not enough; you need SvtAv1EncApp.
A VapourSynth source plugin: L-SMASH-Works, FFMS2 or BestSourceFast, frame-accurate chunking (strongly recommended)
mkvmergeThe default concatenation method
FFmpeg with libvmafVMAF target quality
Vship (GPU) or vszip (CPU)SSIMULACRA2 target quality
Vship or vapoursynth-julek-pluginButteraugli target quality

On Windows, install the plugins with VapourSynth’s plugin manager from the VapourSynth directory: python3 vsrepo.py install lsmas ffms2 bs vszip julek. av1an --version lists which plugins and encoders it can find.

Terminal window
av1an -i input.mkv -o output.mkv -e svt-av1 -v "--preset 4 --crf 30 --tune 0" -m lsmash
  • -e picks the encoder and -v passes options straight to its executable, so use the encoder’s own syntax (--crf 30, not FFmpeg’s -crf 30). Run SvtAv1EncApp --help for the list.
  • --tune 0 selects SVT-AV1’s visual-quality tune; its default (tune 1) optimises for PSNR.
  • -m lsmash is the chunk method. Without -m, Av1an picks the first installed of bestsource, lsmash, ffms2, dgdecnv, then falls back to hybrid. BestSource is accurate but slow, so set -m lsmash when L-SMASH-Works is installed.
  • Audio is copied (-c:a copy) and subtitles are passed through by default. Output is 10-bit 4:2:0 (--pix-format yuv420p10le) even from 8-bit sources, which is what you want for AV1.

To re-encode the audio, pass FFmpeg audio options with -a:

Terminal window
av1an -i input.mkv -o output.mkv -e svt-av1 -v "--preset 4 --crf 30 --tune 0" -a "-c:a libopus -b:a 128k"

-a uses stream specifiers rather than -map; for example -a "-c:a:0 libopus -b:a:0 128k -c:a:1 copy" treats two audio tracks differently.

Terminal window
av1an -i input.mkv -o output.mkv -e aom -v "--cpu-used=4 --end-usage=q --cq-level=30 --threads=2"

aomenc options use =. Av1an runs aomenc (and vpxenc) in two passes by default even in constant-quality mode, because both encoders use the first pass for better decisions; -p 1 turns that off. --threads=2 keeps each instance small so that more workers fit, which is the usual way to run aomenc under Av1an. The automatic worker count assumes about four threads per aomenc worker whatever --threads says, so set -w yourself (up to about half your CPU threads, RAM permitting).

OptionDefaultWhat it does
-w, --workers0 (automatic)Number of parallel encoder instances. Automatic picks the smaller of a CPU-based count (for example threads ÷ 6 for SVT-AV1, ÷ 4 for aomenc) and a RAM-based estimate.
-m, --chunk-methodFirst available (see above)How exact frame ranges are fed to each encoder. See Chunk methods.
-c, --concatmkvmergeHow chunks are joined. ffmpeg can write WebM but does not work with x265; ivf is video-only.
-x, --extra-split / --extra-split-sec10 secondsMaximum chunk length. Longer scenes are split, which also caps the keyframe interval.
--min-scene-len24 framesShortest scene Av1an will cut.
--sc-downscale-heightOffRun scene detection on a downscaled copy (for example 720) to make it faster on 4K sources.
-s, --scenesNoneSave scene cuts to a JSON file, or reuse an existing one. Add --sc-only to detect scenes and exit.
-f, --ffmpegNoneFFmpeg filter arguments applied to the source, such as -f "-vf crop=1920:800". For real filtering, use a VapourSynth script as input.
--photon-noise0 (off)Generates an AV1 film-grain table (ISO-like strength, 1–64) for aomenc, rav1e and SVT-AV1. Do not combine it with the encoder’s own grain option.
--zonesNoneFile of frame ranges with different encoder settings.
--resume / -kOff-k keeps the temporary directory; --resume continues an interrupted job from it.
--tempHash of the input nameLocation of the work directory, which holds the encoded chunks.
Terminal window
av1an -i input.mkv -o output.mkv -e svt-av1 -v "--preset 4 --tune 0" --target-metric ssimulacra2 --target-quality 80

For each chunk, Av1an encodes a few fast probes at different CRFs (four by default), measures them, interpolates the CRF that should hit the target, and encodes the chunk at that value. It costs extra encoding time but evens out quality between easy and hard scenes.

—target-metricScaleRequires
vmaf (default)0–100, higher is betterFFmpeg built with libvmaf
ssimulacra2Up to 100, higher is betterVship or vszip, and a VapourSynth chunk method
butteraugli-infDistance, lower is betterVship or vapoursynth-julek-plugin, and a VapourSynth chunk method
butteraugli-3Distance, lower is betterVship, and a VapourSynth chunk method
xpsnrdB, higher is betterFFmpeg’s xpsnr filter (vszip when --probing-rate > 1). Scores the weakest of the Y, U and V planes.
xpsnr-weighteddB, higher is betterAs xpsnr; weights luma 4:1:1 over the chroma planes

Useful knobs: --qp-range 15-45 bounds the CRF search; --probes sets the number of probes; --probing-stat chooses how per-frame scores are pooled (a low percentile or harmonic mean protects the worst frames better than a mean). Probes use a fast fixed preset by default; --probe-video-params copy probes with your real -v settings, which is more accurate and much slower, or you can pass your own probe settings.

VMAF is the default, but the community generally prefers SSIMULACRA2 or Butteraugli for this: VMAF’s default model scores 1080p viewing on a TV and can be inflated by sharpening. Whatever metric you target, watch the result. See SSIMULACRA2, Butteraugli, XPSNR and VMAF.

Pass a .vpy or .py script as the input to filter (denoise, deband, crop, resize) before encoding:

Terminal window
av1an -i script.vpy -o output.mkv -e svt-av1 -v "--preset 4 --crf 30 --tune 0"

Scene detection and target-quality probing also run through the script, so expensive filters slow them down too. --proxy points those steps at a cheaper input with the same frame count, such as the unfiltered source. With a script input, Av1an has no source file to take audio from; mux audio separately with mkvmerge afterwards.

MethodNotes
lsmashL-SMASH-Works. Usually the best choice: fast, frame-accurate, and errors out on a broken stream instead of hiding it.
ffms2FFMS2. Similar to lsmash, but occasionally produces artifacts that lsmash does not.
bestsourceBestSource. The default when installed. Decodes linearly, so it is slow, but it is the most reliable when seeking is the problem.
dgdecnvDGDecNV. Very fast NVIDIA hardware decoding; AVC, HEVC, MPEG-2 and VC-1 only; needs dgindexnv in PATH.
hybridFFmpeg only. Splits the source at keyframes into temporary files, then trims precisely; needs disk space.
segmentFFmpeg only. Cuts at existing keyframes, so chunks are not frame-exact.
selectFFmpeg only. Decodes from the start every time; extremely slow.

The VapourSynth methods write an index next to the source file on the first run. --cache-mode temp puts it in the work directory instead.

  • Av1an adds its own encoder defaults. Unless you pass --no-defaults, Av1an puts its default arguments in front of your -v string, dropping any flag you set yourself. For SVT-AV1 that leaves --keyint 0 --scd 0 --rc 0; for aomenc it prepends --threads=8 --cpu-used=6 --disable-kf --kf-max-dist=9999 (your own --threads=/--cpu-used= come later and win). The point is that keyframes come from Av1an: every chunk starts with exactly one keyframe and the encoder places none of its own. Use --extra-split-sec (or -x in frames) to change the maximum interval rather than --keyint. With --no-defaults, only your -v is passed, so add --keyint 0 (SVT-AV1) or --disable-kf --kf-max-dist=9999 (aomenc) yourself.
  • Gray or corrupted frames at chunk boundaries. The source filter seeked inaccurately, which happens with some files. Switch to -m bestsource, which decodes linearly, or encode a lossless intermediate first (for example x264 with --qp 0), which fixes seeking problems at the cost of a very large file.
  • Running out of memory. Lower -w. A 4K SVT-AV1 worker can need several gigabytes, and the automatic worker count is estimated from total RAM, not free RAM.
  • Too many short scenes. Flashes and strobes can trigger extra cuts. --min-scene-len stops cuts closer together than that many frames; save the scenes with -s so later attempts reuse the same cuts instead of detecting them again.
  • XPSNR target scores use swapped inputs. FFmpeg’s xpsnr filter treats its first input as the reference, but Av1an (v0.5.2 and current master) passes the encoded probe first. With the default --probing-rate 1, XPSNR targets are therefore computed with the perceptual weighting taken from the encode and do not match XPSNR measured correctly elsewhere. The vszip path (--probing-rate 2–4) passes the inputs correctly.
  • Changed settings while resuming. --resume reuses finished chunks as they are. If you change the encoder settings, the input or the scenes, delete the work directory and start again.