Jak przekonwertować wideo na GIF przy użyciu ffmpeg, z rozsądną jakością?

310

Konwertuję FLVfilm do GIFpliku przy pomocy ffmpeg.

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

Działa świetnie, ale wyjściowy plik gif ma bardzo niską jakość.

Wszelkie pomysły, jak mogę poprawić jakość przekonwertowanego gif?

Wyjście polecenia:

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%

Dzięki.

Kamil Hismatullin
źródło
1
To zabawne, jak ludzie nadal robią palety z GIF-em, gdy APNG jest czymś.
Константин Ван

Odpowiedzi:

447

ffmpeg przykład

Wyjście GIF z ffmpeg
183 tys

ffmpegmoże generować wysokiej jakości GIF. Zawsze zaleca się używanie najnowszej wersji: pobierz lub skompiluj .

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
  • Ten przykład pominie pierwsze 30 sekund ( -ss 30) wejścia i utworzy 3 sekundy wyjścia ( -t 3).
  • filtr fps ustawia liczbę klatek na sekundę.
  • Filtr skali zmieni rozmiar wyjściowy na szerokość 320 pikseli i automatycznie określi wysokość przy zachowaniu współczynnika kształtu.
  • filtry palettegen i paletteuse wygenerują i użyją niestandardowej palety wygenerowanej na podstawie danych wejściowych.
  • podzielony filtr pozwoli wszystko zrobić w jednym poleceniu.
  • Zapętlenie sterowania z -loopopcją wyjścia. Wartość 0to nieskończone zapętlenie.

Zobacz wysokiej jakości GIF z FFmpeg, aby uzyskać więcej przykładów i opcji.


convertPrzykład wyobrażenia

Wyjście GIF z ffmpeg
227k

Inną metodą wiersza polecenia jest przesyłanie strumieniowe z ffmpegdo convert(lub magick) z 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

Ustawianie liczby klatek na sekundę

Ustaw liczbę klatek na sekundę za pomocą kombinacji fpsfiltrów wejściowych ffmpegi -delaywejściowych convert. Może się to komplikować, ponieważ convertpo prostu dostaje nieprzetworzony strumień obrazów, więc żadne fps nie jest zachowywane. Po drugie, -delaywartość w convertjest w tikach (jest 100 tików na sekundę), a nie w klatkach na sekundę. Na przykład przy fps=12.5= 100 / 12,5 = 8 = -delay 8.

convertzaokrągla -delaywartość do liczby całkowitej, więc 8,4 daje wynik 8, a 8,5 daje wynik 9. Oznacza to, że podczas ustawiania jednolitego opóźnienia we wszystkich ramkach obsługiwane są tylko niektóre częstotliwości klatek (określone opóźnienie można ustawić dla każdej klatki, ale jest ono większe ta odpowiedź).

-delaywydaje się być ignorowany, jeśli jest używany jako opcja wyjściowa, więc należy go użyć wcześniej, -jak pokazano w przykładzie.

Wreszcie przeglądarki i przeglądarki obrazów mogą wprowadzać minimalne opóźnienie, więc i tak -delaymożesz zostać zignorowany.

Wideo dzięki uprzejmości US Fish & Wildlife Service National Conservation Training Center.

Llogan
źródło
4
Dodano kilka przykładowych wyników (choć nadal klatki). Tutaj pierwszy plik ma 4,1 MB, drugi około 8 MB.
slhck
2
@ LordNeckbeard, jesteś niesamowity! wielkie dzięki za-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin
6
Nawiasem mówiąc, do convertpolecenia konwersji z ramek PNG ostatecznie skorzystałem convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", co nieco zmniejsza ogólny rozmiar pliku
Wilf
2
Ok, mam to, użyłem scale=0:-1, więc kiedy ustawisz skalę na 0, pobierze skalę z filmu.
Mousa Alfhaily
2
Te pytania i odpowiedzi muszą zostać trwale zakodowane w tomie (a może po prostu „przypięte” na razie), ponieważ za sto lat cała komunikacja będzie się odbywać za pośrednictwem memów. Myślę, że sama aktywność związana z tym postem przemawia do tego.
Jonathan Neufeld
87

Jeśli wolisz unikać pośrednich plików obrazów, polecenia dostarczane przez LordNeckBeard można przesyłać między programami ffmpega ImageMagick, convertdzięki czemu nie są wymagane żadne pliki pośrednie:

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

-f image2pipeMówi ffmpeg podzielić film na obrazy i sprawiają, że nadaje się rurami, i -vcodec ppmokreśla format wyjściowy będzie ppm (z jakiegoś powodu, jeśli format PNG, albo convertnie czytać wszystkie obrazy z rury lub ffmpeg robi nie wypisuje ich wszystkich). -Zarówno poleceń określa, że rura będzie używana do wyjścia i wejścia odpowiednio.

Aby zoptymalizować wynik bez zapisywania pliku, możesz przesłać dane wyjściowe convertdo drugiego convertpolecenia:

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:-Mówi convertdo rury swoje wyjście jako gif sformatowanych danych i -layers Optimizemówi drugi convertdo wykonywania optimize-framei optimize-transparancymetod (patrz ImageMagick Wprowadzenie do optymalizacji animacji ). Zauważ, że dane wyjściowe z -layers Optimizenie zawsze zapewniają mniejszy rozmiar pliku, więc możesz spróbować przekonwertować na gif bez optymalizacji najpierw.

Pamiętaj, że podczas całego tego procesu wszystko jest w pamięci, więc możesz potrzebować wystarczającej ilości pamięci, jeśli obrazy są dość duże.

zauważalny
źródło
1
Ten zestaw poleceń działa również zavconv
raphael
Powinieneś scalić dwa ostatnie polecenia konwersji:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément
Wydaje się, że gif działa z prędkością 2x prędkości źródłowego wideo?
Titan
@ Titan uważa, że ​​to -r 10 w pierwszym poleceniu i -delay 5 w drugim. Zmieniłem również opóźnienie na 10 i wydaje się, że teraz gra normalnie.
Steven Huang
2
Możesz także uniknąć pośrednich plików obrazów, używając splitfiltra w ffmpeg. W ogóle nie trzeba nic 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
potokować
37

Od wersji ffmpeg 2.6 możemy zrobić jeszcze lepiej:

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
źródło
18

Stworzyłem własną wersję skryptu, która parametryzuje również rozdzielczość wyjściową i liczbę klatek na sekundę.

Uruchomienie ./gifenc.sh input.mov output.gif 720 10spowoduje wygenerowanie pliku GIF o szerokości 720p i rozdzielczości 10 kl./s z filmu, który mu dałeś. Może być konieczne wykonanie chmod +x gifenc.shpliku.

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

Możesz przeczytać szczegóły na moim Githubie

Założenia: ffmpeg jest zainstalowany, a skrypt znajduje się w tym samym folderze co inne pliki.

ewangelista
źródło
3
Dziękuję bardzo za skrypt. Właśnie go przetestowałem i działa świetnie!
orschiro
15

Odpowiedź od @Stephane jest bardzo dobra. Ale otrzyma ostrzeżenie, jak w Buffer queue overflow, dropping.przypadku niektórych filmów, a wygenerowana giframka spadła.

Oto lepsza wersja z fifofiltrem, której należy unikać Buffer queue overflowpodczas korzystania z paletteusefiltru. Korzystając z splitfiltra, aby uniknąć tworzenia pliku PNG z paletą pośrednią.

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
źródło
Jeśli dobrze to rozumiem, dzielisz dane wejściowe na o1 i o2 i kopiujesz o2 do o3. Dlaczego więc potrzebujesz O3? Dlaczego nie użyć bezpośrednio O2?
Chloe
1
@Chloe Czy widziałeś fifooperację filtrowania między o2i o3? Aby uniknąć Buffer queue overflowostrzeżenia.
alijandro
+1 To działa naprawdę dobrze dla mnie (i rozwiązało problem, o którym mowa).
Iain Collins,
Absolutnie uwielbiam to rozwiązanie. Sława!
Leonid Usov
10

napisałem skrypt, przetestowałem i działa.

stosowanie:

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

MASZ 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 to DOSKONAŁE narzędzie do przechwytywania ekranu w systemie Linux :)

DZIĘKI DUŻO Michael Kohaupt :) Rock stały.

niektóre statystyki wielkości pliku:

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

zobacz wyniki tutaj.

pieścić
źródło
10

ffmpegZ palety metody mogą być prowadzone w jednym poleceniu, bez pośrednika .pngpliku.

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

Można to zrobić dzięki splitfiltrowi.

Stephane
źródło
10

Linux / Unix / macOS

Zgodnie z podejściem @LordNeckbeard z ffmpegpoleceniem znajdź następującą przydatną funkcję Bash, którą można dodać do ~/.bash_profilepliku:

# 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"
}

Po załadowaniu funkcji (ręcznie lub z . ~/.bash_profile) powinieneś mieć nowe video2gifpolecenie.

Przykładowe użycie:

video2gif input.flv

lub:

video2gif input.flv 320 10

Skaluj do szerokości 320 z 10 klatkami na sekundę.

Możesz także określić inny format wideo (np. MP4).


System operacyjny Mac

Możesz wypróbować aplikację GIF Brewery, która może tworzyć pliki GIF z plików wideo.


Alternatywnie istnieje kilka stron internetowych, które dokonują konwersji online bezpłatnie.

kenorb
źródło
twój skrypt zgłasza błąd dotyczący braku pliku png i nie otrzymuję danych wyjściowych gif, ale plik wejściowy .mp4 pozostaje niezmieniony
lacostenycoder
7

Wybrana odpowiedź zakłada, że ​​chcesz przeskalować wideo źródłowe i zmienić jego fps w utworzonym gifie. Jeśli nie musisz tego robić, działają następujące czynności:

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

Przydało się to, gdy chciałem gif, który wiernie odtworzył wideo źródłowe, którego używałem.

Jet Blue
źródło
6

Dla użytkowników systemu Windows:
utwórz video2gif.batplik w katalogu systemu Windows z następującą zawartością:

@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

A potem gdziekolwiek możesz go użyć, tak jak w tym przykładzie:

video2gif myvideo.mp4

Następnie masz myvideo.gifw bieżącym katalogu.
Jeśli myvideo.gifistnieje, poproś go o zastąpienie.

EDYTOWAĆ:

Sugeruję użycie tego skryptu wsadowego: https://github.com/NabiKAZ/video2gif

Nabi KAZ
źródło
2
Widzę, że zrobiłeś tutaj dwie rzeczy: (1) napisałeś polecenia jako skrypt poleceń Windows (.BAT), i (2) podałeś inną kombinację filtrów (żadna z pozostałych odpowiedzi nie używa obu fps=10 i scale=-1:-1).  Odpowiedź Sun już dała nam plik wsadowy, a ten (podobnie jak skrypty powłoki w odpowiedzi pje i odpowiedź anioła ) ma tę zaletę, że przypisuje listę filtrów do zmiennej ( raz ),… ( ciąg dalszy )
Scott
1
(Ciąg dalszy)… więc nie trzeba dwa razy przeliterować listy (tak jak plik wsadowy). (Zakładam, że stwarza to ryzyko, że jeśli użytkownik edytuje skrypt, aby zmienić jedną z list, ale nie drugą, niespójność spowoduje problem.) Czy potrafisz przynajmniej wyjaśnić swój wybór filtrów ( fps=10,scale=-1:-1)? (Zobacz odpowiedź zauważalnego na przykład wyjaśnienia części polecenia).
Scott
1
@Scott Powiedziałeś poprawnie, więc piszę tutaj nowy przydatny skrypt: github.com/NabiKAZ/video2gif
Nabi KAZ
4

Poniżej znajduje się plik wsadowy dla użytkowników systemu 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

Źródło: Wysokiej jakości GIF z FFmpeg: Wyodrębnianie tylko próbki

Jeśli chcesz użyć tylko jednej zmiennej wejściowej, a nazwa wyjściowa ma tylko rozszerzenie GIF (wymawiane JIF), użyj tego zamiast tego:

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
Słońce
źródło
3

Jak dodać pozycję menu kontekstowego Windows 7/10 „prawym przyciskiem myszy”, aby przekonwertować plik wideo na gif

Niektóre inne odpowiedzi dotyczyły skryptu video2gif , którego użyłem. Ale możesz użyć dowolnego skryptu.

Aby utworzyć opcję menu kontekstowego, musisz edytować rejestr. Otwórz wiersz polecenia PowerShell, uruchamiając w / admin privs. Wykonaj następujące polecenia:

$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

Teraz, kiedy klikniesz plik prawym przyciskiem myszy, pojawi się opcja „Uruchom Video2Gif”!

btw Zainstalowałem ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\i umieściłem video2gif.batskrypt w katalogu bin tuż obok ffmpeg.exe. Dodałem również C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bindo moich okien PATH, ale nie sądzę, że musisz.

Jeśli chcesz mieć możliwość dostarczenia dodatkowych skryptów / argumentów wiersza poleceń do skryptu, utwórz nowy plik o nazwie video2gif-prompt.bati poproś go o odwołanie do rejestru zamiast 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%

Nadal możesz po prostu nacisnąć Enter, aby szybko uzyskać ustawienia domyślne.

Chris
źródło