Skip to content

vmaf-tune — quality-aware encode automation harness

vmaf-tune finds the encoder settings that reach a target VMAF score. It drives FFmpeg over a grid of encoder parameters, scores each encode with vmaf, and either writes a JSONL corpus of (source, encoder, params, bitrate, vmaf) rows or answers a question directly: which CRF hits VMAF 92, which codec is cheapest at that target, what a per-title bitrate ladder looks like.

The tool is a fork-added Python package (ADR-0237, Research-0044). A Go port of the same subcommands is described in vmafx-tune-go.md.

Install

  1. Install the package from the repository root. The core install has no runtime dependencies beyond the Python standard library:

    pip install -e tools/vmaf-tune
    

    This installs two equivalent console scripts, vmaf-tune and vmafx-tune. Without installing, run the checkout shim instead:

    python tools/vmaf-tune/vmaf-tune --help
    
  2. Put the external binaries on PATH (or pass --ffmpeg-bin / --vmaf-bin):

    • ffmpeg built with the encoders you want to tune (--enable-libx264, plus --enable-libsvtav1 for libsvtav1, and so on). ffprobe is needed for container sources and HDR detection.
    • vmaf, this fork's CLI, built with meson (see getting started).
  3. Optional extras, installed as pip install -e "tools/vmaf-tune[NAME]":

    Extra Adds For
    fast Optuna the TPE search of fast
    report matplotlib the charts of report; without it the report renders its tables and a placeholder per chart
    onnx ONNX Runtime ONNX inference: the fast proxy, the per-shot predictor and the saliency models
    dev pytest, ruff, Optuna, matplotlib, ONNX Runtime running the test suite (see Tests)

vmaf-tune --version prints the package version.

Quick start

Sweep two presets and three CRF values over one 1080p clip. The grid is the Cartesian product of --preset and --crf, so this writes six rows:

vmaf-tune corpus \
    --source ref.yuv \
    --width 1920 --height 1080 --pix-fmt yuv420p \
    --framerate 24 --duration 10 \
    --preset medium --preset slow \
    --crf 22 --crf 28 --crf 34 \
    --output corpus.jsonl

Then ask the corpus which CRF reaches a target:

vmaf-tune recommend --from-corpus corpus.jsonl --target-vmaf 92

The corpus page lists every corpus flag and the row schema. Recommend covers the target-VMAF and target-bitrate queries.

Subcommands

vmaf-tune --help lists 14 subcommands. Each one has a page with its flag table and examples.

Subcommand Purpose Page
corpus Encoder grid sweep plus scoring; writes the JSONL corpus corpus
recommend Lowest-bitrate encode that meets a target VMAF, or the row closest to a target bitrate recommend
predict Predict per-shot VMAF with an ONNX predictor and validate it predict
fast Proxy model plus Bayesian search, verified once by a real encode fast path
tune-per-shot Per-shot CRF zones from shot detection per-shot
recommend-saliency Saliency-aware ROI encode saliency-aware
ladder Per-title bitrate ladder (Pareto ABR) ladder
compare Codec comparison at matched VMAF compare
benchmark Offline cross-codec ranking from an existing JSONL benchmark
auto Pick the cheapest strategy and run it auto
prefilter Pelorus deband strength plus CRF joint autotune prefilter
report Render a profile card from compare, ladder and per-shot JSON report
encode-profile Run one recommendation from a report profile report
sidecar Train and inspect the local predictor bias correction predict

There is no hdr subcommand. HDR handling is automatic on corpus and is controlled with --auto-hdr, --force-sdr, --force-hdr-pq and --force-hdr-hlg; see HDR and sampling.

ref.yuv ─► corpus ─► corpus.jsonl ─► recommend ──► CRF for a target
                          │        └► benchmark ─► encoder ranking
                          └─────────► predict / sidecar (predictor training)

ref.yuv ─► compare | ladder | tune-per-shot | fast | auto ─► JSON ─► report
                                                                       └► encode-profile

Topic pages

These pages cover behaviour shared across subcommands.

Topic Page
Codec registry, preset names, quality ranges codec adapters
AV1 encoders (libaom, SVT-AV1, SVT-AV1-HDR knobs) AV1 codecs
NVENC, AMF, QSV and Apple VideoToolbox encoders hardware codecs
x265, VP9 and VVenC encoders software codecs
Which libvmaf backend scores the encodes score backend
Automatic VMAF model choice per resolution resolution-aware
HDR detection and sample-clip mode HDR and sampling
Two-pass encoding (--two-pass) multi-pass
Coarse-to-fine CRF search coarse-to-fine
Target-VMAF bisect contract bisect
No-reference early elimination (--fast-nr) fast NR
Encode cache (Python API) cache
Scratch directory, disk space, environment variables workdir
Ladder variants bitrate grid, default sampler
FFmpeg filter wiring and patches FFmpeg wiring

Design records

Subject Record
Tool and corpus ADR-0237, Research-0061
tune-per-shot ADR-0392
recommend-saliency ADR-0293 (consumes vmaf-roi sidecars)
ladder ADR-0295
fast ADR-0276, ADR-0291
prefilter ADR-1116
benchmark ADR-0424
sidecar ADR-0394
encode-profile ADR-0643

Tests

python3 -m venv .venv-tune
.venv-tune/bin/pip install -e "tools/vmaf-tune[dev]"
.venv-tune/bin/python -m pytest tools/vmaf-tune/tests/

The dev extra holds every package the suite imports, so a run from it has no failure and no skip for a missing package. Each test runs in its own temporary working directory (tests/conftest.py). The suite mocks subprocess.run almost everywhere, so it needs neither ffmpeg nor a built vmaf; the tests that need more skip and name what is missing:

Skip reason Precondition
no vmaf binary reachable this fork's vmaf CLI: VMAF_BIN_FOR_TESTS=/path/to/vmaf, build/tools/vmaf, or a vmaf on PATH that has --backend
set VMAF_TUNE_INTEGRATION=1 opt-in runs against the real ffmpeg / libx265
the train extra PyTorch for the predictor-training test
h264_qsv not compiled in or VA-API driver too old an Intel GPU whose QSV encoder works
BBB corpus missing the BBB clip under /workspace/.corpus/bbb_e2e/ (dev container)

Former section names

ADRs and the changelog archive link to sections of the page this overview replaced; each heading points to the page that now holds the content.

fast subcommand — proxy + Bayesian + GPU-verify (Phase A.5)

Now on vmaf-tune fast.

Codec adapter contract

Now under adapter contract.

Per-content-type recipes (F.4)

Now under per-content-type recipes.

Sample-clip mode

Now under clip sampling.