FFMPEG
::: info Эта статья требует базовых знаний про работу с FFMPEG. Ожидается, что читатель освоил курс Компьютерная графика (модуль 3).
:::
Основная информация FFmpeg — программа с набором библиотек для изменения форматов медиаданных, а также записи и стриминга аудио и видео. FFmpeg помогает в различных повседневных операциях, как обрезка видео, получение аудио из видео, конвертирование из avi в mp4, так и в ситуациях посложнее, например, наложение изображения или другого видео в углу текущего, добавление эффектов и многое многое другое.
Структура команды
Базовая команда начинается с ключевого слова “ffmpeg”. Далее ключ “-i” указывает источник. Источником может быть файл (видео, фото, аудио), поток и устройство. После прописывается название конечного файла или потока. Для файла обязательно указывается расширение.
ffmpeg -i input.avi result.mp4
Если же указать источник без выходного файла, то ffmpeg даст информацию об этом источнике, такую как разрешение сторон, количество кадров в секунду, длина, битрейт и т.д.
::: info
ffmpeg -i input.mp4
:::

Схематично, программа командной строки FFmpeg ожидает, что следующий формат аргументов выполнит свои действия — ffmpeg {1} {2} -i {3} {4} {5}, где:
{1} — глобальные параметры
{2} — параметры входного файла
{3} — входящий URL
{4} — параметры выходного файла
{5} — исходящий URL
В частях {2}, {3}, {4}, {5} может указываться несколько аргументов.
Процесс транскодирования в ffmpeg следует по следующей схеме:

С помощью декодера эти пакеты превращаются в несжатые данные (например, RAW-видео). После происходит обратный процесс: информация сжимается кодером и полученные пакеты мультиплексируются в конечный файл.
Применение
В этом разделе приводится несколько примеров применения FFMPEG с фильтрами и потоками.
Кодирование
Видеокадр кодируется в видеофайле не в экранных пикселях, а в своих собственных, "виртуальных" пикселях. А видеопроигрыватель преобразует эти виртуальные пиксели в экранные.
Полезно знать следующие сокращения и их значения:
- PAR, Pixel Aspect Ratio. Если PAR равен 1:1, то пиксель квадратный.
- SAR, Storage Aspect Ratio, то есть соотношение сторон кадра, записанного в текущем файле. PAR - это про пиксель, а SAR и DAR - это про кадр.
Высчитывается SAR просто путем деления ширины кадра, в своих "виртуальных" пикселях, к высоте кадра, тоже в своих "виртуальных" пикселях. Размер кадра 1920х1080? Значит SAR=16:9. - DAR, Display Aspect Ratio, то есть соотношение сторон кадра, которое должно использоваться при выводе на экран. Если SAR и DAR не совпадают (и это частая ситуация), то видеоплеер должен сделать следующее: взять изображение в "виртуальных" пикселях, и при выводе их на экран растянуть картинку так, чтобы получилось соотношение сторон, заданное в DAR. Иногда это растягивание не увеличивает пропорционально, а деформирует до заполнения экрана полностью из-за неправильного считывания пропорций кадра.
Параметры PAR, SAR и DAR всегда связаны между собой простой формулой:
PAR = DAR / SAR
Мы хотим увидеть картинку в разрешении 640 на 480 то есть в соотношении сторон 4:3. Для этого DAR должен быть именно 640:480=1,3. По формуле ниже определяем, что SAR надо установить равным 1:1.
DAR = HORIZONTAL_RESOLUTION / VERTICAL_RESOLUTION * SAR
Команда:
ffmpeg -i input.mp4 -vf scale=640:480,setsar=1:1 -r 30 -ss 2 -t 10 -c:v libx264 -b:v 1.5M -c:a aac -b:a 160k -cutoff 48000 output.mp4
-
-vf (video filter) – ключ, отвечающий за изменение параметров кадров между процессами декодирования и кодирования;
-
scale=640:480,setsar=1:1 – приводит видео к заданному размеру, а setsar указывает, что “виртуальный” пиксель будет квадратным;
-
-r – (frame Rate) ключ, устанавливающий частоту кадров в секунду
-
-ss 2 – (Set Start) начинает записывать видео со 2 секунды Есть два варианта использования данного ключа:
Когда нужно начать читать исходный файл с определенного момента. В связи с особенностями различных форматов, ffmpeg чаще всего будет находить приблизительно значение, после которого начнётся считывание.
Когда этот параметр стоит до выходного файла, то он будет декодироваться, но отбрасываться до нужного значения (после которого нужно начать запись) -
-t – (Time) ключ, определяющий сколько будет длиться видео
Здесь есть разница в зависимости от расположения ключа в команде.
- Если он стоит до источника, то программа ограничит количество данных, считываемых на входе.
- Когда ключ используется перед выходным файлом, программа останавливает запись после достижения заявленного значения.
ffmpeg -i input.mp4 -vf scale=640:480,setsar=1:1 -r 30 -ss 2 -t 10 -c:v libx264 -b:v 1.5M -c:a aac -b:a 160k -cutoff 48000 output.mp4

ffmpeg -t 10 -ss 2 -i input.mp4 -vf scale=640:480,setsar=1:1 -r 30 -c:v libx264 -b:v 1.5M -c:a aac -b:a 160k -cutoff 48000 output.mp4

В данном случае немного уменьшилось количество обрабатываемых кадров в секунду.
- -c:v – (enCode Video) кодирует видеопоток в соответствии с указанным кодеком (первая буква “с” означает сокращенную версию ключа “-codec”, а буква “v” работу с видеофайлом). Вы можете встретить другую нотацию
-vcodec/-acodec-- этот способ записи считается устаревшим, предпочтительнее писать сответственно-c:v/-c:aили-с, когда нужно указать и аудио, и видео.
Ключ scale в предыдущем примере приведет размер кадра к указанному:
ffmpeg -i input.mp4 -vf scale=1280:720 output.mp4
Нарезка и склейка
Как обрезать видео без перекодирования?
Для указания начала и конца фрагмента, который нужно получить на выходе, используются соответственно ключи -ss и -t для указания длительности фрагмента или -to для указания таймкода конца фрагмента. Параметр copy заставляет ffmpeg пропускать этап декодирования и кодирования, содержимое копируется без изменений -- это выполняется со скоростью копирования файла и не нагружает процессор:
ffmpeg -ss [start_timecode] -i in.mp4 -t [duration] -c copy out.mp4
ffmpeg -ss [start_timecode] -i in.mp4 -to [end_timecode] -c copy out.mp4
Как обрезать видео с перекодированием?
Если не прописать -c copy, то параметры кодирования будут взяты из указанных в команде ключей, а недостающие -- из параметров по умолчанию. Например, в следующей команде кодеки и битрейт аудио указаны, а битрейт видео ffmpeg выберет на своё усмотрение. Обязательно указывайте битрейт и другие критичные для вас параметры, чтобы исключить неподходящих для вас значений в итоговом файле или потоке.
ffmpeg -ss [start] -i in.mp4 -t [duration] -c:v libx264 -c:a aac -strict experimental -b:a 128k out.mp4\n
Как соединить два видео без перекодирования?
Объединение файлов выполняется при помощи конкатенации в ffmpeg.
Для начала создайте текстовый файл, содержащий все файлы, которые вы хотите объединить:
file '/path/to/file1.wav'
file '/path/to/file2.wav'
file '/path/to/file3.wav'
- Файлы желательно располагать в одной папке.
- Важно, чтобы файлы были с одним и тем же кодеком
- Объединение выполняется без перекодирования (
-c copy):
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.wav
- Значение
-safe 0не требуется, если пути совпадают.
Потоки и фильтры
FFMPEG позволяет выполнять сложные комплексные команды с несколькими источниками и путями обработки их потоков. Для этого используется концепция цепочки фильтров (filterchain) — это когда фильтры перечислены через запятую. Например:
-vf rotate=PI/2,crop=600:600,hflip
Когда цепочки фильтров разделены точкой с запятой, то они образуют граф фильтров (filtergraph);
В каких же случаях использовать -vf, а в каких -filter_complex?
-vfиспользуется в случаях, когда в графе есть только один вход и только один выход,-filter_complex— когда есть один или несколько входов и один или несколько выходов.
К примеру,
ffmpeg -i input.mp4 -i logo.png -i logo2.png -filter_complex "[1:v]rotate=PI,hflip[logo];[0:v][logo]overlay=10:10[a];[a][2:v]overlay=main_w-overlay_w-10:main_h-overlay_h-10" result.mp4
В этом случае получается граф:

[0:v]– В ffmpeg все входные файлы пронумерованы. Первый символ (0) означает номер входного файла (отсчёт начинается с нуля), второй (v) определяет тип файла, в данном случае этоv- video.
В основном фильтры принимают на вход один видеопоток и отдают на выходе один видеопоток. Записывается это так:
-filter_complex "[1:v]hflip[logo]"
Сначала идёт входной поток, потом название фильтра и его параметры (или цепочки фильтров), в конце -- название выходного файла.
В данном случае, когда после наложения фильтра на второй входной файлы результат будет помещён в поток с названием logo. Добавим ещё один фильтр:
-filter_complex "[1:v]rotate=PI,hflip[logo]"
Теперь второй входной файл будет повёрнут на 180° и отражён по-горизонтали.
Есть фильтры, которые принимают два и более потоков, а на выходе производят один поток. К таким относится фильтр overlay, который принимает два видеопотока.
-filter_complex"[1:v]rotate=PI,hflip[logo];[0:v][logo]overlay=10:10[a]"
Фильтр берёт первый входной файл ([0:v]) и повёрнутый логотип ([logo]), размещает логотип в координатах 10:10 (левый верхний угол), а результат переходит в именованный поток [a].
overlay – с помощью данного фильтра можно наложить логотип или видео.
Фильтр принимает следующие значения:
main_w / W — ширина исходного видео
main_h / H — высота исходного видео
overlay_w / w — ширина накладываемого видео или изображения
overlay_h / h — высота накладываемого видео или изображения
Вернёмся к предыдущей теме про соединение видео.
Как соединить два видео с перекодированием?
ffmpeg -i input1.mp4 -i input2.webm -i input3.mov -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mkv
[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0] – эта строка сообщает ffmpeg, какие потоки следует брать из входных файлов и отправлять в качестве данных в фильтр concat (объединять). В этом случае видеопоток 0 [0:v:0] и аудиопоток 0 [0:a:0] с нулевого входного файла (input1.mp4 в этом примере), а видеопоток 0 [1:v:0] и аудиопоток 0 [1:v:0] с первого входного файла (input2.webm) и т.д.
concat=n=3:v=1:a=1[outv][outa]
Фильтр concat объединяет видео. n=3 говорит фильтру, что есть три входящих потока, v=1 означает, что на один поток будет одно видео, a=1 тоже самое только с аудио. Фильтр объединяет три сегмента и выдаёт на выход два потока: видеопоток и аудиопоток – [outv] и [outa]
-map "[outv]" -map "[outa]" output.mkv
Это указывает ffmpeg использовать результаты фильтра concat, а не потоки непосредственно из входных файлов.

Потоки
Выбор потоков может потребоваться для создания копии файла с нужными потоками или для случаев, когда нужно скопировать видео или аудио из файла.
Форматы:
-map [индекс]— выбирает все потоки указанного файла (-map 1)-map [индекс:тип_потока]— выбирает все потоки заданного типа (-map 1:v)-map [индекс:номер_поток]— выбирает конкретный поток по номеру (-map 1:0)-map [индекс:тип_потока:номер_потока]— выбирает конкретный поток по номеру и с указанным типом (-map 1:v:0)
В качестве индекса может быть число или название потока, которое задается в -vf / -filter_complex. Если указать отрицательный индекс, поток будет исключён (-map -0:v) Виды потоков:
v(video) — видео (включая обложки, статичные изображения)V(video) — видео (только видео, не изображения)a(audio) — аудиоs(subtitles) — субтитрыd(data) — данные (не очень понимаю, что это, мб это вообще убрать)t(attachment) — вложения (как и это) Есть видео без звука и отдельная звуковая дорожка в mp3. Объединить эти два потока в видео со звуком: \nffmpeg -i input.mp4 -i audio.mp3 -c:v copy -map 1:a result.mp4
Выход пайплайна В качестве выхода может быть не только файл, но и адрес потокового сервера. Например, вам даны видео и путь для доступа к rtmp серверу. Необходимо зациклить видео так, чтобы получилась непрерывная трансляция и застримить её на вышеупомянутый сервер.
input.mp4- видеоrtmp://localhost:1935/stream/input- путь
ffmpeg -re -stream_loop -1 -i input.mp4 -c copy -f flv rtmp://localhost:1935/stream/input
-re– считывает входные данные с собственной частотой кадров-stream_loop -1– Заданное количество раз входной поток будет зациклен.0означает отсутствие цикла,-1означает бесконечный цикл.-f– указывает формат выходного файла
Исходный текст: Покидова А. Ю., 2023