Was ist der richtige Weg, um Keyframes in FFmpeg für DASH zu reparieren?

38

Wenn Sie einen Stream für die DASH-Wiedergabe aufbereiten, müssen sich die Direktzugriffspunkte in allen Streams zur exakt gleichen Quellstreamzeit befinden. Der übliche Weg, dies zu tun, besteht darin, eine feste Bildrate und eine feste GOP-Länge (dh ein Schlüsselbild alle N Bilder) zu erzwingen.

Bei FFmpeg ist die feste Bildrate einfach (-r NUMBER).

Aber für feste Keyframe-Positionen (GOP-Länge) gibt es drei Methoden ... welche ist "korrekt"? Die FFmpeg-Dokumentation ist diesbezüglich frustrierend vage.

Methode 1: Mit den Argumenten von libx264 herumspielen

-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1

Es scheint eine Debatte darüber zu geben, ob Scenecut deaktiviert werden soll oder nicht, da es unklar ist, ob der Keyframe- "Counter" neu gestartet wird, wenn eine Szene geschnitten wird.

Methode 2: Festlegen einer festen GOP-Größe:

-g GOP_LEN_IN_FRAMES

Dies ist leider nur beiläufig in der FFMPEG-Dokumentation dokumentiert, und daher ist die Wirkung dieses Arguments sehr unklar.

Methode 3: Fügen Sie alle N Sekunden einen Keyframe ein ( Möglicherweise? ):

-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)

Dies ist ausdrücklich dokumentiert. Es ist aber immer noch nicht sofort klar, ob der "Zeitzähler" nach jedem Schlüsselbild neu startet. Wenn zum Beispiel in einer erwarteten 5-Sekunden-GOP ein scenecutKeyframe 3 Sekunden von libx264 injiziert wird, ist der nächste Keyframe 5 Sekunden später oder 2 Sekunden später?

In der FFmpeg-Dokumentation wird tatsächlich zwischen dieser und der -gOption unterschieden, aber es wird nicht wirklich angegeben, wie die beiden oben genannten Optionen sich am wenigsten unterscheiden (dies setzt natürlich -geine feste Bildrate voraus).

Welches ist richtig?

Es scheint, dass das -force_key_framesüberlegen wäre , da es keine feste Bildrate erfordern würde. Dies setzt jedoch voraus, dass

  • es entspricht den GOP-Spezifikationen in H.264 ( falls vorhanden )
  • es GARANTIERT, dass ein Keyframe in fester Trittfrequenz vorhanden ist, unabhängig von libx264- scenecutKeyframes.

Es scheint auch, dass -gdies nicht funktionieren könnte, ohne eine feste Bildrate ( -r) zu erzwingen , da nicht garantiert werden kann, dass mehrere Durchläufe ffmpegmit unterschiedlichen Codec-Argumenten in jeder Auflösung die gleiche augenblickliche Bildrate liefern. Feste Bildraten können die Komprimierungsleistung verringern (WICHTIG in einem DASH-Szenario!).

Schließlich scheint die keyintMethode nur ein Hack zu sein . Ich hoffe gegen die Hoffnung, dass dies nicht die richtige Antwort ist.

Verweise:

Ein Beispiel mit der -force_key_framesMethode

Ein Beispiel mit der keyintMethode

Abschnitt mit erweiterten FFmpeg-Videooptionen

Mark Gerolimatos
quelle

Antworten:

27

TL; DR

Ich würde folgendes empfehlen:

  • libx264: (und optional hinzufügen )-g X -keyint_min X-force_key_frames "expr:gte(t,n_forced*N)"
  • libx265: -x265-params "keyint=X:min-keyint=X"
  • libvpx-vp9: -g X

Wo Xist das Intervall in Bildern und Nist das Intervall in Sekunden. Zum Beispiel für ein 2-Sekunden-Intervall mit einem 30-fps-Video X= 60 und N= 2.

Ein Hinweis zu verschiedenen Rahmentypen

Um dieses Thema richtig zu erklären, müssen wir zuerst die beiden Arten von I-Frames / Keyframes definieren:

  • IDR-Frames (Instantaneous Decoder Refresh): Ermöglichen das unabhängige Decodieren der folgenden Frames, ohne auf Frames vor dem IDR-Frame zuzugreifen.
  • Non-IDR-Frames: Diese benötigen einen vorherigen IDR-Frame, damit die Dekodierung funktioniert. Nicht-IDR-Frames können für Szenenschnitte in der Mitte einer GOP (Gruppe von Bildern) verwendet werden.

Was wird für das Streaming empfohlen?

Für den Streaming-Fall möchten Sie:

  • Stellen Sie sicher, dass sich alle IDR-Frames an regulären Positionen befinden (z. B. bei 2, 4, 6,… Sekunden), damit das Video in gleich lange Segmente aufgeteilt werden kann.
  • Aktivieren Sie die Szenenschnitterkennung, um die Codierungseffizienz / -qualität zu verbessern. Dies bedeutet, dass I-Frames zwischen IDR-Frames platziert werden können. Sie können weiterhin mit deaktivierter Szenenschnitterkennung arbeiten (und dies ist immer noch Teil vieler Anleitungen), dies ist jedoch nicht erforderlich.

Was machen die Parameter?

Um den Encoder konfigurieren zu können, müssen wir verstehen, was die Keyframe-Parameter bewirken. Ich habe einige Tests und entdeckt die folgende, für die drei Encoder libx264, libx265und libvpx-vp9in FFmpeg:

  • libx264:

    • -g Legt das Keyframe-Intervall fest.
    • -keyint_min Legt das minimale Keyframe-Intervall fest.
    • -x264-params "keyint=x:min-keyint=y"ist das gleiche wie -g x -keyint_min y.
    • Hinweis: Wenn Sie beide auf den gleichen Wert einstellen, wird das Minimum intern auf die Hälfte des maximalen Intervalls plus eins gesetzt, wie im x264Code gezeigt:

      h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
      
  • libx265:

    • -g ist nicht implementiert.
    • -x265-params "keyint=x:min-keyint=y" funktioniert.
  • libvpx-vp9:

    • -g Legt das Keyframe-Intervall fest.
    • -keyint_min Legt das minimale Keyframe-Intervall fest
    • Hinweis: Aufgrund der Funktionsweise von FFmpeg wird -keyint_mines nur an den Encoder weitergeleitet, wenn es dasselbe ist wie -g. Im Code von libvpxenc.cin FFmpeg finden wir:

      if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
          enccfg.kf_min_dist = avctx->keyint_min;
      if (avctx->gop_size >= 0)
          enccfg.kf_max_dist = avctx->gop_size;
      

      Dies kann ein Fehler sein (oder ein Mangel an Funktionen?), Da dies libvpxdefinitiv das Festlegen eines anderen Werts für unterstützt kf_min_dist.

Solltest du verwenden -force_key_frames?

Die -force_key_framesOption fügt im angegebenen Intervall (Ausdruck) zwangsweise Keyframes ein. Dies funktioniert bei allen Encodern, kann jedoch zu Problemen mit der Geschwindigkeitskontrolle führen. Insbesondere bei VP9 sind mir starke Qualitätsschwankungen aufgefallen, daher kann ich die Verwendung in diesem Fall nicht empfehlen.

slhck
quelle
Vielen Dank! Das ist tolles Feedback. Eine Frage, die ich habe, ist, wie Sie diesen fantastischen Tisch erzeugt haben. Ich könnte sowas total gebrauchen.
Mark Gerolimatos
(Es scheint keine Möglichkeit zu geben, Sie direkt zu schreiben.) Können Sie mich bitte auf Links zu Themen in dieser ITU-T-Diskussion hinweisen? Vielen Dank!
Mark Gerolimatos
2
Ich habe das gerade in Excel gemacht, indem ich die Ausgabe aus drei Durchläufen eingefügt ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_typeund dann die Zellen eingefärbt habe. Ich fürchte, es gibt keine öffentlichen Diskussionen, aber ich werde sehen, ob ich einige der Links ausgraben kann, die ich damals gefunden habe.
Slhck
Könnten Sie bitte Ihr Experiment mit dem -force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)Formular wiederholen ? Ich habe es gerade ausprobiert und festgestellt, dass ich zwar zusätzliche Frames im Stream hatte, aber meine Regel nicht eingehalten zu haben schien. Ein PERL-Programm wird als "Antwort" folgen, da Sie Markup anscheinend nicht in Kommentaren verwenden können.
Mark Gerolimatos
Interessant. Ich glaube, es ist eine separate "echte" Antwort wert, wenn Sie herausfinden, dass es funktioniert. (Stack Exchange-Sites eignen sich nicht wirklich für diese Antwort im Diskussionsstil.) Das letzte Mal, als ich nachgesehen habe, -force_key_frameshat bei mir nicht funktioniert, und deshalb habe ich es nie wieder versucht. Das war vor mehr als einem Jahr. Vielleicht war es ein Fehler. Ich werde es bald wieder versuchen.
slhck
12

Hier sind meine fünfzig Cent für den Fall.

Methode 1:

mit den Argumenten von libx264 herumspielen

-c: v libx264 -x264opts keyint = GOPSIZE: min-keyint = GOPSIZE: scenecut = -1

Generieren Sie iframes nur in den gewünschten Intervallen.

Beispiel 1:

ffmpeg -i test.mp4 -codec:v libx264 \
-r 23.976 \
-x264opts "keyint=48:min-keyint=48:no-scenecut" \
-c:a copy \
-y test_keyint_48.mp4

Generiere iframes wie erwartet so:

Iframes     Seconds
1           0
49          2
97          4
145         6
193         8
241         10
289         12
337         14
385         16
433         18
481         20
529         22
577         24
625         26
673         28
721         30
769         32
817         34
865         36
913         38
961         40
1009        42
1057        44
1105        46
1153        48
1201        50
1249        52
1297        54
1345        56
1393        58

Methode 2 wird abgeschrieben. Weggelassen

Methode 3:

füge alle N Sekunden einen Keyframe ein (MÖGLICHERWEISE):

-force_key_frames expr: gte (t, n_forced * GOP_LEN_IN_SECONDS)

Beispiel 2

ffmpeg -i test.mp4 -codec:v libx264 \
-r 23.976 \
-force_key_frames "expr:gte(t,n_forced*2)"
-c:a copy \
-y test_fkf_2.mp4

Generieren Sie ein iframes auf eine etwas andere Art:

Iframes     Seconds
1           0
49          2
97          4
145         6
193         8
241         10
289         12
337         14
385         16
433         18
481         20
519         21.58333333
529         22
577         24
625         26
673         28
721         30
769         32
817         34
865         36
913         38
931         38.75
941         39.16666667
961         40
1008        42
1056        44
1104        46
1152        48
1200        50
1248        52
1296        54
1305        54.375
1344        56
1367        56.95833333
1392        58
1430        59.58333333
1440        60
1475        61.45833333
1488        62
1536        64
1544        64.33333333
1584        66
1591        66.29166667
1632        68
1680        70
1728        72
1765        73.54166667
1776        74
1811        75.45833333
1824        75.95833333
1853        77.16666667
1872        77.95833333
1896        78.95833333
1920        79.95833333
1939        80.75
1968        81.95833333

Wie Sie sehen, werden alle 2 Sekunden IFrames UND auf Scenecut (Sekunden mit schwebendem Teil) platziert, was meiner Meinung nach für die Komplexität des Videostreams wichtig ist.

Genearated Dateigrößen sind ziemlich gleich. Sehr seltsam, dass selbst mit mehr Keyframes in Methode 3 manchmal weniger Dateien als mit dem standardmäßigen x264-Bibliotheksalgorithmus generiert werden.

Um mehrere Bitrate-Dateien für den HLS-Stream zu generieren, wählen wir Methode drei. Es ist perfekt ausgerichtet mit 2 Sekunden zwischen den Chunks, sie haben Iframe am Anfang jedes Chunks und sie haben zusätzliche Iframes in komplexen Szenen, was eine bessere Erfahrung für Benutzer bietet, die veraltete Geräte haben und keine x264-High-Profile wiedergeben können.

Hoffe es hilft jemandem.

Ara Saahov
quelle
Fantastisch, danke für deine 50 Cent!
BrunoFenzl
7

Die Antwort scheint daher zu sein:

  • Methode 1 funktioniert, ist jedoch libx264-spezifisch und geht zu Lasten der Eliminierung der sehr nützlichen scenecutOption in libx264.
  • Methode 3 funktioniert ab der FFMPEG-Version von April 2015. Sie sollten Ihre Ergebnisse jedoch anhand des Skripts überprüfen, das am Ende dieses Beitrags enthalten ist, da in der FFMPEG-Dokumentation die Auswirkung der Option unklar ist. Wenn es funktioniert, ist es die überlegene der beiden Optionen.
  • NICHT VERWENDEN Methode 2, -gscheint veraltet zu sein. Es scheint weder zu funktionieren, noch ist es explizit in der Dokumentation definiert, noch ist es in der Hilfe zu finden, noch scheint es im Code verwendet zu werden. Die Codeinspektion zeigt, dass die -gOption wahrscheinlich für MPEG-2-Streams gedacht ist (es gibt sogar Codezeilen, die sich auf PAL und NTSC beziehen!).

Ebenfalls:

  • Dateien, die mit Methode 3 erstellt wurden, sind möglicherweise etwas größer als mit Methode 1, da Interstitial-I-Frames (Keyframes) zulässig sind.
  • Sie sollten in beiden Fällen das Flag "-r" explizit setzen, obwohl Methode 3 einen I-Frame am nächsten Frameslot an oder nach der angegebenen Zeit platziert. Wenn Sie das Flag "-r" nicht setzen, sind Sie der Quelldatei ausgeliefert, möglicherweise mit einer variablen Bildrate. Inkompatible DASH-Übergänge können die Folge sein.
  • Trotz der Warnungen in der FFMPEG-Dokumentation ist Methode 3 NICHT weniger effizient als andere. Tatsächlich zeigen Tests, dass es möglicherweise etwas effizienter als Methode 1 ist.

Skript für die -force_key_framesOption

Hier ist ein kurzes PERL-Programm, mit dem ich die I-Frame-Trittfrequenz basierend auf der Ausgabe von slhcks ffprobe-Vorschlag verifiziert habe. Es scheint zu bestätigen, dass die -force_key_framesMethode auch funktioniert, und hat den zusätzlichen Vorteil, dass scenecutFrames zugelassen werden. Ich habe absolut keine Ahnung, wie FFMPEG diese Arbeit macht, oder ob ich irgendwie Glück gehabt habe, weil meine Streams zufällig gut konditioniert sind.

In meinem Fall habe ich mit 30 fps mit einer erwarteten GOP-Größe von 6 Sekunden oder 180 Bildern codiert. Ich habe 180 als gopsize-Argument für dieses Programm verwendet und überprüft, ob bei jedem Vielfachen von 180 ein I-Frame vorhanden ist. Wenn ich es jedoch auf 181 (oder eine andere Zahl, die kein Vielfaches von 180 ist) einsetze, beschwert sich das Programm.

#!/usr/bin/perl
use strict;
my $gopsize = shift(@ARGV);
my $file = shift(@ARGV);
print "GOPSIZE = $gopsize\n";
my $linenum = 0;
my $expected = 0;
open my $pipe, "ffprobe -i $file -select_streams v -show_frames -of csv -show_entries frame=pict_type |"
        or die "Blah";
while (<$pipe>) {
  if ($linenum > $expected) {
    # Won't catch all the misses. But even one is good enough to fail.
    print "Missed IFrame at $expected\n";
    $expected = (int($linenum/$gopsize) + 1)*$gopsize;
  }
  if (m/,I\s*$/) {
    if ($linenum < $expected) {
      # Don't care term, just an extra I frame. Snore.
      #print "Free IFrame at $linenum\n";
    } else {
      #print "IFrame HIT at $expected\n";
      $expected += $gopsize;
    }
  }
  $linenum += 1;
}
Mark Gerolimatos
quelle
Nur eine Anmerkung: Da dies eine Q & A-Site ist und nicht wirklich ein Diskussionsforum, in dem die Beiträge chronologisch geordnet sind, ist es am besten, alle Informationen in einer Antwort zusammenzufassen, damit die Leute, die nach einer Lösung suchen, nur einen Beitrag lesen und nicht suchen müssen at who posted what, when :) Ich habe deine Antworten zusammengeführt und dir auch dazu +1 gegeben. Da Crossposting nicht erlaubt ist , würde ich vorschlagen, dass Sie Ihre Frage auf der Video-Site löschen. Die Antwort (en) finden die Leute hier.
Slhck
1
Ich hatte nur noch einen Gedanken (tatsächlich wurde er auf der FFmpeg-Mailingliste erwähnt). Bei der Verwendung force_key_frameswird der x264-Bitzuweisungsalgorithmus durcheinander gebracht, sodass möglicherweise eine schlechtere Qualität erzielt wird, als wenn lediglich ein festes Keyframe-Intervall festgelegt wird.
Slhck
Heiliger Strohsack. Noch ein Grund mehr, FFMPEG eine Codec-nicht-spezifische Methode dafür anzubieten, ein Argument, das "das Beste für den fraglichen Codec tun würde". Ich habe versucht, ein Ticket dafür mit FFMPEGs Trac einzureichen, aber das prallte ab :-(
Mark Gerolimatos
@slhck: Könntest du bitte mehr Details geben? Ich habe im Mai 2015 in den Mailinglisten-Archiven nachgesehen, aber nichts gefunden. Die Quintessenz wäre, "Methode 3" zu vergessen und sich an "Methode 1" zu halten.
schieferstapel
3
@MarkGerolimatos: -gSie sagen ungefähr: "Es scheint weder zu funktionieren, noch scheint es im Code verwendet zu werden." Ich überprüfte und die die Eingabe von ggespeichert ist avctx->gop_sizeund dass libx264 nutzt es: x4->params.i_keyint_max = avctx->gop_size;. Wenn ich diese generierte Testdatei prüfe ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4, erhalte ich Keyframes genau um 0,37,74,111,148,185,222,259,296,333,370. Eine GOP könnte gekürzt werden, wenn ein Szenenwechsel ausgelöst wird, und dafür -sc_thresholdkönnte eingestellt werden, was auch von x264 aufgenommen wird.
Gyan
4

Ich wollte hier einige Informationen hinzufügen, da mein Googeln diese Diskussion zu einem großen Teil in meiner Suche nach Informationen darüber, wie ich meine DASH-Codierung so segmentieren kann, wie ich es wollte, ausgelöst hat, und keine der Informationen, die ich gefunden habe, war vollständig korrekt.

Zuerst einige Missverständnisse, die beseitigt werden müssen:

  1. Nicht alle I-Frames sind gleich. Es gibt große "I" -Frames und kleine "I" -Frames. Oder um die korrekte Terminologie zu verwenden, IDR-I-Frames und Nicht-IDR-I-Frames. IDR-I-Frames (manchmal als "Keyframes" bezeichnet) erzeugen eine neue GOP. Die Nicht-IDR-Frames werden nicht. Sie sind praktisch, um sich in einer GOP zu befinden, in der sich die Szene ändert.

  2. -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE← Das macht nicht das, was Sie denken. Ich brauchte eine Weile, um das herauszufinden. Es stellt sich heraus, dass das min-keyintim Code begrenzt ist. Es darf nicht größer sein als (keyint / 2) + 1. min-keyintWenn Sie also diesen beiden Variablen denselben Wert zuweisen, wird der Wert beim Codieren halbiert.

Hier ist die Sache: Szenenschnitt ist wirklich großartig, besonders in Videos mit schnellen harten Schnitten. Es bleibt schön und knackig, so dass ich es nicht deaktivieren möchte, aber gleichzeitig konnte ich keine feste GOP-Größe erhalten, solange es aktiviert war. Ich wollte den Szenenschnitt aktivieren, aber nur Nicht-IDR-I-Frames verwenden. Aber es hat nicht funktioniert. Bis ich (aus vielen Lektüren) herausgefunden habe, dass ich falsch gedacht habe # 2.

Es stellte sich heraus, dass ich die keyintgewünschte GOP-Größe verdoppeln musste. Dies bedeutet, dass min-keyintdie gewünschte GOP-Größe eingestellt werden kann (ohne dass der interne Code sie halbiert), wodurch verhindert wird, dass die Szenenschnitterkennung IDR-I-Frames innerhalb der GOP-Größe verwendet, da die Frame-Anzahl seit dem letzten IDR-I-Frame beträgt immer weniger als min-keyinit.

Und schließlich force_key_frameüberschreibt das Setzen der Option die doppelte Größe keyint. Das funktioniert also so:

Ich bevorzuge Segmente in 2 Sekundenblöcken, daher ist meine GOPSIZE = Framerate * 2

ffmpeg <other_options> -force_key_frames "expr:eq(mod(n,<GOPSIZE>),0)" -x264opts rc-lookahead=<GOPSIZE>:keyint=<GOPSIZE * 2>:min-keyint=<GOPSIZE> <other_options>

Sie können mit ffprobe Folgendes überprüfen:

ffprobe <SRC_FLE> -select_streams v -show_frames -of csv -show_entries frame=coded_picture_number,key_frame,pict_type > frames.csv

In der generierten CSV-Datei wird in jeder Zeile Folgendes angegeben frame, [is_an_IDR_?], [frame_type], [frame_number]:

frame,1,I,60  <-- frame 60, is I frame, 1 means is an IDR I-frame (aka KeyFrame)
frame,0,I,71  <-- frame 71, is I frame, 0 means not an IDR I_frame

Das Ergebnis ist, dass Sie IDR-I-Frames nur in festgelegten GOPSIZEIntervallen sehen sollten, während alle anderen I-Frames Nicht-IDR-I-Frames sind, die bei Bedarf von der Szenenschnitterkennung eingefügt werden.

Ruben
quelle
das war fantastisch! Es war sehr eingängig, danke, dass Sie sich Mühe gegeben haben. Und zusammenfassend gehe ich davon aus, dass Ihre Definition von "I-Frames" und "I-Frames" konzeptionell ist (dh in libx264 nicht explizit konfigurierbar ist) und dass Sie dies mit "max * 2" erzwungen haben?
Mark Gerolimatos
Ja, das war konzeptionell, obwohl ich gesehen habe, dass Leute "I" vs "i" verwenden, um zwischen IDR- und Nicht-IDR-I-Frames zu unterscheiden. Und ja, wenn Sie keyinit auf die gewünschte Gop-Größe * 2 einstellen, werden alle I-Frames innerhalb des Gops zu Nicht-IDR-I-Frames. Dann überschreibt das ffmpeg-force-key-frames key-init in den x264opts. Grundsätzlich ist es eine sehr verkehrte Methode, um das gewünschte Ergebnis zu erzielen, das möglich wäre, wenn Sie mit dem x264-Code min-keyinit und keyinit auf den gleichen Wert setzen könnten.
Reuben
... und Sie können gleichzeitig die Szenen-Schnitt-Erkennung aktivieren und die GOP-Größe festlegen.
Reuben
Nochmals vielen Dank für Ihre tolle Arbeit! Klingt so, als müssten wir weniger "rückwärts" arbeiten
Mark Gerolimatos,
Ist rc-lookahead hier nötig? Es betrifft MBTree und VBV, aber hat es Auswirkungen auf die i-Frame-Generierung?
Alexander Svetkin
0

Es scheint, dass diese Syntax nicht immer funktioniert. Ich habe ziemlich viel auf unseren VOD-Inhalten sowie auf Live-Inhalten (Datei-Dumps) getestet, und manchmal funktioniert scenecut nicht und löst einen Zwischen-Iframe aus:

Syntax für eine i50-> p50-Aufwärtskonvertierung, 2 Sek. Gop / Segment, IDR am Anfang, iFrames dazwischen, falls erforderlich

ffmpeg.exe -loglevel verbose -i avc_50i.ts -pix_fmt yuv420p -filter_complex yadif=1,scale=1920:1080 -vcodec libx264 -preset fast -x264-params "rc-lookahead=100:keyint=200:min-keyint=100:hrd=1:vbv_maxrate=12000:vbv_bufsize=12000:no-open-gop=1" -r 50 -crf 22 -force_key_frames "expr:eq(mod(n,100),0)" -codec:a aac -b:a 128k -y target.ts
TEB
quelle
0

Twitch hat einen Beitrag dazu. Sie erklären, dass sie aus mehreren Gründen beschlossen haben, ihr eigenes Programm zu verwenden. Eine davon war, dass Sie mit ffmpeg nicht verschiedene x264-Instanzen in verschiedenen Threads ausführen können, sondern alle angegebenen Threads einem Frame in einer Ausgabe zuweisen, bevor Sie zur nächsten Ausgabe übergehen.

Wenn Sie kein Echtzeit-Streaming durchführen, haben Sie mehr Luxus. Der 'richtige' Weg ist wahrscheinlich, bei einer Auflösung nur die mit -g angegebene GOP-Größe zu codieren und dann die anderen Auflösungen zu codieren, die Keyframes an denselben Stellen erzwingen.

Wenn Sie das tun möchten, können Sie ffprobe verwenden, um die Keyframe-Zeiten abzurufen, und dann ein Shell-Skript oder eine tatsächliche Programmiersprache verwenden, um das in einen ffmpeg-Befehl zu konvertieren.

Bei den meisten Inhalten besteht jedoch kaum ein Unterschied zwischen einem Keyframe alle 5 Sekunden und zwei Keyframes alle 5 Sekunden (eines erzwungen und eines aus Scenecut). Dies ist ungefähr die durchschnittliche Größe von I-Frames im Vergleich zur Größe von P-Frames und B-Frames. Wenn Sie x264 mit typischen Einstellungen verwenden (der einzige Grund, weshalb Sie meines Erachtens irgendetwas tun sollten, um dies zu ändern, ist die Einstellung von -qmin, um zu verhindern, dass x264 bei einfachen Inhalten die Bitrate verwendet), wodurch alle Rahmentypen auf den gleichen Wert begrenzt werden , Denke ich) und erhalte ein Ergebnis wie I-Frame-Durchschnittsgröße von 46 kB, P-Frame 24 kB, B-Frame 17 kB (halb so häufig wie P-Frames), dann ein zusätzliches I-Frame pro Sekunde bei 30 fps ist nur eine 3% ige Zunahme der Dateigröße. Der Unterschied zwischen h264 und h263 könnte aus einer Menge von 3% Abnahmen bestehen, aber eine einzige ist nicht sehr wichtig.

Bei anderen Inhaltstypen unterscheiden sich die Bildgrößen. Fairerweise geht es hier um zeitliche und nicht um räumliche Komplexität. Es geht also nicht nur um einfachen Inhalt, sondern auch um harten Inhalt. Im Allgemeinen ist die Bitrate für Streaming-Video-Websites jedoch begrenzt, und Inhalte mit relativ großen I-Frames sind einfache Inhalte, die unabhängig von der Anzahl der hinzugefügten zusätzlichen Keyframes in hoher Qualität codiert werden. Es ist verschwenderisch, aber diese Verschwendung wird normalerweise nicht bemerkt. Der verschwenderischste Fall ist wahrscheinlich ein Video, das nur ein statisches Bild eines Songs ist, bei dem jeder Keyframe genau gleich ist.

Ich bin mir nicht sicher, wie erzwungene Keyframes mit dem mit -maxrate und -bufsize festgelegten Ratenbegrenzer interagieren. Ich denke, sogar YouTube hatte kürzlich Probleme, die Puffereinstellungen richtig zu konfigurieren, um eine gleichbleibende Qualität zu erzielen. Wenn Sie nur durchschnittliche Bitrateneinstellungen verwenden, wie dies von einigen Sites angezeigt wird (da Sie die x264-Optionen im Header / Mov-Atom mit einem Hex-Editor überprüfen können), ist das Puffermodell kein Problem Durch die durchschnittliche Bitrate wird der Nutzer dazu aufgefordert, am Ende seines Videos einen schwarzen Bildschirm einzufügen.

Die Option -g von Ffmpeg oder eine andere von Ihnen verwendete Encoder-Option wird der encoderspezifischen Option zugeordnet. Also ist '-x264-params keyint = GOPSIZE' gleichbedeutend mit '-g GOPSIZE'.

Ein Problem bei der Szenenerkennung besteht darin, dass Sie aus irgendeinem Grund Keyframes in der Nähe bestimmter Zahlen bevorzugen. Wenn Sie alle 5 Sekunden Keyframes angeben und die Szenenerkennung verwenden und bei 4.5 eine Szenenänderung auftritt, sollte diese erkannt werden, der nächste Keyframe jedoch bei 9.5. Wenn die Zeit so schnell wird, könnten Sie Keyframes bei 42,5, 47,5, 52,5 usw. anstelle von 40, 45, 50, 55 erhalten. Wenn sich die Szene bei 5,5 ändert, ist dies umgekehrt der Fall Ein Keyframe mit 5 und 5.5 ist für einen anderen zu früh. In Ffmpeg können Sie nicht angeben, dass hier ein Keyframe erstellt werden soll, wenn innerhalb der nächsten 30 Frames keine Szenenänderung erfolgt. Jemand, der C versteht, könnte diese Option jedoch hinzufügen.

Wenn Sie bei Videos mit variabler Bildrate nicht wie Twitch Live-Streaming betreiben, sollten Sie in der Lage sein, Szenenänderungen zu verwenden, ohne diese dauerhaft in eine konstante Bildrate zu konvertieren. Wenn Sie den Filter 'select' in ffmpeg verwenden und die Konstante 'scene' im Ausdruck verwenden, wird in der Debug-Ausgabe (-v debug oder drücken Sie mehrmals '+' während der Codierung) die Szenenänderungsnummer angezeigt. Dies unterscheidet sich wahrscheinlich von der von x264 verwendeten Nummer und ist nicht so nützlich, könnte aber dennoch nützlich sein.

Das Verfahren würde dann wahrscheinlich darin bestehen, ein Testvideo zu erstellen, das nur für Keyframe-Änderungen gedacht ist, bei Verwendung von 2-Pass jedoch möglicherweise für Daten zur Ratensteuerung verwendet werden kann. (Sie sind sich nicht sicher, ob die generierten Daten für unterschiedliche Auflösungen und Einstellungen überhaupt nützlich sind; die Makroblock-Baumdaten sind es nicht.) Konvertieren Sie sie in ein Video mit konstanter Framerate, aber sehen Sie diesen Fehler, wenn Sie die Framerate halbieren, falls Sie sich jemals entscheiden um den fps filter für andere zwecke zu verwenden. Führen Sie es über x264 mit den gewünschten Keyframe- und GOP-Einstellungen aus.

Verwenden Sie dann einfach diese Keyframe-Zeiten mit dem Originalvideo mit variabler Bildrate.

Wenn Sie völlig verrückte benutzergenerierte Inhalte mit einer Lücke von 20 Sekunden zwischen Frames zulassen, können Sie für die Codierung mit variabler Framerate die Ausgabe aufteilen, den fps-Filter verwenden und irgendwie einen Auswahlfilter verwenden (möglicherweise einen wirklich langen Ausdruck erstellen, der hat) every keyframe time) ... oder Sie könnten das Testvideo als Eingabe verwenden und entweder nur Keyframes decodieren, wenn diese ffmpeg-Option funktioniert, oder den Auswahlfilter verwenden, um Keyframes auszuwählen. Skalieren Sie es dann auf die richtige Größe (es gibt sogar einen scale2ref-Filter dafür) und überlagern Sie es mit dem Originalvideo. Verwenden Sie dann den Interleave-Filter, um diese zu erzwingenden Keyframes mit dem Originalvideo zu kombinieren. Wenn dies zu zwei Frames mit einem Abstand von 0,001 Sekunden führt, den der Interleave-Filter nicht verhindert, können Sie dieses Problem mit einem anderen Auswahlfilter selbst beheben. Das Hauptproblem könnte hier der Umgang mit Frame Buffer Limits für das Interleave-Filter sein. Diese könnten alle funktionieren: Verwenden Sie eine Art Filter, um den dichteren Strom zu puffern (FIFO-Filter?); Verweisen Sie mehrmals auf die Eingabedatei, damit sie mehrmals dekodiert wird und keine Frames gespeichert werden müssen. Verwende den 'Streamselect'-Filter, den ich noch nie gemacht habe, genau zu den Zeiten der Keyframes. Verbessern Sie den Interleave-Filter, indem Sie sein Standardverhalten ändern oder eine Option hinzufügen, um den ältesten Frame in einem Puffer auszugeben, anstatt einen Frame zu löschen. was ich noch nie gemacht habe, genau zu den Zeiten der Keyframes; Verbessern Sie den Interleave-Filter, indem Sie sein Standardverhalten ändern oder eine Option hinzufügen, um den ältesten Frame in einem Puffer auszugeben, anstatt einen Frame zu löschen. was ich noch nie gemacht habe, genau zu den Zeiten der Keyframes; Verbessern Sie den Interleave-Filter, indem Sie sein Standardverhalten ändern oder eine Option hinzufügen, um den ältesten Frame in einem Puffer auszugeben, anstatt einen Frame zu löschen.

Misaki
quelle