ffmpeg beim Kopieren aller Soundspuren unverhältnismäßig langsam

  • Gestern hab ich meine ersten Schritte mit ffmpeg gemacht und ein Skript gefunden, welches das Proxy-Preset von Handbrake nachahmt. Das ist genau, was ich gesucht habe, weil ffmpeg deutlich schneller und etwas zuverlässiger ist (Handbrake verschluckt gerne mal eine Sekunde, was sehr schlecht ist). So sieht es aus:



    Code
    ffmpeg -i "INPUT" -vf scale=-1:540 -c:v libx264 -profile:v high -preset superfast -crf 16 -x264opts keyint=1:min-keyint=1:ref=1:bframes=0:qcomp=0.8:aq-strength=0.5 -c:a copy -y "OUTPUT"


    Mein Problem damit ist, dass durch dieses Skript nur die erste Soundspur mit exportiert wird. Damit Premiere es als Proxy akzeptiert, muss er aber genau so viele Soundspuren haben, wie die Originaldatei, also habe ich etwas gesucht und -map 0:a zum Skript hinzugefügt, wodurch es jetzt so aussieht:



    Code
    ffmpeg -i "INPUT" -vf scale=-1:540 -c:v libx264 -profile:v high -preset superfast -crf 16 -x264opts keyint=1:min-keyint=1:ref=1:bframes=0:qcomp=0.8:aq-strength=0.5 -c:a copy -map 0:a -y "OUTPUT"


    Das Problem ist aber, dass wenn ich das erste Skript benutze, die Encodierung des Videos sofort beginnt und der Sound scheinbar gleichzeitig bearbeitet wird. Das zweite Skript allerdings lässt ffmpeg erst einmal den Sound bearbeiten und das alleine dauert fast so lange, wie er sonst für die ganze Videospur braucht. Dadurch verdoppelt sich also die Zeit, die er für das ganze Video braucht.


    Ganz anders: Das untere Skript encodiert NUR den Sound und ignoriert das Video komplett!


    Ich mache bestimmt irgendwas falsch oder verstehe etwas nicht - was muss ich ändern?


    (In diesem Zusammenhang sei erwähnt, dass ich den eigentlichen Inhalt der Soundspuren nicht brauche - sie müssen nur vorhanden sein. Den Sound selber nutze ich aus der Originaldatei, nicht aus dem Proxy. Falls es also irgendeine absurde Einstellung gibt, die die gleiche Anzahl an Soundspuren erstellt, wie der Input vorgibt, sie jedoch leer lässt und dadurch überhaupt keine Zeit dafür geopfert werden muss, wäre das auch eine Alternative!)

  • Wenn du 'ne map angibst, muss auch das Video mitgenommen werden, weil du sie ja neu mapst dann, statt Auto.
    Probier mal
    -map 0 -map 1 -map 2
    Gibt glaube ich tatsächlich die Möglichkeit eine dummy leer audio zu generieren. Aber da müsst ich selber erstmal nachlesen.



    qcomp=0.8:aq-strength=0.5

    Was für einen Sinn siehst du in diesen Settings?


    Warum benutzt du nicht NVEnc? Wenn es schnell gehen soll, wäre NVEnc doch wesentlich logischer als über die CPU.

  • Was für einen Sinn siehst du in diesen Settings?

    Sorry, kann ich dir nicht beantworten. Das ist alles noch sehr neu für mich und das Preset von Handbrake hatte als Proxy gut funktioniert und dieses Skript ist praktisch genau das, was Handbrake tut. Was das im einzelnen bedeutet, weiß ich nicht. Ich habe das ganz ignorant übernommen.


    Wenn ich -map 0 hinzufüge, passiert das gleiche, wie wenn ich die Soundspuren einzeln hinzufüge, also per -map 0:0 -map 0:1 -map 0:2 - er gibt mir den Fehler aus "Too many packets buffered for output stream 0:0." Dazu hatte ich auch schon einen Fix gefunden und "-max_muxing_queue_size 1024" hinzugefügt. An anderer Stelle hieß es, man sollte 9999 statt 1024 eingeben. Im Endeffekt verzögert das aber nur den Zeitpunkt, wann der Fehler auftritt.

  • Ich hatte jetzt eher so an:
    -map 0 -map 1 -map 2
    gedacht


    so das dann:
    1:0 (das Video)
    2:0 (Audio1)
    3:0 (Audio2)


    entsteht.


    0:1
    0:2
    0:3
    würde sich alles auf Spur ID 0 beziehen. Aber die sind ja eher aufsteigend, da sie ja seperate Dateien sind und bleiben sollen.

  • Genau das hatte ich glaube ich schon einmal probiert und da kommt wieder "Too many packets buffered for output stream 0:0."


    War wohl mal ein bekannter Bug, der aber inzwischen gefixt wurde und das Hinzufügen von "-max_muxing_queue_size 1024" bringt keine Lösung, die den ganzen Encode übersteht.

  • -map 0:0 == 1. Stream (video)
    -map 0:1 == 2. Stream (1. audio spur)
    -map 0:2 == 3. Stream (2. audio spur)
    usw


    ffmpeg -i 2020.mkv -map 0:0 -c copy -movflags +faststart 0.mp4
    ffmpeg -i 2020.mkv -map 0:1 -c copy 1.aac
    ffmpeg -i 2020.mkv -map 0:2 -c copy 2.aac
    ffmpeg -i 2020.mkv -map 0:3 -c copy 3.aac
    ffmpeg -i 2020.mkv -map 0:4 -c copy 4.aac
    ffmpeg -i 2020.mkv -map 0:5 -c copy 5.aac
    ffmpeg -i 2020.mkv -map 0:6 -c copy 6.aac

  • @Bin Kein Account Danke, dass du versuchst, zu helfen aber deine knappe Formulierung hilft mir leider nicht. Ich bin da nicht so bewandert drin. Wenn ich jeden einzelnen Stream als Kopie definiere, scheint er das auch auf den Videostream zu beziehen. Könntest du vielleicht ein zusammenhängendes Skript als Beispiel posten? Ich werde aus deinem Beitrag leider nicht schlau.


    Natürlich könnte ich auch ein Skript pro Spur erstellen und das am Ende muxen. War das so gemeint? Weil dann kann ich auch nur den Videostream encodieren und mit dem Sound aus dem Original muxen. Dafür brauche ich ja keine Kopie des Streams.

  • Statt es mit einem Befehl den Stream zu zerfleddern (Was bei FFmpeg ewig dauert), würde ich das genau so in Angriff nehmen wie dein Vorposter und alles einzeln machen. Am besten alles in eine Batch Datei kapseln und gut ist. (Das geht schneller, da jeder Stream einzeln behandelt wird)


    Denn dein Problem war ja:

    Das Problem ist aber, dass wenn ich das erste Skript benutze, die Encodierung des Videos sofort beginnt und der Sound scheinbar gleichzeitig bearbeitet wird.


    Und das umgehst du somit.


    Sprich in der Batch Datei sollten folgende FFmpeg Befehle stehen:
    1x FFmpeg Befehl was sich nur um das Video kümmert und Audio Spuren ignoriert.
    1x - 999x FFmpeg Befehle die sich eine Audiospur nach der anderen vornehmen und die Videospur ignorieren.
    1x FFmpeg Befehl das die gesamte Show in einen Stream verkapselt. (Video und Audio Copy Modus aus mehreren Quellen)



    Machst du alles in einem FFmpeg Befehl wird auch alles gleichzeitig verarbeitet, da FFmpeg gleichzeitig auch ein Pipeline Tool ist. Theoretisch kann man Videos samt Audio an ein anderes Consolen Tool pipen lassen. z.B. an x264 oder SoX oder Lame MP3 Encoder oder oder oder...


    Man kann FFmpeg am Anfang oder ans Ende eine Piping Kette setzen. Das ist egal.


    Daher mache am besten alles in einer Batch Datei die eins nach den anderen ab arbeitet. Wichtig ist das das Muxing am Ende steht.
    Und du kannst mir glauben das wenn du alles einzeln machst das gut 10x schneller ist, als wenn du alles gleichzeitig machst.


    (In diesem Zusammenhang sei erwähnt, dass ich den eigentlichen Inhalt der Soundspuren nicht brauche - sie müssen nur vorhanden sein. Den Sound selber nutze ich aus der Originaldatei, nicht aus dem Proxy. Falls es also irgendeine absurde Einstellung gibt, die die gleiche Anzahl an Soundspuren erstellt, wie der Input vorgibt, sie jedoch leer lässt und dadurch überhaupt keine Zeit dafür geopfert werden muss, wäre das auch eine Alternative!)

    Lege dir am beste selbst ein Dummy WAV File an. z.B. mit Audacity. Die Länge ist völlig banal.
    Du kannst diese dann als Zweit Input nutzen bei FFmpeg. Achte darauf das du via -map, die WAV an die richtige Index Position setzt. Ignoriere gleichzeitig aber auch die Audiospuren der Hauptquelle.


    Sieht dann ungefähr so aus: ffmpeg -i "Hauptquelle.mkv" -an -i "DummyWAV" -map 0:1 -c:a copy -map 0:2 -c:a copy


    Ist jetzt aus dem Kopf und es kann sein das das mit der -map Angabe noch geändert werden muss.


    Theoretisch läuft das halt so:
    Von der Hauptquelle werden die Audiospuren ignoriert (das wird mit -an gemacht. Kann sein das du da auch schon mit -map arbeiten musst)


    Hinzugefügt wird die Dummy Audio Spur an als Spur 1 und Spur 2, die einfach nur kopiert wird. Da sie nicht lang ist, sollte das auch fix gehen.


    Bei -map ist wichtig zu wissen:


    -map Q:I


    Q = Quell Index. Sprich welche Quelle angezapft werden soll. Der erste Input währe 0, der 2te 1 usw.
    I = Index. Index der Quelle. Sprich wenn der erste Input 3 Indexe hat sieht das so aus: 0:0, 0:1, 0:2
    Hat die 2te Input Quelle mehrere Indexe sieht das so aus: 1:0, 1:1, 1:2 usw.


    In vielen Fällen sitzt bei Videos auf dem Index 0 einer Quelle immer die Video Spur (Außer bei Trotteln die 0 Ahnung haben und sowas z.B auf den 1 oder 2ten Index setzen. Vergiss sowas. Videospuren kommen immer auf Index 0)
    Danach folgen Indexe mit Audiospuren
    Dann die Indexe mit Untertiteln
    Und zum Schluss andere Meta Daten wie z.B. Font Dateien, Miniaturbilder usw.


    Probiers dir erst mal aus. Wie gesagt, ist jetzt alles aus dem Kopf geschrieben. Habe jetzt auch nicht wirklich Zeit zu prüfen oder konkrete Skripte zu liefern. Aber so sollte es ablaufen und vor allem zügig. Wenn ich Zeit haben sollte, kann ich mich ja noch mal mit befassen. Probiere aber selbst erst mal aus. Vllt. bekommste das ja so hin.
    Für FFmpeg gibt es ja Hilfe im Netz wie Sand am Meer. ^^

  • Ich hab das Gefühl, dass eine Kopie der Streams nicht so sehr eine Kopie ist, wie ich das erwartet habe. Das Muxen der Audiostreams aus der Originaldatei und dem Videostream aus dem Proxy dauert so lange, wie das Erstellen des Videostreams. Das kann doch eigentlich nicht sein? Und das Kopieren der Audiostreams in einzelne Dateien dauert auch sehr lange. Die Geschwindigkeit pendelt sich da bei ~10x ein. Bei mehreren Streams und einer mehrstündigen Aufnahme dauert das alles deutlich länger als Echtzeit.


    Davon abgesehen habe ich das mit dem Dummy probiert und den Skript von weiter oben benutzt, also


    Code
    ffmpeg -i in.mp4 -an -i dummy.wav -map 0:1 -c:a copy -map 0:2 -c:a copy out.map


    und ihn weitergeführt für die entsprechende Anzahl an Streams. Da wird der Fehler "Stream map '0:2' matches no streams.
    To ignore this, add a trailing '?' to the map."
    angezeigt.

  • Ich hab das Gefühl, dass eine Kopie der Streams nicht so sehr eine Kopie ist, wie ich das erwartet habe.

    Eine Kopie eines Streams erfordert den Codec + den passenden Container.


    Ein Beispiel:
    Kopierst du ein PCM Stream in ein MP3 Container, dann wird entweder FFmpeg dir sagen das es nicht geht ODER er macht es im Zusammenhang das er es Konvertiert. In diesem Falle ist es keine Kopie mehr.


    Wichtig ist halt wie du dein FFmpeg Befehl schreibst. Die Argumente die du nach ffmpeg schreibst, haben alle ihre Bedeutungen. Die darf man nicht wild durcheinander schreiben, sondern muss wirklich eine Reihenfolge beachten.


    Daher immer Wichtig, wenn du da kein Plan hast dein Skript vllt. hier im Forum zu posten. Dann kann der eine oder andere auch helfen was genau schief geht.


    und ihn weitergeführt für die entsprechende Anzahl an Streams. Da wird der Fehler "Stream map '0:2' matches no streams.
    To ignore this, add a trailing '?' to the map." angezeigt.

    Stream 0:2 bezieht sich auf die Datei "in.mp4". Das ist mit der 0 gekennzeichnet. Und da willst du den Stream 2 haben. Den gibt es aber nicht.
    Du zeigst praktisch auf etwas Leeres.


    Als Beispiel wie du Map verstehen musst:



    Deine InputsDeine Streams (Index)
    0 (in.MP4)0 (Video Stream)
    1 (Audio Stream 1)
    2 (Audio Stream 2)
    3 (Untertitel Stream 1)
    4 (Untertitel Stream 2)
    1 (Dummy.wav)0 (Audio Stream)
    2 (Untertitel.srt)0 (Untertitel Stream)



    usw.


    An sich selektierst du nur mit map aus solch einer Liste.


    Bei in.mp4 hast du die Audio Streams schon mit -an gekillt. Die sind also nicht mehr da. Daher kannst du sie nicht mit map 0:1 und map 0:2 ansprechen. Die sind einfach nicht mehr da.


    WICHTIGER HINWEIS: Du arbeitest mit einem MP4 Container. Dieser versteht kein PCM WAV Audio. Erzeuge entweder eine passende leere AAC oder MP3 Audio Datei indem du die Dummy WAV umwandelst.
    ODER du nutzt als Ausgabe ein MKV Container.


    An sich müsste es so aussehen:
    Dummy1 und Dummy2 sind identisch.


    Code
    ffmpeg -i "in.mp4" -an -c:v copy -i "dummy1.wav" -c:a copy -i "dummy2.wav" -c:a copy out.mkv


    ODER

    Code
    ffmpeg -i "in.mp4" -an -c:v copy -i "dummy1.aac" -c:a copy -i "dummy2.aac" -c:a copy out.mp4

    Hier wird jetzt folgendes gemacht:
    Vom Video "in.mp4" werden alle Audio Spuren gekillt. Der Videostream wird mit aktuellem Codec kopiert (das macht das -c:v copy).


    Dann wird eine Audiospur Dummy1 angehangen (Diese hat im File Out.mp4 die Position map 0:1)
    Dieser Stream wird mit aktuellem Codec kopiert.


    Dann wird zum Schluss die Audiospur Dummy2 angehangen (Diese hat im File Out.mp4 die Position map 0:2)
    Auch dieser Stream wird kopiert.


    Im Endeffekt sind alle Streams kopiert. Außer die die entfernt wurden.



    Hältst du die Reihenfolge nicht ein, muss -map genutzt werden.
    Auch hier ein Beispiel:


    Code
    ffmpeg -i "in.mp4" -i "dummy1.aac" -i "dummy2.aac" -map 0 -an -c:v copy -map 1:0 -c:a copy -map 2:0 -c:a copy out.mp4

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!