В прошлом ролике я сделал простое видео из картинки с использованием двух фильтров FFmpeg. Картинка была вертикальная, её размер изменялся по ширине видео и видео заключалось в скролле картинки. Для растягивания картинки я использовал фильтр scale, а для эффекта прокрутки картинки фильтр overlay.
Эти фильтры я буду использовать и в дальнейшем. Но картинки не всегда будут вертикальные, иногда будут горизонтальные и нам будет нужна прокрутка по горизонтали. С этими двумя фильтрами можно добиться и некоторых других эффектов.
Кроме того на примере этих двух простых фильтров можно получше разобраться как работают фильтры в FFmpeg и как работает filter_complex.
В бат файле сегодня появились переносы строк с помощью ^. Раньше я их не использовал, но при больших коммандах без них не удобно. Чтобы не было ошибок надо запомнить — пробел перед ^, а сразу после перенос строки.
Входные и выходные потоки для фильтров FFmpeg
Фильтры получают на вход поток, это может быть аудио или видео поток. Видеопоток это набор кадров. По умолчанию в FFmpeg задано 25 кадров в секунду. Некоторые фильтры обрабатывают поток один раз, некоторые обрабатывают каждый кадр. Входящие потоки указываются в квадратных скобках перед именем фильтра. Это может быть индекс входящего файла (где через двоеточие можно указать взять видео поток или аудиопоток) или тегированный поток после обработки предыдущим фильтром. После обработки потоку можно присвоить тег, который можно использовать для передачи последующему фильтру в цепочке.
Если фильтр первый в цепочке и входных потоков не указано, то берутся первые переданные подходящие фильтру во входящих файлах (-i). Если фильтр не первый, то берется первый предыдущий не тегированный поток.
Если выходящий поток не задан (нет тега в квадратных скобках), то он либо передается следующему фильтру с неуказанными входящими потоками, либо сразу на выход цепочки фильтров для сохранения в файл.
Параметры фильтров FFmpeg
Для использования фильтров в цепочки filter_complex мы указываем эти фильтры через запятую. Перед названием фильтра мы можем указать входные потоки (или можем не указывать см. выше), затем пишем название фильтра, затем знак равно (=), затем аргументы фильтра, затем выходные потоки (см. выше).
Аргументы фильтра, с которыми фильтр может работать и формат их передачи могут отличаться от фильтра к фильтру и лучше их посмотреть в документации к фильтру.
Фильтр может исполнятся один раз на команду, может исполняться каждый фрейм (или секунду), часто в фильтрах такое поведение можно переопределить аргументом eval. Иногда можно использовать математические операции или встроенные функции для расчета аргументов (например в зависимости от номера кадра/секунды) за счет чего и получаются интересные эффекты.
Список поддерживаемых функций здесь .
Фильтр Overlay
Все принимаемые аргументы фильтра Overlay и примеры его использования можно посмотреть по этой ссылке .
Фильтр берет один поток и кладет его сверху другого. В одном фильтре используется только два потока. То есть за одно применение фильтра нельзя наложить сразу больше двух потоков. Для этого нужно строить цепочку (наложили два, передали поток сложенных в следующее применение фильтра overlay и наложили там третий).
Фильтру может быть передана координата расположения наложения от верхнего левого угла кадра. Координату можно менять каждый кадр и пересчитывать наложение, или сделать расчет единожды за одну команду.
Фильтр scale FFmpeg
Официальное описание фильтра здесь.
Фильтр масштабирует картинку для использования в других фильтрах цепочки фильтров filter_complex. Может работать в двух режимах eval — init, когда картинка масштабируется один раз и eval=frame, когда масштаб пересчитывается каждый фрейм. За счет использования режима eval=frame и получается делать некоторые анимационные эффекты с картинками, например. Подробнее в третьем ролике про использование FFmpeg.
Код использованный в финале видео:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
echo "** Hey, Azzrael Youtube viewers!!!" set F11=[1]scale=-1:'if(between(t, 0, 6), 3240-t*(1080/3), 1)':eval=frame[im1] set F12=[1]scale=-1:'if(between(t, 6, 8), 1080, 1)':eval=frame[im2] set F13=[1]scale=-1:'if(between(t, 8, 12), (t-7)*(3240/2), 1)':eval=frame[im3] set F2=[0][im1]overlay=(W-w)/2:(H-h)/2[x1], [x1][im2]overlay=(W-w)/2:(H-h)/2[x2], [x2][im3]overlay=(W-w)/2:(H-h)/2 ffmpeg.exe ^ -f lavfi -i color=c=white:s=1920x1080 -loop 1 ^ -i 22.png ^ -s "1920x1080" -t 12 ^ -filter_complex "%F11%, %F12%, %F13%, %F2%" ^ -y out.mp4 "C:\Program Files\VideoLAN\VLC\vlc.exe" out.mp4 |
Скрипт можно подкорректировать и сделать вот так:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
set F11=[1]scale=-1:3240-t*(1080/3):eval=frame[im1] set F12=[1]scale=-1:1080:eval=frame[im2] set F13=[1]scale=-1:(t-7)*(3240/2):eval=frame[im3] set F2=[0][im1]overlay=(W-w)/2:(H-h)/2:enable='between(t, 0, 6)'[x1], [x1][im2]overlay=(W-w)/2:(H-h)/2:enable='between(t, 6, 8)'[x2], [x2][im3]overlay=(W-w)/2:(H-h)/2:enable='between(t, 8, 12)' ffmpeg.exe ^ -f lavfi -i color=c=white:s=1920x1080 -loop 1 ^ -i 22.png ^ -s "1920x1080" -t 12 ^ -filter_complex "%F11%, %F12%, %F13%, %F2%" ^ -y out.mp4 |
Это избавит от необходимости думать как спрятать скейл и слегка упростит код.
Результат работы скрипта
sotastroy 2020-09-28