Как объединить несколько видео с переходами (от и к черному) между ними?

Недавно у меня возникла следующая проблема:

Я хотел, используя ffmpeg, объединить несколько видео (со звуком), добавив между ними черные клипы (с нулевым звуком) и, наконец, исчезнуть видео из этих черных клипов ( fade-in ) и этих черных клипов ( fade-out ) .

Схематически, например, с 2 видео:

black (1s) --> part_1 (60s) --> black (3s) --> part_2 (120s) --> black (1s)
            ^                ^              ^                 ^
       (2s-fade-in)     (2s-fade-out)  (2s-fade-in)      (2s-fade-out)

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

Разобравшись, захотел задокументировать свое решение для тех, кто после меня наткнется на подобную проблему :)

Ответы (1)

Итак, вот что я придумал.

Не полностью однострочное решение

1) Создание черных клипов

ffmpeg -f lavfi -i "color=black:s=1920x1080:r=30" \
 -f lavfi -i "anullsrc=r=48000:cl=stereo" \
 -c:v libx264 -c:a aac -t 3 empty_3s.mp4

Используйте фильтры lavfi для создания пустого клипа. Конечно, измените параметры в соответствии с вашими видео и тем, чего вы хотите достичь. Особенно:

  • в первом (видео) исходном фильтре:
    • s(размер) должен соответствовать размеру видео, которые вы хотите объединить.
    • r(частота кадров) также должна соответствовать вашим видео (особенно если вам нужна постоянная частота кадров)
  • во втором (аудио) исходном фильтре:
    • r(частота дискретизации) должна совпадать с частотой звуковых дорожек из видео, которые вы хотите объединить.
    • cl(макет канала) также должен соответствовать звуку из ваших видео.

Выходные параметры (например, кодеки) должны соответствовать параметрам ваших видео. Используйте -tдля установки длины (в секундах) пустого клипа.

2) Объединяйте и затухайте ваши видео, используя сложную графику фильтров.

ffmpeg -i empty_1s.mp4 -i part_1.mp4 -i empty_3s.mp4 -i part_2.mp4 -i empty_1s.mp4 \
 -filter_complex \
  "[1:v] fade=t=in:st=0:d=2, fade=t=out:st=58:d=2 [1v]; \
   [1:a] afade=t=in:st=0:d=2, afade=t=out:st=58:d=2 [1a]; \
   [3:v] fade=t=in:st=0:d=2, fade=t=out:st=118:d=2 [3v]; \
   [3:a] afade=t=in:st=0:d=1, afade=t=out:st=118:d=2 [3a]; \
   [0:v] [0:a] [1v] [1a] [2:v] [2:a] [3v] [3a] [4:v] [4:a] concat=n=5:v=1:a=1 [v] [a]" \
 -map "[v]" -map "[a]" -c:v libx264 -c:a aac output.mp4

Объяснение:

  • мы сначала указываем входные данные ( -i), которые мы будем конкатенировать
  • затем мы устанавливаем сложный фильтр ( -filter_complex), который мы используем для:
    • во- первых, плавное появление и исчезновение наших видео. Для этого мы используем фильтры fade(для видео) и afade(для аудио). Мы указываем начало ( st) и продолжительность ( d) для каждого затухания. Мы выводим результаты с внешними именами ( [1v], [1a]...).
    • затем объедините черные клипы и ранее выцветшие видео, используя concatфильтр. Мы указываем количество входных сегментов n(т. е. количество наборов видео+аудио, в нашем случае 5), которые мы хотим объединить, и количество видео ( v=1) и аудио ( a=1) потоков для вывода.
  • мы mapокончательный вывод в выходные потоки из фильтра concat
  • укажите параметры кодирования на все, что хотите :)

Важные заметки:

  • ваши видео (входы) должны иметь одинаковые характеристики (пиксель и формат образца для видео, частота дискретизации и расположение каналов для аудио). См. документацию concat для получения дополнительной информации.
  • в фильтре затухания мы указываем время начала и продолжительность в секундах, но вы также можете использовать кадры или образцы с параметрами sи n(видео) или ssи ns(аудио). См . документацию по фильтрам затухания и затухания .
  • вы должны знать продолжительность ваших видео для фильтра затухания, особенно для затухания. См. этот вопрос для подсказок о том, как два клипа постепенно исчезают без необходимости вручную указывать время начала.

Истинный однострочный

Если вам действительно нужен однострочный (и вам не нужно кодировать пустые черные клипы), вы можете использовать:

ffmpeg \
 -f lavfi -t 1 -i "color=black:s=1920x1080:r=30" -f lavfi -t 1 -i "anullsrc=r=48000:cl=2" \
 -i part_1.mp4 \
 -f lavfi -t 3 -i "color=black:s=1920x1080:r=30" -f lavfi -t 3 -i "anullsrc=r=48000:cl=2" \
 -i part_2.mp4 \
 -f lavfi -t 1 -i "color=black:s=1920x1080:r=30" -f lavfi -t 1 -i "anullsrc=r=48000:cl=2" \
 -filter_complex \
  "[0:v] null [0v]; [1:a] anull [0a]; [3:v] null [2v]; [4:a] anull [2a]; \
   [6:v] null [4v]; [7:a] anull [4a]; \
   [2:v] fade=t=in:st=0:d=2, fade=t=out:st=58:d=2 [1v]; \
   [2:a] afade=t=in:st=0:d=2, afade=t=out:st=58:d=2 [1a]; \
   [5:v] fade=t=in:st=0:d=1, fade=t=out:st=118:d=2 [3v]; \
   [5:a] afade=t=in:st=0:d=1, afade=t=out:st=118:d=2 [3a]; \
   [0v] [0a] [1v] [1a] [2v] [2a] [3v] [3a] [4v] [4a] concat=n=5:v=1:a=1 [v] [a]" \
 -map "[v]" -map "[a]" -c:v libx264 -c:a aac output.mp4

В этом случае мы должны остерегаться входных индексов , так как черные видеоклипы и нулевые аудиоклипы являются отдельными входными данными (я не понял, как поместить их как два потока в один вход, если у вас есть идея, не стесняйтесь поделиться Это).

nullЗдесь я применил anullфильтры к этим входам, чтобы дать им внешние теги, чтобы использовать согласованные идентификаторы в concatфильтре. Но это чисто опционально.

Надеюсь, это поможет, не стесняйтесь улучшать мое решение с помощью ваших идей :)

Вам не нужно генерировать отдельные входные данные исходного фильтра для пустых видео- и аудиосегментов. Их можно использовать несколько раз в filter_complex.