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

Ich habe eine große Anzahl von JPGs, die ich verlustfrei in ein Video konvertieren möchte (oder zumindest sehr nahe an verlustfrei, solange die Codierungszeit nicht viel länger als sonst ist).

Naiverweise würde ich denken, dass es einen Codec geben sollte, der jeden einzelnen JPG-Frame so speichern kann, wie er ist (ohne erneute Komprimierung), und vielleicht eine nette Komprimierung erreichen kann, indem er einige der Frames nur durch die Informationen zum Delta des vorherigen Frames ersetzt. In meinem Fall gibt es viele Sequenzen von Einzelbildern, die untereinander identisch sind oder einen winzigen Unterschied zwischen sich aufweisen.

Gibt es einen Codec und geeignete Einstellungen für ffmpeg, mit denen dies erreicht werden kann?

Sequence-of-JPEGs ist seit LANGER Zeit ein Codec. Digitalkameras, die kein h.264 verwenden, zeichnen ausnahmslos MJPEG auf, und Videoaufnahmekarten haben es verwendet, denke ich.

Antworten (4)

Einfach die Bilder muxen

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, wenn Sie weglassen, -framerateein Standard von -framerate 25auf die Eingabe angewendet wird.

Verlustfreie Optimierung

Sie können verwenden jpegtran, um eine verlustfreie Optimierung für jeden Frame durchzuführen, was zu erheblichen Einsparungen bei der Dateigröße führen kann:

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

Jetzt muxen Sie mit ffmpegwie oben gezeigt.

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

Der Framehash-Muxer kann verwendet werden, um den eindeutigen Hash jedes Frames zu vergleichen, 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 teilen sich alle zugehörigen Frames für die Ein- und Ausgabe denselben Hash, wodurch sichergestellt wird, dass die Frames identisch und die Ausgabe verlustfrei ist.

Siehe auch

könnten Sie bitte klarstellen, was die beiden framemd5Befehle über das bloße Auflisten der Hashes hinaus erreichen sollen? Wie würde ich eine zusätzliche Komprimierung erhalten, wenn identische Frames so identifiziert werden?
Die Hashes wurden nur eingefügt, um Ihnen zu zeigen, dass die Frames mit den einzelnen Bildern identisch sind, sodass Sie Ihre Anforderung erfüllen, "jeden einzelnen JPG-Frame unverändert (ohne Neukomprimierung)" zu speichern.
Ich habe eine eigene Antwort mit einer ungetesteten Idee zum Löschen der doppelten Frames gepostet, um am Ende eine VFR MJPEG.mkv zu erhalten. VFR ist die einzige Möglichkeit, die ich mir vorstellen kann, um die zeitliche Redundanz mit MJPEG zu nutzen. :P
SSIM kann eine schnellere Möglichkeit sein, die Wiedergabetreue zu vergleichen.

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

Erläuterung der Optionen:

  • -f image2- weist ffmpeg an, eine Gruppe von Bildern auszuwählen
  • -r 30- weist ffmpeg an, mit 30 Bildern (oder Bildern) pro Sekunde zu codieren (ändern Sie dies auf Ihre gewünschte Bildrate)
  • -i %09d.jpg- weist ffmpeg an, die Bilder 000000000.jpg bis 999999999.jpg als Eingabe zu verwenden. Ändern Sie das 9in %09d.jpgwie viele Nullen der Name Ihrer Bildsequenz hat. 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 Profil High 4:4:4 Predictive Lossless zu verwenden, was eine verlustfreie Codierung ermöglicht
  • -refs 16- weist libx264 an, 16 Bilder in einem Puffer zu speichern, damit sie von anderen Bildern im Video referenziert werden können
  • -crf 0- weist libx264 an, eine verlustfreie Codierung durchzuführen
  • -preset ultrafast- weist libx264 an, der Codierungsgeschwindigkeit Vorrang vor der Größe der Ausgabedatei zu geben
  • a.mp4- weist ffmpeg an, die Ausgabe in einer MP4-Datei namens a.mp4 zu speichern. Ändern Sie dies in den Dateinamen und das Format, das Sie verwenden möchten
Ein paar Anmerkungen: -f image2ist hier überflüssig. Der Bilddatei-Demuxer sollte -framerateanstelle von -r. libx264 wählt automatisch die passende -profilefür verlustfrei aus und -presetbehandelt die -refs.
-refs 5bei MOST, es sei denn, Sie wissen, dass Ihr Inhalt identische Bilder enthält, die durch mehrere andere getrennt sind, kann dies dazu führen, dass x264 die Referenz verliert, bevor es zum Duplikat gelangt. Höher als ultrafastmacht im verlustfreien Modus kaum einen Unterschied, abgesehen von CABACs ~ 10% Gewinn gegenüber CAVLC (für hohe CPU-Kosten bei den für verlustfreien Bitraten erforderlichen Bitraten). Im Ernst, bei einer Live-Action waren 720 x 480p60 (Deinterlace-Ausgabe) superfast28 GB, slowerwaren 27 GB. Wenn die Codierungszeit keine Rolle spielt, die Decodierungszeit jedoch, stellen Sie sicher, dass Sie CABAC vermeiden. Vielleicht sogar -tune fastdecode. Eine moderate Anzahl von Refs sollte nicht schaden.
Und wenn Sie CPU zum Brennen haben, können Sie sogar versuchen -preset placebo, ein paar Prozent mehr zu bekommen.
Der Vollständigkeit halber hat h265 auch einen eigenen verlustfreien Modus. -vcodec libx265 -x265-params lossless=1ist die gleichwertige Option. (Aber nach meiner Erfahrung (= Aufzeichnung von Powerpoint-Diashow-Präsentationen) ist es nicht unbedingt besser und viel langsamer als h264) Bleiben Sie dran für AV1 von AOMedia/NETVC1 von IETF/Daala von Xiph/wie auch immer es bis dahin umbenannt wird ... im verlustfreien Modus
Gott segne dich !

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 Ihre Bilder einen Namen habenimg_0001.jpg

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

wobei "25" die Bildrate ist, die Sie im resultierenden Video haben möchten. -start_numberist nicht erforderlich, wenn es 1 ist, aber es ist nützlich, wenn Ihre erste Videonummer nicht 1 ist.

Wenn Sie mit höchster Qualität kodieren möchten, mjpegist die Befehlszeile:

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 Anforderungen des Fragestellers. Er sucht nach einer Möglichkeit, dass der Rahmen nur dann verlustfrei aktualisiert werden kann, wenn sich das Bild ändert. Das bedeutet, dass dasselbe Bild mehr als einmal verwendet werden kann. Auch JPEG ist von Natur aus nicht verlustfrei, da es meines Erachtens selbst bei maximaler Qualität die JPEG-Komprimierung verwendet.
Eigentlich war er wohl bereit, etwas zu komprimieren, obwohl ich nicht sicher bin, wie es bei langen Sequenzen desselben Frames funktionieren wird. Ich denke immer noch, dass ein Präsentationsformat mit variabler Bildrate benötigt wird, obwohl ich nicht sicher bin, ob ffmpeg eines unterstützt.
CorePNG kann auch P-Frames erstellen. Normalerweise ist JPEG keine verlustfreie Komprimierung, und ich bezweifle, dass MJPEG P-Frames erstellen 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.

Um die Antwort von LordNeckbeard zu erweitern, ja, muxen Sie einfach die JPEG-Daten in einen MJPEG-Videostream. Das 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 nicht einmal eine Intra-Vorhersage.

Sie können ein MJPEG-Video mit variabler Framerate 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 bei komprimierten Daten nicht funktioniert und wir ffmpeg die Bilddaten nicht ohne Verlust und CPU-Kosten dekodieren und dann neu jpegieren können.

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

Da diese Frage noch nicht einmal neu ist, werde ich mir nicht die Zeit nehmen, herauszufinden, wie es geht, es sei denn, jemand antwortet, um zu fragen, wie. Aber da MJPEG in einen mkv-Container gehen kann, bin ich sicher, dass es möglich ist, eine Datei zu haben, die die JPEG-Daten für wiederholte Frames nicht dupliziert, sondern einfach keinen Ausgabeframe zum Decodieren hat, bis die Sequenz von Duplikaten ist über.

Ach hier eine Idee:

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

Entfernen (oder verschieben) Sie dann alle JPEGs für Frames, die mpdecimate löschen möchte (wahrscheinlich hat es einige Protokollierungsoptionen? Oder -vf showinfo, und analysieren Sie das und verschieben oder verlinken Sie nur die Frames, die in seiner Ausgabe angezeigt werden, und lassen Sie sie zurück die gelöschten JPEGs?). muxen Sie das in eine MJPEG.mkv, dann tun Sie etwas mit mkvmerge, um die Frame-Zeitstempel darin 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 einfach meinen ersten Befehl mit mpdecimate und einem anderen Codec als verwenden copywürden, und es würde einfach funktionieren (tm).

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 Zeitstempel-Stream tatsächlich verwenden.