Leistung mehrerer FFMPEG-Ausgänge (Einzelinstanz vs. Mehrfachinstanzen)

2897
shalin

Ich arbeite daran, mehrere kodierte Streams aus der einzelnen Dateieingabe (.mp4) zu erstellen. Eingangsstrom hat kein Audio. Jeder codierte Stream wird erstellt, indem ein anderer Teil der Eingabe zugeschnitten und anschließend auf 32-Kern-Systemen mit derselben Bitrate codiert wird.

Hier sind die Szenarien, die ich im ffmpeg-Wiki zum Erstellen mehrerer Ausgaben versuche. https://trac.ffmpeg.org/wiki/Erstellen von%20multiple%20outputs

Szenario1 (Verwenden einer einzelnen ffmpeg-Instanz)

ffmpeg -i input.mp4 \

-filter: v crop = iw / 2: ih / 2: 0: 0 -c: v libx264 -b: v 5M out_1.mp4 \

-filter: v crop = iw / 2: ih / 2: iw / 2: 0 -c: v libx264 -b: v 5M out_2.mp4 \

-filter: v crop = iw / 2: ih / 2: 0: ih / 2 -c: v libx264 -b: v 5M out_3.mp4

In diesem Fall gehe ich davon aus, dass ffmpeg die Eingabe nur einmal decodiert und allen Zuschneidefiltern zur Verfügung gestellt wird. Bitte korrigieren Sie mich, wenn das nicht stimmt.

Szenario2 (Verwendung mehrerer ffmpeg-Instanzen und somit drei separate Prozesse)

ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: 0: 0 -c: v libx264 -b: v 5M out_1.mp4

ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: iw / 2: 0 -c: v libx264 -b: v 5M out_2.mp4

ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: 0: ih / 2 -c: v libx264 -b: v 5M out_3.mp4

In meinem Fall muss ich tatsächlich noch mehr Streams kodieren, indem ich verschiedene Abschnitte des Eingangsvideos zuschneide. Ich zeige hier drei, um dieses Beispiel zu vereinfachen.

In Bezug auf die fps-Leistung sehe ich nun, dass Szenario 2 bessere Ergebnisse erzielt. Es nutzt auch die maximale CPU-Auslastung (mehr als 95% CPU-Auslastung). Szenario 1 hat weniger FPS und die CPU-Auslastung ist viel niedriger (fast 65%). In diesem Fall steigt die CPU-Auslastung mit zunehmender Anzahl der zu codierenden Ströme nicht linear an. es wird fast 1,5x, wenn ich von einem Stream zu zwei gehe. Danach sind die Inkremente jedoch sehr niedrig (wahrscheinlich 10% und bei mehr Streams sogar noch weniger).

Meine Frage ist also: Ich möchte die Einzelinstanz ffmpeg verwenden, weil sie das mehrfache Dekodieren vermeidet und auch, weil die Eingabe, die ich habe, so groß wie 4K oder sogar größer sein könnte. Was muss ich tun, um eine bessere CPU-Auslastung (> 90%) und damit hoffentlich bessere FPS zu erreichen? Warum steigt die CPU-Auslastung nicht linear mit der Anzahl der zu codierenden Streams? Warum funktioniert die Einzelinstanz ffmpeg nicht so gut wie mehrere Instanzen? Mir scheint, dass mit einer einzigen ffmpeg-Instanz nicht alle Codierungen wirklich parallel laufen.

Edit: Hier ist der einfachste Weg, wie ich das Problem reproduzieren und erklären kann, falls die Dinge nicht so klar sind. Denken Sie daran, dass dies nur experimentell ist, um das Problem zu verstehen.

Einzelinstanz: ffmpeg -y -i input.mp4 -c: v libx264 -x264opts Threads = 1 -b: v 1M -f null - -c: v libx264 -x264opts Threads = 1 -b: v 1M -f null - - c: v libx264 -x264opts Threads = 1 -b: v 1M -f null -

Mehrere Instanzen: ffmpeg -y -i input.mp4 -c: v libx264 -x264opts Threads = 1 -b: v 1M -f null - | ffmpeg -y -i input.mp4 -c: v libx264 -x264opts Threads = 1 -b: v 1M -f null - | ffmpeg -y -i input.mp4 -c: v libx264 -x264opts-thread = 1 -b: v 1M -f null -

Beachten Sie, dass ich x264 auf einen einzelnen Thread beschränke. Im Falle einer einzelnen Instanz würde ich davon ausgehen, dass ffmpeg für jede x264-Codierung 1 Codierungsthread generiert und parallel ausführt. Ich sehe jedoch, dass nur ein CPU-Kern voll ausgelastet ist. Dies lässt mich glauben, dass jeweils nur eine Codierungssitzung läuft. Auf der anderen Seite sehe ich bei mehreren Instanzen, dass drei CPU-Kerne voll ausgelastet sind. Dies bedeutet, dass alle drei Codierungen parallel laufen.

Ich hoffe wirklich, dass einige Experten dabei helfen können.

5
Übrigens, ich habe ausführlich nach dem oben genannten Thema gesucht und keiner der Beiträge spricht wirklich darüber, warum die einzelne Instanz nicht so gut funktioniert. Der nächste Post, den ich finden konnte, war dieser (https://stackoverflow.com/questions/12465914/how-to-optimize-ffmpeg-w-x264-for-multiple-bitrate-output-files), aber ohne die Art von Details, nach denen ich suche. shalin vor 6 Jahren 0

3 Antworten auf die Frage

1
aergistal

Ein weniger offensichtliches Problem besteht darin, dass je nach Eingabe / Ausgabe oder Filtern ffmpegmöglicherweise eine interne Konvertierung des Pixelformats erforderlich ist. In bestimmten Fällen wird dies zu einem Engpass, wenn parallele Ausgaben verwendet werden, wenn dies für jeden Stream separat erfolgt.

Die Idee ist, die Konvertierung des Pixelformats möglichst einmal durchzuführen, z.

-filter_complex '[0:v]format=yuv420p, split=3[s1][s2][s3]' \ -map '[s1]' ... \ -map '[s2]' ... \ -map '[s3]' ... \ 

Dieselben Filter, die auf alle Ausgänge angewendet werden, sollten auch nur einmal verwendet werden. Einige Filter benötigen möglicherweise ein bestimmtes Pixelformat.

Für andere Ursachen sehen Sie den kleinen Hinweis am Ende des Wikis :

Parallele Kodierung

Die mehrfache Ausgabe und erneute Codierung im selben FFmpeg-Prozess wird in der Regel auf den "langsamsten Encoder" in Ihrer Liste verlangsamt. Einige Encoder (wie libx264) führen ihre Codierung "im Thread und im Hintergrund" durch, so dass sie tatsächlich parallele Codierungen zulassen. Die Audiocodierung kann jedoch seriell sein und zum Flaschenhals werden, wird es von FFmpeg als "echte serielle" behandelt und daher verwendet Ihr FFmpeg möglicherweise nicht alle verfügbaren Kerne.

0
Akumaburn

Ich habe dies selbst mit einer niedrigen / standardmäßigen Videopuffergröße bemerkt.

Erhöhen Sie Ihre Größe auf 50M oder die Hälfte Ihrer Dateigröße, je nachdem, welche Größe kleiner ist.

Beachten Sie auch, dass der Parameter "bufsize" in Einheiten von k angegeben wird. In diesem Fall handelt es sich also um "-bufsize 50000k"

Also habe ich die Befehlszeile so geändert, dass sie bufsize auf folgende Weise enthält: ffmpeg -i input.mp4 -filter: v crop = iw / 2: ih / 2: 0: 0 -c: v libx264 -b: v 5M ** - bufsize 50000k ** out_1.mp4 -filter: v crop = iw / 2: ih / 2: iw / 2: 0 -c: v libx264 -b: v 5M ** - bufsize 50000k ** out_2.mp4 -filter: v crop = iw / 2: ih / 2: 0: ih / 2 -c: v libx264 -b: v 5M ** - Größe 50000k ** out_3.mp4 **, aber ich sehe keine Verbesserung der fps-Leistung oder der CPU Nutzung** shalin vor 6 Jahren 0
Seltsamerweise verbesserte sich meine CPU-Auslastung mit der höheren Puffergröße erheblich. Wie lange dauert die Videodatei / Dateigröße? Akumaburn vor 6 Jahren 0
Ich habe dies mit der Dateigröße (100 MB bis 1 GB) und der Dauer (1 Minute bis 10 Minuten) versucht. Ich kann wirklich nicht verstehen, warum die Dateigröße / -dauer hierauf Einfluss hat. Die Auflösung des Eingangsrahmens, die ich ausprobiert habe, ist 1080p, 4K und höher. shalin vor 6 Jahren 1
Ich habe das selbst getestet, direkt mit libx264, allerdings nicht über die Befehlszeile von ffmpeg. Vielleicht erwartet ffmpeg ein anderes Format? Was passiert, wenn Sie -bufsize 50M ausprobieren? Akumaburn vor 6 Jahren 0
0
flolilolilo

Ich kann dein Problem nicht reproduzieren. Konfiguration:

Mein Code in Powershell:

# Measure time of FFMPEG process $time = Measure-Command{ ffmpeg -ss 00:01:00.000 -i .\ToS-4k-1920.mov ` -to 00:00:25.000 -c:v libx264 -b:v 5M -y .\out_1.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_2.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:ih/2" -c:v libx264 -b:v 5M -y .\out_3.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_4.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_5.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_6.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_7.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_8.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_9.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_10.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_11.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_12.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:0" -c:v libx264 -b:v 5M -y .\out_13.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_14.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:ih/2" -c:v libx264 -b:v 5M -y .\out_15.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_16.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_17.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_18.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_19.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_20.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_21.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_22.mp4 ` -to 00:00:25.000 -c:v libx264 -b:v 5M -y .\out_23.mp4 ` -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_24.mp4 }  Write-Host "Time spent: $time" 

Ergebnis:

  • $time: 00: 05: 52.7747482
  • ffmpegs Geschwindigkeit: speed=0.0711x

Beide Werte erscheinen mir vernünftig.

Selbst 24 parallele Ausgänge zeigen hier kein Problem - die CPU bleibt während des gesamten Prozesses bei> 95%, fast keine Verwendung der SSD (<5%) und ~ 75% des Arbeitsspeichers (im Leerlauf ~ 30%). werden verwendet). (Manuell überprüfte Werte über den Task-Manager)

Hier gibt es also einige Möglichkeiten:

  • Sie verwenden eine alte Version von FFmpeg
  • Etwas anderes (HDD, RAM) führt zu Engpässen
  • Mit Ihrer Datei stimmt etwas nicht - unwahrscheinlich, denke ich
  • Etwas stimmt nicht mit Ihrer CPU - ebenso unwahrscheinlich, wie Sie feststellen, dass sie mit voller Kapazität arbeitet, wenn Sie mehrere Instanzen von ffmpeg verwenden.
  • -threadsProbieren Sie verschiedene -Werte in Ihrem Code aus und prüfen Sie, ob dies einen Unterschied macht.
Ich verwende Google Cloud-Instanz mit 64 CPU und 416 GB RAM. So können wir CPU-, RAM-, HDD-Probleme usw. problemlos ausschließen. Ich verwende dies seit einiger Zeit und hat eine sehr konstante und zuverlässige Leistung für alle Benchmarks. Die FFMPEG-Version, die ich hatte, war etwa 6 Monate alt und ich habe auch den neuesten 3.3.2-Build ausprobiert, aber das hat nicht geholfen. Ich hatte auch versucht, die Anzahl der Threads ohne Erfolg zu ändern. shalin vor 6 Jahren 0
Zurück zur Hauptdiskussion habe ich versucht, Ihre Befehlszeile auszuführen. Damit bekomme ich etwa 12 Bilder pro Sekunde bei weniger als 50% CPU-Auslastung. Wenn ich jedoch jede Codierung als separaten ffmpeg-Prozess ausführte, kann ich mit fast 100% CPU-Auslastung fast 30fps erreichen. Denken Sie daran, ich habe 64 Kerne, daher muss die Arbeitslast wirklich parallel sein und eine hohe Rechenleistung erfordern, um die volle Auslastung zu erreichen. In Ihrem Fall ist es einfach, 100% CPU zu erreichen, da Sie nur 4 Kerne haben. shalin vor 6 Jahren 1
Natürlich haben Sie Recht, dass mein 4-Core-Setup nicht mit Ihrem 64-Core-One vergleichbar ist - es tut mir leid, ich habe den Satz, der dies erklärt hat, total vermisst. In etwa 72 Stunden konnte ich es auf einer i7-5820k-CPU testen, aber ich denke, das ist auch nicht wirklich vergleichbar und daher auch nutzlos. Haben Sie es mit der oben genannten Datei versucht? Ändert "-an" auch etwas? Abgesehen davon habe ich keine Ideen - es tut mir leid ... flolilolilo vor 6 Jahren 0
Ja, ich habe es mit der Datei versucht, die Sie mir gegeben haben. auch -an ändert nichts. Vielen Dank, dass Sie Ihre Zeit damit verbracht haben. shalin vor 6 Jahren 0
Übrigens, wenn Sie Zeit haben, können Sie den Bearbeitungsbereich meiner ursprünglichen Frage auschecken und beide Fälle mit Ihrer Eingabedatei ausprobieren. Ich bin mir sicher, dass Sie mit Ihrer 4-Kern-Plattform reproduzieren können, was ich versuche zu erklären. shalin vor 6 Jahren 0
Ich habe das überprüft und kann das Problem mit '-x264opts Threads = 1' reproduzieren. Dies ist jedoch zu erwarten, da es die Threads reduziert. Normalerweise sollte ein Thread pro Kern (oder mehr) verwendet werden. Ich lasse PowerShell einige CSVs mit Start- und Endzeiten der Tests und RAM- + CPU-Statistiken erstellen - das ist ein riesiger Datenstapel. Ich fütterte es in ein Diagramm in Excel und stellte fest, dass: a) `x264opts`-Threads effizienter sind als` -threads`. B) alles, was über einem Thread steht, zumindest die Chance hat, 100% CPU zu erhalten. C) mehr Threads = mehr RAM verwendet d) auto (was nichts mit Threads zu tun hat) funktioniert recht gut. flolilolilo vor 6 Jahren 0
(kann meinen letzten Kommentar nicht mehr bearbeiten). Aber ich weiß, dass du das weißt. Ich würde mich sehr freuen, meine Testergebnisse verteilen zu können (mittlerweile habe ich sie sogar auf meinem 5820k laufen lassen), aber ich habe keine Ahnung, wie ich dies innerhalb der Grenzen von superuser.com tun sollte, da das Diagramm allein 200 cm betragen muss breit für einen etwas zu sehen ... flolilolilo vor 6 Jahren 0