Как быстро создать анимированные GIF-файлы низкого качества с помощью ffmpeg?

Как быстро создать анимированные GIF-файлы низкого качества с помощью ffmpeg?

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

Вычисление палитры занимает большую часть времени выполнения следующей команды (взято из ответа multi-chain filtergraph здесь):Как эффективно создать gif-анимацию с лучшей палитрой из фрагмента видео прямо из Интернета):

ffmpeg -y -threads 8 -r 24 -f image2 -start_number 1 -i "frames.%04d.jpg" -filter_complex "fps=24,scale=150:-1:flags=fast_bilinear,split=2 [a][b]; [a] palettegen [pal] fifo [b]; [b] [pal] paletteuse" output.gif

Время выполнения этой команды с 1000 кадрами составляет около 72 секунд. Около 67 секунд из них — проход палитры, а затем он проносится через фактическую генерацию GIF примерно за 5 секунд. Я хотел бы максимально сократить общее время выполнения и готов пожертвовать большим количеством качества изображения ради скорости.

решение1

Использование вами фильтров palettegen/ paletteuseзамедляет выполнение команды. Простой способ получить GIF-файл более низкого качества:

ffmpeg -f image2 -i "frames.%04d.jpg" output.gif

С дополнительным масштабированием:

ffmpeg -f image2 -i "frames.%04d.jpg" -vf scale=150:-1 output.gif

Вы также можете пропустить кадры в выходном GIF, т.е. сделать выборку кадров, чтобы не все они обрабатывались. Например, чтобы иметь только 1 FPS на выходе, используя фильтр fps:

ffmpeg -i "frames.%04d.jpg" -vf "fps=fps=1,scale=150:-1" output.gif

решение2

Мне было поручено сократить время, необходимое для создания анимированного GIF-анимации, максимально приблизившись к 30 кадрам в длину при ширине 150 пикселей. Большинство последовательностей, которые мы генерируем, имеют длину менее 1000 кадров. У нас была последовательность из 15 000 кадров, и наши узлы рендеринга занимали17 минутдля создания этого GIF-файла из ~30 кадров, что неприемлемо медленно.

Мы использовали ffmpeg в качестве демультиплексора и передавали поток в imagemagick. После нескольких часов экспериментов я пришел к следующим выводам:

  • Количество входных кадров, которые вы просите обработать ffmpeg, равноДАЛЕКОнаиболее эффективный ввод с точки зрения скорости выполнения. Если использование concat demuxer для пропуска кадров ввода является опцией, это даст наибольшую разницу в производительности. Взяв каждый 5-й кадр, я смог сократить общее время вычислений до1 минута 45 секундс высококачественным масштабированием Ланцоша и покадровым вычислением палитры.Создание миниатюры предварительного просмотра из 30 кадров теперь занимает менее 1 секунды..

  • Алгоритм масштабирования был следующим по величине фактором, влияющим на производительность (но далеко вторым). Использование fast_bilinear вместо lanczos сэкономило 150 секунд вычислительного времени для всех 15 000 кадров.

  • Наименее влиятельной переменной было вычисление палитры, и оно менялось в зависимости от алгоритма изменения масштаба. Более 15 000 кадров с использованием lanczos, мы сэкономили около 17 секунд времени выполнения, если исключили вычисление палитры. Используя fast_bilinear, мы сэкономили около 75 секунд времени выполнения.

Поскольку алгоритм масштабирования и вычисление палитры были незначительными, мы в итоге сохранили их на самом высоком уровне качества. Мы сократили время вычислений с 17 минут до менее 1 секунды, в основном за счет того, что сказали ffmpeg пропустить чтение входных файлов.

КЛЮЧЕВОЙ ВЫВОД: ПРОПУСК ВХОДНЫХ КАДРОВ против ПРОПУСКА ВЫХОДНЫХ КАДРОВ

Причина, по которой наш процесс занял так много времени, заключается в том, что пропуск кадров не помогает сократить время выполнения при использовании демультиплексора image2. Если вы накосячите с флагом -rи fpsфильтром, вы повлияете на количество кадров, которые появятся в конечном GIF, но ffmpeg, похоже, все равно что-то делает со всеми 15 000 входных кадров.

Единственный способ, который я смог найти, чтобы ffmpeg пропускал входные кадры, — это использование демультиплексора concat.

Вот как я теперь создаю высококачественные анимированные миниатюры GIF на своей машине разработчика менее чем за 1 секунду, пропуская входные кадры:

# create text file which describes the ~30 input frames we want ffmpeg to process
seq -f "file 'left_frames.%04g.jpg'" 10000 500 25000 > tmp.txt

# generate the animated gif using ffmpeg only
ffmpeg -f concat -i tmp.txt -filter_complex "scale=150:-1:flags=lanczos,split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" output.gif

Связанный контент