easyVmaf

March 20, 2026 · View on GitHub

Python tool based on FFmpeg and FFprobe to handle the video preprocessing required for VMAF:

  • Deinterlacing
  • Upscaling / downscaling
  • Frame-to-frame syncing
  • Frame rate adaptation

Details about How it Works can be found here.

Requirements

  • Linux / macOS
  • Python >= 3.8
  • FFmpeg >= 5.0 built with --enable-libvmaf (built-in models required)
  • Python package: ffmpeg-progress-yield

For GPU-accelerated VMAF:

  • NVIDIA GPU with CUDA support
  • FFmpeg built with --enable-nonfree --enable-ffnvcodec --enable-libvmaf
  • libvmaf built with -Denable_cuda=true -Denable_float=true
  • NVIDIA Container Toolkit (for Docker GPU usage)

Installation

pip install easyvmaf

Or from source:

git clone https://github.com/gdavila/easyVmaf.git
cd easyVmaf
pip install -e .

FFmpeg must be on PATH, or override via environment variables:

FFMPEG=/path/to/ffmpeg FFPROBE=/path/to/ffprobe easyvmaf ...

Usage

easyvmaf -d <distorted> -r <reference> [options]

Required arguments

FlagDescription
-d DDistorted video path (supports glob patterns for batch)
-r RReference video path

Optional arguments

FlagDefaultDescription
-sw SW0Sync window size in seconds. Enables automatic sync search between the first frames of the distorted and a subsample of the reference. 0 disables sync.
-ss SS0Sync start time: offset into the reference where the sync window begins.
-fps FPS0Force frame rate conversion. Disables auto-deinterlace when set.
-subsample N1Frame subsampling factor to speed up computation.
-reverseoffReverse sync direction: match reference first-frames against distorted instead of the default.
-model MODELHDVMAF model. Options: HD, 4K.
-threads N0Number of threads (0 = auto).
-output_fmt FMTjsonPer-frame VMAF output file format: json, xml, or csv.
-verboseoffEnable verbose log level.
-progressoffShow FFmpeg progress during VMAF computation.
-endsyncoffStop when the shorter video ends.
-cambi_heatmapoffCompute and save CAMBI banding heatmap.
-sync_onlyoffMeasure sync offset only — skip VMAF computation.
-jsonoffPrint final results as JSON to stdout. Compatible with -sync_only and full VMAF runs. In batch mode, one JSON object per line (NDJSON).
-gpuoffUse GPU-accelerated VMAF via libvmaf_cuda. Requires a CUDA-capable FFmpeg build (see Docker: CUDA).

Examples

Basic VMAF (no sync)

easyvmaf -d distorted.mp4 -r reference.mp4

With automatic sync

# Sync window of 2 seconds starting from the beginning of reference
easyvmaf -d distorted.mp4 -r reference.mp4 -sw 2

# Sync window starting at 6 s into reference, reverse direction
easyvmaf -d distorted.mp4 -r reference.mp4 -sw 3 -ss 6 -reverse

Sync measurement only

# Human-readable output
easyvmaf -d distorted.mp4 -r reference.mp4 -sw 2 -sync_only

# Structured JSON output
easyvmaf -d distorted.mp4 -r reference.mp4 -sw 2 -sync_only -json

Structured JSON output

The -json flag prints a single JSON object to stdout (or one object per line in batch mode):

easyvmaf -d distorted.mp4 -r reference.mp4 -sw 2 -json
{
  "distorted": "distorted.mp4",
  "reference": "reference.mp4",
  "sync": { "offset": 0.7007, "psnr": 48.863779 },
  "vmaf": {
    "model": "HD",
    "vmaf_hd": 89.123456,
    "vmaf_hd_neg": 88.654321,
    "vmaf_hd_phone": 91.234567,
    "output_file": "distorted_vmaf.json"
  }
}

Batch processing

# Glob pattern — one result per file
easyvmaf -d "folder/*.mp4" -r reference.mp4 -json

4K model

easyvmaf -d distorted_4k.mp4 -r reference_4k.mp4 -model 4K

GPU-accelerated VMAF

Requires a CUDA build of FFmpeg/libvmaf (see Docker section below):

easyvmaf -d distorted.mp4 -r reference.mp4 -gpu

Sync computation always runs on CPU regardless of -gpu. The GPU is used only for the final VMAF scoring step.


Docker

CPU build

docker build -t easyvmaf .

CUDA / GPU build

docker build -f Dockerfile.cuda -t easyvmaf:cuda .

Note: The CUDA image links FFmpeg with --enable-nonfree components (nvcc/CUDA). It cannot be legally redistributed — build and use locally only.

Build arguments

Both Dockerfiles accept these build-time arguments:

ARGDefaultDescription
FFMPEG_version8.1FFmpeg release tag
VMAF_version3.0.0libvmaf release tag
EASYVMAF_VERSION2.1.0easyVmaf version label
DAV1D_version1.4.3dav1d release (CUDA image only — built from source)
# Custom versions
docker build --build-arg FFMPEG_version=8.1 --build-arg VMAF_version=3.0.0 -t easyvmaf .

Running with Docker

# CPU
docker run --rm -v /path/to/videos:/videos \
  easyvmaf -d /videos/distorted.mp4 -r /videos/reference.mp4

# With sync
docker run --rm -v /path/to/videos:/videos \
  easyvmaf -d /videos/distorted.mp4 -r /videos/reference.mp4 -sw 2

# JSON output
docker run --rm -v /path/to/videos:/videos \
  easyvmaf -d /videos/distorted.mp4 -r /videos/reference.mp4 -json

# GPU (requires NVIDIA Container Toolkit)
docker run --rm --gpus all -v /path/to/videos:/videos \
  easyvmaf:cuda -d /videos/distorted.mp4 -r /videos/reference.mp4 -gpu

Docker Compose

A docker-compose.yml is included with pre-configured easyvmaf (CPU) and easyvmaf-cuda (GPU) services:

# CPU service
VIDEO_DIR=/path/to/videos docker compose run easyvmaf \
  -d /videos/distorted.mp4 -r /videos/reference.mp4

# GPU service
VIDEO_DIR=/path/to/videos docker compose run easyvmaf-cuda \
  -d /videos/distorted.mp4 -r /videos/reference.mp4 -gpu

VIDEO_DIR defaults to ./video_samples if not set.


Sync examples explained

Reference delayed relative to distorted

reference.ts starts 0.7 seconds after distorted-A.ts. Use -sw to search for the offset automatically:

easyvmaf -d distorted-A.ts -r reference.ts -sw 2

The sync window sw=2 means easyVmaf searches the first 2 seconds of reference.ts for the best PSNR match against the first frames of distorted-A.ts.

Distorted delayed relative to reference

distorted-B.ts starts 8.3 seconds after reference.ts. Use -reverse to flip the sync direction:

easyvmaf -d distorted-B.ts -r reference.ts -sw 3 -ss 6 -reverse

-ss 6 begins the sync search 6 seconds into reference.ts; -reverse matches reference first-frames against the distorted stream.