FFmpeg VMAF: измеряем качество видео и libvmaf

Автор: Николай СапуновОбновлено: август 202619 мин чтения
Содержание статьи +

Кратко

FFmpeg с библиотекой libvmaf – это стандартный бесплатный способ измерить качество видео: одна команда сравнивает кодированный файл с оригиналом и печатает VMAF, PSNR, SSIM и MS-SSIM. Базовая команда, которая нужна большинству, – это ffmpeg -i distorted.mp4 -i reference.mp4 -lavfi libvmaf=... -f null -, но четыре детали решают, можно ли доверять числу: порядок входов, выравнивание кадров, масштабирование к разрешению оригинала и выбор модели VMAF. Ошибитесь в любой из них – и инструмент всё равно напечатает уверенное, но тихо бессмысленное число, потому что оценка качества без названной модели, масштаба и выравнивания – это не измерение. Эта статья разбирает точные команды, читает вывод строку за строкой, называет каждую ловушку и поставляет переиспользуемый скрипт, который запускает измерение и отказывается печатать число, которое не может обосновать.

Почему это важно

Почти каждое число о качестве, которое произведёт инженер, выходит из этого одного инструмента, поэтому цена неправильного использования копится на каждом кодировании. Статья для инженера стриминга или кодирования, который уже поставил FFmpeg и теперь должен измерить кодирование честно: сравнить два кодека, проверить битрейтную лестницу или встроить гейт качества в сборку. Команды выглядят короткими – и в этом опасность: FFmpeg с радостью посчитает VMAF между 1080p-мастером и 480p-кодированием и напечатает «VMAF 71», не предупредив, что сравнение было невалидным. Освоить четыре детали, которые двигают число, – это разница между измерением, которое можно защитить в бенчмарке, и числом, которое введёт в заблуждение всю команду. К концу вы сможете запустить измерение, прочитать каждую строку вывода и точно знать, где результат может врать.

Ментальная модель: FFmpeg – это движок, libvmaf – библиотека метрик

Начнём с того, что означают два имени, потому что их путают, а это не одно и то же. FFmpeg – это универсальный видеоинструмент: он декодирует, масштабирует, кодирует и прокачивает кадры между фильтрами. libvmaf – отдельная библиотека, написанная Netflix, которая берёт два потока кадров и считает на них метрики качества. Когда вы «измеряете качество с FFmpeg», FFmpeg – это движок, который читает ваши файлы и подаёт кадры парами в libvmaf, а libvmaf – та часть, что собственно производит числа.

Это разделение важно, потому что libvmaf считает не только VMAF. Имя библиотеки несёт заглавную метрику – VMAF, перцептивную оценку, которую Netflix открыл, – но та же библиотека считает и меру попиксельной ошибки PSNR, структурную меру SSIM, её многомасштабный вариант MS-SSIM и меру цветового различия CIEDE2000. Так что один проход libvmaf может выдать четыре метрики разом. Вы не запускаете три отдельных инструмента – вы просите один фильтр о нескольких признаках (features). У каждой из этих метрик есть своя полная статья в этом разделе – PSNR простыми словами, SSIM простыми словами и VMAF простыми словами, – а эта статья про инструмент, который их вычисляет, а не про математику внутри каждой.

Ещё одна рамка перед командами. Каждая метрика здесь – полноэталонная (full-reference): ей нужен безупречный оригинал – мастер – чтобы сравнивать с ним кодирование, как корректору нужна авторская рукопись, чтобы поймать каждую опечатку. Если у вас есть мастер, эти инструменты применимы и это самый точный вариант. Если вы оцениваете прямую трансляцию или пользовательскую загрузку, у которых у плеера нет мастера, ни одна команда FFmpeg не посчитает VMAF, и нужны безэталонные инструменты из статьи no-reference качество для live и UGC. Вся эта статья предполагает, что оригинал у вас есть.

Сначала убедитесь, что ваш FFmpeg действительно содержит libvmaf

Перед любым измерением проверьте, что ваша сборка FFmpeg включает библиотеку, потому что не все включают. libvmaf – это опция времени компиляции: FFmpeg должен быть собран с --enable-libvmaf, и сборка без неё отвергнет каждую команду ниже с «No such filter: 'libvmaf'». Одна строка покажет:

ffmpeg -hide_banner -filters | grep -E "vmaf|psnr|ssim"

Если libvmaf, psnr и ssim появились – вы готовы. Стандартные релизы FFmpeg идут с включённым libvmaf (релиз 8.1 «Hoare», март 2026, и точечный релиз 8.1.2 от июня 2026 оба его содержат), как и обычные сборки Homebrew, apt и Docker. Если в вашей сборке его нет, надёжнее всего взять официальный Docker-образ Netflix VMAF или пересобрать FFmpeg с флагом; варианты установки разобраны в статье ландшафт инструментов качества. Записывайте версии, которые использовали, – ffmpeg -version и версию libvmaf, – потому что обе меняют результат со временем, а число бенчмарка воспроизводимо только с ними.

Ваша первая команда VMAF, разобранная по частям

Вот команда, которая считает VMAF между кодированием и его мастером. Прочитайте её один раз, а затем разберём по частям.

ffmpeg -i encoded.mp4 -i master.mp4 \
  -lavfi "[0:v]setpts=PTS-STARTPTS[dist]; \
          [1:v]setpts=PTS-STARTPTS[ref]; \
          [dist][ref]libvmaf=log_fmt=json:log_path=vmaf.json:n_threads=8" \
  -f null -

Часть -i encoded.mp4 -i master.mp4 загружает два входа: вход 0 – кодирование, которое вы оцениваете, вход 1 – безупречный мастер. Флаг -lavfi (сокращение от -filter_complex) держит граф фильтров в кавычках. Внутри [0:v] и [1:v] – это видео входа 0 и входа 1. setpts=PTS-STARTPTS на каждом сбрасывает временную метку презентации в ноль, чтобы два потока совпали кадр в кадр; без этого клип, не начинающийся со временной метки ноль, будет измерен против неправильных кадров. Переименованные потоки [dist] и [ref] затем подаются в libvmaf. Наконец, -f null - говорит FFmpeg выбросить видеовыход – вам нужна оценка, а не перекодированный файл.

Самая частая ошибка живёт в одной паре скобок: искажённый вход идёт первым, эталон – вторым. Фильтр читает [dist][ref]libvmaf, а не [ref][dist]. Поменяйте их местами – и оценка всё равно напечатается, иногда выглядя правдоподобно, но метрике сказали, что мастер – это кодирование, и наоборот. Всегда ставьте оцениваемый файл первым. Это та ошибка, что переживает код-ревью, потому что ничего не падает – единственный симптом – неправильное число.

Рисунок 1. Каноническая команда измерения, разобранная по частям. Деталь, которую надо запомнить: искажённый (кодированный) поток называется первым, эталон (мастер) – вторым: `[dist][ref]libvmaf`.

Запустите её – и FFmpeg напечатает строку вроде этой, записав полный покадровый лог в vmaf.json:

[libvmaf @ 0x55b3…] VMAF score: 93.241830

Эти 93,24 – это среднее VMAF по всем кадрам, на модели по умолчанию, по шкале 0–100. Прежде чем доверять им, надо знать четыре вещи о том, как они получены.

Четыре детали, которые решают, реально ли число

Оценка VMAF бессмысленна без названной модели, масштаба, на котором сравнивали кадры, выравнивания и метода пулинга. Это не продвинутые опции – это разница между измерением и догадкой. Возьмём их по порядку.

1. Выравнивание: вы обязаны сравнивать одни и те же кадры

Метрика сравнивает кадр 1 кодирования с кадром 1 мастера, кадр 2 с кадром 2 и так далее. Если у двух файлов разное число кадров, разная частота кадров или один начинается с задержкой в несколько кадров, инструмент тихо сравнивает несовпадающие пары, и оценка падает по причине, не имеющей ничего общего с качеством. setpts=PTS-STARTPTS выше чинит смещение временных меток. Если у входов разная частота кадров, выровняйте её, поставив -r перед каждым -i (FFmpeg синхронизирует фильтры по временной метке, а не по индексу кадра, поэтому частота должна совпадать). Привычка предполётной проверки, которая экономит часы: подтвердите, что оба файла сообщают одинаковое число кадров через ffprobe -count_frames, прежде чем измерять. VMAF, вернувшийся неожиданно низким – скажем, 40 на визуально чистом кодировании, – гораздо чаще баг синхронизации, чем проблема качества.

2. Масштабирование: измеряйте на разрешении эталона и апскейльте правильно

Это та ловушка, что порождает больше всего неправильных чисел бенчмарка. VMAF спроектирован считаться на разрешении источника, с обоими видео одного размера. Когда вы кодируете 1080p-мастер в 540p-представление, нельзя сравнить 540p-пиксели с 1080p-пикселями напрямую – они разного размера. Правильная процедура – апскейлить искажённое представление обратно до разрешения мастера и сравнивать там, потому что это повторяет то, что делает плеер зрителя, растягивая 540p-поток на 1080p-экран. Собственная рекомендация Netflix указывает bicubic как метод апскейла:

ffmpeg -i encoded_540p.mp4 -i master_1080p.mp4 \
  -lavfi "[0:v]scale=1920:1080:flags=bicubic,setpts=PTS-STARTPTS[dist]; \
          [1:v]setpts=PTS-STARTPTS[ref]; \
          [dist][ref]libvmaf=log_fmt=json:log_path=vmaf.json" \
  -f null -

Повторяются две ошибки масштабирования. Первая – сравнивать на низком разрешении кодирования, даунскейля мастер: это льстит кодированию, потому что уменьшение мастера прячет детали, которые кодирование не сохранило. Вторая – позволить сработать внутреннему масштабированию libvmaf неосознанно; будьте явны с фильтром scale, чтобы контролировать алгоритм и целевой размер. Всегда апскейльте искажённое до эталона, всегда bicubic, если нет задокументированной причины иначе, и указывайте разрешение, на котором измеряли, рядом с каждой оценкой.

3. Модель: число VMAF без названной модели нечитаемо

VMAF – это не одно число, а семейство моделей, обученных под разные условия просмотра, и оценка меняется с моделью. Модель по умолчанию предполагает 1080p-телевизор на обычном расстоянии. Модель phone предсказывает, как то же кодирование выглядит на маленьком экране смартфона, где артефакты сжатия заметить труднее, поэтому она возвращает более высокие оценки на том же файле. Модель 4K обучена для 4K-дисплеев. Загрузка модели по умолчанию выглядит так:

libvmaf=model=version=vmaf_v0.6.1:log_fmt=json:log_path=vmaf.json

version=vmaf_v0.6.1 – это давняя модель по умолчанию, её можно опустить, но называть её явно – честная привычка. Здесь инструмент посреди реального изменения, о котором стоит знать. В июне 2026 Netflix выпустил VMAF v1 – первое крупное обновление модели со времён v0.6.1, – которое включает по умолчанию вариант без выигрыша от улучшений (NEG), заменяет старый полином phone-модели моделью контрастной чувствительности к расстоянию просмотра и добавляет признаки бандинга и цветности, к которым модель v0 была слепа. Модели v0 всё ещё поставляются и остаются дефолтными в текущих сборках FFmpeg, поэтому пока вы обязаны называть модель и её версию в каждом отчёте – «VMAF 93,2, модель vmaf\_v0.6.1» – и следить за сборками, что переключат дефолт. Нюанс моделей, доверительный интервал и зачем нужен NEG – тема статьи VMAF в деталях.

4. Пулинг: как покадровые оценки становятся одним числом

libvmaf оценивает каждый кадр, а затем пулит эти сотни чисел в одну оценку, которую печатает. Пулинг по умолчанию – арифметическое среднее, и у среднего есть конкретное слепое пятно: оно прячет короткие резкие провалы. Кодирование, которое отлично выглядит пятьдесят девять секунд и разваливается на одну секунду, может выдать высокое среднее VMAF, содержа видимый сбой. libvmaf даёт выбрать метод пулинга через pool=mean, pool=harmonic_mean или pool=min, и полные покадровые данные в любом случае лежат в JSON-логе. Дисциплина, которой учит этот раздел, – читать худшие кадры, а не только среднее: пульте по гармоническому среднему или читайте низкий перцентиль из покадрового лога, потому что одна плохая секунда – это то, что запоминает зритель. Пулинг: как покадровые оценки превращаются в одно число разбирает методы полностью.

Рисунок 2. Четыре регулятора, которые решают, можно ли доверять числу VMAF. Каждый может сдвинуть оценку на несколько пунктов или вовсе её обесценить, и ни один не выдаёт сообщения об ошибке, когда выставлен неверно.

Получаем PSNR, SSIM и MS-SSIM в том же проходе

VMAF в одиночку нужен редко. PSNR и SSIM дёшевы, понятны всем и полезны как перекрёстная проверка, и современный libvmaf считает их как признаки в том же прогоне – без лишних проходов. Вы просите их по имени:

ffmpeg -i encoded.mp4 -i master.mp4 \
  -lavfi "[0:v]setpts=PTS-STARTPTS[dist]; \
          [1:v]setpts=PTS-STARTPTS[ref]; \
          [dist][ref]libvmaf=feature='name=psnr|name=float_ssim|name=float_ms_ssim':\
log_fmt=json:log_path=metrics.json" \
  -f null -

Часть feature='name=psnr|name=float_ssim|name=float_ms_ssim' добавляет три метрики; вертикальная черта | разделяет признаки. Ваш JSON теперь несёт VMAF, PSNR, SSIM и MS-SSIM покадрово и пулингом. Если нужен только PSNR или SSIM без VMAF, у FFmpeg есть и отдельные фильтры psnr и ssim, пишущие файл статистики:

ffmpeg -i encoded.mp4 -i master.mp4 \
  -lavfi "ssim=stats_file=ssim.log;[0:v][1:v]psnr=stats_file=psnr.log" \
  -f null -

Слово о том, как их читать, потому что единицы различаются, и смешивать их – классическая ошибка. PSNR в децибелах (dB), выше – лучше, и у него нет фиксированного потолка: идентичные кадры дают бесконечные dB. SSIM и MS-SSIM идут от 0 до 1, где 1 – полное совпадение. VMAF идёт от 0 до 100. Это три разные шкалы, и нельзя сравнивать PSNR 42 с VMAF 93, будто они на одной линейке. Всегда несите единицу вместе с числом.

Разобранный пример: формула PSNR в децибелах, вслух

PSNR стоит один раз посчитать вручную, потому что увиденная арифметика снимает мистику с децибел. Метрика сравнивает кодирование с мастером попиксельно, возводит разницы в квадрат и усредняет их в одно число – среднеквадратичную ошибку (MSE). Формула dB тогда такова:

PSNR = 10 · log10( MAX² / MSE )

где MAX – наибольшее возможное значение пикселя, 255 для 8-битного видео. Допустим, FFmpeg сообщает MSE 25 для канала яркости. Подставим:

PSNR = 10 · log10( 255² / 25 )
     = 10 · log10( 65025 / 25 )
     = 10 · log10( 2601 )
     = 10 · 3,415
     = 34,15 dB

Итак, среднеквадратичная попиксельная ошибка 25 – это 34,15 dB. Этот разбор также показывает, почему PSNR растёт так медленно по мере улучшения качества: поскольку он логарифмический, уменьшение ошибки вдвое добавляет лишь около 3 dB. Поэтому прирост PSNR в 2 dB может быть как пустяком, так и значимым в зависимости от того, откуда начали, и поэтому этот раздел трактует PSNR как полезную перекрёстную проверку, а не перцептивную истину – полный аргумент в статье PSNR простыми словами.

Чтение вывода и использование доверительного интервала

Строка в консоли даёт пулинг-среднее; настоящая информация – в файле лога. С log_fmt=json вы получаете структуру с массивом frames – по записи на кадр, каждая несёт VMAF, PSNR и SSIM этого кадра – и сводку pooled_metrics со средним, гармоническим средним, min и max. Покадровый массив – это то, что позволяет найти точный кадр, где упало качество, и подать его на покадровый график качества. Выберите log_fmt=csv, если грузите данные в таблицу или быстрый график; xml – для старых инструментов, что его ожидают.

VMAF также сообщает доверительный интервал, и использовать его – то, что отличает аккуратное измерение от вводящего в заблуждение. Поскольку VMAF – модель, подогнанная под человеческие оценки, каждая оценка несёт неопределённость, которую libvmaf может выразить как 95%-й интервал через бутстрэп. Практическое правило: когда вы сравниваете два кодирования, если их доверительные интервалы пересекаются, победителя объявить нельзя. Разберём: кодирование A набирает VMAF 93,2 с 95%-м интервалом [92,4, 94,0], а кодирование B набирает 93,6 с [92,8, 94,4]. Интервалы сильно пересекаются, поэтому разница в 0,4 пункта внутри шума, и они неразличимы, как бы уверенно 93,6 ни обходило 93,2 на бумаге. Грубо шесть пунктов VMAF соответствуют одному «едва заметному различию» (JND), так что приросты меньше пункта почти никогда не важны зрителю.

Переводим прирост VMAF в экономию битрейта

Причина, по которой команды вообще измеряют, обычно – деньги: лучшее кодирование достигает того же качества на меньшем битрейте. Арифметика проста, когда вы измеряете на фиксированной цели по качеству. Допустим, ваша цель – VMAF 95, текущий кодировщик достигает её на 5,0 Мбит/с, а новый достигает того же VMAF 95 на 3,5 Мбит/с. Экономия:

экономия = (5,0 − 3,5) / 5,0 = 1,5 / 5,0 = 0,30 = 30%

Эти 30% – полоса пропускания, за которую вы перестаёте платить на каждом потоке, поэтому измеренный прирост качества – это строка бюджета, а не тщеславная метрика. Сравнивать кодировщики правильно по всей битрейтной лестнице, а не в одной точке, – задача BD-rate и выпуклой оболочки; одноточечная версия выше – интуиция, стоящая за ней.

Скорость: потоки, сабсэмплинг и GPU

VMAF не дёшево считать, поэтому три регулятора меняют скорость на полноту. n_threads распределяет работу по ядрам CPU – выставьте по числу ядер (n_threads=8) для почти линейного ускорения, без влияния на оценку. n_subsample=N оценивает только каждый N-й кадр, что режет время примерно в N раз, но значит, что вы можете перешагнуть единственный плохой кадр, так что это годится для быстрой оценки и неверно для финального бенчмарка или гейта качества. Самый большой рычаг – железо: CUDA-сборка VMAF, доступная через FFmpeg с GPU NVIDIA, по сообщениям поднимает пропускную способность до 4,4× над CPU. Для разовой сверки потоков достаточно; для измерения каталога сабсэмплинг и GPU-ускорение – это то, как удержать счёт вменяемым; вопрос масштаба подхватывает статья интеграция измерения качества в CI/CD.

Частые ошибки, дающие уверенные неправильные числа

У каждой ловушки этой статьи одна черта: ничего не падает, поэтому число выглядит нормальным. Держите этот список рядом с первыми измерениями.

  • Перевёрнутые входы. [dist][ref] – правильный порядок; [ref][dist] измеряет наоборот. Без ошибки, неправильная оценка.
  • Сравнение разных разрешений без масштабирования или даунскейл мастера. Всегда апскейльте искажённое до разрешения эталона через bicubic. Даунскейл мастера завышает оценку.
  • Оценка VMAF без названной модели. «VMAF 93» нечитаемо; «VMAF 93,2, модель vmaf\_v0.6.1, измерено на 1080p, пулинг mean» – это измерение.
  • Доверие среднему и игнорирование худших кадров. Среднее прячет односекундные сбои; читайте гармоническое среднее или низкий перцентиль из покадрового лога.
  • Несовпавшие кадры из-за рассинхрона частоты или временных меток. Неожиданно низкая оценка – обычно баг синхронизации, а не проблема качества; сначала проверьте число кадров.
  • Объявление победителя при пересекающихся доверительных интервалах. Разница в 0,4 VMAF внутри полос погрешности – не разница.
Рисунок 3. Три метрики, которые даёт один проход libvmaf, рядом. Столбец «где врёт» – тот, что надо держать в голове: у каждой метрики есть контент, который она оценивает неверно, поэтому они перекрёстно проверяют друг друга, а не заменяют.

Переиспользуемый скрипт измерения

Каждый раз правильно набирать весь граф фильтров – это и есть способ, которым заползают баги порядка входов и масштабирования, поэтому к статье прилагается скрипт, который строит команду за вас и защищает результат. Скачайте скрипт измерения FFmpeg + libvmaf – это Python без зависимостей (только стандартная библиотека, Python 3.8+) и кросс-секционный актив раздела B1. Дайте ему кодирование и мастер – и он автоматически ставит искажённый вход первым, апскейлит искажённое до разрешения эталона через bicubic, запускает libvmaf для VMAF плюс PSNR и SSIM, затем парсит JSON и печатает чистый отчёт: среднее, гармоническое среднее, пол 5-го перцентиля, min и шкалу каждой метрики с единицами. Он отказывается печатать голое «VMAF 93» – каждое число выходит со штампом модели, разрешения измерения и метода пулинга, потому что оценка без этого контекста – именно тот невоспроизводимый показатель, который этот раздел существует, чтобы искоренить. Запустите --demo, чтобы воспроизвести разобранные числа этой статьи, включая пример PSNR 34,15 dB, со встроенной самопроверкой.

Скрипт строит команду и парсит вывод; он не переписывает метрики – математика остаётся в libvmaf, эталонной реализации. Это безопасная парадная дверь к инструменту, а не его замена.

Где здесь Фора Софт

Измерение доставленного качества с FFmpeg и libvmaf – это рутина, лежащая под каждым решением по кодированию и стримингу, что мы поставляем в Фора Софт, в видеостриминге, OTT, конференциях, e-learning и телемедицине. Когда клиент спрашивает, стоит ли смена кодека инженерных затрат, ответ – это измерение: те же числа VMAF, PSNR и SSIM, что производит эта статья, взятые яблоки-к-яблокам на фиксированной цели по качеству с названной моделью и разрешением. Дисциплина важнее инструмента: мы сообщаем доверительный интервал, читаем худшие кадры и никогда не сравниваем через несовпадающие шкалы, потому что заявление о качестве хорошо ровно настолько, насколько строга стоящая за ним работа. Наша методология бенчмарков документирует, как именно мы проводим эти измерения, чтобы результаты были воспроизводимы и цитируемы.

Ключевые выводы

  • FFmpeg – движок; libvmaf – библиотека, что считает VMAF, PSNR, SSIM и MS-SSIM в одном проходе.
  • Ставьте искажённый вход первым: [dist][ref]libvmaf. Перестановка даёт неправильное число без ошибки.
  • Измеряйте на разрешении эталона – апскейльте искажённое через bicubic; никогда не даунскейльте мастер.
  • Оценка VMAF нечитаема без названных модели, шкалы и пулинга. Указывайте все три.
  • Читайте худшие кадры и доверительный интервал, а не только среднее; пересекающиеся интервалы – нет победителя.
  • VMAF v1 (июнь 2026) на подходе; пока называйте версию модели явно в каждом отчёте.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.