Wie vermeide ich flackernde Kanten von Objekten, wenn ich eine Bildschirmaufnahme mit x264 und ffmpeg in mp4 kodiere?

Das Ziel

Ich erstelle kurze Tutorials, indem ich meinen Bildschirm aufnehme (720p30fps). Der Inhalt ist nur eine Aufzeichnung der Verwendung einer Desktop-Software - also Mausbewegungen und Öffnen von Dialogen, Tippen, Zeichnen von Formen usw. Keine Hochgeschwindigkeitsaktion wie in einem Spiel, kein Live-Material, kein sprechender Kopf oder ähnliches. Nach der grundlegenden Bearbeitung der ursprünglichen Bildschirmaufnahme möchte ich die Videos mit genau der gleichen Auflösung und Framerate, die ich aufgenommen habe, in die Formate webm und mp4 codieren, und ich möchte, dass die Wiedergabequalität so nah wie möglich an der ursprünglichen Aufnahmequalität liegt. Daher sollten nach der endgültigen Codierung keine sichtbaren Komprimierungsartefakte auftreten.

Zur Originalaufnahme: Die Auflösung beträgt 1280x720 Pixel. Die Framerate beträgt 30 Bilder pro Sekunde. Die Aufzeichnungssoftware ist Simple Screen Recorder. Die Codierung ist H.264 mit einem konstanten Ratenfaktor von 10 (so nah genug an verlustfrei) in einem Matroska-Container. Die Wiedergabe des Originals zeigt überhaupt keine Artefakte.

Dann füge ich mit Blender einige sehr grundlegende Effekte wie Überblendungen und Textüberlagerungen zum ursprünglichen MKV hinzu. Rendern Sie dann in eine Bildsequenz (PNG-Format). Ich verwende einen hochwertigen Bildexport von Blender, und auch hier zeigen die Ausgabebilder keine Anzeichen von Komprimierungsartefakten.

Das Problem

Das Problem tritt auf, nachdem ich die Bildsequenz mit dem x264-Encoder mit ffmpeg in ein mp4-Video codiert habe. Manchmal flackern einige Teile einiger harter Kanten / Formumrisse. Dies sind keine beweglichen Objekte. Sie sind im Hintergrund bewegungslos im Vergleich zu der Stelle, an der sich die Maus bewegt. Es scheint zufällig. Zum Beispiel könnte ich zwei gelbe Rechtecke nebeneinander haben, jedes mit einem schwarzen Umriss, und nur der obere Teil eines der rechteckigen Umrisse flackert für ein paar Frames und stoppt dann. Es ist ein bisschen ablenkend und hässlich für eine wirklich saubere/einfache Codierung basierend auf einer Bildschirmaufnahme.

Ich sehe dies im Allgemeinen für die horizontalen dunklen Linien / harten Kanten. Gelegentlich habe ich ähnliches für vertikale Kanten gesehen.

Ich habe dieses Problem noch nicht mit den von ffmpeg erzeugten Ausgabe-Webm-Dateien bemerkt, nur mit den x264-codierten mp4-Dateien. Der ffmpeg-Befehl, den ich verwende, lautet wie folgt:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -pix_fmt yuv420p -movflags +faststart -crf 22 -r 30 -g 300 -y myvideo.mp4

Für webm verwende ich denselben grundlegenden Befehl und denselben crf-Wert, aber offensichtlich einen anderen Encoder (libvpx-vp9). Die Webm-Datei ist etwa 9 MB groß für 2 Minuten Filmmaterial. Die mp4 ist etwa 3,5 MB groß. Im Allgemeinen ist die Qualität zwischen den beiden nicht zu unterscheiden, nur in den Zeiten, in denen das mp4 einige harte Liniensegmente flimmert.

Ich habe das Problem unten anhand von ASCII-Grafiken grob dargestellt, wobei ich versuche, ein Rechteck über vier Frames zu zeigen. Zuerst ist es in Ordnung, dann wird bei einigen Frames ein Teil der Umrisslinie des Rechtecks ​​an einigen Stellen mit etwas zusätzlicher Dicke gezeichnet, sodass es ein wenig zu flackern oder zu wackeln scheint. Dann ist es wieder perfekt.

-----------------
|               |
-----------------


------=====------
|               |
-----------------


______=====______
|               |
-----------------


-----------------
|               |
-----------------

Beispiele

Vergleichen Sie die folgenden Bilder. Beachten Sie im zweiten Bild, dass bei den unteren 2 Rechtecken eine zusätzliche graue Linie über oder unter einem Teil ihres schwarzen Randes erscheint. Ich habe diese Bilder aufgenommen, während VLC meine x264-codierten mp4-Dateien mit 100 % (keine Skalierung) abgespielt hat. Dies ist kein wirklich dramatisches Beispiel, aber es reicht hoffentlich aus, um zu zeigen, was los ist. Da die zusätzlichen Linien erscheinen und verschwinden, entsteht eine Art Flimmereffekt.

Anmerkungen:

  1. Die Aufnahme wurde mit Simple Screen Recorder auf einem 1280x720-Bildschirm mit maximiertem LibreOffice Draw aufgenommen. Sie können weder in der Originalaufnahme noch in der PNG-Bildsequenz, die ich aus Blender exportiert habe, Artefakte sehen.
  2. Der Befehl, den ich zum Generieren des mp4-Videos verwendet habe, lautete:ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -coder ac -pix_fmt yuv420p -movflags +faststart -crf 22 -bf 16 -b_strategy 2 -refs 16 -direct-pred spatial -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4

Screenshot, wenn beim Abspielen von mp4 in VLC keine Artefakte angezeigt werden

Bildschirmaufnahme, wenn Artefakte erscheinen, während dieselbe MP4-Datei in VLC abgespielt wird

(Es ist einfacher, die Artefakte zu bemerken, wenn Sie zwischen den beiden Bildern in Originalgröße wechseln.)

Fragen

Wie nennt man diese Art von Kompressionsartefakt?

Welches Flag kann ich an ffmpeg übergeben, um es zu unterdrücken?

Was ich bisher probiert habe

Viel Experimentieren mit den CRF- und Geschwindigkeitswerten. Für CRF bin ich auf 18 gesunken und das scheint das Flimmern ein wenig zu reduzieren, aber nicht zu beseitigen. Aber dieser Ratenfaktor scheint viel zu niedrig zu sein, um eine anständige Codierung von Inhalten zu erhalten, die so einfach ist wie eine Bildschirmaufnahme mit geringer Aktion in 720p.

Ich habe auch versucht, b-Frames und Referenzframes manuell auf Werte zwischen 1 und 16 einzustellen, die Gop-Größe zwischen 30 und 300 variiert und verschiedene Werte für die Option -me_method ausprobiert. Und ich habe ein paar der Deinterlace-Einstellungen über die Option yadif ausprobiert, aber ich bin mir ziemlich sicher, dass dies für dieses Problem nicht relevant ist und die Qualität des Ausgabevideos nur zu verschlechtern scheint. Ich habe am Ende ffmpeg-Befehle, die eher so aussehen:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -coder ac -pix_fmt yuv420p -movflags +faststart -crf 22 -bf 16 -b_strategy 2 -refs 16 -direct-pred spatial -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4

Aber bisher hat nur das Variieren des CRF-Wertes einen merklichen Effekt gehabt. Ich möchte nicht so viel tiefer fallen, weil es die Videogröße zu sehr sprengen wird.

Update: Testergebnisse

Ich habe das obige Beispiel mit LibreOffice Draw und einem 1280x720p-Bildschirm verwendet, um einen Clip von etwa 47 Sekunden in einer H.264-codierten MKV-Datei aufzuzeichnen. Ich habe dies in Blender importiert und direkt als PNG-Bildsequenz wieder exportiert - überhaupt keine Effekte oder Bearbeitungen. Dann habe ich die Bildsequenz mit dem x264-Encoder durch ffmpeg laufen lassen, um die mp4-Videodatei zu erzeugen.

Ich habe angefangen, meinen ursprünglichen ffmpeg-Befehl Parameter für Parameter zu variieren, um den Unterschied zu sehen. Ich habe mich hauptsächlich auf den CRF-Wert konzentriert, denn nur so konnte ich definitiv eine Reduzierung der Kompressionsartefakte feststellen. Selbst wenn der CRF auf 10 eingestellt war, konnte ich an einigen Stellen immer noch das seltsame Flackern/Streifenbildung an den Rändern sehen. Schließlich habe ich den Wert auf 5 gesenkt und überhaupt keine Artefakte bemerkt. Der ideale Wert liegt für diesen Inhalt möglicherweise irgendwo zwischen 5 und 10.

Das hat mir ein Video hinterlassen, das viel zu groß für das ist, was es ist. Nachdem ich mit B-Frame- und Referenz-Frame-Werten herumgespielt hatte, um geringfügige Verringerungen der Dateigröße zu erreichen, ging ich schließlich zurück, um den gop-Wert zu variieren, und das hatte einen relativ großen Einfluss. Wenn Sie den gop auf 300 statt 30 setzen, wird die Dateigröße im Grunde halbiert. Mein letzter ffmpeg-Befehl war also dieser:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4

(Update: Ich habe den obigen Befehl ursprünglich als -crf 10 gepostet ... jetzt korrigiert auf -crf 5)

Die wichtigsten Parameter, die ich fallen ließ, waren:

  • -pix_fmt yuv420p(es könnte die Qualität beeinträchtigen)
  • -coder ac(Ich konnte keine positiven Auswirkungen mit oder ohne dies feststellen)
  • -b_strategy 2(Dies hat die Dateigröße in einigen Fällen tatsächlich leicht erhöht)
  • -direct-pred spatial(absolut keine Auswirkungen auf die Qualität/Größe der Ausgabedatei, die ich beobachten konnte)

Wenn ich die Ausgabedatei an YouTube liefern würde, würde ich erwägen, -pix_fmt yuv420pund -coder acund zurückzusetzen -flags cgop, nur weil sie diese empfehlen.

Diese Parameter führten zu einer geringfügigen Verbesserung/Verringerung der Dateigröße (wie in Bruchteilen von 1 MB):

  • -bf 16
  • -refs 16
  • -me_method umh -me_range 16

Sie können die Variation der Dateigröße im folgenden Bildschirm sehen, wo ich jede Ausgabedatei nach den von mir variierten ffmpeg-Parametern benannt habe. Alles, was nicht crf05 im Namen hat, manifestiert das Artefaktproblem.

Ausgabedateien, die durch Variieren von ffmpeg- und x264-Parametern erstellt wurden

Zum Vergleich habe ich einen ähnlichen Befehl ausgeführt, um eine Webm-Datei zu erstellen, jedoch mit einem viel schlechteren/höheren CRF-Wert. Bei einem CRF-Wert von 22 war die resultierende mp4-Datei 1,4 MB groß und hatte überhaupt keine merklichen Komprimierungsartefakte. Der ffmpeg-Befehl, den ich verwendet habe, war:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libvpx-vp9 -b:v 0 -tile-columns 2 -crf 22 -r 30 -g 300 -y myvideo.webm

Update: Weitere Testergebnisse

Den Vorschlägen von stib und Mulvya folgend habe ich die Optionen and ausprobiert und den Wert zwischen 5 und 10 variiert -tune. Ich habe dasselbe für meine eigenen Experimente mit den Optionen and getan . Die Ausgabe mp4, basierend auf meinem Eingabe-mkv-Video, hatte alle sichtbare, flackernde Komprimierungsartefakte an derselben Stelle, bis ich den crf bei Verwendung von auf 6 und bei Verwendung von auf 5 verringert habe-trelliscrf-me_method-bf-trellis-bf -refs-tune. Hier sind Screenshots, die das letzte Artefakt zeigen, das ich zu beseitigen versuche, während ich höhere crf-Werte verwende. Der erste Bildschirm ist das eingegebene mkv-Video, der zweite ist ein codiertes Beispiel-mp4-Video, das mit der Option -trellis 0 erstellt wurde. Sie können die Artefakte am oberen Rand eines der Rechtecke sehen. (Es gibt auch ein dickes graues Band im schwarzen Hintergrund – das ist jedoch kein Komprimierungsartefakt, ich denke, es ist ein Dialog, der gerade verschwindet, nachdem ich in meiner Demo/Beispielaufnahme auf „Abbrechen“ geklickt habe.)

Teil des Frames im ursprünglichen MKV-Video ohne Komprimierungsartefakte

fast der gleiche Teil des codierten MP4-Videos, der Komprimierungsartefakte zeigt

Hier sind die Befehle und die resultierenden Dateigrößen

-Tuning-Animation:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -tune animation -r 30 -g 300 -y myvideo.mp4
Größe: 2.757.370
Sichtbare Artefakte: Nein

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -tune animation -r 30 -g 300 -y myvideo.mp4
Größe: 2.593.711
Sichtbare Artefakte: Ja

-Gitter 0:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -pix_fmt yuv420p -x264opts trellis=0 -r 30 -g 300 -y myvideo.mp4
Größe: 2.214.534 Bytes
Sichtbare Artefakte: Nein

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts trellis=0 -r 30 -g 300 -y myvideo.mp4
Größe: 2.074.544 Bytes
Sichtbare Artefakte: Ja (obwohl eine winzige Menge – buchstäblich ein paar Pixel in einem Bruchteil einer Sekunde)

-fast_skip 0:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Größe: 2.012.596 Byte
Sichtbare Artefakte: Nein

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 8 -pix_fmt yuv420p -x264opts fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Größe: 1.883.919 Bytes
Sichtbare Artefakte: Ja (sehr kleine/kurze Menge)

-psy 0 -fast_pskip 0:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts psy=0:fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Größe: 1.886.919 Byte
Sichtbare Artefakte: Nein

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 8 -pix_fmt yuv420p -x264opts psy=0:fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Größe: 1.764.771 Bytes
Sichtbare Artefakte: Ja

-bf -refs:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Größe: 2.257.420 Byte
Sichtbare Artefakte: Nein

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Größe: 2.106.439 Bytes
Sichtbare Artefakte: Ja (wenn auch in winziger Menge)

-deblock:
ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -r 30 -g 300 -y myvideo.mp4
Größe: 982.549 Byte
Sichtbare Artefakte: Nein

ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -bf 16 -refs 16 -me_method umh -me_range 64 -r 30 -g 300 -y myvideo.mp4
Größe: 961.460 Bytes
Sichtbare Artefakte: Nein

Fazit

Entweder ist der vp9-Encoder viel besser darin, mit dieser Art von Videoinhalten umzugehen, oder es gibt einen mir nicht bekannten x264-Parameter, der die Dinge verbessern würde. Hat jemand eine Idee für eine Option, die ich ffmpeg geben kann, um mit x264/mp4 ein besseres Ergebnis zu erzielen? (Und ich versuche nicht, einen Codec-Krieg zu beginnen – ich muss in beiden Formaten veröffentlichen!)

Kommentare sind nicht für längere Diskussionen gedacht; diese Konversation wurde in den Chat verschoben .

Antworten (2)

Der Parameter, der den größten Einfluss auf das Entfernen dieses Artefakts zu haben scheint (für die Art des Inhalts im ursprünglichen Beitrag), während er höhere CRF-Werte zulässt, ist deblock. Die Verwendung -deblock -3,-3erlaubte einen CRF-Wert von 14, wobei die Artefakte vollständig eliminiert wurden. Die Verwendung von CRF-Werten von 15 und 16 führt das Artefakt wieder ein, wenn auch in winzigen Mengen und nicht wirklich wahrnehmbar, es sei denn, Sie suchen gezielt danach. Auch Deblock-Werte von -3 -1 und -3 -0 funktionierten recht gut, beseitigten das Artefakt bei CRF 14 jedoch nicht vollständig.

Der letzte Befehl lautete:

ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -r 30 -g 300 -y myvideo.mp4

Um noch mehr kb Komprimierung herauszuquetschen, könnten Sie die Parameter bf refs me_method umhund lesen me_range. Aber ich fand, dass ich den me_rangeSatz auf 64 brauchte. Niedrigere Werte würden das Kompressionsartefakt wieder einführen.

Hinweis: Ich hatte einige Erfolge mit dem Variieren von aq-modeund aq-strength, aber das war nicht so gut wie deblockieren zum Entfernen der Artefakte.

Die Ergebnisse der Verwendung dieses Ansatzes wurden dem ursprünglichen Beitrag zum Vergleich mit den anderen Methoden hinzugefügt.
Danke, dass du das durchgearbeitet hast. Ich denke, es ist wahrscheinlich, dass der Encoder sich nicht für Schwarz entscheiden kann, und durch die Zufälligkeit gemäß der Notwendigkeit des Encoders endet es in diesem Bereich als zufällig. Ich denke, es kann hilfreich sein, das OP jetzt zu bereinigen, damit andere es nicht durchwaten müssen, es kann helfen, eine Antwort zu erhalten. Ich war dort. Es braucht viel Zurückhaltung, wenn man eine gute Frage stellt. nicht einfach mit etwas so Kompliziertem. Könnte vielleicht sogar Antworten kombinieren, wenn sie verwandt sind? nur ein Gedanke.

Variieren Sie den CRF-Wert nach unten, bis Sie keine Komprimierungsartefakte mehr sehen. Gehen Sie bei Bedarf lächerlich niedrig, wie CRF = 5.

Variieren Sie den GOP-Wert nach oben, um die größere Ausgabedateigröße zu kompensieren. Versuchen Sie beispielsweise für ein Video mit 30 Bildern pro Sekunde gop=300

Ihr ffmpeg-Befehl könnte so aussehen:ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4

Bearbeiten: (Verwendung der richtigen Geschwindigkeitsoption für x264, Hinzufügen von pix_fmt und anderen x264-Optionen)

ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 5 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0 -bf 16 -refs 16 -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4

Ich gebe im Grunde auf, dieses Problem auf vernünftige Weise zu lösen. Dies ist eine schlecht informierte und wahrscheinlich schlechte Antwort auf meine eigene Frage. Hoffentlich kann jemand, der sich besser auskennt, mit vernünftigeren ffmpeg/x264-Parametern für diese Art von Inhalten antworten, anstatt nur den CRF-Wert auf etwas Extremes zu variieren.
Ich verwende seit einigen Monaten einen Ansatz, der meinem Beitrag ähnelt, und er funktioniert gut. Normalerweise brauche ich den CRF-Wert nicht so niedrig wie 5 ... aber 7 ist normalerweise ein vernünftiger Ausgangspunkt. Auch bei späteren Versionen von ffmpeg musste ich von -speed 1 auf -preset veryslow wechseln. (Es scheint, dass -speed eigentlich für libvpx ist, nicht für libx264). Auch diese Optionen nutze ich jetzt: -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0Antwort entsprechend aktualisiert.