Firefox
Website development
Working with video
Google Chrome
HTML
March 5

Новый кодек AV1: ускоряем загрузку видео в браузере

Original author: Andrey Sitnik
Translation Tutorial
В этом руководстве мы научимся использовать видео в Вебе, как это принято в 2019. Chrome и Firefox начали поддерживать новый кодек AV1 — для них видео можно сделать в два раза меньше.

Отдельно поговорим, как заменить GIF на видео в AV1 и H.264 — тогда его размер упадёт в 20-40 раз.

AV1 в браузере

YouTube уже использует его в TestTube. Netflix заявил, что AV1 будет «их основным кодеком следующего поколения».

Мы в Злых Марсианах уже используем его на нашем сайте и на Ампллифере. В этой статье я поделюсь опытом внедрения AV1 и шаг-за-шагом расскажу, как вставить видео, чтобы оно работало во всех браузерах.

Кодеки и контейнеры


С картинками всё просто: или JPEG с PNG для всех браузеров, или делать более компактные файлы в WebP для современных браузеров. Мы всегда можем быть уверены, что в файлах .png будет PNG-формат (за редким исключением PNG-бомб, от которых может защитить imgproxy).

С видео-файлами всё сложнее. Расширение файла (.mp4, .wmv, .webm или .mov) говорит только о контейнере. В то время, как видео-файлы состоят из трёх различных компонентов:

  1. Видео-кодек определяет как сильно вы сможете сжать видео, и чем придётся пожертвовать. Основные видео-кодеки Веба: H.264, HEVC, VP9 и, теперь, AV1.
  2. Аудио-кодек сжимает звук. Само собой, он не нужен, если в видео нет звука. Популярные варианты: MP3, Opus и AAC.
  3. Контейнер хранит оба видео- (сжатого каким-то видео-кодеком) и аудио-потока (сжатого каким-то аудио-кодеком). А также дополнительные данные, типа субтитров и мета-информации. Популярные контейнеры: MP4, MOV, WebM.

Когда мы видим расширение файла .mp4, мы может только сказать, что был использован контейнер MP4. А вот кодеки в нём могут быть разные — автор мог взять H.264 и AAC, AV1 и Opus или что-то другое.

Узрите AV1


AV1 — видео-кодек, который был выпущен год назад, в марте 2018. Его создавали, чтобы превзойти кодеки предыдущего поколения — HEVC, VP9, H.264 и VP8.

Диаграмма поколений видео-кодеков
Диаграмма поколений кодеков от Цахи Левент-Леви

Если вам стало интересно, как именно AV1 удалось превзойти остальные кодеки в сжатии, почитайте технические подробности в переводах на Хабре:
«Видео следующего поколения: представляем AV1»
«Кодек нового поколения AV1: корректирующий направленный фильтр CDEF»

За счёт новых оптимизаций, AV1 сжимает видео на 30—50% лучше, чем H.264 или VP8, и до 30% лучше, чем HEVC. Но кодек был выпущен недавно и пока имеет несколько детских болезней:

  • Текущий кодер не оптимизирован. AV1 сжимает видео очень медленно (новый быстрый кодер на Rust уже в разработке). Кодек не подойдёт для потокового вещания. Если мы говорим о статичных видео на лэндингах — эта проблема нам не актуальна.
  • Пока кодек поддерживается только десктопным Chrome и Firefox под Windows. Поддержки Safari и Edge пока нет (хотя Microsoft уже тестирует её). Надо будет, как минимум, 2 файла: AV1 для Chrome и Firefox и H.264 для остальных браузеров.

Самая крутая штука в AV1 — на низких битрейтах не появляются квадраты «шакализации».

Сравнение качества картинки у разных кодеков на разном битрейте
Сравнение качества картинки у разных кодеков на разном битрейте — AV1 выигрывает

Готовим AV1 правильно


Давайте, наконец-то, перейдём к практике. Вначале определимся с контейнером. В теории, AV1 можно поместить в разные контейнеры, но MP4 компактнее и рекомендуется в спецификации. Для звука в AV1 мы возьмём Opus, потому что отлично сжимает звук.

Чтобы видео работало во всех браузерах, мы будем генерировать 3 файла:

  1. Для десктопного Chrome и Firefox на Windows (31% рынка на март 2019): контейнер MP4 с AV1 для видео и Opus для звука.
  2. Для Safari и Edge (16% рынка) — MP4 с HEVC и AAC.
  3. Для остальных: большой MP4-файл с H.264 и AAC.

Можете взять только AV1 и H.264 — видео будет тоже работать у всех.

Для сжатия я рекомендую взять консольный FFmpeg. Есть много графических утилит, но в консоли легче сохранить опции и потом запускать конвертацию автоматически. Убедитесь, что используете именно последнюю версию FFmpeg. Версии до 4.1 не поддерживают AV1 в MP4.

Для Mac OS X:

  1. Установите Homebrew.
  2. brew install ffmpeg

Для Линукса лучше взять свежую сборку с официального сайта — пока во многих дистрибутивах нет версии с поддержкой AV1 в MP4:

  1. wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
  2. tar -xf ffmpeg-release-amd64-static.tar.xz
  3. sudo cp ffmpeg-4.1-64bit-static/ff* /usr/local/bin/

Для Windows можете установить FFmpeg по руководству Уильяма Диаса.

Переходим к конвертации файла H.264, который нужен нам для старых браузеров. Поскольку все наши файлы используют контейнер MP4, я буду использовать .av1.mp4, .hevc.mp4 и .h264.mp4 постфиксы. Не пугайтесь длинной команды, мы потом её всю разберём:

# Замените SOURCE.mov на путь к исходному видео-файлу

ffmpeg -i SOURCE.mov -map_metadata -1 -c:a libfdk_aac -c:v libx264 -crf 24 -preset veryslow -profile:v main -pix_fmt yuv420p -movflags +faststart -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.h264.mp4

Теперь откройте video.h264.mp4. Если качество хорошее, а размер большой — попробуйте увеличить -crf (-crf 26 потом -crf 28). Эта опция уменьшит размер файла ценой уменьшения качества. Подбор баланса качества и размера — искусство.

Если исходного видео-файла нет, то можно сконвертировать старый H.264 файл в AV1.

Теперь пришло время для конвертации AV1 — напоминаю, будет дольше H.264. Кодек пока не использует всю мощь процессора (имеет смысл запустить конвертацию нескольких файлов параллельно).

ffmpeg -i SOURCE.mov -map_metadata -1 -c:a libopus -c:v libaom-av1 -crf 34 -b:v 0 -pix_fmt yuv420p -movflags +faststart -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -strict experimental video.av1.mp4

Снова поиграйте с -crf для подбора идеального баланса качества и размера.

Теперь то же самое для HEVC.

ffmpeg -i SOURCE.mov -map_metadata -1 -c:a libfdk_aac -c:v libx265 -crf 24 -preset veryslow -pix_fmt yuv420p -movflags +faststart -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.hevc.mp4

Скопируйте video.h264.mp4, video.hevc.mp4 и video.av1.mp4 в корень вашего сайта.

Разбираемся с опциями FFmpeg


Команды выше выглядят как заклинание вызова демона? Не волнуйтесь, это не PostCSS. Давайте разберём опции.

-i SOURCE.mov указывает входящий файл, откуда FFmpeg возьмёт потоки видео и аудио, пережмёт их и запакует в новый контейнер.

-map_metadata -1 удалит мета-информацию из видео (например, программу, в которой видео было создано). В Вебе такая информация редко бывает полезной.

-c:a libopus или -c:a libfdk_aac выставляют аудио-кодеки. Если вам не нужен звук, замените их на -an.

-c:v libaom-av1 выбирает видео-кодек — библиотеку, которая сожмёт кадры видео-потока.

-crf 34 — Constant Rate Factor, баланс качества и размера. Это как слайдер качества JPEG, только он идёт в другом направлении (0 — лучшее качество и самый большой файл). Шкала CRF разная у H.264 и AV1 — у H.264 идёт до 51, у AV1 до 61. CRF для AV1 и H.264 будет разный.

Facebook подобрал примерное соответствие между значениями CRF для H.264 и AV1:
19 → 27, 23 → 33, 27 → 39, 31 → 45, 35 → 51, 39 → 57.

-preset veryslow заставляет H.264 и HEVC ккодеки сжимать файл сильнее даже ценой резкого роста времени конвертации.

-profile:v main используется у H.264, чтобы выбрать профиль кодека. Только «Main» будет работать в Safari.

-b:v 0 выставляет минимальный битрейт для AV1, чтобы в видео было постоянное качество.

-pix_fmt yuv420p (формат пикселя) — хитрый способ уменьшить размер файла. Он оставляет оригинальное разрешение для яркости, но уменьшает разрешение для цвета. Наши глаза хуже видят цвет, поэтому не замечают эту хитрость. Удалите эту опцию, если в вашем случае она будет мешать.

-movflags +faststart перемещает всё само важное в начало файла, чтобы браузер мог проигрывать видео до окончания загрузки.

-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" изменит размер сторон видео к ближайшим чётным (некоторые кодеки могут работать с разрешением 300×200 и 302×200, но не будут работать с 301×200). Если вы уверены, что везде разрешение делится на 2 — можете убрать эту опцию.

-strict experimental нужна для AV1, его кодер ещё экспериментальный.

video.av1.mp4 выставляет имя итогово файла.

Запускаем видео в браузерах


Теперь нам нужно, чтобы каждый браузер загружал видео, которое он поддерживает. Для этого у <source> есть атрибут type. И советую почитать про опции у <video>.

<video controls width="600" height="400">
  <source src="video.hevc.mp4" type="video/mp4; codecs=hevc,mp4a.40.2" />
  <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08,opus" />
  <source src="video.h264.mp4" type="video/mp4; codecs=avc1.4D401E,mp4a.40.2" />
</video>

<source> похожи на выражения if…else — браузер читает их сверху вниз, пока не найдёт тот, чей type он поддерживает.

В type можно указать весь формат файла: контейнер (video/mp4 для MP4), видео-кодек (av01.0.05M.08 для AV1, hevc для HEVC и avc1.4D401E для H.264) и аудио-кодек (opus для Opus и mp4a.40.2 для AAC).

Бонус: как сконвертировать GIF в AV1 и H.264


В 2019 использовать GIF для коротких видео — большой грех. GIF весит в 20—40 раз больше, чем H.264 или AV1. GIF сильнее бьёт по CPU, заставляет аккумулятор утекать быстрее. Если вам нужно короткое зацикленное видео, берите видео-кодеки. И FFmpeg может конвертировать видео прямо из GIF.

Конвертируем GIF в H.264:

ffmpeg -i IMAGE.gif -map_metadata -1 -an -c:v libx264 -crf 24 -preset veryslow -profile:v main -pix_fmt yuv420p -movflags +faststart -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.h264.mp4

Генерируем ещё более маленький AV1:

ffmpeg -i IMAGE.gif -map_metadata -1 -an opus -c:v libaom-av1 -crf 50 -b:v 0 -pix_fmt yuv420p -movflags +faststart -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -strict experimental video.av1.mp4

Теперь вставим animation.h264.mp4 и animation.av1.mp4 в HTML.

<video autoplay loop muted playsinline width="300" height="200">
  <source src="animation.av1.mp4" type="video/mp4; codecs=av01.0.05M.08" />
  <source src="animation.h264.mp4" type="video/mp4" />
</video>

Опции autoplay и loop делают из видео «гифку» — цикленное видео, которое сразу играет после загрузки страницы. playsinline блокирует Safari от открытия видео на весь экран при клике на видео.

Время выводов


AV1 ещё экспериментальный. Но его уже можно использовать, чтобы сделать четверть ваших пользователей счастливее. Пара команд FFmpeg сгенерируют видео-файлы. <video> с самого начала создан, чтобы отдавать видео по возможностям браузеров. Мы уже используем AV1 в продакшене и всё работает отлично (исключая время ожидания, пока AV1-кодер закончит работу).
+49
15.1k 140
Comments 85
Top of the day