Wie konvertiere ich ein Video mit ffmpeg in GIF mit angemessener Qualität?

311

Ich konvertiere einen FLVFilm in eine GIFDatei mit ffmpeg.

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

Es funktioniert sehr gut, aber die Ausgabe-GIF-Datei hat eine sehr niedrige Qualität.

Irgendwelche Ideen, wie ich die Qualität von konvertiertem GIF verbessern kann?

Ausgabe des Befehls:

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%

Vielen Dank.

Kamil Hismatullin
quelle
1
Es ist komisch, wie Leute mit GIF immer noch Palettenarbeiten machen, wenn APNG eine Sache ist.
Константин Ван

Antworten:

447

ffmpeg Beispiel

GIF-Ausgabe von ffmpeg
183k

ffmpegkann qualitativ hochwertiges GIF ausgeben. Es wird immer empfohlen, eine aktuelle Version zu verwenden: Herunterladen oder Kompilieren .

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
  • In diesem Beispiel werden die ersten 30 Sekunden ( -ss 30) der Eingabe übersprungen und eine Ausgabe von 3 Sekunden ( -t 3) erstellt.
  • Mit dem FPS- Filter wird die Bildrate eingestellt.
  • Durch den Skalierungsfilter wird die Größe der Ausgabe auf 320 Pixel geändert und die Höhe automatisch bestimmt, wobei das Seitenverhältnis beibehalten wird.
  • palettegen- und paletteuse- Filter generieren und verwenden eine benutzerdefinierte Palette, die aus Ihrer Eingabe generiert wird.
  • Mit dem geteilten Filter kann alles in einem Befehl ausgeführt werden.
  • Regelkreis mit -loopAusgangsoption. Ein Wert von 0ist Endlosschleife.

Siehe Hochwertige GIF mit FFmpeg für viele weitere Beispiele und Optionen.


Imagemagick convertBeispiel

GIF-Ausgabe von ffmpeg
227k

Eine andere Befehlszeilenmethode ist die Weiterleitung von ImageMagick ffmpegnach convert(oder magick).

 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

Bildrate einstellen

Stellen Sie die Bildrate mit einer Kombination der fpsFilter in ffmpegund -delayin ein convert. Dies kann kompliziert werden, da convertnur ein Rohdatenstrom von Bildern abgerufen wird, sodass keine Bilder pro Sekunde erhalten bleiben. Zweitens ist der -delayWert in convertist in Ticks (es gibt 100 Ticks pro Sekunde), nicht in Frames pro Sekunde. Zum Beispiel mit fps=12.5= 100 / 12.5 = 8 = -delay 8.

convertRundet den -delayWert auf eine ganze Zahl, sodass 8,4 zu 8 und 8,5 zu 9 führen. Dies bedeutet effektiv, dass nur einige Frameraten unterstützt werden, wenn eine einheitliche Verzögerung für alle Frames eingestellt wird (eine bestimmte Verzögerung kann pro Frame eingestellt werden, die jedoch darüber hinausgeht diese Antwort).

-delayscheint ignoriert zu werden, wenn es als Ausgabeoption verwendet wird, daher muss es zuvor verwendet werden, -wie im Beispiel gezeigt.

Schließlich können Browser und Bildbetrachter eine Mindestverzögerung implementieren, sodass Ihre -delayohnehin ignoriert werden können.

Video mit freundlicher Genehmigung des National Conservation Training Center des US Fish & Wildlife Service.

Logan
quelle
4
Einige Beispielergebnisse hinzugefügt (nur noch Frames). Hier ist die erste Datei 4,1 MB groß, die zweite etwa 8 MB.
Slhck
2
@LordNeckbeard, du bist großartig! -vf scale=320:-1,format=rgb8,format=rgb24
Vielen
6
Übrigens, für den convertBefehl zum Konvertieren von PNG-Frames habe ich letztendlich verwendet convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", wodurch sich die Gesamtgröße der Datei erheblich verringert
Wilf
2
Okay, ich habe es, ich habe verwendet scale=0:-1, also wenn Sie die Skala auf einstellen 0, wird es die Skala aus dem Video nehmen.
Mousa Alfhaily
2
Diese Fragen und Antworten müssen permanent in einem Band verschlüsselt sein (oder vielleicht erst einmal "festgesteckt" sein), da in hundert Jahren die gesamte Kommunikation über Memes erfolgen wird. Ich denke, die Aktivität in diesem Beitrag allein spricht dafür.
Jonathan Neufeld
87

Wenn Sie Zwischenbilddateien vermeiden möchten, können die von LordNeckBeard bereitgestellten Befehle zwischen ffmpegund den Befehlen von ImageMagick weitergeleitet werden, convertsodass keine Zwischenbilddateien erforderlich sind:

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

Im -f image2pipeBefehl ffmpeg wird angegeben, dass das Video in Bilder aufgeteilt werden soll, damit es weitergeleitet werden kann, und -vcodec ppmdas Ausgabeformat wird auf ppm festgelegt (aus irgendeinem Grund convertliest das Format png entweder nicht alle Bilder aus der Pipe oder ffmpeg nicht alle ausgeben). Der -Befehl für beide Befehle gibt an, dass eine Pipe für die Ausgabe bzw. die Eingabe verwendet wird.

Um das Ergebnis zu optimieren, ohne eine Datei zu speichern, können Sie die Ausgabe convertan einen zweiten convertBefehl weiterleiten:

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

Der gif:-Befehl weist Sie convertan, die Ausgabe als gif-formatierte Daten weiterzuleiten und -layers Optimizeden zweiten Befehl convertauszuführen optimize-frameund zu optimize-transparancyverwenden (siehe ImageMagick Einführung in die Animationsoptimierung ). Beachten Sie, dass die Ausgabe von -layers Optimizemöglicherweise nicht immer eine kleinere Dateigröße liefert. Sie können daher versuchen, eine Konvertierung in ein GIF ohne Optimierung durchzuführen, um sicherzugehen.

Denken Sie daran, dass sich während des gesamten Vorgangs alles im Speicher befindet, sodass Sie möglicherweise ausreichend Speicher benötigen, wenn die Bilder sehr groß sind.

bemerkenswert
quelle
1
Dieser avconv
Befehlssatz
Sie sollten die letzten beiden Konvertierungsbefehle zusammenführen:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément
Das GIF scheint mit der doppelten Geschwindigkeit des Quellvideos zu laufen.
Titan
@Titan glaube, es ist die -r 10 im ersten Befehl und die -delay 5 im zweiten. Ich habe die Verzögerung ebenfalls auf 10 geändert und sie scheint jetzt normal zu spielen.
Steven Huang
2
Sie können auch Zwischenbilddateien vermeiden, indem Sie den splitFilter in ffmpeg verwenden. Keine Notwendigkeit, etwas zu 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
pfeifen
37

Ab ffmpeg 2.6 können wir noch besser:

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
quelle
18

Ich habe eine eigene Version des Skripts erstellt, die auch die Ausgabeauflösung und die Bildrate parametrisiert.

Laufen ./gifenc.sh input.mov output.gif 720 10wird 720p 10fps GIF von dem Film ausgeben, den Sie ihm gegeben haben. Möglicherweise müssen Sie chmod +x gifenc.shfür die Datei tun .

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

Sie können die Details auf meinem Github lesen

Annahmen: ffmpeg ist installiert und das Skript befindet sich im selben Ordner wie die anderen Dateien.

Thevangelist
quelle
3
Vielen Dank für Ihr Skript. Ich habe es gerade getestet und es funktioniert super!
Orschiro
15

Die Antwort von @Stephane ist sehr gut. Aber es wird eine Warnung wie Buffer queue overflow, dropping.bei einigen Videos angezeigt, und bei dem generierten gifist ein Teil des Frames gefallen.

Hier ist eine bessere Version mit fifoFilter, um Buffer queue overflowbei der Verwendung von paletteuseFilter zu vermeiden . Verwenden Sie splitFilter, um die Erstellung einer PNG-Datei für die Zwischenpalette zu vermeiden.

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
quelle
Wenn ich das richtig verstehe, teilen Sie die Eingabe in o1 und o2 und kopieren o2 nach o3. Warum brauchst du o3? Warum nicht einfach o2 direkt nutzen?
Chloe
1
@Chloe Hast du die Filteroperation fifozwischen o2und gesehen o3? Um die Buffer queue overflowWarnung zu vermeiden .
Alijandro
+1 Das funktioniert wirklich gut für mich (und hat das Problem behoben, auf das verwiesen wird).
Iain Collins
Ich liebe diese Lösung absolut. Ein dickes Lob!
Leonid Usov
10

habe ein script gemacht, getestet und funktioniert.

Verwendungszweck:

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

PHUN HABEN :)

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 ist ein AUSGEZEICHNETES ScreenCapturing-Tool für Linux :)

Vielen Dank Michael Kohaupt :) Rock stetig.

Einige Dateigrößenstatistiken:

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

Die Ergebnisse finden Sie hier.

abknutschen
quelle
10

Die ffmpegmit Palette Verfahren kann in einem einzigen Befehl ausgeführt werden, ohne Vermittler - .pngDatei.

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

Dies ist dank des splitFilters möglich.

Stephane
quelle
10

Linux / Unix / macOS

Nach dem @ LordNeckbeard-Ansatz mit ffmpegBefehl finden Sie die folgende nützliche Bash-Funktion, die in Ihre ~/.bash_profileDatei eingefügt werden kann:

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

Sobald die Funktion geladen ist (manuell oder von . ~/.bash_profile), sollten Sie einen neuen video2gifBefehl haben.

Anwendungsbeispiel:

video2gif input.flv

oder:

video2gif input.flv 320 10

Mit 10 Bildern pro Sekunde auf 320 Breite skalieren.

Sie können auch ein anderes Videoformat (z. B. mp4) angeben.


Mac OS

Sie können die GIF-Brauerei- App ausprobieren , mit der Sie GIFs aus Videodateien erstellen können.


Alternativ gibt es mehrere Websites, die eine kostenlose Online-Konvertierung durchführen.

Kenorb
quelle
Ihr Skript löst einen Fehler für mich über keine PNG-Datei und ich bekomme keine GIF-Ausgabe, aber die MP4-Eingabedatei bleibt unverändert
Lacostenycoder
7

Bei der ausgewählten Antwort wird davon ausgegangen, dass Sie das Quellvideo skalieren und dessen fps im erstellten GIF ändern möchten. Wenn Sie dies nicht tun müssen, funktioniert Folgendes:

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

Dies hat sich als nützlich erwiesen, als ich ein GIF wollte, das das von mir verwendete Quellvideo originalgetreu wiedergibt.

Jet Blue
quelle
6

Für Windows-Benutzer:
Erstellen Sie eine video2gif.batDatei im Windows-Verzeichnis mit folgendem Inhalt:

@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

Und wo immer Sie es verwenden können, sehen Sie so aus:

video2gif myvideo.mp4

Dann hast du myvideo.gifim aktuellen Verzeichnis.
Wenn myvideo.gifes eine Frage gibt, die Sie beantworten müssen, um sie zu überschreiben.

BEARBEITEN:

Ich schlage vor, dieses Batch-Skript zu verwenden: https://github.com/NabiKAZ/video2gif

Nabi KAZ
quelle
2
Ich sehe, dass Sie hier zwei Dinge getan haben: (1) Sie haben die Befehle als Windows-Befehlsskript (.BAT) geschrieben und (2) eine andere Kombination von Filtern bereitgestellt (keine der anderen Antworten verwendet beide fps=10 und scale=-1:-1).  Die Antwort von Sun hat uns bereits eine Batch-Datei gegeben, und diese hat (wie die Shell-Skripte in der Antwort von pje und die Antwort von thevangelist ) den Vorteil, dass sie die Liste der Filter einer Variablen ( einmal ) zuweist ,… (Fortsetzung)
Scott
1
(Fortsetzung)… damit die Liste nicht zweimal buchstabiert werden muss (wie bei Ihrer Batch-Datei). (Ich gehe davon aus, dass dies zu dem Risiko führt, dass die Inkonsistenz ein Problem verursacht, wenn der Benutzer das Skript bearbeitet, um eine der Listen zu ändern, die andere jedoch nicht.) Können Sie zumindest Ihre Filterauswahl erläutern ( fps=10,scale=-1:-1)? ( Ein Beispiel für die Erläuterung von Teilen eines Befehls finden Sie in der Antwort von aware .)
Scott,
1
@Scott Du hast richtig gesagt, also schreibe ich hier ein neues nützliches Skript: github.com/NabiKAZ/video2gif
Nabi KAZ
4

Unten ist die Batch-Datei für Windows-Benutzer:

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

Quelle: Hochwertiges GIF mit FFmpeg: Nur ein Beispiel extrahieren

Wenn Sie nur eine Eingabevariable verwenden möchten und der Ausgabename nur die Erweiterung GIF (ausgesprochen JIF) hat, verwenden Sie stattdessen Folgendes:

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
Sonne
quelle
3

So fügen Sie einen Kontextmenüeintrag für Windows 7/10 mit der rechten Maustaste hinzu, um Ihre Videodatei in GIF zu konvertieren

In einigen anderen Antworten wurde das von mir verwendete video2gif- Skript erwähnt . Sie können jedoch jedes Skript verwenden.

Um die Kontextmenüoption zu erstellen, müssen Sie Ihre Registrierung bearbeiten. Öffnen Sie eine Powershell-Eingabeaufforderung mit Administratorrechten. Führen Sie diese Befehle aus:

$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

Wenn Sie nun mit der rechten Maustaste auf eine Datei klicken, haben Sie die Option "Video2Gif ausführen"!

Übrigens habe ich ffmpeg auf installiert C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\und das video2gif.batSkript in das Bin-Verzeichnis direkt daneben gestellt ffmpeg.exe. Ich habe auch C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\binzu meinen Fenstern hinzugefügt PATH, aber ich glaube nicht, dass Sie müssen.

Wenn Sie die Option möchten, dem Skript einige zusätzliche Befehlszeilenflags / -argumente zur Verfügung zu stellen video2gif-prompt.bat, erstellen Sie eine neue Datei mit dem Namen und lassen Sie die Registrierung darauf verweisen, anstatt 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%

Sie können immer noch einfach die Eingabetaste drücken, um die Standardeinstellungen schnell zu erhalten.

chris
quelle