Mögliche Speicherorte für Sequenz- / Bildparametersätze für H.264-Stream

82

Ich arbeite an einem H.264-Decoder und frage mich, wo ich SPS und PPS finden kann. Aus meiner Referenzliteratur geht hervor, dass dies NAL-Einheiten sind, die im H.264-Stream codiert sind. Wenn ich mir jedoch eine Beispiel-MP4-Datei mit IsoViewer anschaue, heißt es, dass sich SPS und PPS in der avcC-Box befinden.

Wie genau funktioniert das? Wie sieht es für .mkv-Dateien oder andere H.264-Container aus?

Danke im Voraus!

bananenbär
quelle

Antworten:

291

Zunächst ist es wichtig zu verstehen, dass es kein einzelnes Standard-H.264-Elementarbitstream-Format gibt. Das Spezifikationsdokument enthält einen Anhang, insbesondere Anhang B, der ein mögliches Format beschreibt, ist jedoch keine tatsächliche Anforderung. Der Standard legt fest, wie Videos in einzelne Pakete codiert werden. Wie diese Pakete gespeichert und übertragen werden, bleibt dem Integrator offen.


1. Anhang B.

Network Abstraction Layer Units

Die Pakete werden als Network Abstraction Layer Units bezeichnet. Oft abgekürzt NALU (oder manchmal nur NAL) kann jedes Paket einzeln analysiert und verarbeitet werden. Das erste Byte jeder NALU enthält den NALU-Typ, insbesondere die Bits 3 bis 7. (Bit 0 ist immer ausgeschaltet, und die Bits 1-2 geben an, ob eine NALU von einer anderen NALU referenziert wird).

Es sind 19 verschiedene NALU-Typen definiert, die in zwei Kategorien unterteilt sind: VCL und Nicht-VCL:

  • VCL- oder Video Coding Layer-Pakete enthalten die tatsächlichen visuellen Informationen.
  • Nicht-VCLs enthalten Metadaten, die möglicherweise zum Dekodieren des Videos erforderlich sind oder nicht.

Eine einzelne NALU oder sogar eine VCL-NALU ist NICHT dasselbe wie ein Frame. Ein Frame kann in mehrere NALUs unterteilt werden. Genau wie Sie eine Pizza schneiden können. Ein oder mehrere Slices werden dann virtuell zu Access Units (AU) gruppiert, die einen Frame enthalten. Das Schneiden ist mit geringen Qualitätskosten verbunden, daher wird es nicht oft verwendet.

Unten finden Sie eine Tabelle aller definierten NALUs.

0      Unspecified                                                    non-VCL
1      Coded slice of a non-IDR picture                               VCL
2      Coded slice data partition A                                   VCL
3      Coded slice data partition B                                   VCL
4      Coded slice data partition C                                   VCL
5      Coded slice of an IDR picture                                  VCL
6      Supplemental enhancement information (SEI)                     non-VCL
7      Sequence parameter set                                         non-VCL
8      Picture parameter set                                          non-VCL
9      Access unit delimiter                                          non-VCL
10     End of sequence                                                non-VCL
11     End of stream                                                  non-VCL
12     Filler data                                                    non-VCL
13     Sequence parameter set extension                               non-VCL
14     Prefix NAL unit                                                non-VCL
15     Subset sequence parameter set                                  non-VCL
16     Depth parameter set                                            non-VCL
17..18 Reserved                                                       non-VCL
19     Coded slice of an auxiliary coded picture without partitioning non-VCL
20     Coded slice extension                                          non-VCL
21     Coded slice extension for depth view components                non-VCL
22..23 Reserved                                                       non-VCL
24..31 Unspecified                                                    non-VCL

Es gibt einige NALU-Typen, bei denen Kenntnisse später hilfreich sein können.

  • Sequenzparametersatz (SPS). Diese Nicht-VCL-NALU enthält Informationen, die zum Konfigurieren des Decoders erforderlich sind, z. B. Profil, Pegel, Auflösung und Bildrate.
  • Bildparametersatz (PPS). Ähnlich wie die SPS enthält diese Nicht-VCL Informationen zum Entropiecodierungsmodus, zu Slice-Gruppen, zur Bewegungsvorhersage und zu Deblocking-Filtern.
  • Instantaneous Decoder Refresh (IDR). Diese VCL-NALU ist eine in sich geschlossene Bildscheibe. Das heißt, ein IDR kann dekodiert und angezeigt werden, ohne auf andere NALU-Speicher-SPS und -PPS zu verweisen.
  • Access Unit Delimiter (AUD). Ein AUD ist eine optionale NALU, mit der Frames in einem Elementarstrom abgegrenzt werden können. Es ist nicht erforderlich (sofern im Container / Protokoll nicht anders angegeben, wie z. B. TS) und wird häufig nicht enthalten, um Platz zu sparen. Es kann jedoch nützlich sein, den Anfang eines Frames zu finden, ohne jede NALU vollständig analysieren zu müssen.

NALU-Startcodes

Eine NALU enthält nicht ihre Größe. Daher funktioniert es nicht, die NALUs einfach zu verketten, um einen Stream zu erstellen, da Sie nicht wissen, wo einer aufhört und der nächste beginnt.

Die Spezifikation in Anhang B löst dieses Problem, indem "Startcodes" vor jeder NALU verlangt werden. Ein Startcode besteht aus 2 oder 3 0x00Bytes, gefolgt von einem 0x01Byte. zB 0x000001oder 0x00000001.

Die 4-Byte-Variante ist nützlich für die Übertragung über eine serielle Verbindung, da es trivial ist, den Stream byteweise auszurichten, indem nach 31 Null-Bits gefolgt von einer Eins gesucht wird. Wenn das nächste Bit 0 ist (weil jede NALU mit einem 0-Bit beginnt), ist dies der Beginn einer NALU. Die 4-Byte-Variante wird normalerweise nur zum Signalisieren von Direktzugriffspunkten im Stream verwendet, z. B. SPS PPS AUD und IDR. Die 3-Byte-Variante wird überall verwendet, um Platz zu sparen.

Emulationsschutzbytes

Startcodes arbeiten , weil die vier Byte - Sequenzen 0x000000, 0x000001, 0x000002und 0x000003sind illegal in einem nicht-RBSP NALU. Beim Erstellen einer NALU wird daher darauf geachtet, diese Werte zu umgehen, die andernfalls mit einem Startcode verwechselt werden könnten. Dies wird erreicht durch eine ‚Emulation Prävention‘ Byte eingefügt 0x03, so dass 0x000001wird 0x00000301.

Beim Decodieren ist es wichtig, nach Emulationsschutzbytes zu suchen und diese zu ignorieren. Da Emulationsschutzbytes fast überall in einer NALU auftreten können, ist es in der Dokumentation häufig bequemer anzunehmen, dass sie bereits entfernt wurden. Eine Darstellung ohne Emulationsverhinderungsbytes wird als Raw Byte Sequence Payload (RBSP) bezeichnet.

Beispiel

Schauen wir uns ein vollständiges Beispiel an.

0x0000 | 00 00 00 01 67 64 00 0A AC 72 84 44 26 84 00 00
0x0010 | 03 00 04 00 00 03 00 CA 3C 48 96 11 80 00 00 00
0x0020 | 01 68 E8 43 8F 13 21 30 00 00 01 65 88 81 00 05
0x0030 | 4E 7F 87 DF 61 A5 8B 95 EE A4 E9 38 B7 6A 30 6A
0x0040 | 71 B9 55 60 0B 76 2E B5 0E E4 80 59 27 B8 67 A9
0x0050 | 63 37 5E 82 20 55 FB E4 6A E9 37 35 72 E2 22 91
0x0060 | 9E 4D FF 60 86 CE 7E 42 B7 95 CE 2A E1 26 BE 87
0x0070 | 73 84 26 BA 16 36 F4 E6 9F 17 DA D8 64 75 54 B1
0x0080 | F3 45 0C 0B 3C 74 B3 9D BC EB 53 73 87 C3 0E 62
0x0090 | 47 48 62 CA 59 EB 86 3F 3A FA 86 B5 BF A8 6D 06
0x00A0 | 16 50 82 C4 CE 62 9E 4E E6 4C C7 30 3E DE A1 0B
0x00B0 | D8 83 0B B6 B8 28 BC A9 EB 77 43 FC 7A 17 94 85
0x00C0 | 21 CA 37 6B 30 95 B5 46 77 30 60 B7 12 D6 8C C5
0x00D0 | 54 85 29 D8 69 A9 6F 12 4E 71 DF E3 E2 B1 6B 6B
0x00E0 | BF 9F FB 2E 57 30 A9 69 76 C4 46 A2 DF FA 91 D9
0x00F0 | 50 74 55 1D 49 04 5A 1C D6 86 68 7C B6 61 48 6C
0x0100 | 96 E6 12 4C 27 AD BA C7 51 99 8E D0 F0 ED 8E F6
0x0110 | 65 79 79 A6 12 A1 95 DB C8 AE E3 B6 35 E6 8D BC
0x0120 | 48 A3 7F AF 4A 28 8A 53 E2 7E 68 08 9F 67 77 98
0x0130 | 52 DB 50 84 D6 5E 25 E1 4A 99 58 34 C7 11 D6 43
0x0140 | FF C4 FD 9A 44 16 D1 B2 FB 02 DB A1 89 69 34 C2
0x0150 | 32 55 98 F9 9B B2 31 3F 49 59 0C 06 8C DB A5 B2
0x0160 | 9D 7E 12 2F D0 87 94 44 E4 0A 76 EF 99 2D 91 18
0x0170 | 39 50 3B 29 3B F5 2C 97 73 48 91 83 B0 A6 F3 4B
0x0180 | 70 2F 1C 8F 3B 78 23 C6 AA 86 46 43 1D D7 2A 23
0x0190 | 5E 2C D9 48 0A F5 F5 2C D1 FB 3F F0 4B 78 37 E9
0x01A0 | 45 DD 72 CF 80 35 C3 95 07 F3 D9 06 E5 4A 58 76
0x01B0 | 03 6C 81 20 62 45 65 44 73 BC FE C1 9F 31 E5 DB
0x01C0 | 89 5C 6B 79 D8 68 90 D7 26 A8 A1 88 86 81 DC 9A
0x01D0 | 4F 40 A5 23 C7 DE BE 6F 76 AB 79 16 51 21 67 83
0x01E0 | 2E F3 D6 27 1A 42 C2 94 D1 5D 6C DB 4A 7A E2 CB
0x01F0 | 0B B0 68 0B BE 19 59 00 50 FC C0 BD 9D F5 F5 F8
0x0200 | A8 17 19 D6 B3 E9 74 BA 50 E5 2C 45 7B F9 93 EA
0x0210 | 5A F9 A9 30 B1 6F 5B 36 24 1E 8D 55 57 F4 CC 67
0x0220 | B2 65 6A A9 36 26 D0 06 B8 E2 E3 73 8B D1 C0 1C
0x0230 | 52 15 CA B5 AC 60 3E 36 42 F1 2C BD 99 77 AB A8
0x0240 | A9 A4 8E 9C 8B 84 DE 73 F0 91 29 97 AE DB AF D6
0x0250 | F8 5E 9B 86 B3 B3 03 B3 AC 75 6F A6 11 69 2F 3D
0x0260 | 3A CE FA 53 86 60 95 6C BB C5 4E F3

Dies ist eine vollständige AU mit 3 NALUs. Wie Sie sehen können, beginnen wir mit einem Startcode, gefolgt von einem SPS (SPS beginnt mit 67). Innerhalb der SPS werden zwei Bytes zur Verhinderung der Emulation angezeigt. Ohne diese Bytes würde die unzulässige Sequenz 0x000000an diesen Positionen auftreten. Als nächstes sehen Sie einen Startcode, gefolgt von einem PPS (PPS beginnt mit 68) und einen endgültigen Startcode, gefolgt von einem IDR-Slice. Dies ist ein vollständiger H.264-Stream. Wenn Sie diese Werte in einen Hex-Editor eingeben und die Datei mit einer .264Erweiterung speichern , können Sie sie in dieses Bild konvertieren:

Lena

Anhang B wird üblicherweise in Live- und Streaming-Formaten wie Transportströmen, drahtlosen Sendungen und DVDs verwendet. In diesen Formaten ist es üblich, SPS und PPS regelmäßig zu wiederholen, normalerweise vor jedem IDR, wodurch ein Direktzugriffspunkt für den Decoder erstellt wird. Dies ermöglicht die Verbindung zu einem bereits laufenden Stream.


2. AVCC

Die andere übliche Methode zum Speichern eines H.264-Streams ist das AVCC-Format. In diesem Format wird jeder NALU ihre Länge vorangestellt (im Big-Endian-Format). Diese Methode ist einfacher zu analysieren, aber Sie verlieren die Byte-Ausrichtungsfunktionen von Anhang B. Um die Sache zu verkomplizieren, kann die Länge mit 1, 2 oder 4 Bytes codiert werden. Dieser Wert wird in einem Header-Objekt gespeichert. Dieser Header wird oft als "Extradaten" oder "Sequenzheader" bezeichnet. Das Grundformat lautet wie folgt:

bits    
8   version ( always 0x01 )
8   avc profile ( sps[0][1] )
8   avc compatibility ( sps[0][2] )
8   avc level ( sps[0][3] )
6   reserved ( all bits on )
2   NALULengthSizeMinusOne
3   reserved ( all bits on )
5   number of SPS NALUs (usually 1)
repeated once per SPS:
  16     SPS size
  variable   SPS NALU data
8   number of PPS NALUs (usually 1)
repeated once per PPS
  16    PPS size
  variable PPS NALU data

In demselben Beispiel wie oben sehen die AVCC-Extradaten folgendermaßen aus:

0x0000 | 01 64 00 0A FF E1 00 19 67 64 00 0A AC 72 84 44
0x0010 | 26 84 00 00 03 00 04 00 00 03 00 CA 3C 48 96 11
0x0020 | 80 01 00 07 68 E8 43 8F 13 21 30

Sie werden feststellen, dass SPS und PPS jetzt außerhalb des Bandes gespeichert sind. Das heißt, getrennt von den Elementarstromdaten. Die Speicherung und Übertragung dieser Daten ist Aufgabe des Dateicontainers und geht über den Rahmen dieses Dokuments hinaus. Beachten Sie, dass Emulationsschutzbytes immer noch eingefügt werden, obwohl wir keine Startcodes verwenden.

Zusätzlich gibt es eine neue Variable namens NALULengthSizeMinusOne. Diese verwirrend benannte Variable gibt an, wie viele Bytes zum Speichern der Länge jeder NALU verwendet werden sollen. Wenn NALULengthSizeMinusOnealso 0 gesetzt ist, wird jeder NALU ein einzelnes Byte vorangestellt, das ihre Länge angibt. Bei Verwendung eines einzelnen Bytes zum Speichern der Größe beträgt die maximale Größe einer NALU 255 Byte. Das ist offensichtlich ziemlich klein. Viel zu klein für einen ganzen Schlüsselrahmen. Die Verwendung von 2 Bytes ergibt 64 KB pro NALU. In unserem Beispiel würde es funktionieren, aber es ist immer noch eine ziemlich niedrige Grenze. 3 Bytes wären perfekt, werden aber aus irgendeinem Grund nicht allgemein unterstützt. Daher sind 4 Bytes bei weitem am häufigsten und werden hier verwendet:

0x0000 | 00 00 02 41 65 88 81 00 05 4E 7F 87 DF 61 A5 8B
0x0010 | 95 EE A4 E9 38 B7 6A 30 6A 71 B9 55 60 0B 76 2E
0x0020 | B5 0E E4 80 59 27 B8 67 A9 63 37 5E 82 20 55 FB
0x0030 | E4 6A E9 37 35 72 E2 22 91 9E 4D FF 60 86 CE 7E
0x0040 | 42 B7 95 CE 2A E1 26 BE 87 73 84 26 BA 16 36 F4
0x0050 | E6 9F 17 DA D8 64 75 54 B1 F3 45 0C 0B 3C 74 B3
0x0060 | 9D BC EB 53 73 87 C3 0E 62 47 48 62 CA 59 EB 86
0x0070 | 3F 3A FA 86 B5 BF A8 6D 06 16 50 82 C4 CE 62 9E
0x0080 | 4E E6 4C C7 30 3E DE A1 0B D8 83 0B B6 B8 28 BC
0x0090 | A9 EB 77 43 FC 7A 17 94 85 21 CA 37 6B 30 95 B5
0x00A0 | 46 77 30 60 B7 12 D6 8C C5 54 85 29 D8 69 A9 6F
0x00B0 | 12 4E 71 DF E3 E2 B1 6B 6B BF 9F FB 2E 57 30 A9
0x00C0 | 69 76 C4 46 A2 DF FA 91 D9 50 74 55 1D 49 04 5A
0x00D0 | 1C D6 86 68 7C B6 61 48 6C 96 E6 12 4C 27 AD BA
0x00E0 | C7 51 99 8E D0 F0 ED 8E F6 65 79 79 A6 12 A1 95
0x00F0 | DB C8 AE E3 B6 35 E6 8D BC 48 A3 7F AF 4A 28 8A
0x0100 | 53 E2 7E 68 08 9F 67 77 98 52 DB 50 84 D6 5E 25
0x0110 | E1 4A 99 58 34 C7 11 D6 43 FF C4 FD 9A 44 16 D1
0x0120 | B2 FB 02 DB A1 89 69 34 C2 32 55 98 F9 9B B2 31
0x0130 | 3F 49 59 0C 06 8C DB A5 B2 9D 7E 12 2F D0 87 94
0x0140 | 44 E4 0A 76 EF 99 2D 91 18 39 50 3B 29 3B F5 2C
0x0150 | 97 73 48 91 83 B0 A6 F3 4B 70 2F 1C 8F 3B 78 23
0x0160 | C6 AA 86 46 43 1D D7 2A 23 5E 2C D9 48 0A F5 F5
0x0170 | 2C D1 FB 3F F0 4B 78 37 E9 45 DD 72 CF 80 35 C3
0x0180 | 95 07 F3 D9 06 E5 4A 58 76 03 6C 81 20 62 45 65
0x0190 | 44 73 BC FE C1 9F 31 E5 DB 89 5C 6B 79 D8 68 90
0x01A0 | D7 26 A8 A1 88 86 81 DC 9A 4F 40 A5 23 C7 DE BE
0x01B0 | 6F 76 AB 79 16 51 21 67 83 2E F3 D6 27 1A 42 C2
0x01C0 | 94 D1 5D 6C DB 4A 7A E2 CB 0B B0 68 0B BE 19 59
0x01D0 | 00 50 FC C0 BD 9D F5 F5 F8 A8 17 19 D6 B3 E9 74
0x01E0 | BA 50 E5 2C 45 7B F9 93 EA 5A F9 A9 30 B1 6F 5B
0x01F0 | 36 24 1E 8D 55 57 F4 CC 67 B2 65 6A A9 36 26 D0
0x0200 | 06 B8 E2 E3 73 8B D1 C0 1C 52 15 CA B5 AC 60 3E
0x0210 | 36 42 F1 2C BD 99 77 AB A8 A9 A4 8E 9C 8B 84 DE
0x0220 | 73 F0 91 29 97 AE DB AF D6 F8 5E 9B 86 B3 B3 03
0x0230 | B3 AC 75 6F A6 11 69 2F 3D 3A CE FA 53 86 60 95
0x0240 | 6C BB C5 4E F3

Ein Vorteil dieses Formats ist die Möglichkeit, den Decoder zu Beginn zu konfigurieren und in die Mitte eines Streams zu springen. Dies ist ein häufiger Anwendungsfall, bei dem das Medium auf einem Direktzugriffsmedium wie einer Festplatte verfügbar ist und daher in gängigen Containerformaten wie MP4 und MKV verwendet wird.

szatmary
quelle
2
Danke Mann, das hat mir wirklich geholfen! Sie haben jedoch einige Tippfehler in Ihrem Artikel ... Ich denke;) Manchmal bezeichnen Sie die VCL als "VLC", was ziemlich verwirrend sein kann, weil ich VLC als "Codierung mit variabler Länge" kenne. Trotzdem hat Ihr Artikel ein paar Dinge für mich geklärt, gute Arbeit! Und ... Entschuldigung, ich kann dich nicht positiv bewerten, ich bin neu hier und es gibt hier eine Art Newbe-Filter;)
Bananenbär
5
Ja, tut mir leid wegen der Tippfehler. Ich bin ein wenig Legastheniker und eine sehr arme Schreibkraft. Du hast Recht. VLC hat in diesem Text keinen Platz.
Szatmary
2
Tolle Zusammenfassung! Das hat mir wirklich geholfen. Auch wenn es offensichtlich ist, wenn man sich den zweiten Satz (AVCC) von Bytes genau ansieht, sollte darauf hingewiesen werden, dass der Wert für die Länge von 4 Bytes, der den NALU-Daten vorausgeht, im Big-Endian-Format vorliegt. Ich konnte den Stream unter iOS nicht zum Dekodieren bringen, bis mir klar wurde, dass der Längenwert bytegetauscht werden musste.
12.
1
Vielen Dank Alter! Übrigens, der Windows Media Foundation h264-Decoder möchte nur Beispiele für Anhang B. Glücklicherweise ist es recht einfach, sie zwischen Anhang B und AVCC umzuwandeln.
Bald
2
Fehlt am Offset 0x0022 des AVCC-Extradatenbeispiels ein Nullbyte? Die Formatbeschreibung besagt, dass es ein 16-Bit-Feld für die PPS-Größe gibt. Ich denke, dies sollte 0x00 0x07statt nur sein 0x07.
Rhashimoto