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

311

Я конвертирую 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%

Благодарю.

Камил Хисматуллин
источник
1
Забавно, что люди все еще делают палитры с GIF, когда APNG - вещь.
Константин Ван

Ответы:

447

ffmpeg пример

GIF вывод из ffmpeg
183K

ffmpegможет вывести высокое качество GIF. Всегда рекомендуется использовать последнюю версию: скачать или скомпилировать .

ffmpeg -ss 30 -t 3 -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
  • Этот пример пропустит первые 30 секунд ( -ss 30) ввода и создаст 3 секунды вывода ( -t 3).
  • Фильтр fps устанавливает частоту кадров.
  • Масштабный фильтр изменит размер выходного изображения до 320 пикселей в ширину и автоматически определит высоту, сохранив соотношение сторон.
  • Фильтры palettegen и paletteuse будут генерировать и использовать пользовательскую палитру, сгенерированную из вашего ввода.
  • Разделенный фильтр позволит сделать все одной командой.
  • Контроль зацикливания с -loopвозможностью вывода. Значение 0бесконечного цикла.

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


convertПример ImageMagick

GIF вывод из ffmpeg
227k

Другой метод командной строки - это передача из ffmpegto convert(или magick) из ImageMagick.

 ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos" -c:v pam -f image2pipe - | convert -delay 10 - -loop 0 -layers optimize output.gif

Установка частоты кадров

Установите частоту кадров с помощью комбинации fpsфильтров в ffmpegи -delayв convert. Это может быть сложно, потому что convertпросто получает сырой поток изображений, поэтому не сохраняется fps. Во- вторых, -delayзначение convertв клещами (есть 100 тиков в секунду), а не в кадрах в секунду. Например, с fps=12.5= 100 / 12,5 = 8 = -delay 8.

convertокругляет -delayзначение до целого числа, поэтому 8.4 приводит к 8, а 8.5 - к 9. Это фактически означает, что при установке равномерной задержки для всех кадров поддерживаются только некоторые частоты кадров (конкретная задержка может быть установлена ​​для каждого кадра, но она превышает этот ответ).

-delayПо-видимому, игнорируется, если используется в качестве параметра вывода, поэтому его необходимо использовать до того, -как показано в примере.

Наконец, браузеры и средства просмотра изображений могут реализовывать минимальную задержку, так что вы -delayвсе равно можете проигнорировать.

Видео любезно предоставлено Национальным центром по охране природы Службы охраны рыб и дикой природы США.

llogan
источник
4
Добавлены некоторые примеры результатов (только кадры). Здесь первый файл составляет 4,1 МБ, второй - около 8 МБ.
Slhck
2
@LordNeckbeard, ты потрясающий! Большое спасибо за-vf scale=320:-1,format=rgb8,format=rgb24
Камил Хисматуллин
6
Кстати, для convertкоманды для преобразования из кадров PNG я в конечном итоге использовал convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", что немного уменьшает общий размер файла
Уилф
2
Хорошо, у меня есть, я использовал scale=0:-1, поэтому, когда вы установите масштаб 0, он будет брать масштаб из видео.
Муса Альфайли
2
Эти вопросы и ответы должны быть постоянно закодированы в томе (или, может быть, на данный момент просто «закреплены»), потому что через сто лет вся связь будет осуществляться через мемы. Я думаю, что активность на этом посте говорит только об этом.
Джонатан Нойфельд
87

Если вы предпочитаете избегать промежуточных файлов изображений, команды, предоставляемые LordNeckBeard, могут передаваться между ffmpegImageMagick и convertтак, чтобы промежуточные файлы не требовались:

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

Он -f image2pipeсообщает ffmpeg разделить видео на изображения и сделать его пригодным для передачи по конвейеру, а также -vcodec ppmуказывает формат вывода ppm (по какой-то причине, если формат png, либо convertне читает все изображения из канала, либо ffmpeg делает не выводить их всех). Для -обеих команд указывает, что канал будет использоваться для вывода и ввода соответственно.

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

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

gif:-Говорит convertк трубе его выход , как GIF данные в формате , и -layers Optimizeговорит вторая convertдля выполнения optimize-frameи optimize-transparancyметоды (см ImageMagick Введение в анимации оптимизации ). Обратите внимание, что выходные данные -layers Optimizeмогут не всегда обеспечивать меньший размер файла, поэтому вы можете попробовать сначала преобразовать его в gif без оптимизации, чтобы быть уверенным.

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

notedible
источник
1
Этот набор команд также работает сavconv
Raphael
Вы должны объединить две последние команды конвертации:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément
GIF, кажется, работает в 2 раза быстрее исходного видео?
Титан
@Titan верят, что в первой команде это -r 10, а во второй - -delay 5. Я также изменил задержку на 10, и теперь кажется, что она играет нормально.
Стивен Хуанг
2
Вы также можете избежать промежуточных файлов изображений, используя 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
пайпить
37

Начиная с 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

PJE
источник
18

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

Запуск ./gifenc.sh input.mov output.gif 720 10будет выводить GIF 10pps шириной 720p из фильма, который вы дали. Возможно, вам придется сделать chmod +x gifenc.shдля файла.

#!/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"

Вы можете прочитать подробности на моем Github

Предположения: ffmpeg установлен, и скрипт находится в той же папке, что и другие файлы.

thevangelist
источник
3
Большое спасибо за ваш сценарий. Я только что проверил это, и он прекрасно работает!
Орширо
15

Ответ от @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
alijandro
источник
Если я правильно понимаю, вы разделяете входные данные на o1 и o2 и копируете o2 в o3. Так зачем тебе o3? Почему бы просто не использовать o2 напрямую?
Хлоя
1
@Chloe Вы видели работу fifoфильтра между o2и o3? Чтобы избежать Buffer queue overflowпредупреждения.
Алиандро
+1 Это работает очень хорошо для меня (и решил проблему, на которую ссылаются).
Иэн Коллинз
Я очень люблю это решение. Престижность!
Леонид Усов
10

сделал скрипт, протестировал и работает.

использование:

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

ИМЕЙТЕ ФАН :)

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

кстати: vokoscreen - ОТЛИЧНЫЙ инструмент для захвата экрана для Linux :)

СПАСИБО МНОГО Майкл Кохаупт :) Рок устойчиво.

некоторая статистика по размеру файла:

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

увидеть результаты здесь.

ласкаться
источник
10

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фильтру.

Stephane
источник
10

Linux / Unix / MacOS

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

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

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

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

video2gif input.flv

или же:

video2gif input.flv 320 10

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

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


Macos

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


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

kenorb
источник
Ваш скрипт вызывает ошибку из-за отсутствия png-файла, и я не получаю вывод gif, но входной файл .mp4 остается неизменным
lacostenycoder
7

Выбранный ответ предполагает, что вы хотите масштабировать исходное видео и изменять его 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

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

Jet Blue
источник
6

Для пользователей Windows:
создайте video2gif.batфайл в каталоге Windows со следующим содержимым:

@echo off
set arg1=%1
set arg2=%arg1:~0,-4%
ffmpeg -y -i %arg1% -vf fps=10,scale=-1:-1:flags=lanczos,palettegen %TEMP%\palette.png
ffmpeg -i %arg1% -i %TEMP%\palette.png -filter_complex "fps=10,scale=-1:-1:flags=lanczos[x];[x][1:v]paletteuse" %arg2%.gif
del /f %TEMP%\palette.png

И тогда везде, где вы можете использовать это, как этот пример:

video2gif myvideo.mp4

Тогда у вас есть myvideo.gifв текущем каталоге.
Если myvideo.gifсуществует, вопрос от вас, чтобы перезаписать его.

РЕДАКТИРОВАТЬ:

Я предлагаю использовать этот пакетный скрипт: https://github.com/NabiKAZ/video2gif

Наби КАЗ
источник
2
Я вижу, что вы сделали здесь две вещи: (1) записали команды в виде командного сценария Windows (.BAT) и (2) предоставили другую комбинацию фильтров (ни один из других ответов не использует оба fps=10 и scale=-1:-1).  Ответ Sun, уже дал нам пакетный файл, и что один (например , сценарии оболочки в ответ ПРД в и ответ thevangelist в ) имеет преимущество , что он присваивает список фильтров переменной ( один раз ), ... (продолжение)
Скотт
1
(Продолжение) ... так что нет необходимости прописывать список дважды (как это делает ваш пакетный файл). (Я предполагаю, что это создает риск того, что, если пользователь отредактирует скрипт, чтобы изменить один из списков, но не другой, несогласованность вызовет проблему.) Можете ли вы хотя бы объяснить свой выбор фильтров ( fps=10,scale=-1:-1)? (См. Заметный ответ для примера объяснения частей команды.)
Скотт,
1
@ Скотт Вы правильно сказали, поэтому я пишу новый полезный сценарий здесь: github.com/NabiKAZ/video2gif
Наби КАЗ
4

Ниже приведен пакетный файл для пользователей 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
солнце
источник
3

Как добавить пункт контекстного меню Windows 7/10 «щелкнуть правой кнопкой мыши», чтобы преобразовать ваш видеофайл в GIF

В некоторых других ответах упоминался скрипт video2gif , который я использовал. Но вы можете использовать любой скрипт.

Чтобы создать опцию контекстного меню, вам нужно отредактировать ваш реестр. Откройте командную строку powershell, запустив w / admin privs. Выполните эти команды:

$key = "Registry::HKEY_CLASSES_ROOT\`*\shell\Run Video2Gif"
New-Item -Path $key"\Command" -Value "C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat `"%1`"" -Force

Теперь, когда вы щелкнете правой кнопкой мыши по файлу, у вас будет опция «Запустить Video2Gif»!

Кстати, я установил ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\и поместил video2gif.batскрипт в папку bin прямо рядом с ffmpeg.exe. Я также добавил C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\binк своим окнам PATH, но я не думаю, что вам нужно.

Если вы хотите иметь возможность предоставлять некоторые дополнительные флаги / аргументы командной строки для сценария, то создайте новый файл с именем video2gif-prompt.batи попросите реестр использовать его вместо video2gif.bat:

@echo off
set /p inp=Enter extrta args, if desired:
C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat %* %inp%

Вы все еще можете просто нажать Enter, чтобы быстро получить значения по умолчанию.

Крис
источник