Как стать автором
Обновить
2687.08
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Кодирование с кодеком HEVC простым языком — гайд на FFmpeg. Высокое качество, но низкий вес

Уровень сложностиПростой
Время на прочтение11 мин
Количество просмотров21K

Казалось бы, довольно простой вопрос: «Чем сжать видео?». На ум сразу приходят Handbrake, Movavi Converter или ещё что-нибудь пострашнее. Однако когда речь заходит о более гиковском подходе с упором на максимальное качество и экономию места, такие программы сложно назвать инструментами. Равно как и для обратной ситуации, когда картинку нужно сильно сжать и сохранить в целостности большую часть полезной информации. Все эти программы только лишь предоставляют набор наиболее общих конфигов для обычной съёмки и 2D.

В этой статье мы изучим, как при помощи самого большого сборника свободных библиотек FFmpeg научиться кодировать видео самому именно под ваши задачи.

Содержание



Кодеки


Даже сам вопрос о том, что такое кодек, ставит многих в тупик. Можно легко услышать ответ: «.avi, .mkv, .mp4...», но это лишь контейнеры, которые в большинстве случаев содержат видео, аудио и другие данные. А кодек — это преобразователь видео/аудиосигнала.


Существует три основных кодека для домашних устройств: HEVC (H265), H264 и AV1. Какой выбрать? Самый продвинутый — это HEVC: в нём много различных алгоритмов сжатия и самая тонкая настройка. Но есть минус, который может перечеркнуть все плюсы — его поддержка устройствами. Обязательно убедитесь, что устройства, на которых вы планируете смотреть контент, поддерживают этот кодек.

H264 — воспроизводится без проблем практически везде, но имеет оскорбительно плохую эффективность в сжатии видео в сравнении с другими актуальными кодеками. AV1 — открытый кодек, который сжимает видео более эффективно, чем HEVC, но требует значительно больше ресурсов как для кодирования, так и для декодирования, что, несмотря на его свободу от лицензий, делает его непригодным для использования за пределами таких онлайн-кинотеатров, как Netflix или Amazon Prime, которыми как раз и поддерживается его развитие.

Теоретически, видео размером 100 МБ при минимальных потерях при сжатии кодек HEVC уменьшит на 50%, H264 — на 30-35%, а AV1 — на 60%. Конечно, учитываются идеальные условия; в реальности эти значения обычно ниже на 10-15%.

В данной статье наш выбор падает на HEVC. Если же вам интересно, как настроить H264, который даже на микроволновке запустится, то на Хабре уже присутствует много статей о нём.

Логика кодирования на примере видео


Видео — это не просто набор картинок одна за другой. Видео — это смесь базового представления и алгоритмов для сжатия этой информации. Например, на экране шарик скачет из одного угла в другой всего за 24 кадра в секунду.

Вместо показа множества картинок кодек может сжать эту информацию. Один из алгоритмов отслеживает движение только мячика на картинке и вырезает его из общего изображения, а затем, выстраивая векторы движения, перемещает уже статичную картинку по нужным позициям. То есть, если бы раньше это был просто поток картинок, каждая из которых весит 1 МБ, то итоговый размер составил бы 24 МБ, но алгоритм разрезает нашу первую картинку весом в 1 МБ на 800 КБ фона и 200 КБ шарика. Фон остаётся неподвижным, поэтому информация о нём не будет обновляться в каждом кадре — она появится только один раз в самом начале. А единственным фактором увеличения веса видео будет шарик, для которого алгоритм записывает информацию о его отдельных позициях в каждом кадре.

Эту информацию можно значительно сжать при помощи простой математики. Вместо перечисления чисел 1, 2, 3, 4… 9 можно записать это как функцию: 1+x, где x < 9.

Соответственно, логику можно усложнить, применяя всё более продвинутые методы и создавая очень эффективные алгоритмы сжатия. Использование проекции векторов, расчёт размера секторов кадра и т. п. Однако за это приходится платить: алгоритмам сложно находить такие закономерности, поэтому видео с хорошим сжатием кодируются довольно долго. Хотя итоговое воспроизведение видео занимает минимальные ресурсы.

Прямой пример работы векторов движения в кодеке

Базовые настройки


Ни для кого не секрет, что FFmpeg — это программа с интерфейсом командной строки, а значит, мы оказываемся в среде, которая не слишком дружелюбна к обычному пользователю.


Самое простое — указание исходного и итогового видео.

ffmpeg -i "название видео.mp4" -c:v libx265 -с:a copy "название итогового видео.mkv"

Из этого примера мы можем понять, что FFmpeg использует простые в понимании аббревиатуры: -i — input, -c:v — codec for video, -c:a — codec for audio (в нашем случае мы не указали кодек, и все аудио будут перенесены без изменений), и в этом нет ничего сложного. Далее будут приведены основные базовые настройки. Это лишь часть возможностей данного кодека, так как я опущу те, что могут быть не нужны для большинства задач. Все команды, приведённые в статье, работают как на Linux, так и на Windows.

Cамые базовые параметры, которые необходимо знать


▍ Rate


Начнём с параметра -r, который задаёт значение FPS (кадров в секунду) видео.

ffmpeg -i input.mp4 -c:v libx265 -r 60 output.mp4

Если вам необходимо установить классические киношные 23.976 FPS, то используйте следующее значение:

ffmpeg -i input.mp4 -c:v libx265 -r 24000/1001 output.mp4


▍ Scale


Разрешение видео. FFmpeg масштабирует видео до указанного разрешения. Если мы вместо одной из координат укажем -1, то FFmpeg сам выставит необходимое значение, и изображение масштабируется правильно, без растягивания по одной из осей.

ffmpeg -i input.mp4 -c:v libx265 -scale 1920:1080 output.mp4

Параметры -ss и -to: используются для указания начала и конца обрезки видео в секундах.

ffmpeg -i input.mp4 -c:v libx265 -ss 10 -to 60 output.mp4


▍ Crop


Кадрирование (обрезка) видео. Задаётся в формате: ширина: высота:x:y. X и Y — координаты верхнего левого угла обрезанной области относительно исходного видео. В данном примере мы обрезаем видео в разрешении 1920:1080 на 400 пикселей сверху, снизу и справа. Здесь вы можете сами понять логику, как делать правильный синтаксис команды.

ffmpeg -i input.mp4 -c:v libx265 -vf "crop=1120:280:400:400" output.mp4


Базовые параметры для кодирования


▍ Preset


Крайне важный параметр. От него напрямую зависит скорость выполнения кодирования и его качество.


Градация: 100% — условная единица измерения от максимальной скорости, которую вы можете получить при кодировании. Чем больше это число — тем медленнее будет кодирование.

0. ultrafast 100%
1. superfast ~110-130%
2. veryfast ~130-160%
3. faster ~160-200%
4. fast ~200-250%
5. medium ~250-350%
6. slow ~350-500%
7. slower ~500-700%
8. veryslow ~700-1000% >=
9. placebo ~2000-3000% >=

Говоря по сути, крайними значениями желательно не пользоваться — либо только в тех случаях, когда вам до самой крайности это надо. Наиболее целесообразным выбором для большинства процессоров, например, уровня 9100f и ниже, будет fast. Для остальных же уже середнячков и получше определённо стоит опускаться на более низкие значения, вплоть до slow. После slow скорость выполнения падает значительно, примерно в 6 раз; точнее, я даже не совсем смог выявить рамки падения скорости. Placebo я вообще ума не приложу, для каких сценариев он предназначен.

▍ Tune


Есть дополнительная поднастройка -tune, которая оптимизирует кодирование для конкретного типа входных данных. Есть пресеты psnr, ssim, grain, zero-latency, fast-decode, animation. Для общего понимания, что поднастройка делает с видео, обратимся к -tune animation. Кодек оптимизирует кодирование для анимации, которая часто имеет большие участки однотонных областей, резкие края и повторяющиеся детали. То есть алгоритм адаптирован так, что уменьшается количество шума и число артефактов на краях линий объектов. Он также выделяет меньше ресурсов для обработки однотонных участков, тем самым уменьшая вес. Эту задачу решает и базовый пресет — fast, который выставляется автоматически, но делает это менее эффективно.

ffmpeg -i input.mp4 -c:v libx265 -preset fast -tune animation output.mp4


▍ Bitrate


Битрейт на человеческом языке — это довольно абстрактное понятие. Количество выделяемого веса (битов) на одну секунду видео. Чем выше значение, тем лучше качество, но и вес тоже больше. Топорный инструмент, но нужный в случае жёсткого ограничения по весу видео. Например, для создания видеостикеров в Telegram может пригодиться.

ffmpeg -i input.mp4 -c:v libx265 -b:v "значение в кб" output.mp4

Ещё более грубый подход, если говорить о видео, — это кодирование в два прохода: -pass 1 и -pass 2. В первый проход собирается информация об участках видео, а во второй на основе этой информации распределяется битрейт. Это более эффективно сжимает видео до определённого веса. Но это уже смахивает на помешательство на самом процессе и обычно не имеет смысла этим пользоваться.

ffmpeg -i input.mkv -c:v libx265 -b:v 5000k -pass 1 -an -f null NUL && ffmpeg -i input.mkv -c:v libx265 -b:v 5000k -pass 2 output.mkv

Проценты относительно веса оригинального файла

▍ CRF


Это инструмент, перекочевавший из кодека H264. По сути, это просто указание уровня качества видео, что значительно проще, чем работа с -bitrate. Чем выше значение CRF, тем ниже битрейт видео и его размер. На первый взгляд CRF похож на preset, но на самом деле это менее сложный инструмент, поэтому указание большего или меньшего значения CRF в большей степени зависит от скорости вашего накопителя, нежели от процессора. Однако с помощью других настроек можно компенсировать высокое значение CRF. Можно провести аналогию: выгоднее передавать ценную информацию, чем лишние данные. Информацию можно упаковать значительно более качественно, если задействовать больше времени.

ffmpeg -i input.mp4 -c:v libx265 -crf 20 output.mp4

Рекомендованных значений не существует. Вам необходимо вручную сравнить, какое значение будет удовлетворительным для вашего материала. Для этого мы можем вырезать небольшой фрагмент из вашего видео, чтобы процесс занимал меньше времени.

ffmpeg -i input.mp4 -ss 00:00:05 -to 00:00:06 -c copy output.mp4

*ss — stream start или же начало видео **to — до.

Проценты относительно веса оригинального файла

▍ Scale


При неправильном назначении разрешения (scale) могут возникнуть серьёзные проблемы с отображением видео на различных устройствах. Кодеки часто не обрабатывают значения, не являющиеся кратными двум, и даже при ошибке не сообщают, что причина именно в этом. Чтобы избежать подобных ситуаций, важно указывать корректные значения и придерживаться стандартных разрешений. Кроме того, многие Smart TV телевизоры с разрешением UHD, независимо от их стоимости, не поддерживают видео с разрешением, превышающим 4000 пикселей по ширине или высоте. Чтобы избежать проблем с воспроизведением, нужно внимательно выбирать параметры фильтров и настройки в процессе обработки.

ffmpeg -i input.mp4 -c:v libx265 -vf "scale=x:y" output.mp4

*-vf — video filter, соответственно все необходимые видеофильтры записываем после него в кавычки и разделяем разные фильтры запятой, без пробела.

Слева ТВ отказался воспринимать видео, справа — всё нормально

▍ Cropdetect


Обнаружение рамок для кадрирования. Иногда необходимо обрезать тёмные полосы по краям видео. Для этого существует специальная команда — cropdetect. Однако она только находит нужные значения. Чтобы передать их в FFmpeg, можно использовать простую команду с конвейером.

Пример команды для PowerShell:

ffmpeg -i input.mp4 -vf cropdetect -ss 0 -t 600 -f null - 2>&1 | findstr "crop" > temp.txt && for /f "tokens=" %j in (temp.txt) do set crop=%j && ffmpeg -i input.mp4 -vf "%crop%" output.mp4

*-ss 0 -t 600 — мы можем применить данный параметр для сокращения времени обработки видео, так он будет собирать данные только с этого участка видео (от 0 до 600 секунд), а не со всего файла.

И аналогичная команда для Linux (bash):

video="your_video.mp4"; crop=$(ffmpeg -i "$video" -vf cropdetect -ss 0 -t 600 -f null - 2>&1 | awk '/crop/ { print $NF }' | tail -1); ffmpeg -i "$video" -vf "$crop" "${video%.*}_cropped.mp4"

До и после обрезки

Продвинутые настройки(-x265-params).


Этот сегмент уже значительно сложнее и требует больше внимания. Выбор подходящего пресета требует значительного времени на перебор всех вариантов. Потратив много времени на изучение документации, я отобрал то, что действительно работает и оказывает значительное влияние на качество изображения, во всех случаях.

▍ B-frames


Количество кадров, используемых алгоритмом для анализа. Чем больше кадров, тем медленнее происходит обработка, потому что здесь происходит расчёт векторов движения и выполняется более сложная работа. Максимальное значение — 16. но это не означает, что алгоритм всегда будет брать для анализа 16 кадров; он выберет самые оптимальные участки для расчётов, чтобы добиться наиболее эффективного сжатия информации. Значение 16 обычно считается заоблачным, но я не заметил значительного падения производительности, по крайней мере в случае с анимацией. На иллюстрации работа представлена в упрощённом виде, но она показывает основной принцип.

ffmpeg -i input.mp4 -c:v libx265 -x265-params bframes=12 output.mp4

Примерное изображение логики работы алгоритма.
Для знатоков
Я понимаю, что данное описание работы B-frames не совсем точное, но у меня и не стоит задачи это объяснить с углубленно технической точки зрения. Введение в понимание читателя I и P кадров в данной статье будет совершенно лишним нагромождением.

▍ ME и subME


ME (motion estimation) — алгоритм оценки движения объектов. Может показаться, что это похоже на работу B-frames, однако это разные процессы. Если B-frames используют информацию о движении объекта в кадре, то ME определяет, какие объекты движутся, а какие нет, подсказывая кодеку при кодировании. Так можно избежать лишней информации о сдвигах на видео, тем самым уменьшив его вес. Эти алгоритмы не заменяют друг друга, а работают отдельно.

Значения me=2 в целом хватает для большинства сценариев, но если вы пытаетесь чересчур сэкономить вес на видео, если в видео с высоким разрешением много мелких движущихся объектов, то вероятно значение 3 или 4 будет лучше. То есть, при недостаточном значении движущиеся мелкие объекты на фоне будут содержать артефакты. Однако повышение значения ME сильно снижает производительность.

У ME есть дополнительный параметр — subME, он управляет точностью самого ME. Чтобы не запутаться: ME на каждом значении (1, 2, 3… 7) имеет совершенно разные алгоритмы нахождения движения, и они становятся всё сложнее и сложнее. Получается, что subME условно ставит количество циклов выполнения ME в одном и том же месте. Оптимальное значение subMEпри me=2 — это 7 или меньше. Более высокие значения subME снова очень сильно влияют на производительность.

ffmpeg -i input.mp4 -c:v libx265 -x265-params bframes=12:me=2:subme=7 output.mp4

*Все дополнительные параметры в -x265-params разделяются двоеточием.


▍ Pix format и Profile


Как правило, обычному пользователю рекомендуется оставлять стандартные настройки. Profile определяет глубину цветности и формат цветового пространства YUV (яркость и цветоразностные компоненты). Оба параметра очень сильно влияют на сложность воспроизведения конечного видео на устройстве. Почти никогда не стоит поднимать планку выше 8 бит и YUV420. Битность экрана у большинства устройств не превышает 8 бит. Вы в большинстве случаев просто усложните кодирование и воспроизведение видео до непригодного для использования уровня. Но лучше не трогать значение YUV. Вы можете выбрать профили main, main-10 или main-12.

ffmpeg -i input.mp4 -c:v libx265 -profile main10 output.mp4

Однако если вы хотите гарантированно иметь определённые значения YUV (что я и советую делать), то лучше воспользоваться параметром -pix_fmt

ffmpeg -i input.mp4 -c:v libx265 -pix_fmt yuv420 output.mp4

*Чтобы указать значение битности (по умолчанию 8, если не указана), то после yuv420 надо добавить ваше значение p10 или p12, как пример — yuv420p10.

▍ HDR


HDR отвечает за то, будет ли картинка в HDR-качестве. Если оригинальная картинка не снята в HDR, включение этой функции не имеет смысла. Но по умолчанию она всегда отключена, поэтому стоит упомянуть о ней.

Пример с HDR10:

ffmpeg -i input.mp4 -c:v libx265 -pix_fmt yuv420p10le -x265-params colorprim=bt2020:colormatrix=bt2020nc:transfer=st2084:hdr10=1 output.mp4


Аппаратное кодирование


Помимо кодирования процессором, HEVC предлагает блок, предназначенный для гораздо более быстрого кодирования с использованием ГПУ. Для этого вам достаточно иметь установленные драйверы видеокарты с нужным тулкитом, а также указать одну из библиотек вместо libx265, hevc_nvenc, hevc_amf или hevc_qsv. Первая библиотека предназначена для NVIDIA, вторая — для AMD, и третья — для Intel. Скорость кодирования видео значительно вырастет, но, как всегда, есть особенность: будут заблокированы все более сложные настройки кодека, такие, как параметр -x265-params. А это, по сути, единственный параметр, который может повысить качество при меньшем размере видео после CRF и preset.

ffmpeg -i input.mp4 -c:v hevc_amf -rc cqp -qp_i 12 -qp_p 13 output.mp4

*-qp_i и -qp_p играют роль аналога -crf, при этом -qp_p всегда должно быть на 1 больше, чем -qp_i.

Заключение


Надеюсь, что CLI-интерфейс FFmpeg открылся для вас с новой стороны. Даже такое неглубокое погружение, как в моей статье, дало многим из вас базис для почти любого сценария кодирования видео. Помните, что в видеосжатии не существует универсального решения. Каждый проект требует индивидуального подхода, и FFmpeg предоставляет безграничные возможности для экспериментов и оптимизации. Не бойтесь пробовать разные настройки и комбинации параметров, чтобы добиться наилучшего результата, соответствующего вашим требованиям.

Telegram-канал со скидками, розыгрышами призов и новостями IT 💻
Теги:
Хабы:
Всего голосов 95: ↑94 и ↓1+123
Комментарии143

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds