Как конвертировать видео в GIF с использованием ffmpeg, с приемлемым качеством?

192115
Kamil Hismatullin

Я конвертирую FLVфильм в GIFфайл с помощью ffmpeg.

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000 output.gif 

Он прекрасно работает, но выходной GIF-файл имеет очень низкое качество.

Любые идеи, как я могу улучшить качество конвертированного GIF?

Вывод команды:

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000 output.gif 
ffmpeg version 0.8.5-6:0.8.5-0ubuntu0.12.10.1, Copyright (c) 2000-2012 the Libav developers built on Jan 24 2013 14:52:53 with gcc 4.7.2 *** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead. Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.flv': Metadata: major_brand : mp42 minor_version : 0 compatible_brands: isommp42 creation_time : 2013-02-14 04:00:07 Duration: 00:00:18.85, start: 0.000000, bitrate: 3098 kb/s Stream #0.0(und): Video: h264 (High), yuv420p, 1280x720, 2905 kb/s, 25 fps, 25 tbr, 50 tbn, 50 tbc Metadata: creation_time : 1970-01-01 00:00:00 Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16, 192 kb/s Metadata: creation_time : 2013-02-14 04:00:07 [buffer @ 0x92a8ea0] w:1280 h:720 pixfmt:yuv420p [scale @ 0x9215100] w:1280 h:720 fmt:yuv420p -> w:320 h:240 fmt:rgb24 flags:0x4 Output #0, gif, to 'output.gif': Metadata: major_brand : mp42 minor_version : 0 compatible_brands: isommp42 creation_time : 2013-02-14 04:00:07 encoder : Lavf53.21.1 Stream #0.0(und): Video: rawvideo, rgb24, 320x240, q=2-31, 200 kb/s, 90k tbn, 10 tbc Metadata: creation_time : 1970-01-01 00:00:00 Stream mapping: Stream #0.0 -> #0.0 Press ctrl-c to stop encoding frame= 101 fps= 32 q=0.0 Lsize= 8686kB time=10.10 bitrate=7045.0kbits/s dup=0 drop=149  video:22725kB audio:0kB global headers:0kB muxing overhead -61.778676% 

Благодарю.

258

12 ответов на вопрос

390
LordNeckbeard

ffmpegТеперь можно выводить более качественный GIF. Если вы используете более старую сборку, подумайте о загрузке последней статической сборки или компиляцииffmpeg .

ffmpeg пример

gif with ffmpeg
203K

Этот пример пропустит первые 30 секунд ввода и создаст 3 секунды вывода. Он масштабирует вывод до 320 пикселей в ширину и автоматически определяет высоту, сохраняя соотношение сторон. В palettegenи paletteuseфильтры будут генерировать и использовать пользовательскую палитру генерируемый из источника.

  1. Создайте палитру:

    ffmpeg -y -ss 30 -t 3 -i input.flv \ -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png 
  2. Выведите GIF, используя палитру:

    ffmpeg -ss 30 -t 3 -i input.flv -i palette.png -filter_complex \ "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif 

Посмотрите Высокое качество GIF с FFmpeg для многих других примеров и опций.


convert пример

Другой метод командной строки - экспортировать фильм в кадры, используя, а ffmpegзатем создать GIF с помощью convertImageMagick (или GraphicsMagick).

ffmpeg and convert
246k

  1. Экспорт кадров:

     mkdir frames ffmpeg -i input -vf scale=320:-1:flags=lanczos,fps=10 frames/ffout%03d.png 
  2. Затем используйте convert(или, gm convertесли вы предпочитаете GraphicsMagick), чтобы сделать анимированный GIF:

     convert -loop 0 frames/ffout*.png output.gif 

С помощью convertвы можете контролировать задержку между кадрами -delayпри желании.

Добавлены некоторые примеры результатов (только кадры). Здесь первый файл составляет 4,1 МБ, второй - около 8 МБ. slhck 11 лет назад 4
@LordNeckbeard, ты потрясающий! большое спасибо за `-vf scale = 320: -1, format = rgb8, format = rgb24` Kamil Hismatullin 11 лет назад 2
@LordNeckbeard - опция `convert` сработала блестяще - также с использованием древней версии ffmpeg напрямую получен размер файла 300 Мб с выводом мусора, в то время как высококачественный конверт был 13 Мб ... Wilf 9 лет назад 0
Кстати, для команды `convert` для конвертации из кадров PNG я в итоге использовал` convert -delay 5 -loop 0 -dither None -colors 80 "frames / ffout * .png" -fuzz "40%" -layers OptimizeFrame "output.gif" `, который немного уменьшает общий размер файла Wilf 9 лет назад 5
Я думаю, что команда `convert` должна использовать` -delay 10` (0,1 секунды между кадрами), чтобы соответствовать частоте кадров `-r 10` (10 кадров в секунду), которую вы подаете в` ffmpeg`. Когда я использую `-delay 5`, я вижу, как gif играет на двойной скорости. Jack O'Connor 9 лет назад 1
Возможно ли обрезать несколько пикселей из полученного GIF? Мне нравится этот забавный GIF из реальных сцен из фильмов / мультфильмов, но я нашел один с плохим качеством, в котором верх ... 5 см, более или менее, поврежден. Если мне нужно открыть новую тему, я с удовольствием Bruno Augusto 7 лет назад 0
Браво! Я использовал «пример ffmpeg» для преобразования записи CamStudio моего экрана, показывающей восстановление четности RAID5 массива RAID5 флэш-накопителя. Восстановление заняло около часа. За это время я преобразовал вывод в текстовый файл. Видео было фактически записью моего разбора текста. AVI был 1,4 ГБ; GIF был 2,5 МБ. user38537 7 лет назад 0
Во втором подходе вы можете использовать ffmpeg вместо imagick. Все, что вам нужно сделать, это использовать параметр ** framrate ** демультиплексора image2, чтобы вы могли установить задержку между отдельными кадрами: `ffmpeg -framerate -i frames / ffout * .png output.gif` Gergely Lukacsy 7 лет назад 0
Ваш пример ffmpeg стал для меня достаточно распространенным рабочим процессом, и я написал скрипт-оболочку bash для его автоматизации. Поделиться здесь: https://github.com/jordanh/ffmpeg2gif Jordan 7 лет назад 0
Как, если я не хочу устанавливать масштаб, мне нужно сделать его автоматически масштабом видео? Mousa Alfhaily 6 лет назад 0
Хорошо, я понял, я использовал `scale = 0: -1`, поэтому, когда вы устанавливаете масштаб в` 0`, он будет брать масштаб из видео. Mousa Alfhaily 6 лет назад 2
Giphy Engineering недавно выпустила хорошую статью, объясняющую все варианты: https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg Marcus Mangelsdorf 6 лет назад 0
@LordNeckbeard Как я могу изменить ваш код, скажем, из определенного интервала фильма, скажем, между 00:24:45 до 00:25:52? Я попытался использовать команду поиска, и она не сработала! Можете ли вы помочь мне с этим? Я хотел бы знать, как заставить это работать с палитрой, которую вы говорите, чтобы сделать и использовать ffmpeg для создания из этого GIF. Кстати, я использовал код, как вы упомянули, и он работает, но брать образец с более длинных интервалов, как я упоминал, не очень практично, так как мне приходится переводить минуты или часы в секунды. Chris Steinbeck Bell 5 лет назад 0
@LordNeckbeard Также частота кадров, которую вы используете, как вы получили ?. Это происходит из входного фильма или это просто случайное значение, которое вы выбрали? Chris Steinbeck Bell 5 лет назад 0
@ChrisSteinbeckBell Я выбрал достаточно низкое значение, чтобы уменьшить размер файла GIF, но достаточно высокое, чтобы оно выглядело приемлемым. Вам просто придется экспериментировать в зависимости от вашего контента. LordNeckbeard 5 лет назад 0
@LordNeckbeard Спасибо за ответ, но я был бы признателен, если бы вы помогли мне с частью кода, касающейся времени, так как я не настолько умен, чтобы делать эту модификацию самостоятельно. Как я уже упоминал, я пытался использовать команду поиска, так как документация ffmpeg предлагает путь от -ss 00:24:25 до 00:25:52. Chris Steinbeck Bell 5 лет назад 0
@LordNeckbeard сразу после ввода, но я не могу заставить ffmpeg интерпретировать команду так, как мне нужно, возможно, вы можете мне помочь с этим ?. Я был бы очень благодарен. Chris Steinbeck Bell 5 лет назад 0
@ChrisSteinbeckBell Может быть стоит задать этот вопрос как новый вопрос, и я или кто-то другой может помочь. Комментарии могут быть слишком ограниченными. LordNeckbeard 5 лет назад 0
Попытка самой первой команды - сгенерировать палитру (с ffmpeg-4.0.1): `Option 'flags' not found`. ffmpeg был бы намного полезнее, если бы разработчики знали концепцию обратной совместимости ... Mikhail T. 5 лет назад 0
@MikhailT. Работает для меня. Пожалуйста, покажите вашу фактическую команду и полный журнал. Вы можете использовать сайт pastebin и предоставить ссылку здесь. LordNeckbeard 5 лет назад 0
Эээ, не бери в голову. Я попытался удалить часть `scale = 360`, но это не сработало. Не знаю, почему ... Mikhail T. 5 лет назад 0
@MikhailT. Полная часть масштаба: `scale = 320: -1: flags = lanczos`. `Флаги` - это опция для масштабирования. Я, вероятно, не должен был включать это в пример, поскольку это увеличило сложность примера. LordNeckbeard 5 лет назад 1
Эти вопросы и ответы должны быть постоянно закодированы в томе (или, может быть, на данный момент просто «закреплены»), потому что через сто лет все общение будет осуществляться через мемы. Я думаю, что активность на этом посте говорит только об этом. Jonathan Neufeld 5 лет назад 1
80
notedible

If you would prefer to avoid intermediate image files, the commands provided by LordNeckBeard can be piped between ffmpeg and ImageMagick's convert so that no intermediate files are required:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - output.gif 

The -f image2pipe tells ffmpeg to split the video into images and make it suitable to be piped out, and -vcodec ppm specifies the output format to be ppm (for some reason if the format is png, either convert does not read all the images from the pipe, or ffmpeg does not output them all). The - for both commands specifies that a pipe will be used for output and input respectively.

To optimize the result without saving a file, you can pipe the output from convert to a second convert command:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - gif:- | convert -layers Optimize - output.gif 

The gif:- tells convert to pipe its output as gif formatted data and -layers Optimize tells the second convert to perform optimize-frame and optimize-transparancy methods (see the ImageMagick Introduction to Animation Optimization). Note that the output from the -layers Optimize may not always provide a smaller file size, so you may want to try converting to a gif without optimization first to be sure.

Remember that during this whole process everything is in memory so you may need sufficient memory if the images are quite large.

Этот набор команд также работает с `avconv` raphael 8 лет назад 1
Вам следует объединить две последние команды конвертирования: `convert -delay 5 -loop 0 -layers Optimize - output.gif` Clément 7 лет назад 0
GIF, по-видимому, работает в 2 раза быстрее исходного видео? Titan 7 лет назад 0
@Titan верят, что в первой команде это -r 10, а во второй - -delay 5. Я также изменил задержку на 10, и теперь кажется, что она играет нормально. Steven Huang 7 лет назад 0
Вы также можете избежать промежуточных файлов изображений, используя фильтр `split` в ffmpeg. Нет необходимости передавать что-либо вообще: `ffmpeg -ss 30 -t 3 -i" input.flv fps = 10, scale = 320: -1: flags = lanczos, split [x] [z]; [z] palettegen [ y]; [x] [y] paletteuse "output.gif` Ajedi32 7 лет назад 2
Есть ли способ сохранить весы? Например, мой видеофайл 904: 774. Как мне сделать это без установки `scale = 320: -1`? Есть ли способ автоматизировать это без взрыва размера? Sudhir Khanger 5 лет назад 0
29
pje

Начиная с ffmpeg 2.6, мы можем сделать еще лучше:

palette="/tmp/palette.png" filters="fps=15,scale=320:-1:flags=lanczos"  ffmpeg -i input.flv -vf "$filters,palettegen" -y $palette ffmpeg -i input.flv -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y output.gif 

HT

13
thevangelist

I made my own version of the script, which parameterizes the output resolution and frame rate as well.

Running ./gifenc.sh input.mov output.gif 720 10 will output 720p wide 10fps GIF from the movie you gave it. You might need to do chmod +x gifenc.sh for the file.

#!/bin/sh palette="/tmp/palette.png" filters="fps=$4,scale=$3:-1:flags=lanczos" ffmpeg -v warning -i "$1" -vf "$filters,palettegen" -y "$palette" ffmpeg -v warning -i "$1" -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y "$2" 

You can read the details on my Github

Assumptions: ffmpeg is installed, and the script is in the same folder as the other files.

Большое спасибо за ваш сценарий. Я только что проверил, и это прекрасно работает! orschiro 8 лет назад 2
8
canoodle

made a script, tested and works.

usage:

./avi2gif.sh ./vokoscreen-2015-05-28_12-41-56.avi 

HAVE PHUN :)

vim avi2gif.sh

#!/bin/sh INPUT=$1 # default settings, modify if you want. START_AT_SECOND=0; # in seconds, if you want to skip the first 30 seconds put 30 here LENGTH_OF_GIF_VIDEO=9999999; # in seconds, how long the gif animation should be echo "Generate a palette:" ffmpeg -y -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png echo "Output the GIF using the palette:" ffmpeg -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" $INPUT.gif 

btw: vokoscreen is an EXCELLENT ScreenCapturing tool for Linux :)

THANKS A LOT Michael Kohaupt :) Rock steady.

some file size stats:

5.3M = vokoscreen-2015-04-28_15-43-17.avi -> vokoscreen-2015-05-28_12-41-56.avi.gif = 1013K

see the results here.

8
alijandro

Ответ от @Stephane очень хороший. Но он получит предупреждение, как Buffer queue overflow, dropping.для некоторого видео, и в сгенерированном виде gifпропущен какой-то кадр.

Вот лучшая версия с fifoфильтром, чтобы избежать Buffer queue overflowпри использовании paletteuseфильтра. С помощью splitфильтра можно избежать создания промежуточной палитры PNG-файла.

ffmpeg -i input.mp4 -filter_complex 'fps=10,scale=320:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' out.gif 
Если я правильно понимаю, вы разделяете входные данные на o1 и o2 и копируете o2 в o3. Так зачем тебе o3? Почему бы просто не использовать o2 напрямую? Chloe 5 лет назад 0
@Chloe Вы видели работу фильтра `fifo` между` o2` и `o3`? Чтобы избежать предупреждения о переполнении буфера очереди. alijandro 5 лет назад 0
7
kenorb

Linux / Unix / MacOS

Следуя @LordNeckbeard подходу с ffmpegкомандой, найдите следующую полезную функцию Bash, которую можно добавить в ваш ~/bash_profileфайл:

# Convert video to gif file. # Usage: video2gif video_file (scale) (fps) video2gif() { ffmpeg -y -i "$" -vf fps=$,scale=$:-1:flags=lanczos,palettegen "$.png" ffmpeg -i "$" -i "$.png" -filter_complex "fps=$,scale=$:-1:flags=lanczos[x];[x][1:v]paletteuse" "$".gif rm "$.png" } 

Как только файл загружен ( . ~/.bash_profile), у вас должна появиться новая video2gifкоманда.

Пример использования:

video2gif input.flv 

или же:

video2gif input.flv 320 10 

Масштаб до 320 с шириной 10 кадров в секунду.

Вы также можете указать другой формат видео (например, mp4).


Macos

Вы можете попробовать приложение GIF Brewery, которое может создавать GIF-файлы из видеофайлов.


В качестве альтернативы есть несколько сайтов, которые делают онлайн-конвертацию бесплатно.

6
Stephane

ffmpegС палитрой метод может работать в одной команде, без промежуточного .pngфайла.

ffmpeg -y -ss 30 -t 3 -i input.flv -filter_complex \ "fps=10,scale=320:-1:flags=lanczos[x];[x]split[x1][x2]; \ [x1]palettegen[p];[x2][p]paletteuse" output.gif 

Это можно сделать благодаря splitфильтру.

4
Jet Blue

Выбранный ответ предполагает, что вы хотите масштабировать исходное видео и изменять его fps в произведенном gif. Если вам не нужно это делать, работает следующее:

src="input.flv" dest="output.gif" palette="/tmp/palette.png"  ffmpeg -i $src -vf palettegen -y $palette ffmpeg -i $src -i $palette -lavfi paletteuse -y $dest 

Это пригодилось, когда я хотел подарить подарок, который точно воссоздает исходное видео, которое я использовал.

3
Sun

Ниже приведен пакетный файл для пользователей Windows:

gifenc.bat:

set start_time=0 set duration=60 set palette="c:\temp\palette.png" set filters="fps=15,scale=-1:-1:flags=lanczos" ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette% ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %2 

Источник: высококачественный GIF с FFmpeg: извлечение только образца

Если вы просто хотите использовать одну входную переменную и иметь имя выхода, имеющее только расширение GIF (произносится JIF), используйте вместо этого:

set start_time=0 set duration=60 set palette="c:\temp\palette.png" set filters="fps=15,scale=-1:-1:flags=lanczos" ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette% set var1=%1 set var2=%var1:~0,-4% ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %var2%.gif 

Похожие вопросы