День 1. "Мне больше не придётся крякать Фотошоп и Вегас!".
День 2. Научился блюрить лица и айпишники через командную строку.
День 4. Провёл сравнительное тестирование аппаратных и программных видеокодеков.
День 8. Натравил ИИ-агентов на задачу по монтажу видео.
День 16. Объясняю жене, почему не могу просто запустить Paint и нажать две кнопки.

Хабр, привет! В последнее время моя работа во многом сосредоточена на вопросах Remote Desktop и стриминга медиа в реальном времени. Я часто использую FFmpeg в работе - и со временем всё чаще и чаще.

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

Запасайтесь сэмплами - вперёд!

Навигатор по статье

Контекст

Небольшая сводка про FFmpeg в целом - что это такое и какие основные кейсы применения.
Если Вы знаете, что это такое, то рекомендую не тратить время и переходить в следующий раздел.
Если Вы знаете про FFmpeg и даже умеете работать с ним в командной строке на базовом уровне, то рекомендую сразу перескочить ещё дальше, к интересностям.

FFmpeg/libav - это проект с открытым исходным кодом. Суть - кросс-платформенная библиотека на С, объединяющая под одним зонтиком тонны более низкоуровневых инструментов для работы с видео и аудио. Среди этих инструментов: библиотеки, реализующие кодеки (напр. libx264 для видеокодека H.264 или libopus для аудиокодека Opus); абстракции для доступа к аппаратно ускоренным функциям (напр. AVFoundation для платформ Apple или Quick Sync Video для кросс-платформенного доступа к медиа-акселератору внутри десктопных процессоров Intel); самостоятельно реализованные операции над видео и аудио; и другое.

FFmpeg можно использовать как утилиты командной строки (собственно ffmpeg + дополнительно ffplay и ffprobe) и вводить пайплайн на исполнение (прото-промпт), а можно подключать как библиотеки и пользоваться внутренним API самих компонентов.

Компоненты FFmpeg

FFmpeg состоит из следующих библиотек (= умеет делать следующее):

  • libavcodec - энкодеры и декодеры для аудио и видео. Все задачи по сжатию, распаковке и смене кодеков - это сюда.

  • libavdevice - интерфейсы различных устройств ввода/вывода. Получить изображение с веб-камеры или микрофона, отправить звук в колонки - это сюда.

  • libavfilter - фильтры для преобразования данных, организованные в виде математических функций. Уместно думать о фильтрах как о графовых нодах. Такое представление позволяет создать цепочку фильтров в виде графа и собрать пайплайн практически любой сложности. Поменять разрешение видео, вырезать из гифки половину цветов, поменять тональность звука - это сюда.

  • libavformat - библиотека для работы с контейнерыми форматами (например, мультиплексоры и демультиплексоры). Вычленить конкретную аудиодорожку из фильма с семью дубляжами, скачанного с торрента - это сюда.

  • libavutil - внутренняя кухня с вспомогательным кодом сложена здесь. Как пользователь командной строки, эту библиотеку вы нигде не заметите.

  • libswresample - набор операций для преобразования аудиоданных собственной разработки. Задумка такая: дать полный набор в виде софтварной реализации, а производители устройств и авторы плагинов могут предоставлять свои аппаратно ускоренные альтернативы. Ресэмплинг (смена частоты дискретизации) аудио - это сюда.

  • libswscale - то же самое, что и в предыдущем пункте, но уже для видео. Масштабирование изображения, смена цветового формата или data layout - это сюда.

FFmpeg - это бэкенд многих аудио- и видеоплееров, например, для VLC. И для других библиотек/фреймворков - тот же GStreamer имеет собственные реализации многих кодеков, но всё остальное подключает через интеграцию с FFmpeg.

Базовые примеры

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

Начнём с того, что я использую чаще всего - перевод видео из одного формата в другой. Выделю два самых частых сценария перекодирования видео в своей практике:

  1. Смена кодека. Можно, например, перекодировать видео из H264/H265 в контейнер WebM с кодеком VP9, чтобы видео было совместимо с бОльшим числом пользовательским устройств. WebM - это, например, YouTube, а значит, откроется с любого браузера, в то время как с поддержкой H265 в браузерах могут быть проблемы (напр. Firefox, иногда - Safari).

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

Транскодирование видео

Пожалуй, самое простое, что можно сделать. Задаём видео на вход (input, -i), целевой кодек (video codec, -c:v), и имя выходного файла (без ключей):

ffmpeg -i ./input.mp4 -c:v libvpx-vp9 ./output.webm

Чем FFMPEG хорош - помимо списка кодеков, не влезающих ни в один экран здорового человека, - так это фильтрами и мультиплексированием. Фильтров, как и кодеков, огромное количество и они напоминают определение математической функции из школы: вход, преобразование, выход. И их можно объединять в цепочку, получая за один проход все нужные вам изменения.

Добавим в наш простейший пример фильтр (video filter, -vf) на смену разрешения, потому что для наших (демонстрационных) целей повышенная детализация ни к чему:

ffmpeg -i ./input.mp4 -c:v libvpx-vp9 -vf "scale=640:-1" ./output.webm

-1 вместо вертикального разрешения - это автоматический выбор значения с сохранением пропорций. Например, если видео было в разрешении 1920х1080, то конструкция scale=640:-1 понизит его до 640х360.

Пример. Возьму случайный футаж с одного из прошлых мест работы: запись экрана на NVIDIA Shadowplay в 1080p, простая сцена с примитивной 3D-моделью в VR. Я хочу показать этот футаж прямо здесь, но Хабр позволяет загружать только GIF (с ограничением сверху на размер файла), поэтому пойдём по порядку.

Картинка по цветам довольно сочная, запись в 60 FPS. Аппаратные видеоэнкодеры NVIDIA оптимизированы больше на скорость нежели на степень сжатия, а потому у видео вес немаленький - 36 мегабайт за 10 секунд (при том, что это уже H264).

Применяем первую команду - и размер сократился до 22.2 МБ. Применяем вторую - и уже 2.4 МБ. Если заменим кодек VP9 (libvpx-vp9) на H265 (libx265) - то размер сократится до 4.3 МБ и 720 КБ соответственно.

Про параметры видеоэнкодеров

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

Иллюстрация треугольника компромиссов при работе с энкодерами (Gemini)
Иллюстрация треугольника компромиссов при работе с энкодерами (Gemini)

Замечали, что YouTube и другие хостинги жмут загружаемое видео подолгу? Для платформодержателя важно сэкономить своё внутреннее дисковое пространство и дать пользователю качественный поток, поэтому ты, дорогой автор, подождёшь...

Никто не запрещает вместо webm сделать формат вывода gif:

ffmpeg -i ./vr-dummy.mp4 -vf "scale=640:-1" ./vr-dummy.gif

Специальные опции не нужны, FFmpeg сам всё выберет исходя из расширения выходного файла. И, в отличие от mp4 и webm, формат gif уже можно пригоден для вставки как вложение в статью на Хабре. Но вес стал снова большим - 25.6 МБ даже в разрешении 640х360. Поэтому...

Сжатие гифки

GIF - это ведь последовательность кадров, а не видео, поэтому формат по определению прожорливый, что нас не всегда устраивает. Вот что можно сделать:

ffmpeg -i ./vr-dummy.mp4 \
-filter_complex "[0:v] fps=6,crop=iw:ih-130:0:90,scale=iw/3:-1,split [a][b];\
[a] palettegen=max_colors=32 [p];\
[b][p] paletteuse=dither=bayer:bayer_scale=3" \
./vr-dummy.gif

Здесь применён специфический фильтр модификации палитры, поэтому команда стала сложнее. Разберу все неочевидные заклинания команды по порядку (объясняю как можно короче):

  • -filter_complex вместо -vf - потому что фильтр для палитры устроен так, что нужно склонировать видеопоток и прогонять его дважды (параллельно). -vf по умолчанию работает только с линейной цепочкой фильтров;

  • [0:v] - указание, что фильтр дальше относится к видеопотоку с индексом 0;

  • fps=6 - урезаем частоту кадров, поскольку для гифки 60 FPS - выбор странный (*"шесть кадров..."(с)*);

  • crop=iw:ih-130:0:90 - убираю лишние элементы сверху (рамка окна) и снизу (панель задач Windows). iw - ширина региона совпадает с шириной видео, 0 - начало региона слева совпадает с началом видео, ih-130 - высота региона меньше высоты видео на 130 пикселей (90 на рамку окна + 40 на панель задач), 90 - начало региона сверху отступает от начала видео на 90 пикселей.

  • scale=iw/3:-1 - уменьшаем ширину в 3 раза от исходника, высоту уменьшаем пропорционально. Исходник имеет разрешение 1920х1080, поэтому гифка будет в 640х360, как и в прошлый раз;

  • split [a][b] - форкаем дорожку с видео и даём им имена a и b. По сути - то же самое, что назвать переменную;

  • [a] - указание, что фильтр далее относится к форку a;

  • palettegen=max_colors=32 - урезаем число цветов с 256 (стандарт в GIF) до 32 и на выходе получаем палитру кадра. Моя гифка от этого сильно пострадает, но сильно облегчится - во многих случаях понижение разрядности для хранения цветов может остаться незамеченным;

  • [p] - урезанную палитру именуем как p;

  • [b][p] - указание, что фильтр далее совмещает форк b и нашу палитру p;

  • paletteuse=dither= - берём кадр и добавляем к ней палитру с дизерингом - сглаживанием резких цветовых переходов. Базовый вариант после знака "равно" здесь none, но он оставляет все цветовые переходы как есть, поэтому...

  • bayer:bayer_scale=3 - самый популярный вариант сглаживания. Параметр изменяется от 0 (цвета ровные, весит больше) до 5 (цвета резкие, весит минимально).

И, наконец, Вы можете увидеть мой старый футаж:

Гифка, сконвертированная с большими потерями качества из видео
Гифка, сконвертированная с большими потерями качества из видео

Итого, видео на 6 секунд в виде гифки весит 3.2 МБ против 25.6 МБ в конце предыдущего раздела. Пусть качество и оставляет желать сильно лучшего, понять происходящее можно.

Напоминаю задачу: преобразовать в GIF и влезть в ограничения по размеру от Хабра. Если воображаемому коллеге понадобится полноценный вариант, то я уже вышлю перекодированный исходник в VP9 или H265, где всё чётко и в 60 FPS. Или гифку, но без тотального сжатия.

А шо вы хотели?...

Извлечение кадра из видео

Едем дальше. Интересный пример - вытаскивание скриншота из видео. Конечно, можно вырезать стоп-кадр из окна с видеоплеером ножницами - и не обязательно экранными ;) Но мы так теряем в качестве и получаем произвольное разрешение, зависящее от размеров окна, а не от размеров видео. А можно поступить вот так:

# По таймкоду
ffmpeg -i ./vr-dummy.mp4 -ss 00:00:07.00 -frames:v 1 vr-dummy-frame.jpg
# По номеру кадра
ffmpeg -i ./vr-dummy.mp4 -vf "select=eq(n\,420)" -frames:v 1 ./vr-dummy-frame.jpg

Тяжело определить конкретный номер кадра или таймкод? Не проблема! Давайте сгрузим покадрово целую секунду из видео и выберем себе то, что нам нужно:

mkdir -p ./vr-dummy-frames/ \
&& ffmpeg -ss 00:00:07 -i ./vr-dummy.mp4 -t 1 ./vr-dummy-frames/frame-%03d.jpg

Здесь:

  • -ss - таймкод старта. Видео интересует нас начиная отсюда;

  • -t - длительность в секундах. Альтернатива: использовать -to, описывающий таймкод конца.

Получим ровно 60 кадров:

zaburunovleonid@fedora:~/$ ls ./vr-dummy-frames/
frame-001.jpg  frame-006.jpg  frame-011.jpg  frame-016.jpg  frame-021.jpg  frame-026.jpg  frame-031.jpg  frame-036.jpg  frame-041.jpg  frame-046.jpg  frame-051.jpg  frame-056.jpg
frame-002.jpg  frame-007.jpg  frame-012.jpg  frame-017.jpg  frame-022.jpg  frame-027.jpg  frame-032.jpg  frame-037.jpg  frame-042.jpg  frame-047.jpg  frame-052.jpg  frame-057.jpg
frame-003.jpg  frame-008.jpg  frame-013.jpg  frame-018.jpg  frame-023.jpg  frame-028.jpg  frame-033.jpg  frame-038.jpg  frame-043.jpg  frame-048.jpg  frame-053.jpg  frame-058.jpg
frame-004.jpg  frame-009.jpg  frame-014.jpg  frame-019.jpg  frame-024.jpg  frame-029.jpg  frame-034.jpg  frame-039.jpg  frame-044.jpg  frame-049.jpg  frame-054.jpg  frame-059.jpg
frame-005.jpg  frame-010.jpg  frame-015.jpg  frame-020.jpg  frame-025.jpg  frame-030.jpg  frame-035.jpg  frame-040.jpg  frame-045.jpg  frame-050.jpg  frame-055.jpg  frame-060.jpg

Извлечение аудиодорожки из видео

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

ffmpeg -i ./input_video.mp4 -vn -c:a copy ./audio.mp3

Здесь:

  • -vn - отбросить видео поток вообще (*video null*);

  • -с:a copy - использовать аудио в исходном виде, без нового кодека (*audio codec* по аналогии с video codec, -c:v).

Консольный редактор

В разделе выше было показано то, из-за чего FFmpeg в основном все знают: кодирование/декодирование аудио/видео, смена формата контейнера и другое. А теперь - к коллекции кейсов поинтереснее.

Конвертация SVG в PNG (и не только)

Чем Вы обычно пользуетесь для смены формата изображения, например, из SVG в PNG? Раньше я использовал веб-конвертеры (напр. Convertio). Ещё раньше я использовал Adobe Photoshop. Про всё это я давно забыл и иду в терминал:

ffmpeg -i ./logo.svg ./logo.png

Примитивная команда - полезный результат, т. к. SVG может поддерживаться не везде.

На всякий случай отмечу, что FFmpeg по задумке не предназначен для изображений. Например, обратно в SVG сконвертировать не получится. Для этих целей лучше использовать всякие инструменты а-ля Image Magick.

Текст на фото

Рисование кистью как в редакторах, встроенных в запрещённую соцсеть для фоточек, которую я решительно осуждаю и Telegram, конечно, не прокатит. Но наложить текст (хоть для пояснения коллеге прямо на скриншоте, хоть для публикации истории в те же соцсети) вполне себе можно:

ffmpeg -i ./vr-dummy-frames/frame-001.jpg \
-vf "drawtext=\
fontfile=/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf:\
text='VR Frame #001':\
fontsize=48:fontcolor=white:\
x=(w-text_w)/2:y=h-text_h-30:\
shadowcolor=black:shadowx=3:shadowy=3" \
./vr-dummy-frames/frame-001-text.jpg

Здесь:

  • drawtext - видеофильтр наложения текста;

  • fontfile - чем пишем;

  • text - что пишем;

  • fontsize, fontcolor - как пишем;

  • x и y - где пишем;

  • shadowcolor - дополнительно рендерим тень от текста.

Результат наложения текста на скриншот, полученный в одном из разделов выше
Результат наложения текста на скриншот, полученный в одном из разделов выше

Прямоугольное выделение на фото

Собственно, помимо текста можно подсветить важную область на скриншоте цветным прямоугольником и отправить гневный комментарий своим коллегам без подписей к фото:

ffmpeg -i ./input.jpg \
-vf "drawbox=x=100:y=50:w=200:h=150:color=red@0.8:t=5" \
./output.jpg

Здесь:

  • drawbox - видеофильтр наложения прямоугольной рамки;

  • x, y w и h - где рисуем;

  • color - каким цветом рисуем, @0.8 - прозрачность цвета;

  • t - кистью какой толщины (в пикселях) рисуем. Можно написать fill - прямоугольник будет полностью закрашен.

Пример. Беру один из старых рабочих скриншотов и задаю прямо на нём вопрос коллеге:

ffmpeg -i ~/Pictures/screenshot.png \
-vf "drawtext=\
fontfile=/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf:\
text='What the hell is 0\:0?':\
fontsize=48:fontcolor=red:\
x=(w-text_w)/2-400:y=h-text_h-150:\
shadowcolor=black:shadowx=3:shadowy=3,\
drawbox=x=375:y=ih-40:w=120:h=40:color=red@0.5:t=2,\
scale=960:-1" \
~/Pictures/screenshot-note.png

Input -> drawtext -> drawbox -> scale -> Output:

Результат рисования прямоугольной области и текста на скриншоте
Результат рисования прямоугольной области и текста на скриншоте

Координаты, конечно, приходится высчитывать самому - и проходить через несколько итераций. Интерактивного превью у FFmpeg нет. Это безусловный недостаток при работе в командной строке. Для более быстрого итерирования я использую цепочку команд с открытием результата по готовности: ffmpeg -i ./input.mp4 … ./output.mp4 && xdg-open ./output.mp4

Размытие области на фото/видео

Обратите внимание на скриншот из примера выше. Там сверху размытая область. Это я заблюрил айпишник внутреннего хоста в рабочем ЦОДе.

То же самое я делал, например, при подготовке демонстрационных видео к презентации продукта (протокол доставки рабочего стола в системе виртуализации) - туда, конечно же, попали наши внутренние адреса хостов и их доменные имена. Нехорошо светить таким в интернете.

А как убрать? Открыть видеоредактор, руками выбрать область размытия и разместить эффект, например, отдельной дорожкой с ограничением по времени? Да нет же:

ffmpeg -i ~/Pictures/screenshot-note.png \
-filter_complex "[0]crop=50:20:470:20[ip];\
[ip]scale=iw/5:ih/5,scale=iw*5:ih*5:flags=neighbor[px];\
[0][px]overlay=470:20" \
~/Pictures/screenshot-note-blur.png

Блюров в FFmpeg несколько, даже есть отдельные фильтры. Я выбрал самый простой вариант - пикселизацию через downscale.

Это пример для фото. Для видео одно замечание: если нужно блюрить только конкретный временной отрезок, то к фильтру overlay нужно добавить параметр enable: overlay=470:20:enable='between(t,2,4)

Коллаж из кадровой развёртки

Как получить превью в виде склейки нескольких кадров? Вырезать кадры по очереди и выдр...высматривать пиксели в Paint при стыковке? Избавьте:

ffmpeg -ss 00:00:18 -i ./vr-block1.mp4 -frames:v 1 \
-vf "fps=1/8,crop=iw-600:ih-130:400:90,scale=480:-1,\
tile=4x1:padding=4:margin=4:color=white" \
./vr-block1-preview.jpg

Здесь:

  • fps=1/8 - частота сбора кадров для коллажа;

  • crop и scale - управление областью видео, из которого берём кадры для коллажа;

  • tile - фильтр создания склейки, padding и margin - границы итоговой склейки, color - цвет границы.

Коллаж из покадровой развёртки: 18-я, 26-я, 34-я и 42-я секунды видео
Коллаж из покадровой развёртки: 18-я, 26-я, 34-я и 42-я секунды видео

Это, кстати, отлично сочетается с пунктом про извлечение кадров.

Водяной знак

Выше я размещал иллюстрации от Gemini. В правом нижнем углу у каждого сгенерированного изображения всегда стоит водяной знак в виде логотипа ИИ от Google. Как он это делает, не генерирует же?

В случае с Gemini я наверняка не знаю, но вы на свои скриншоты или видео можете добавить любой водяной знак вот так:

ffmpeg \
-i ./vr-dummy-frames/frame-001-text.jpg \
-i ~/Downloads/habr-pill.png \
-filter_complex "[0] scale=720:-1 [src];\
[1] format=rgba,colorchannelmixer=aa=0.8 [watermark];\
[src][watermark] overlay=W-w-20:H-h-20" \
./vr-dummy-frames/frame-001-text-watermark.jpg

Здесь:

  • -i дважды - входное изображение и водяной знак;

  • -filter_complex - потому что у нас два входных потока, линейный фильтр не работает;

  • [0] scale=720:-1 [src] - уменьшаю размер входного изображения и называю поток src;

  • [1] format=rgba,colorchannelmixer=aa=0.8 [watermark] - делаю alpha-premultiply для водяного знака, 80% непрозрачности, и называю поток watermark;

  • [src][watermark] overlay - совмещаем оба потока прямым наложением (прозрачность здесь учитывается);

  • W-w-20:H-h-20 - координаты размещения водяного знака. W и H - ширина левого слоя (=операнда), w и h - правого. Указание через заглавные и строчные буквы - соглашение в фильтре overlay

И вот один из скриншотов выше с добавлением водяного знака:

Добавление водяного знака на скриншот из раздела выше
Добавление водяного знака на скриншот из раздела выше

Пакетная обработка

Как вы себе представляете групповую операцию для любого из сценариев выше? Или, скажем, для снимков фотосессии? У вас много файлов в неподходящем вам виде: слишком много весят, слишком большое разрешение, не тот формат, ...

Через GUI, скорее всего, придётся открывать каждый файл и сохранять его в другом качестве. В веб-конвертерах иногда есть возможность выбора нескольких файлов, но это надо уходить в браузер, прокликать до папки с исходниками, затем - выбрать, куда сохранить, как назвать...

А что если...

for f in ./vr-dummy-frames/*.jpg; do
  ffmpeg -v quiet \
    -i "$f" -i ~/Downloads/habr-pill.png \
    -filter_complex "[0] scale=[src];\
    [1] format=rgba,colorchannelmixer=aa=0.6 [watermark];\
    [src][watermark] overlay=W-w-20:H-h-20" \
    "$f-watermark.jpg";
done

Это я наложил водяной знак - точно так же, как в разделе выше, но для всех 60 кадров, полученных из раскадровки здесь.

Сравните количество действий на одну фотографию с условным Adobe Lightroom.

Полный расколбас

Ну а теперь немного н*ркомании. Неочевидные команды, дающих интересные визуализации. Сложно представить себе сценарии применения многих команд в работе, но в личных целях возможно всё ;)

И заодно возможности FFmpeg наглядно оценим...

Эквалайзер

Предлагаю поностальгировать по временам Winamp и добавить к MP3 визуализацию:

ffmpeg -i ~/Music/Queen_We_Will_Rock_You.mp3  \
-filter_complex  \
"[0:a]showfreqs=s=1280x720:mode=bar:ascale=log:fscale=log:colors=0x1D9E75,format=yuv420p[v]" \
-map "[v]" -map 0:a -c:v libx264 -c:a copy we_will_rock_you_vis.mp4
Визуализация первой секунды "Queen - We Will Rock You"
Визуализация первой секунды "Queen - We Will Rock You"

Или ещё развёрнутее:

ffmpeg -ss 00:00:22.0 -i ~/Music/Queen_-_We_Will_Rock_You_47828511.mp3 -t 08 \
-filter_complex "
[0:a]showspectrum=s=640x360:slide=scroll:color=rainbow:scale=log[spec];
[0:a]showwaves=s=640x180:mode=cline:colors=0x00ff88[wave];
[0:a]avectorscope=s=320x540:zoom=1.5:draw=line[vec];
[spec][wave]vstack[left];
[left][vec]hstack
" \
-map 0:a -c:a libopus \
-c:v libvpx-vp9 -crf 18 \
we_will_rock_you_portrait_cut.webm
Визуализация "Queen - We Will Rock You", в этот раз - поближе к припеву
Визуализация "Queen - We Will Rock You", в этот раз - поближе к припеву

Визуализация работы кодека

Видеокодеки - это магия. Они умеют так много всего, что это сложно описать, ещё сложнее - представить визуально. Но FFmpeg умеет раскладывать кодек на дельты с векторами движения:

ffmpeg -flags2 +export_mvs \
-i ./town-cut.mp4 \
-vf "scale=iw/3:-1,hue=s=0,codecview=mv=pf+bf+bb:qp=1" \
-pix_fmt gray \
./town-cut-vis.gif

Визуализация потерь

Здоровый человек ничего не знает про видеокодеки - за исключением того, что видео весят меньше последовательности картинок. Но какие при этом происходят потери, пусть даже если глазу зрителя они не видны? Узнаем лобовым сравнением трёх показателей качества на примере опции -crf:

# Готовим три варианта
ffmpeg -i ./superposition_cut.mp4 -c:v libx264 -crf 18 ./superposition_crf18.mp4
ffmpeg -i ./superposition_cut.mp4 -c:v libx264 -crf 28 ./superposition_crf28.mp4
ffmpeg -i ./superposition_cut.mp4 -c:v libx264 -crf 40 ./superposition_crf40.mp4
# Визуализируем дифф всех трёх на одном экране
ffmpeg -i ./superposition_cut.mp4 -i superposition_crf18.mp4 -i superposition_crf28.mp4 -i superposition_crf40.mp4 -filter_complex   "[0][1]blend=all_mode=difference,format=gray,curves=all='0/0 0.01/0.5 0.1/0.9 1/1'[d1];
   [0][2]blend=all_mode=difference,format=gray,curves=all='0/0 0.01/0.5 0.1/0.9 1/1'[d2];
   [0][3]blend=all_mode=difference,format=gray,curves=all='0/0 0.01/0.5 0.1/0.9 1/1'[d3];
   [d1]drawtext=text='CRF 18 (diff x10)':fontsize=28:fontcolor=white:x=10:y=10[a];
   [d2]drawtext=text='CRF 28 (diff x10)':fontsize=28:fontcolor=white:x=10:y=10[b];
   [d3]drawtext=text='CRF 40 (diff x10)':fontsize=28:fontcolor=white:x=10:y=10[c];
   [a][b][c]hstack=inputs=3"   superposition_crf_diff.mp4

Вот исходник (пережатый для вставки в виде гифки):

Запись работы бенчмарка Unigine Superposition
Запись работы бенчмарка Unigine Superposition

А вот что получим при визуализации потерь:

Сравнение потерь записи работы бенчмарка Unigine Superposition при разных crf (18, 28 и 40 соот-но)
Сравнение потерь записи работы бенчмарка Unigine Superposition при разных crf (18, 28 и 40 соот-но)

Из интересного: при -crf 40 потери видны даже на статичном тексте. Вот этот вариант отдельно:

Своего рода тепловая карта потерь кодека при перекодировании с -crf 40
Своего рода тепловая карта потерь кодека при перекодировании с -crf 40

ASCII-кинотеатр

Напоследок - пример, который больше не про FFmpeg. Я хочу выводить видео прямо в терминал, а для этого понадобится обвязка на Python. Полный код оставлю в комментариях, а здесь - команда запуска: python3 ./ascii-cinema.py ~/Downloads/rick-astley.gif

Трейлер GTA 4 в каждый дом!
Трейлер GTA 4 в каждый дом!

А что это всё даст?

У такого подхода, как работа (с медиа) в командной строке, есть много достоинств - и, конечно, свои недостатки. Изложу своё видение в этом разделе.

Дело совсем не в задачах по типу "вырезать из скриншота квадрат x:y:w:h". Я начинал с FFmpeg по прямому назначению: сменить кодек у аудио или видео, понизить разрешение видео для уменьшения размеров и т. д. А затем заметил, что за время на открытие программы с GUI зачастую можно решить вопрос через терминал "от и до".

В целом, будучи инженером-программистом, я на себе ощутил, что один из самых дорогих контекстов, который мне приходится переключать - это переход из режима "клавиатура + минимум тачпада" в режим "хирургически точный курсор". По этой причине я минимизирую GUI в своей работе и максимально задействую хоткеи, например:

Действие

Через указатель с клавиатурой

Через клавиатуру с хоткеями

Переключение вкладок

Перевод курсора через весь экран с необходимостью точного позиционирования

Alt+1/2/3/4

Выделение текста

Зажатие ЛКМ и перенос курсора руками

Зажатие Shift с навигацией по тексту с помощью клавиатуры.

Скажем, Shift+End - выделить всё от текущей позиции курсора до конца строки

Управление положением окна на экране

Ручное изменение размеров через хэнлды рамок окна

Win+Up/Down/Left/Right
(для GNOME)

Перенос окна между мониторами

Ручной перенос окна через зажатие ЛКМ

Win+Shift+Left/Right
(для GNOME)

Перенос окна между рабочими пространствами (desktops, workspaces)

Переход в меню десктопов через системный хоткей, затем - ручной перенос окна через зажатие ЛКМ

Win+Alt+Shift+Left/Right
(для GNOME)

... и много чего ещё, ведь современные популярные IDE (и не только) имеют массу хоткеев для ускорения работы.

То же самое - с CLI. Если есть возможность избежать необходимости точного позиционирования указателя мыши, я такой возможностью воспользуюсь. И, если вы разработчик, который часто работает через командную строку, но ещё не пробовал массово адаптировать хоткеи в своей работе, рекомендую вам попробовать так же.

Про Claude Code

Кстати, по той же причине я использую Claude Code в терминале через tmux:

  • На одной половине основного монитора - терминал с LLM;

  • На другой - командная строка (для сборки проекта, использования git и минимального редактирования файлов через nano);

  • На втором мониторе - IDE с проектом (для чтения проекта и больших работ с файлами);

  • Ну а на третьем мониторе - браузер (для всего остального есть Mastercard).

Иногда пользуюсь плагином для VS Code, если не хочется вылезать из IDE :)

Хоткеи и минимизация мыши в своей работе (напр. с помощью tmux) дали мне выигрыш во времени и энергии в разы:

  • Времени - потому что управление клавиатурой быстрее;

  • Энергии - потому что мозг остаётся в потоке (конечно, после того, как наработается привычка).

А в режим работы с курсором можно переходить тогда, когда альтернатив нет - например, для ревью MR в GitLab.

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

Да, это потребует привыкания и перестройки. Да, не хватает наглядности и интерактивности. Но вы же прибегаете к использованию регулярных выражений, а не обрабатываете строки каждый раз через стандартную библиотеку языка C, верно?...

Заключение

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

FFmpeg - это очень полезный инструмент, который экономит мне много времени даже там, где я изначально этого не ожидал. Ни больше, ни меньше. И освоить его сейчас гораздо проще, чем раньше: многие неочевидные кейсы, приведённые в этой статье, я узнал через чат с LLM - и чем дальше, тем больше использую именно консольную команду, а не графические редакторы. Хоть ИИ-агентов для видеомонтажа собирай (да, так уже делают).

Такие дела, братюни! Не пренебрегайте инструментами командной строки, и уж тем более добротной визуализацией данных ;) Счастливо!

Комментарии (0)