Wie kann ich mit ffmpeg ein Video mit vernünftiger Qualität in GIF konvertieren?

192305
Kamil Hismatullin

Ich konvertiere FLVFilm in 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 gut, aber die Ausgabegif-Datei hat eine sehr schlechte Qualität.

Wie kann ich die Qualität der konvertierten GIFs verbessern?

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.

258

12 Antworten auf die Frage

390
LordNeckbeard

ffmpegkann jetzt GIF mit höherer Qualität ausgeben. Wenn Sie einen älteren Build verwenden, sollten Sie einen kürzlich erstellten statischen Build herunterladen oder kompilierenffmpeg .

ffmpeg Beispiel

gif with ffmpeg
203k

In diesem Beispiel werden die ersten 30 Sekunden der Eingabe übersprungen und eine Ausgabe von 3 Sekunden erstellt. Es skaliert die Ausgabe auf 320 Pixel und bestimmt automatisch die Höhe, wobei das Seitenverhältnis beibehalten wird. Die palettegenund- paletteuseFilter erstellen eine benutzerdefinierte Palette, die aus Ihrer Quelle generiert wird, und verwenden diese.

  1. Erzeugen Sie eine Palette:

    ffmpeg -y -ss 30 -t 3 -i input.flv \ -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png 
  2. Geben Sie das GIF mithilfe der Palette aus:

    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 

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


convert Beispiel

Eine andere Befehlszeilenmethode wäre, den Film in Frames zu exportieren und ffmpegdann die GIF-Datei mit convertImageMagick (oder GraphicsMagick) zu erstellen .

ffmpeg and convert
246k

  1. Frames exportieren:

     mkdir frames ffmpeg -i input -vf scale=320:-1:flags=lanczos,fps=10 frames/ffout%03d.png 
  2. Dann convert(oder gm convertwenn Sie GraphicsMagick bevorzugen), um ein animiertes GIF zu erstellen:

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

Mit können convertSie die Verzögerung zwischen Bildern mit einstellen, -delayfalls gewünscht.

Einige Beispielergebnisse hinzugefügt (nur Standbilder). Hier beträgt die erste Datei 4,1 MB, die zweite etwa 8 MB. slhck vor 11 Jahren 4
@LordNeckbeard, du bist großartig! vielen dank für -vf scale = 320: -1, format = rgb8, format = rgb24` Kamil Hismatullin vor 11 Jahren 2
@LordNeckbeard - die `convert'-Option hat hervorragend funktioniert - auch bei der Verwendung einer alten Version von ffmpeg erhielt die Datei eine Dateigröße von 300 MB mit Abfallausgabe, während die hochwertige Version von Convert 13 MB betrug. Wilf vor 10 Jahren 0
Für den Befehl "convert" zum Konvertieren aus den PNG-Frames habe ich übrigens "convert -delay 5 -loop 0 -dither None -colors 80" frames / ffout * .png "-fuzz" 40% "-Schichten verwendet OptimizeFrame "output.gif" `, wodurch die Dateigröße erheblich reduziert wird Wilf vor 10 Jahren 5
Ich denke, der `convert'-Befehl sollte` -delay 10` (0,1 Sekunden zwischen Frames) verwenden, um die Framerate von `-r 10 '(10 fps) zu erfüllen, die Sie an` ffmpeg` liefern. Wenn ich `-delay 5` verwende, sehe ich, dass das Gif mit doppelter Geschwindigkeit spielt. Jack O'Connor vor 10 Jahren 1
Ist es möglich, einige Pixel aus der resultierenden GIF zu beschneiden? Ich liebe diese lustigen GIFs aus echten Film- / Cartoonszenen, aber ich habe eine gefunden, die eine schlechte Qualität hat, bei der die Oberseite ... 5cm mehr oder weniger beschädigt ist. Wenn ich einen neuen Thread öffnen muss, freue ich mich Bruno Augusto vor 8 Jahren 0
Bravo! Ich habe das "ffmpeg-Beispiel" verwendet, um eine CamStudio-Aufnahme meines Bildschirms zu konvertieren, die eine RAID5-Paritätswiederherstellung eines RAID5-Arrays eines Flash-Laufwerks zeigt. Die Genesung dauerte etwa eine Stunde. Während dieser Zeit habe ich die Ausgabe in eine Textdatei getickt. Das Video war eigentlich die Aufnahme meiner Analyse des Textes. das AVI betrug 1,4 GB; Die GIF betrug 2,5 MB. user38537 vor 8 Jahren 0
Im zweiten Ansatz können Sie ffmpeg anstelle von imagick verwenden. Alles, was Sie tun müssen, ist die ** Framrate ** -Option des Image2-Demuxers, mit der Sie die Verzögerung zwischen einzelnen Frames einstellen können: `ffmpeg -framerate -i frames / ffout * .png output.gif` Gergely Lukacsy vor 8 Jahren 0
Ihr ffmpeg-Beispiel ist für mich zu einem allgemein bekannten Workflow geworden, so dass ich ein Bash-Wrapper-Skript geschrieben habe, um es zu automatisieren. Hier teilen: https://github.com/jordanh/ffmpeg2gif Jordan vor 8 Jahren 0
Wenn ich nicht die Skala einstellen möchte, muss ich ihn automatisch der Skala des Videos anpassen? Mousa Alfhaily vor 7 Jahren 0
Okay, ich habe es verstanden, ich habe "scale = 0: -1" verwendet. Wenn Sie also die Skala auf "0" setzen, wird die Skala aus dem Video übernommen. Mousa Alfhaily vor 7 Jahren 2
Giphy Engineering hat kürzlich einen schönen Artikel veröffentlicht, in dem alle Optionen erläutert werden: https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg Marcus Mangelsdorf vor 6 Jahren 0
@LordNeckbeard Wie kann ich Ihren Code so ändern, dass er von einem bestimmten Intervall eines Films abhängt, sagen wir zwischen 00:24:45 bis 00:25:52? Ich habe versucht, den Suchbefehl zu verwenden, und es hat nicht funktioniert! Kannst du mir vielleicht dabei helfen ?. Ich würde gerne wissen, wie man es mit der Palette machen kann, die man sagt, und ffmpeg verwenden, um daraus das GIF aufzubauen. Übrigens, ich habe den Code wie Sie erwähnt haben und er funktioniert, aber es ist nicht sehr praktisch, eine Probe aus längeren Intervallen zu nehmen, wie ich es erwähnt habe, da ich die Minuten oder Stunden in Sekunden übersetzen muss. Chris Steinbeck Bell vor 6 Jahren 0
@LordNeckbeard Auch die Framerate, die Sie verwenden, wie haben Sie diese erhalten? Kommt es aus dem Eingabefilm oder ist es nur ein Zufallswert, den Sie gewählt haben? Chris Steinbeck Bell vor 6 Jahren 0
@ ChrisSteinbeckBell Ich habe einen Wert gewählt, der niedrig genug ist, um die GIF-Datei kleiner zu machen, aber hoch genug, um akzeptabel zu wirken. Sie müssen nur je nach Inhalt experimentieren. LordNeckbeard vor 6 Jahren 0
@LordNeckbeard Vielen Dank für Ihre Rückmeldung, aber ich würde mich freuen, wenn Sie mir bei dem Teil des Codes bezüglich der Zeit helfen könnten, da ich nicht genug bin, um diese Änderung selbst vorzunehmen. Wie bereits erwähnt, habe ich versucht, den Suchbefehl zu verwenden, da die ffmpeg-Dokumentation den Weg von -ss 00:24:25 bis 00:25:52 vorschlägt Chris Steinbeck Bell vor 6 Jahren 0
@LordNeckbeard gleich nach der Eingabe, aber ich kann es nicht machen, dass ffmpeg den Befehl so interpretiert, wie ich es brauche. Vielleicht können Sie mir dabei helfen? Ich wäre wirklich dankbar. Chris Steinbeck Bell vor 6 Jahren 0
@ChrisSteinbeckBell Könnte es sich lohnen, dies als neue Frage zu stellen, und ich oder jemand anderes kann helfen. Kommentare können zu begrenzt sein. LordNeckbeard vor 6 Jahren 0
Beim allerersten Befehl - zum Generieren der Palette (mit ffmpeg-4.0.1): `Option 'Flags' nicht gefunden`. ffmpeg wäre viel sinnvoller, wenn die Entwickler das Konzept der Rückwärtskompatibilität kennen ... Mikhail T. vor 6 Jahren 0
@MikhailT. Funktioniert bei mir. Bitte zeigen Sie Ihren aktuellen Befehl und das vollständige Protokoll. Sie können eine Pastebin-Site verwenden und den Link hier angeben. LordNeckbeard vor 6 Jahren 0
Äh, egal. Ich habe versucht, den Teil "scale = 360" zu entfernen, und das hat nicht funktioniert. Ich weiß nicht warum ... Mikhail T. vor 6 Jahren 0
@MikhailT. Der Teil im vollen Maßstab ist `scale = 320: -1: flags = lanczos`. Die "Flags" sind eine Option für die Skalierung. Ich hätte das wahrscheinlich nicht in das Beispiel aufnehmen sollen, da es die Komplexität des Beispiels erhöht hat. LordNeckbeard vor 6 Jahren 1
Diese Fragen und Antworten müssen dauerhaft in einem Folio codiert sein (oder vielleicht gerade erst "festgesteckt" werden), da in hundert Jahren die gesamte Kommunikation über Memes erfolgen wird. Ich denke, dass die Aktivität in diesem Beitrag alleine dazu spricht. Jonathan Neufeld vor 6 Jahren 1
80
notedible

Wenn Sie es vorziehen, Zwischenbilddateien zu vermeiden, können die von LordNeckBeard bereitgestellten Befehle zwischen ffmpegund ImageMagick's geleitet werden, convertso dass keine Zwischendateien erforderlich sind:

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

Der -f image2pipeBefehl ffmpeg teilt das Video in Bilder auf und macht es für die Weiterleitung geeignet. -vcodec ppmDas Ausgabeformat wird in ppm angegeben (aus irgendeinem Grund convertliest das Format png entweder nicht alle Bilder aus der Pipe oder ffmpeg) nicht alle ausgeben). Der -Befehl für beide gibt an, dass eine Pipe für die Ausgabe bzw. 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 

Das gif:-sagt convertdem Rohr seinen Ausgang als GIF - formatierten Daten und -layers Optimizeteilt die zweiten convertauszuführen optimize-frameund optimize-transparancyMethoden (siehe ImageMagick Einführung in Animations Optimization ). Beachten Sie, dass die Ausgabe von the -layers Optimizemöglicherweise nicht immer eine kleinere Dateigröße aufweist. Sie sollten daher zunächst versuchen, die Konvertierung in eine GIF-Datei ohne Optimierung zu starten.

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

Dieser Befehlssatz funktioniert auch mit `avconv` raphael vor 8 Jahren 1
Sie sollten die letzten beiden Konvertierungsbefehle zusammenführen: `convert -delay 5 -loop 0 -layers Optimize - output.gif` Clément vor 8 Jahren 0
Das GIF scheint mit der doppelten Geschwindigkeit des Quellvideos zu laufen. Titan vor 8 Jahren 0
@Titan glaubt, dass es die -r 10 im ersten Befehl und die -Delay 5 im zweiten ist. Ich habe die Verzögerung auch auf 10 geändert und scheint jetzt normal zu spielen. Steven Huang vor 7 Jahren 0
Sie können auch Zwischenbilddateien vermeiden, indem Sie den Filter 'split' in ffmpeg verwenden. Keine Notwendigkeit, irgendetwas weiterzuleiten: ffmpeg -ss 30 -t 3 -i "input.flv fps = 10, Maßstab = 320: -1: flags = lanczos, split [x] [z]; [z] palettegen [ y]; [x] [y] paletteuse "output.gif" Ajedi32 vor 7 Jahren 2
Gibt es eine Möglichkeit, die Waage beizubehalten? Zum Beispiel ist meine Videodatei 904: 774. Wie mache ich das ohne Einstellung von scale = 320: -1? Gibt es eine Möglichkeit, sie zu automatisieren, ohne die Größe zu explodieren? Sudhir Khanger vor 6 Jahren 0
29
pje

Ab ffmpeg 2.6 können wir es noch besser machen:

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

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

Beim Laufen ./gifenc.sh input.mov output.gif 720 10werden 720p 10fps GIF aus dem von Ihnen angegebenen Film ausgegeben. Sie müssen möglicherweise 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.

Vielen Dank für Ihr Skript. Ich habe es gerade getestet und es funktioniert super! orschiro vor 8 Jahren 2
8
canoodle

ein Skript gemacht, getestet und funktioniert.

Verwendungszweck:

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

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

DANKE VIEL Michael Kohaupt :) Rock ruhig.

Einige Dateigrößenstatistiken:

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

sehen Sie die Ergebnisse hier.

8
alijandro

Die Antwort von @Stephane ist sehr gut. Es wird jedoch wie Buffer queue overflow, dropping.bei einigen Videos eine Warnung angezeigt, und bei dem generierten gifBild wurde ein Frame verloren.

Hier ist eine bessere Version mit fifoFilter, die Buffer queue overflowbei Verwendung des paletteuseFilters zu vermeiden ist . Verwenden Sie einen 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 
Wenn ich das richtig verstanden habe, teilen Sie die Eingabe in o1 und o2 auf und kopieren o2 nach o3. Warum brauchst du o3? Warum nicht einfach o2 direkt verwenden? Chloe vor 6 Jahren 0
@Chloe Haben Sie die Filteroperation "fifo" zwischen "o2" und "o3" gesehen? Um die Warnung "Pufferwarteschlangenüberlauf" zu vermeiden. alijandro vor 6 Jahren 0
7
kenorb

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

Sobald die Datei geladen ist ( . ~/.bash_profile), sollten Sie einen neuen video2gifBefehl haben.

Verwendungsbeispiel:

video2gif input.flv 

oder:

video2gif input.flv 320 10 

Skalieren Sie mit 10 Bildern pro Sekunde auf 320 Breite.

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


Mac OS

Sie können die GIF Brewery- App ausprobieren, mit der GIFs aus Videodateien erstellt werden können.


Alternativ gibt es mehrere Websites, die kostenlos online konvertieren.

6
Stephane

Die ffmpegwith-palette- Methode kann in einem einzigen Befehl ohne Zwischendatei ausgeführt .pngwerden.

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.

4
Jet Blue

Bei der ausgewählten Antwort wird davon ausgegangen, dass Sie das Quellvideo skalieren und seine Fps in der erzeugten 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 

Das war praktisch, wenn ich ein GIF wollte, das das Quellvideo, das ich verwendete, originalgetreu nachgebildet hat.

3
Sun

Unten ist die Batchdatei 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: Extrahieren einer Probe

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