Stellen Sie die Anzeigezeit einzelner Frames in FFmpeg ein

Ich habe eine Reihe von Bildern, die ich zum Zweck der Verbesserung aus einer GIF-Animation extrahiert habe (was ich getan habe), aber jetzt ist es an der Zeit, die Standbilder in ein Video umzuwandeln (ich werde webm für eine Ausgabe mit höherer Qualität verwenden ) Ich bin auf ein Problem gestoßen. Das GIF-Format ermöglicht die Anzeige einzelner Frames für eine künstliche Zeitspanne, und diese spezielle GIF-Animation nutzt diese Funktion, wobei die meisten Frames 125 Millisekunden lang angezeigt werden, einige jedoch bis zu 3000 Millisekunden auf dem Bildschirm bleiben. Das einfache Generieren eines Videos mit einer festgelegten Bildrate wird also nicht funktionieren, da dies den Ablauf der Animation unterbrechen würde. Ich brauche eine Möglichkeit, die Bilddauerdaten aus der ursprünglichen GIF-Datei zu importieren und die extrahierten, modifizierten Bilder mit diesen Daten in ein Video zu codieren.

Gibt es eine Möglichkeit, dies mit FFmpeg oder vielleicht einer Kombination aus FFprobe und FFmpeg zu tun? Ich habe das GIF durchlaufen ffprobe -show_frameslassen und es scheint, dass die Informationen, die ich brauche pkt_duration_time, die Anzeigedauer des Frames sind.

@Gyan Danke, dass du mich in die richtige Richtung gewiesen hast. Ich habe unten eine Antwort auf meine Frage gepostet.

Antworten (1)

Ich habe eine ganze Weile mit Googeln und Trial-and-Error gebraucht, aber ich habe endlich herausgefunden, wie man das tatsächlich macht. Danke an Gyan, der mich in die richtige Richtung weist.

Ich habe versucht, mehr von dem Prozess als Einzeiler zu machen, aber es wurde immer zu einem nicht funktionierenden, nicht debuggbaren Durcheinander. Wenn Sie glauben, Sie könnten dies skripten, tun Sie dies bitte, testen Sie es und posten Sie es dann als neue Antwort.


Zeile drucken pkt_duration_timeund in einer Datei speichern:

ffprobe -show_frames input.gif | grep pkt_duration_time= >frames.txt

Ändern Sie die Zeile in das Format, das der Concat-Filter von FFmpeg erfordert:

sed 's/pkt_duration_time=/duration /g' frametimes.txt >frametimes.txt

Drucken Sie eine Liste Ihrer Eingabedateien (Frames), die sich in befinden, folder/und ändern Sie die Liste in das Format, das der Concat-Filter von FFmpeg erfordert:

ls --quoting-style=shell folder/ >filenames.txt && sed -i -e 's/^/file /' filenames.txt

Kombinieren Sie Ihre Frame-Time-Datei und die Dateinamendatei zu einer Concat-Datei, die FFmpeg akzeptiert:

paste -d \\n filenames.txt frametimes.txt > folder/concatfile.txt

Wir haben die Concat-Datei dort gespeichert, wo sich die Eingabedateien befinden, da FFmpeg sie sonst nicht akzeptiert. Eine Sache noch, bevor wir das Video kodieren können: Die Daten für das letzte Bild müssen aus irgendeinem Grund zweimal in der Concat-Datei vorhanden sein. Ich habe kein CLI dafür, also kopiere es einfach manuell und füge es ein.

Jetzt können wir FFmpeg verwenden, um die Bilddateien in ein animiertes Video mit korrekten Bildzeiten umzuwandeln:

cd folder/

ffmpeg -f concat -safe 0 -i concatfile.txt -pix_fmt yuv420p -c:v libvpx-vp9 -b:v 0 -cpu-used 0 -tile-columns 2 -row-mt 1 -lag-in-frames 25 -threads 16 -crf 35 ../output.webm

  • Der -safe 0Schalter ist erforderlich, da sich FFmpeg sonst über unsichere Dateinamen beschwert. Zumindest in meinem Fall, möglicherweise weil die Dateinamen eckige Klammern enthielten.

  • Das -pix_fmt yuv420pstellt sicher, dass der richtige Farbraum verwendet wird. Wenn Sie dies weglassen, wird ein Farbraum verwendet, der kein Standard für Webvideos ist, und im Fall von VP9 verwendet die resultierende Datei Profil 1, das keine so breite Hardware-Decodierungsunterstützung wie Profil 0 hat. Sie könnten -profile:v 0es verwenden Stellen Sie sicher, dass dies nicht unbemerkt geschieht.

Die restlichen Parameter sind Qualitäts- und Ratenkontrollfunktionen für libvpx-vp9. Denken Sie daran, zumindest zu verwenden -b:v 0, sonst verhält sich CRF nicht wie erwartet. Beachten Sie auch, dass die Einstellung -tile-columnsund -threadsmanuell erforderlich ist, da die Codierung ansonsten auf einen einzelnen Thread beschränkt ist.