Wie kann ich mit ffmpeg schnell animierte GIFs von geringer Qualität erstellen?


3

Wir generieren eine Menge von Miniatur-GIFs, deren Qualität nicht annähernd so wichtig ist wie die Zeit, die für deren Generierung erforderlich ist. Das Generieren von qualitativ hochwertigen GIFs mit ffmpeg ist sehr gut abgedeckt, aber ich habe nicht viel Glück, herauszufinden, wie Sie qualitativ minderwertige GIFs so schnell wie möglich generieren können.

Die Palettenberechnung nimmt mit dem folgenden Befehl die meiste Ausführungszeit in Anspruch (entnommen aus der Antwort des Filtergraphen mit mehreren Ketten hier: So erstellen Sie effizient ein GIF mit der besten Palette aus einem Videoteil direkt aus dem Web ):

ffmpeg -y -threads 8 -r 24 -f image2 -start_number 1 -i "frames.%04d.jpg" -filter_complex "fps=24,scale=150:-1:flags=fast_bilinear,split=2 [a][b]; [a] palettegen [pal] fifo [b]; [b] [pal] paletteuse" output.gif

Die Ausführungszeit dieses Befehls mit 1000 Bildern beträgt ungefähr 72 Sekunden. Ungefähr 67 Sekunden davon sind der Palettendurchlauf, und dann durchläuft er die eigentliche GIF-Erzeugung in ungefähr 5 Sekunden. Ich möchte die gesamte Ausführungszeit so weit wie möglich verkürzen und bereit sein, viel Bildqualität für die Geschwindigkeit zu opfern.


1
Ihr Befehl ist syntaktisch falsch. Ihnen fehlt ein [b]Etikett. In beiden Fällen ist die Verwendung der Palette nach einem Schnelltest etwa 200 ° langsamer. Es überhaupt nicht zu benutzen, ist für Sie keine Option?
Slhck

@slhck Ich finde die ffmpeg-Dokumente zu diesem Thema ziemlich schwierig, aber ich habe es mir ausgedacht, um die Palette zu entfernen: ffmpeg -y -r 24 -f image2 -start_number 1 -i "frames.%04d.jpg" -filter:v "scale=150:-1:flags=fast_bilinear" output.gifDie beiden folgenden Probleme: 1) Es wurden nur 13 Sekunden gespart (59 Sekunden statt 72) und 2 ) Ich bin nicht zu 100% sicher, dass dieser Befehl die Palettenberechnung vollständig eliminiert (nur dass die Palettenberechnung, die ich zuvor angegeben habe, nicht enthalten ist).
Rjak

1
Ja, das habe ich eigentlich gemeint. Entschuldigen Sie, dass Sie nicht so explizit sind. Ich dachte, Sie wüssten, was der von Ihnen verwendete Filterbefehl tat. In meinen Tests hat das Weglassen der Palette den Befehl erheblich beschleunigt . Was hat Sie zu der ursprünglichen Schlussfolgerung geführt, dass die eigentliche Codierung nur 5 Sekunden dauerte?
Slhck

Beobachtung der Ausgabe, die wahrscheinlich kein guter Indikator ist. Wenn ich den Befehl ohne Palettengenerierung ausführe, wird die Anzeige "Aktueller Frame" sofort eingeblendet, und wir beginnen mit der Verarbeitung der Frames. Wenn ich es mit Palettengenerierung ausführe, befindet sich das aktuelle Bild bis ca. 5 Sekunden vor dem Ende der Verarbeitung auf 0 und dreht sich dann sehr schnell durch die Bilder.
Rjak

1
Ja, das beobachte ich auch, aber dann geht es viel schneller. Aber ich denke, es hängt von der Länge des Videos ab. Um ehrlich zu sein, ich weiß nicht, ob es einen schnelleren Weg gibt, das GIF zu generieren, als es nur zu tun ffmpeg -i <input> <scale> <output.gif>.
Slhck

Antworten:


2

Ihre Verwendung der palettegen/ paletteuse-Filter verlangsamt die Ausführung des Befehls. Der einfache Weg, um ein GIF mit geringerer Qualität zu erhalten, wäre:

ffmpeg -f image2 -i "frames.%04d.jpg" output.gif

Mit zusätzlicher Skalierung:

ffmpeg -f image2 -i "frames.%04d.jpg" -vf scale=150:-1 output.gif

Sie können auch Frames in das Ausgabe-GIF einfügen, dh die Frames abtasten, damit nicht alle verarbeitet werden. Um zB nur 1 FPS-Ausgabe zu haben, verwenden Sie einen fpsFilter:

ffmpeg -i "frames.%04d.jpg" -vf "fps=fps=1,scale=150:-1" output.gif

Ich denke, in diesem letzten Beispiel gibt es einen Tippfehler ... sollte -vf "fps = 1, scale = 150: -1" sein. Die Ausführungszeit des zweiten Beispiels beträgt 68,48s. Wenn Sie fps = 1 angeben, erhalten Sie zwar ein 1-fps-GIF, die Quelle ist jedoch 120 fps, sodass das Ergebnis zu langsam wiedergegeben wird und die Ausführungszeit nicht ausreichend verbessert wird (59,44 s). Ich experimentiere mit dem Concat Loader und lasse ffmpeg jeden N-ten Frame lesen. Wenn ich dabei jedes fünfte Bild mit Lanczos-Skalierung und Palettengenerierung pro Bild abtaste, sieht die zeitliche Qualität gut aus, die Farbqualität sieht gut aus und der Befehl wird in weniger als 8 Sekunden ausgeführt.
Rjak

Werde das Ganze hier in einem Kommentar teilen, sobald ich es vollständig getestet habe und die Ausführungszeiten festgelegt habe.
Rjak

@Rjak Die erste Option des fpsFilters trägt den Namen fps, diese sind also gleichwertig. Wenn Ihre Quelle 120fps ist, müssen Sie angeben -framerate 120 -i "frames…", da der Standard für Eingang 24.
slhck

1

Ich hatte die Aufgabe, die Zeit zu verkürzen, die erforderlich war, um ein animiertes GIF mit einer Länge von 30 Bildern und einer Breite von 150 Pixeln zu erstellen. Die meisten Sequenzen, die wir generieren, sind unter 1000 Frames. Wir hatten eine Sequenz von 15.000 Bildern und unsere Renderknoten brauchten 17 Minuten , um dieses ~ 30-Bilder-GIF zu erzeugen, was inakzeptabel langsam ist.

Wir haben ffmpeg als Demuxer und Piping für imagemagick verwendet. Durch mehrstündiges Experimentieren bin ich zu folgenden Schlussfolgerungen gekommen:

  • Die Anzahl der Eingaberahmen Sie ffmpeg Prozess fragen , ist bei weitem die meisten impactful Eingabe in Bezug auf die Ausführungsgeschwindigkeit. Wenn die Verwendung des Concat-Demuxers zum Überspringen von Eingaberahmen eine Option ist, macht dies den größten Leistungsunterschied aus. Bei jeder fünften Aufnahme konnte ich die Gesamtberechnungszeit auf 1 Minute und 45 Sekunden reduzieren, indem ich hochwertige Lanczos neu skalierte und die Palette pro Bild berechnete. Das Erstellen unseres Vorschaubilds mit 30 Bildern dauert jetzt weniger als 1 Sekunde .

  • Der Neuskalierungsalgorithmus war der zweitgrößte Leistungsfaktor (aber eine weit entfernte Sekunde). Die Verwendung von fast_bilinear anstelle von lanczos sparte über alle 15.000 Frames hinweg 150 Sekunden Rechenzeit.

  • Die Variable mit der geringsten Auswirkung war die Palettenberechnung, die mit dem Rescale-Algorithmus variiert wurde. Über 15.000 Frames mit Lanczos konnten wir etwa 17 Sekunden Ausführungszeit einsparen, wenn wir die Palettenberechnung eliminierten. Mit fast_bilinear konnten wir rund 75 Sekunden Ausführungszeit einsparen.

Da der Neuskalierungsalgorithmus und die Palettenberechnung vernachlässigbar waren, haben wir sie letztendlich auf höchstem Qualitätsniveau gehalten. Wir haben die Rechenzeit von 17 Minuten auf unter 1 Sekunde verkürzt, hauptsächlich, indem wir ffmpeg angewiesen haben, das Lesen von Eingabedateien zu überspringen.

KEY TAKEAWAY: SKIPPING INPUT FRAMES vs. SKIPPING OUTPUT FRAMES

Der Grund, warum unser Prozess so lange gedauert hat, ist, dass das Löschen von Frames die Ausführungszeit bei Verwendung des Image2-Demuxers nicht verkürzt. Wenn Sie mit dem -rFlag und dem fpsFilter herumspielen, werden Sie die Anzahl der Bilder beeinflussen, die im endgültigen GIF erscheinen, aber ffmpeg scheint mit allen 15.000 Eingangsbildern noch etwas zu tun.

Der einzige Weg, wie ich FFMPEG-Eingabeframes überspringen lassen kann, ist die Verwendung des concatDemuxers.

So generiere ich jetzt auf meinem Entwicklungscomputer animierte GIF-Thumbnails in hoher Qualität in weniger als 1 Sekunde, indem ich Eingaberahmen überspringe:

# create text file which describes the ~30 input frames we want ffmpeg to process
seq -f "file 'left_frames.%04g.jpg'" 10000 500 25000 > tmp.txt

# generate the animated gif using ffmpeg only
ffmpeg -f concat -i tmp.txt -filter_complex "scale=150:-1:flags=lanczos,split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" output.gif
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.