Как создать видео из изображений с помощью FFmpeg?

Вопрос или проблема

Возможно ли использовать ffmpeg для создания видео из набора последовательностей, где номер не начинается с нуля?

Например, у меня есть несколько изображений [test_100.jpg, test_101.jpg, test_102.jpg, …, test_200.jpg], и я хочу преобразовать их в видео. Я попробовал следующую команду, но она не сработала (похоже, номер должен начинаться с нуля):

ffmpeg -i test_%d.jpg -vcodec mpeg4 test.avi

Есть ли какие-нибудь советы?

Нет необходимости переименовывать файлы, если использовать параметр -start_number таким образом:

ffmpeg -start_number n -i test_%d.jpg -vcodec mpeg4 test.avi

где n — это начало последовательности изображений.

Обратите внимание, что это будет работать, пока последовательность не прерывается. Если есть пробелы, и вы хотите включить все изображения, то может потребоваться переименование, чтобы заполнить пробелы.

Есть и некоторые другие параметры, которые могут быть полезны.

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

ffmpeg.exe -f image2 -framerate 25 -pattern_type sequence -start_number 1234 -r 3 -i Imgp%04d.jpg -s 720x480 test.avi

Опция -r 3 устанавливает частоту кадров полученного видео в 3 кадра в секунду, так что я могу видеть каждое изображение короткое время. Опция -s изменяет масштаб изображений до желаемого разрешения, чтобы управлять размером полученного видео.

(В командной строке Windows замените -i Imgp%04d.jpg на -i "Imgp%%04d.jpg". За это спасибо Майку Фицпатрику https://superuser.com/a/344178/153054)

Вы можете использовать следующий код:

 cat *.jpg | ffmpeg -f image2pipe -r 1 -vcodec mjpeg -i - -vcodec libx264 out.mp4

С документации ffmpeg:

Использование шаблона glob

ffmpeg также поддерживает глобальные шаблоны в стиле bash (* представляет любое количество любых символов).

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

ffmpeg -r 1 -pattern_type glob -i 'test_*.jpg' -c:v libx264 out.mp4

Таким образом, пока ваши файлы отсортированы, использование параметра -pattern_type glob должно сработать.

Обратите внимание, что кавычки вокруг шаблона важны в случае использования glob.

Вы можете найти пример скрипта в документации ffmpeg:

3.2 Как я могу кодировать одиночные фотографии в фильмы?

Если у вас много изображений для переименования, вы можете использовать следующую команду, чтобы облегчить задачу. Команда, используя синтаксис bourne shell, символически связывает все файлы в текущем каталоге, которые соответствуют *jpg, с каталогом /tmp в последовательности img001.jpg, img002.jpg и так далее.

x=1; for i in *jpg; do counter=$(printf %03d $x); ln "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done

Затем выполните:

ffmpeg -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg

-pattern_type glob конкретные примеры с аудио

Эта опция была упомянута на: https://superuser.com/a/782520/128124, но здесь приведены несколько конкретных примеров её использования, включая добавление аудио в выходное видео.

Слайд-шоу видео с одним изображением в секунду

ffmpeg -framerate 1 -pattern_type glob -i '*.png' \
  -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

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

ffmpeg -framerate 1 -pattern_type glob -i '*.png' -i audio.ogg \
  -c:a copy -shortest -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

Вот два демо на YouTube:

Будьте как хиппи и используйте формат видео Theora без патентов в контейнере OGG:

ffmpeg -framerate 1 -pattern_type glob -i '*.png' -i audio.ogg \
  -c:a copy -shortest -c:v libtheora -r 30 -pix_fmt yuv420p out.ogv

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

0001-first-thing.jpg
0002-second-thing.jpg
0003-and-third.jpg

и так далее.

Я бы также сначала убедился, что все изображения, которые будут использованы, имеют одинаковое соотношение сторон, возможно, предварительно обрезав их с помощью imagemagick или nomacs, так чтобы ffmpeg не пришлось принимать трудные решения. В частности, ширина должна быть четной, иначе преобразование завершится с ошибкой: “ширина не делится на 2”.

Полное реальное исследование случая слайд-шоу шаг за шагом

Создание слайд-шоу требует больше усилий, чем просто выполнение одной команды ffmpeg, поэтому вот более интересный подробный пример, вдохновленный этой хронологией.

Получите входные медиа:

mkdir -p orig
cd orig
wget -O 1.png https://upload.wikimedia.org/wikipedia/commons/2/22/Australopithecus_afarensis.png
wget -O 2.jpg https://upload.wikimedia.org/wikipedia/commons/6/61/Homo_habilis-2.JPG
wget -O 3.jpg https://upload.wikimedia.org/wikipedia/commons/c/cb/Homo_erectus_new.JPG
wget -O 4.png https://upload.wikimedia.org/wikipedia/commons/1/1f/Homo_heidelbergensis_-_forensic_facial_reconstruction-crop.png
wget -O 5.jpg https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Sabaa_Nissan_Militiaman.jpg/450px-Sabaa_Nissan_Militiaman.jpg
wget -O audio.ogg https://upload.wikimedia.org/wikipedia/commons/7/74/Alnitaque_%26_Moon_Shot_-_EURO_%28Extended_Mix%29.ogg
cd ..

# Преобразовать все в PNG для согласованности.
# https://unix.stackexchange.com/questions/29869/converting-multiple-image-files-from-jpeg-to-pdf-format
# Жесткая ссылка на те, которые уже являются PNG.
mkdir -p png
mogrify -format png -path png orig/*.jpg
ln -P orig/*.png png

Теперь мы быстро посмотрим на все размеры изображений, чтобы решить, какое соотношение сторон будет финальным:

identify png/*

что выводит:

png/1.png PNG 557x495 557x495+0+0 8-bit sRGB 653KB 0.000u 0:00.000
png/2.png PNG 664x800 664x800+0+0 8-bit sRGB 853KB 0.000u 0:00.000
png/3.png PNG 544x680 544x680+0+0 8-bit sRGB 442KB 0.000u 0:00.000
png/4.png PNG 207x238 207x238+0+0 8-bit sRGB 76.8KB 0.000u 0:00.000
png/5.png PNG 450x600 450x600+0+0 8-bit sRGB 627KB 0.000u 0:00.000

поэтому классическое соотношение 480p (640×480 == 4/3) кажется подходящим.

Выполните одно преобразование с минимальным изменением размера, чтобы сделать ширину равной (TODO автоматизировать для любой ширины, здесь я просто вручную посмотрел на вывод identify и уменьшил ширину и высоту на один):

mkdir -p raw
convert png/1.png -resize 556x494 raw/1.png
ln -P png/2.png png/3.png png/4.png png/5.png raw
ffmpeg -framerate 1 -pattern_type glob -i 'raw/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p raw.mp4

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

ffprobe raw.mp4

ffmpeg просто берет размер первого изображения, 556×494, а затем преобразует все остальные в этот точный размер, нарушая их соотношение сторон.

Теперь давайте автоматически преобразуем изображения в целевое соотношение сторон 480p, обрезая, как это указано в https://stackoverflow.com/questions/21262466/imagemagick-how-to-minimally-crop-an-image-to-a-certain-aspect-ratio

mkdir -p auto
mogrify -path auto -geometry 640x480^ -gravity center -crop 640x480+0+0 png/*.png
ffmpeg -framerate 1 -pattern_type glob -i 'auto/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p auto.mp4

Теперь соотношение сторон хорошее, но неизбежно произошло некоторое обрезание, что, конечно, разрушило интересные части изображений.

Другой вариант — это обложка черным фоном, чтобы иметь то же самое соотношение сторон, как показано на: https://stackoverflow.com/questions/18514083/resize-to-fit-in-a-box-and-set-background-to-black-on-empty-part/18514327

mkdir -p black
mogrify -path black -thumbnail 640x480 -background black -gravity center -extent 640x480 png/*.png
ffmpeg -framerate 1 -pattern_type glob -i 'black/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p black.mp4

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

О параметрах командной строки

Обратите внимание, однако, что несмотря на название, -glob это не так уж и универсально, как шаблоны оболочки. Например: -i '*' не срабатывает: https://trac.ffmpeg.org/ticket/3620 (похоже, потому что тип файла определяется по расширению).

-r 30 устанавливает видео с -framerate 1 на 30 FPS, чтобы преодолеть ошибки в плеерах, таких как VLC, для низкой частоты кадров: https://stackoverflow.com/questions/19267443/playback-issues-in-vlc-with-low-fps-video-from-images-using-ffmpeg/41797724#41797724. Таким образом, он повторяет каждый кадр 30 раз, чтобы сохранить желаемый эффект одной картинки в секунду.

Следующие шаги

Вам также потребуется:

  • вырезать часть аудиодорожки, которую вы хотите, перед объединением: https://stackoverflow.com/questions/18444194/cutting-the-videos-based-on-start-and-end-time-using-ffmpeg

    ffmpeg -i in.mp3 -ss 03:10 -to 03:30 -c copy out.mp3
    

    В качестве альтернативы, вы также можете обрезать это прямо в команде преобразования, добавив -ss сразу перед аудио -i:

    ffmpeg -framerate 1 -pattern_type glob -i 'raw/*.png' -ss 0:36 -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p raw.mp4
    

TODO: научиться обрезать и конкатенировать несколько аудиофайлов в видео без промежуточных файлов, я почти уверен, что это возможно:

Видео нормальной скорости с одним изображением на кадр при 30 FPS

ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
  -c:v libx264 -pix_fmt yuv420p out.mp4

Вот как это выглядит:

GIF, сгенерированный с помощью: https://askubuntu.com/questions/648603/how-to-create-an-animated-gif-from-mp4-video-via-command-line/837574

Добавьте к этому аудио:

ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
  -i audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4

Результат: https://www.youtube.com/watch?v=HG7c7lldhM4

Преобразовать один аудиофайл в видео с фиксированным изображением для загрузки на YouTube

Ответ на: Как преобразовать MP3 в видеоформат, разрешенный YouTube?

Получить некоторые синтетические тестовые входные изображения

Это тестовые изображения, которые я использовал в этом ответе:

wget -O opengl-rotating-triangle.zip https://github.com/cirosantilli/media/blob/master/opengl-rotating-triangle.zip?raw=true
unzip opengl-rotating-triangle.zip
cd opengl-rotating-triangle
wget -O audio.ogg https://upload.wikimedia.org/wikipedia/commons/7/74/Alnitaque_%26_Moon_Shot_-_EURO_%28Extended_Mix%29.ogg

Изображения созданы с помощью: https://stackoverflow.com/questions/3191978/how-to-use-glut-opengl-to-render-to-a-file/14324292#14324292

Интересно наблюдать, насколько хорошо видео сжимает последовательность изображений гораздо лучше, чем ZIP, так как оно способно сжимать между кадрами с помощью специализированных алгоритмов:

  • opengl-rotating-triangle.mp4: 340K
  • opengl-rotating-triangle.zip: 7.3M

О параметрах командной строки

Обратите внимание, однако, что несмотря на название, -glob, это не так уж общий, как шаблоны оболочки. Например: -i '*' не срабатывает: https://trac.ffmpeg.org/ticket/3620 (похоже, потому что тип файла определяется по расширению).

-r 30 устанавливает видео с -framerate 1 на 30 FPS, чтобы преодолеть ошибки в проигрывателях, таких как VLC, для низких частот кадров: https://stackoverflow.com/questions/19267443/playback-issues-in-vlc-with-low-fps-video-from-images-using-ffmpeg/41797724#41797724. Таким образом, он повторяет каждый кадр 30 раз, чтобы сохранить желаемый эффект одной картинки в секунду.

Следующие шаги

Вам также потребуется:

TODO: научиться обрезать и конкатенировать несколько аудиофайлов в видео через командную строку:

Проверено на

ffmpeg 3.4.4, vlc 3.0.3, Ubuntu 18.04.

Библиография

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

Также, как указано в комментариях к моему ответу, помните, что вам нужно указать ширину вашего индекса. Например:

image%03d.jpg

И если вы используете тип индекса %03d, вам нужно дополнить имена файлов нулями, например :

image001.jpg
image002.jpg
image003.jpg

и так далее.

Я согласен с Франциско, но в качестве обходного пути вы могли бы просто написать быстрый скрипт, чтобы переместить или создать символические ссылки на файлы с последовательными номерами, которые нужны ffmpeg. Затем скрипт мог бы вызвать ffmpeg и затем удалить ссылки или вернуть файлы на свои места.

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

cat {0032..1501}*.png | ffmpeg -f image2pipe -framerate 5 -i - -s 720x480 test2.avi

Причина, по которой я использовал подобную команду, заключается в том, что…

  1. Cat и -f image2pipe дают вам более тонкий контроль над тем, какие изображения вы используете. Например, это позволяет использовать функции bash, такие как расширение скобок, и другие команды, такие как grep, для тонкой настройки ваших результатов, если вы решите.
  2. Меньше параметров для запоминания.
  3. Я рекомендую не использовать -r, а просто использовать -framerate. По моему опыту, -r чаще приводит к потере кадров.
  4. Меньше сложностей, никаких ненужных параметров, и он будет работать как есть. Вы можете добавить больше сложности (например, указав кодировщик) и настроить его под свои нужды.

посмотрите

x=1; for i in *jpg; do counter=$(printf %03d $x); ln "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done

Я использовал кодировщик flv, так как моё видео шло в flash-плеер (Jwplayer)

ffmpeg -i %d.jpg -vcodec flv test.flv

Согласно документации, вы можете просто использовать *

Для создания видео из имен файлов, соответствующих шаблону glob foo-*.jpeg:

ffmpeg -f image2 -pattern_type glob -framerate 12 -i 'foo-*.jpeg' -s WxH foo.avi

Как заметка, для повышения качества может быть важна частота кадров (например, сначала укажем очень низкую/высокую частоту кадров, а затем перейдем во второй фильтр, который сделает замедленное видео нормальным?)

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

$ ls | head -5
2014_aq_unprocessed 001.jpg
2014_aq_unprocessed 002.jpg
2014_aq_unprocessed 003.jpg
2014_aq_unprocessed 004.jpg
2014_aq_unprocessed 005.jpg

а вот команда, которую я использовал:

ffmpeg -i 2014_aq_unprocessed\ %3d.jpg  -vcodec mpeg4 test.avi

Вы можете сделать это с помощью convert -morph:

convert *.jpg -delay 10 -morph 10 %05d.jpg

Если вы хотите использовать ffmpeg, я использовал

ffmpeg -pattern_type glob -i '*.jpg' -vf "setpts=10*PTS" movie.mp4

где 10*PTS указывает ffmpeg замедлить его в 10 раз. Вы также можете использовать дробные значения для ускорения.

Ответ или решение

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

Основные варианты

  1. Использование параметра -start_number

    Если ваши изображения имеют последовательно увеличивающиеся индексы, но не начинаются с нуля, вы можете использовать параметр -start_number, чтобы указать, с какого числа начинаются ваши изображения. Например, если ваши изображения называются test_100.jpg, test_101.jpg и т.д., вы можете выполнить следующее:

    ffmpeg -start_number 100 -i test_%d.jpg -vcodec mpeg4 test.avi

    Этот способ работает, если последовательность изображений непрерывна.

  2. Использование шаблонов glob

    Если ваши изображения могут не следовать строгой нумерации или состоят в произвольном порядке, FFmpeg поддерживает использование шаблонов glob. Например, если ваши файлы называются test_100.jpg, test_101.jpg и т.д., можно использовать:

    ffmpeg -r 1 -pattern_type glob -i 'test_*.jpg' -c:v libx264 -pix_fmt yuv420p out.mp4

    Здесь -r задает частоту кадров, а -pix_fmt определяет используемый пиксельный формат.

  3. Использование image2pipe для тонкой настройки

    Еще один способ создать видео — это использовать image2pipe. Это позволяет вам более точно контролировать, какие изображения вы будете использовать. Например:

    cat *.jpg | ffmpeg -f image2pipe -r 1 -vcodec mjpeg -i - -vcodec libx264 out.mp4

    Это даёт вам возможность использовать функционал Shell для фильтрации изображений перед обработкой.

Дополнительные параметры

  • Частота кадров: Используйте -framerate для указания частоты кадров, как показано выше.

  • Изменение размера: При необходимости, используйте -s для задания размера выходного видео, например:

    ffmpeg -framerate 1 -pattern_type glob -i 'test_*.jpg' -s 1280x720 -c:v libx264 out.mp4
  • Добавление аудио: Вы также можете добавить аудиотрек в ваше видео:

    ffmpeg -framerate 1 -pattern_type glob -i 'test_*.jpg' -i audio.mp3 -c:v libx264 -c:a aac -shortest out.mp4

Обработка изображений перед созданием видео

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

mogrify -resize 1280x720 *.jpg

Примечание

  • Убедитесь, что у вас установлена последняя версия FFmpeg для доступа ко всем функциям.
  • При использовании шаблонов glob важно оборачивать ваш шаблон в одинарные кавычки, чтобы избежать интерпретации оболочкой.

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

Оцените материал
Добавить комментарий

Капча загружается...