Av1an
37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0Cross-platform command-line AV1 / VP9 / HEVC / H264 encoding framework with per scene quality encoding
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.
Install it
Section titled “Install it”- Windows: download
av1an.exefrom thelatestpre-release, a nightly build ofmaster. The tagged releases carry no binaries. - Arch Linux:
pacman -S av1an(release build) orav1an-gitfrom the AUR (master). - Cargo:
cargo install av1anfor the release. For master, clone the repository and runcargo build --release. Building needs Rust, NASM, clang, FFmpeg and VapourSynth. - macOS: build with Cargo; MacPorts also has a port.
- Docker:
masterofzen/av1an:mastercontains every supported encoder and the optional plugins. Mount your working directory at/videos:
docker run --privileged -v "$(pwd):/videos" --user $(id -u):$(id -g) -it --rm masterofzen/av1an:master -i input.mkv -o output.mkvOutside Docker you provide the dependencies yourself:
| Dependency | Needed for |
|---|---|
| FFmpeg and VapourSynth | Always |
| At least one encoder executable | Always. A library package such as libSvtAv1Enc is not enough; you need SvtAv1EncApp. |
| A VapourSynth source plugin: L-SMASH-Works, FFMS2 or BestSource | Fast, frame-accurate chunking (strongly recommended) |
| mkvmerge | The default concatenation method |
| FFmpeg with libvmaf | VMAF target quality |
| Vship (GPU) or vszip (CPU) | SSIMULACRA2 target quality |
| Vship or vapoursynth-julek-plugin | Butteraugli 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.
Encode with SVT-AV1
Section titled “Encode with SVT-AV1”av1an -i input.mkv -o output.mkv -e svt-av1 -v "--preset 4 --crf 30 --tune 0" -m lsmash-epicks the encoder and-vpasses options straight to its executable, so use the encoder’s own syntax (--crf 30, not FFmpeg’s-crf 30). RunSvtAv1EncApp --helpfor the list.--tune 0selects SVT-AV1’s visual-quality tune; its default (tune 1) optimises for PSNR.-m lsmashis the chunk method. Without-m, Av1an picks the first installed ofbestsource,lsmash,ffms2,dgdecnv, then falls back tohybrid. BestSource is accurate but slow, so set-m lsmashwhen 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:
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.
Encode with aomenc
Section titled “Encode with aomenc”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).
Options that matter
Section titled “Options that matter”| Option | Default | What it does |
|---|---|---|
-w, --workers | 0 (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-method | First available (see above) | How exact frame ranges are fed to each encoder. See Chunk methods. |
-c, --concat | mkvmerge | How chunks are joined. ffmpeg can write WebM but does not work with x265; ivf is video-only. |
-x, --extra-split / --extra-split-sec | 10 seconds | Maximum chunk length. Longer scenes are split, which also caps the keyframe interval. |
--min-scene-len | 24 frames | Shortest scene Av1an will cut. |
--sc-downscale-height | Off | Run scene detection on a downscaled copy (for example 720) to make it faster on 4K sources. |
-s, --scenes | None | Save scene cuts to a JSON file, or reuse an existing one. Add --sc-only to detect scenes and exit. |
-f, --ffmpeg | None | FFmpeg filter arguments applied to the source, such as -f "-vf crop=1920:800". For real filtering, use a VapourSynth script as input. |
--photon-noise | 0 (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. |
--zones | None | File of frame ranges with different encoder settings. |
--resume / -k | Off | -k keeps the temporary directory; --resume continues an interrupted job from it. |
--temp | Hash of the input name | Location of the work directory, which holds the encoded chunks. |
Target quality
Section titled “Target quality”av1an -i input.mkv -o output.mkv -e svt-av1 -v "--preset 4 --tune 0" --target-metric ssimulacra2 --target-quality 80For 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-metric | Scale | Requires |
|---|---|---|
vmaf (default) | 0–100, higher is better | FFmpeg built with libvmaf |
ssimulacra2 | Up to 100, higher is better | Vship or vszip, and a VapourSynth chunk method |
butteraugli-inf | Distance, lower is better | Vship or vapoursynth-julek-plugin, and a VapourSynth chunk method |
butteraugli-3 | Distance, lower is better | Vship, and a VapourSynth chunk method |
xpsnr | dB, higher is better | FFmpeg’s xpsnr filter (vszip when --probing-rate > 1). Scores the weakest of the Y, U and V planes. |
xpsnr-weighted | dB, higher is better | As 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.
Use a VapourSynth script
Section titled “Use a VapourSynth script”Pass a .vpy or .py script as the input to filter (denoise, deband, crop, resize) before encoding:
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.
Chunk methods
Section titled “Chunk methods”| Method | Notes |
|---|---|
lsmash | L-SMASH-Works. Usually the best choice: fast, frame-accurate, and errors out on a broken stream instead of hiding it. |
ffms2 | FFMS2. Similar to lsmash, but occasionally produces artifacts that lsmash does not. |
bestsource | BestSource. The default when installed. Decodes linearly, so it is slow, but it is the most reliable when seeking is the problem. |
dgdecnv | DGDecNV. Very fast NVIDIA hardware decoding; AVC, HEVC, MPEG-2 and VC-1 only; needs dgindexnv in PATH. |
hybrid | FFmpeg only. Splits the source at keyframes into temporary files, then trims precisely; needs disk space. |
segment | FFmpeg only. Cuts at existing keyframes, so chunks are not frame-exact. |
select | FFmpeg 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.
Common problems
Section titled “Common problems”- Av1an adds its own encoder defaults. Unless you pass
--no-defaults, Av1an puts its default arguments in front of your-vstring, 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-xin frames) to change the maximum interval rather than--keyint. With--no-defaults, only your-vis 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-lenstops cuts closer together than that many frames; save the scenes with-sso later attempts reuse the same cuts instead of detecting them again. - XPSNR target scores use swapped inputs. FFmpeg’s
xpsnrfilter 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-rate2–4) passes the inputs correctly. - Changed settings while resuming.
--resumereuses finished chunks as they are. If you change the encoder settings, the input or the scenes, delete the work directory and start again.