Wie codiere ich verlustfrei eine JPG-Bildsequenz in ein Video in ffmpeg?


21

Ich habe eine große Anzahl von JPEGs, die ich verlustfrei in ein Video konvertieren möchte (oder zumindest nahezu verlustfrei, solange die Kodierungszeit nicht viel höher ist als sonst).

Naiv würde ich denken, dass es einen Codec geben sollte, der die einzelnen JPG-Frames so speichert, wie sie sind (ohne erneute Komprimierung), und möglicherweise eine nette Komprimierung erzielt, indem einige der Frames nur durch die Delta-Informationen aus dem vorherigen Frame ersetzt werden. In meinem Fall gibt es viele Sequenzen von Frames, die identisch sind oder einen winzigen Unterschied zwischen ihnen aufweisen.

Gibt es einen Codec und geeignete Einstellungen für ffmpeg, die dies erreichen können?




1
sequence-of-jpegs war lange Zeit ein Codec. Digitalkameras, die kein h.264 verwenden, zeichnen ausnahmslos MJPEG auf, und Videoaufnahmekarten, die verwendet wurden, denke ich.
Peter Cordes

Antworten:


24

Muxen Sie einfach die Bilder

Sie können die JPG-Bilder einfach muxen, um ein Video zu erstellen:

ffmpeg -framerate 30 -i input%03d.jpg -codec copy output.mkv

Beachten Sie, dass beim Weglassen -framerateein Standardwert von -framerate 25auf die Eingabe angewendet wird.

Verlustfreie Optimierung

Mit dieser Option können Sie jpegtranverlustfreie Optimierungen für jeden Frame durchführen, wodurch möglicherweise erhebliche Einsparungen bei der Dateigröße erzielt werden:

mkdir outputdir
for f in *.jpg; do jpegtran -optimize -copy none -perfect -v "$f" > "outputdir/$f"; done

Nun muxen Sie mit ffmpegwie oben gezeigt.

Überprüfen, ob es tatsächlich verlustfrei ist

Mit dem Framehash-Muxer kann der eindeutige Hash jedes Frames verglichen werden, um sicherzustellen, dass das Ergebnis wirklich verlustfrei ist:

$ ffmpeg -i input%03d.jpg -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

$ ffmpeg -i output.mkv -map 0:v -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

In den obigen Beispielen hat jeder zugeordnete Frame für die Eingabe und die Ausgabe den gleichen Hash, um sicherzustellen, dass die Frames identisch sind und die Ausgabe verlustfrei ist.

Siehe auch


Können Sie bitte klarstellen, was die beiden framemd5Befehle bewirken sollen, ohne nur die Hashes aufzulisten? Wie würde ich zusätzliche Komprimierung erhalten, wenn identische Frames identifiziert werden?
GJ.

1
Die Hashes wurden nur eingefügt, um Ihnen zu zeigen, dass die Frames mit den einzelnen Bildern identisch sind, sodass Sie die Anforderung erfüllen, "jeden einzelnen JPG-Frame unverändert (ohne erneute Komprimierung)" zu speichern.
Logan

Habe eine eigene Antwort mit einer ungeprüften Idee zum Löschen der doppelten Frames gepostet, um eine VFR MJPEG.mkv zu erhalten. VFR ist der einzige Weg, den ich mir vorstellen kann, um die zeitliche Redundanz mit MJPEG zu nutzen. : P
Peter Cordes

SSIM ist möglicherweise eine schnellere Methode zum Vergleichen der Wiedergabetreue.
Gyan

11

Dadurch wird ein verlustfreies H.264-Video ausgegeben, bei dem Frames Informationen aus anderen Frames verwenden

ffmpeg -f image2 -r 30 -i %09d.jpg -vcodec libx264 -profile:v high444 -refs 16 -crf 0 -preset ultrafast a.mp4

Erklärung der Optionen:

  • -f image2 - weist ffmpeg an, eine Gruppe von Bildern auszuwählen
  • -r 30 - Weist ffmpeg an, mit 30 Frames (oder Bildern) pro Sekunde zu codieren (ändern Sie dies auf die gewünschte Framerate)
  • -i %09d.jpg- Weist ffmpeg an, die Bilder 000000000.jpg bis 999999999.jpg als Eingabe zu verwenden. Ändern Sie den Wert 9in %09d.jpg, wie viele Nullen die Namen Ihrer Bildsequenz haben. Wenn Ihre Dateinamen beispielsweise img0001.jpg lauten, wird dies als img% 04d.jpg ausgedrückt
  • -vcodec libx264 - Weist ffmpeg an, in eine H.264-kompatible Datei auszugeben
  • -profile:v high444 - Weist libx264 an, das High 4: 4: 4 Predictive Lossless-Profil zu verwenden, um verlustfreie Codierung zu ermöglichen
  • -refs 16 - weist libx264 an, 16 Bilder in einem Puffer zu speichern, damit auf sie von anderen Bildern im Video verwiesen werden kann
  • -crf 0 - weist libx264 an, eine verlustfreie Codierung durchzuführen
  • -preset ultrafast - weist libx264 an, der Kodierungsgeschwindigkeit Vorrang vor der Größe der Ausgabedatei zu geben
  • a.mp4- weist ffmpeg an, die Ausgabe in einer MP4-Datei mit dem Namen a.mp4 zu speichern. Ändern Sie dies in den Dateinamen und das Format, das Sie verwenden möchten

3
Ein paar Anmerkungen: -f image2ist hier überflüssig. Der Image File Demuxer sollte -framerateanstelle von verwenden -r. libx264 wird automatisch die entsprechende Auswahl -profilefür störfreie und -presetwird behandeln -refs.
Logan

-refs 5Wenn Sie nicht wissen, dass in Ihren Inhalten identische Bilder enthalten sind, die durch mehrere andere getrennt sind, kann dies dazu führen, dass x264 den Verweis verliert, bevor das Duplikat vorliegt. Höher als ultrafastmacht im verlustfreien Modus wenig anders, abgesehen von CABACs ~ 10% Gewinn gegenüber CAVLC (für hohe CPU-Kosten bei den für verlustfrei erforderlichen Bitraten). Im Ernst, auf einigen Live-Action-720x480p60 (Deinterlace-Ausgang), superfastwar 28 GB, slowerwar 27 GB. Wenn die Kodierungszeit keine Rolle spielt, die Dekodierungszeit jedoch, sollten Sie CABAC vermeiden. Vielleicht sogar -tune fastdecode. Eine moderate Ref-Anzahl sollte nicht schaden.
Peter Cordes

Und wenn Sie CPU zum Brennen haben, können Sie sogar -preset placeboein paar zusätzliche Bruchteile prozentual versuchen .
DrYak

Der Vollständigkeit halber hat h265 auch einen eigenen verlustfreien Modus. -vcodec libx265 -x265-params lossless=1ist die entsprechende Option. (Aber meiner Erfahrung nach (= Aufzeichnung von Powerpoint-Diashow-Präsentationen) ist es nicht unbedingt besser und viel langsamer als h264.) Seien Sie gespannt auf das NETVC1 / Xiph's Daala von AOMedia / IETF / was auch immer es bis dahin umbenannt wird ... verlustfreier Modus
DrYak

5

Sie können eine aviAnimation als eine Reihe von pngBildern erstellen ( png ist verlustfrei, sodass die jpeg => pngKonvertierung Ihre Bilder nicht beeinträchtigen sollte):

wenn deine bilder einen namen haben img_0001.jpg

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec png video.avi

Dabei ist "25" die Bildrate, die Sie im resultierenden Video wünschen. -start_numberwird nicht benötigt, wenn es 1 ist, aber es ist nützlich, wenn Ihre erste Videonummer nicht 1 ist.

Wenn Sie mjpegmit der Befehlszeile höchster Qualität codieren möchten, gilt Folgendes :

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec mjpeg -qscale 1 video.avi

Und das Schöne an der Sache ist, dass Sie das Video wieder in eine Bilderserie umwandeln können:

ffmpeg -i video.avi "img_series_%04d.png"
ffmpeg -i video.avi "img_series_%04d.jpg"

etc...


Dies entspricht nicht wirklich den Bedürfnissen der Fragesteller. Er sucht nach einer Möglichkeit, den Rahmen nur dann verlustfrei zu aktualisieren, wenn sich das Bild ändert. Dies bedeutet, dass dasselbe Bild mehr als einmal verwendet werden kann. Auch JPEG von Natur aus ist nicht verlustfrei, da es meiner Meinung nach JPEG-Komprimierung auch bei maximaler Qualität verwendet.
AJ Henderson

Eigentlich war er zu Komprimierung bereit, obwohl ich mir nicht sicher bin, wie es mit langen Sequenzen desselben Frames weitergeht. Ich denke immer noch, dass ein Präsentationsformat mit variabler Framerate erforderlich ist, obwohl ich nicht sicher bin, ob ffmpeg eines unterstützt.
AJ Henderson

CorePNG kann auch P-Frames erstellen. Normalerweise ist JPEG keine verlustfreie Komprimierung, und ich bezweifle, dass JPEG P-Frames erzeugen kann. Ich stimme zu, dass ich die Frage nicht so beantworte, wie sie gestellt wird, aber ich gebe eine Lösung, um ein verlustfreies Video mit ffmpeg zu haben.
Olivier S

4

Um die Antwort von LordNeckbeard zu erweitern, muxen Sie einfach die JPEG-Daten in einen MJPEG-Videostream. Dies ist die kleinste Darstellung der exakten Folge von Ausgabebildern, obwohl MJPEG nach heutigen Maßstäben ein schrecklich ineffizienter Codec ist. (keine zeitliche Redundanz und auch keine Intra-Vorhersage.

Sie können ein MJPEG-Video mit variabler Bildrate erstellen, um die doppelten Bilder in Ihrer Eingabe zu nutzen.

ffmpeg -framerate 30 -i input%03d.jpg -vf mpdecimate -codec copy output.mkv  # doesn't work.

Hrm, das wird nicht funktionieren, da mpdecimate nicht für komprimierte Daten geeignet ist und wir es nicht zulassen können, dass ffmpeg die Bilddaten ohne Verlust und ohne CPU-Kosten dekodiert und erneut jpegiert.

Vielleicht, wenn Sie doppelte JPG-Quelldateien durch leere Dateien mit dieser Sequenznummer ersetzt haben, oder so?

Da diese Frage noch nicht ganz aktuell ist, werde ich mir nicht die Zeit nehmen, um herauszufinden, wie es geht, es sei denn, jemand antwortet und fragt, wie. Da MJPEG jedoch in einen mkv-Container verschoben werden kann, ist es sicher möglich, dass eine Datei die JPEG-Daten für wiederholte Frames nicht dupliziert, sondern nur einen Ausgabeframe zum Dekodieren hat, bis die Sequenz der Duplikate erreicht ist Über.

Oh, hier ist eine Idee:

ffmpeg -framerate blah -input blah -vf mpdecimate -f mkvtimestamp_v2 mpdecimate.timestamps

Entfernen (oder verschieben) Sie dann alle JPEG-Dateien für Frames, die mpdecimate löschen möchte (wahrscheinlich hat es einige Protokollierungsoptionen). Oder -vf showinfo und parsen Sie diese und verschieben oder verknüpfen Sie nur die Frames, die in der Ausgabe angezeigt werden die abgelegten JPEGs?). muxen Sie das in eine MJPEG.mkv, und machen Sie dann etwas mit mkvmerge, um die Frame-Zeitstempel durch die Zeitstempel von zu ersetzen mpdecimate.timestamps.

Wenn Sie xcodieren würden, anstatt nur JPEG-Daten in MJPEG zu muxen, wäre dies VIEL einfacher, da Sie nur meinen ersten Befehl mit mpdecimate und einem anderen Codec als verwenden würden copy, und es würde einfach funktionieren .

Ich habe nichts davon ausprobiert, da dies eine alte Frage war. Auch der Grund, warum ich die Lücken nicht ausgefüllt habe, wie Sie Ihr JPEG-Verzeichnis basierend auf der mpdecimate-Ausgabe tatsächlich filtern oder wie Sie den Timestamp-Stream tatsächlich verwenden.

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.