В этом руководстве мы научимся использовать видео в Вебе, как это принято в 2019. Chrome и Firefox начали поддерживать новый кодек AV1 — для них видео можно сделать в два раза меньше.
Отдельно поговорим, как заменить GIF на видео в AV1 и H.264 — тогда его размер упадёт в 20-40 раз.
YouTube уже использует его в TestTube. Netflix заявил, что AV1 будет «их основным кодеком следующего поколения».
Мы в Злых Марсианах уже используем его на нашем сайте и на Ампллифере. В этой статье я поделюсь опытом внедрения AV1 и шаг-за-шагом расскажу, как вставить видео, чтобы оно работало во всех браузерах.
Кодеки и контейнеры
С картинками всё просто: или JPEG с PNG для всех браузеров, или делать более компактные файлы в WebP для современных браузеров. Мы всегда можем быть уверены, что в файлах .png
будет PNG-формат (за редким исключением PNG-бомб, от которых может защитить imgproxy).
С видео-файлами всё сложнее. Расширение файла (.mp4
, .wmv
, .webm
или .mov
) говорит только о контейнере. В то время, как видео-файлы состоят из трёх различных компонентов:
- Видео-кодек определяет как сильно вы сможете сжать видео, и чем придётся пожертвовать. Основные видео-кодеки Веба: H.264, HEVC, VP9 и, теперь, AV1.
- Аудио-кодек сжимает звук. Само собой, он не нужен, если в видео нет звука. Популярные варианты: MP3, Opus и AAC.
- Контейнер хранит оба видео- (сжатого каким-то видео-кодеком) и аудио-потока (сжатого каким-то аудио-кодеком). А также дополнительные данные, типа субтитров и мета-информации. Популярные контейнеры: 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 файла:
- Для десктопного Chrome и Firefox на Windows (26% рынка на февраль 2019): контейнер MP4 с AV1 для видео и Opus для звука.
- Для Safari и Edge (16% рынка) — MP4 с HEVC и AAC.
- Для остальных: большой MP4-файл с H.264 и AAC.
Можете взять только AV1 и H.264 — видео будет тоже работать у всех.
Для сжатия я рекомендую взять консольный FFmpeg. Есть много графических утилит, но в консоли легче сохранить опции и потом запускать конвертацию автоматически. Убедитесь, что используете именно последнюю версию FFmpeg. Версии до 4.1 не поддерживают AV1 в MP4.
Для Mac OS X:
- Установите Homebrew.
brew install ffmpeg
Для Линукса лучше взять свежую сборку с официального сайта — пока во многих дистрибутивах нет версии с поддержкой AV1 в MP4:
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar -xf ffmpeg-release-amd64-static.tar.xz
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 30 -profile:v main -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.h264.mp4
Теперь откройте video.h264.mp4
. Если качество хорошее, а размер большой — попробуйте увеличить -crf
(-crf 35
потом -crf 40
). Эта опция уменьшит размер файла ценой уменьшения качества. Подбор баланса качества и размера — искусство.
Если исходного видео-файла нет, то можно сконвертировать старый H.264 файл в AV1.
Теперь пришло время для конвертации AV1 — напоминаю, будет дольше H.264. Кодек пока не использует всю мощь процессора (имеет смысл запустить конвертацию нескольких файлов параллельно).
ffmpeg -i SOURCE.mov -map_metadata -1 -c:a libopus -c:v libaom-av1 -crf 40 -b:v 0 -pix_fmt yuv420p -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 30 -pix_fmt yuv420p -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
удалит мета-информацию из видео (например, программу, в которой видео было создано). В Вебе такая информация редко бывает полезной.
-a:c opus
или -a:c aac
выставляют аудио-кодеки. Если вам не нужен звук, замените их на -an
.
-c:v libaom-av1
выбирает видео-кодек — библиотеку, которая сожмёт кадры видео-потока.
-crf 40
— 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.
-profile:v main
используется у H.264, чтобы выбрать профиль кодека. Только «Main» будет работать в Safari.
-b:v 0
выставляет минимальный битрейт для AV1, чтобы в видео было постоянное качество.
-pix_fmt yuv420p
(формат пикселя) — хитрый способ уменьшить размер файла. Он оставляет оригинальное разрешение для яркости, но уменьшает разрешение для цвета. Наши глаза хуже видят цвет, поэтому не замечают эту хитрость. Удалите эту опцию, если в вашем случае она будет мешать.
-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 30 -profile:v main -pix_fmt yuv420p -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 -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-кодер закончит работу).
Автор: Андрей «A.I.» Ситник