Як перетворити відео в GIF за допомогою ffmpeg з розумною якістю?


310

Я перетворюю 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 для багатьох інших прикладів та варіантів.


Imagemagick convertприклад

GIF вихід з ffmpeg
227k

Інший метод командного рядка для труби від ffmpegдо 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просто отримується необроблений потік зображень, тому не зберігається кадрів в секунду. По-друге, -delayзначення in convertє в тиках (є 100 тиків в секунду), а не в кадрах на секунду. Наприклад, при fps=12.5= 100 / 12,5 = 8 = -delay 8.

convertокругляє -delayзначення на ціле число, тому 8,4 призводить до 8 та 8,5 результатів у 9. Це ефективно означає, що підтримуються лише деякі частоти кадрів при встановленні рівномірної затримки для всіх кадрів (конкретна затримка може бути встановлена ​​на кадр, але це виходить ця відповідь).

-delayЗдається, ігнорується, якщо використовується як вихідний параметр, тому його потрібно використовувати раніше, -як показано в прикладі.

Нарешті, веб-переглядачі та переглядачі зображень можуть впроваджувати мінімальну затримку, тому ви -delayвсе одно можете ігнорувати.

Відео надано Національним навчальним центром з охорони риби та дикої природи США.


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, він зніме масштаб з відео.
Mousa Alfhaily

2
Це питання повинні бути постійно закодовані у томе (або, можливо, поки що просто "приколото"), оскільки через сто років все спілкування буде здійснюватися через меми. Я думаю, що про це говорить лише діяльність на цій посаді.
Джонатан Нойфельд

87

Якщо ви хочете уникати проміжних файлів зображень, команди, надані LordNeckBeard, можна переносити між зображеннями ffmpegі ImageMagick, 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визначає формат виведення бути частин на мільйон (за якою - то причини , якщо формат 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 без оптимізації спочатку, щоб бути впевненим.

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


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


18

Я створив власну версію сценарію, яка також параметризує вихідну роздільну здатність і частоту кадрів.

Запуск ./gifenc.sh input.mov output.gif 720 10буде виводити GIF з 720p шириною 10 кадрів в секунду з фільму, який ви йому дали. Можливо, вам доведеться зробити 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 встановлений, а сценарій знаходиться в тій самій папці, що й інші файли.


3
Дуже дякую за ваш сценарій. Я просто перевірив це, і він чудово працює!
orschiro

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

Якщо я правильно це розумію, ви розділяєте вхід на 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

btw: 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фільтру.


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 з відеофайлів.


Крім того, є кілька веб-сайтів, які здійснюють конверсію в Інтернеті безкоштовно.


ваш сценарій викликає у мене помилку про відсутність png-файлу, і я не отримую gif-виводу, але вхідний файл .mp4 залишається незмінним
lacostenycoder

7

Вибрана відповідь передбачає, що ви бажаєте масштабувати вихідне відео та змінити його кадрів в секунду у створеному 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

Це було корисно, коли я хотів подарувати подарунок, який сумлінно відтворив вихідне відео, яке я використовував.


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
@Scott Ви сказали правильно, тому я пишу новий корисний сценарій тут: github.com/NabiKAZ/video2gif
Nabi KAZ

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 , який я використав. Але ви можете використовувати будь-який сценарій.

Щоб створити параметр контекстного меню, вам потрібно відредагувати свій реєстр. Відкрийте командний рядок powerhell, запустивши 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"!

btw Я встановив ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\і поставив video2gif.batскрипт у bin dir прямо поруч 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, щоб швидко отримати налаштування за замовчуванням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.