fwrite

fwrite

好好生活
twitter
github
email

H264

概念#

  • SODB: データビット列 -> 最も原始的なエンコードデータ
  • RBSP: 原始バイト列ペイロード ->SODB の後ろに終端ビット(RBSP trailing bits 1 ビットの “1”)といくつかのビット “0” を追加して、バイトアラインメントを行う。
  • EBSP: 拡張バイト列ペイロード ->RBSP に基づいて擬似チェックバイト(0X03)を追加したもので、その理由は、NALU が Annexb に追加される際、各 NALU の前にスタートコード StartCodePrefix を追加する必要があるからです。この NALU に対応するスライスがフレームの開始であれば 4 バイトで表現し、0x00000001、そうでなければ 3 バイトで表現し、0x000001 となります。NALU の主体にスタートコードと衝突するものが含まれないようにするため、エンコード時に連続する 2 バイトが 0 の場合、1 バイトの 0x03 を挿入します。デコード時には 0x03 を取り除きます。これを脱殻操作とも呼びます。

H.264 の機能は 2 層に分かれており、ビデオコーディング層(VCL)とネットワーク抽出層(NAL)です。

VCL データは、圧縮エンコードされた後のビデオデータシーケンスです。VCL データが NAL ユニットにカプセル化された後にのみ、転送または保存に使用できます。

H.264 のエンコードされたビデオシーケンスは、一連の NAL ユニットを含み、各 NAL ユニットには RBSP が含まれています(表 1 を参照)。エンコードされたスライス(データ分割スライス IDR スライスを含む)およびシーケンス RBSP 終了符は VCL NAL ユニットとして定義され、それ以外は NAL ユニットとされます。典型的な RBSP ユニットシーケンスは図 2 に示されています。

2_1656856049435_0

各ユニットは独立した NAL ユニットとして送信されます。ユニットの情報ヘッダー(1 バイト)は RBSP ユニットのタイプを定義し、NAL ユニットの残りの部分は RBSP データです。

NAL ユニット#

各 NAL ユニットは、一定の構文要素の可変長バイト列であり、1 バイトのヘッダー情報(データタイプを示すために使用)といくつかの整数バイトのペイロードデータを含みます。1 つの NAL ユニットは、エンコードされたスライス、A/B/C 型データ分割、またはシーケンスまたは画像パラメータセットを運ぶことができます。

NALU ヘッダーは 1 バイトで構成され、その構文は次のとおりです:

NAL ユニットは RTP シーケル番号に従って順番に送信されます。その中で、T はペイロードデータタイプを示し、5 ビットを占めます;R は重要性指示ビットで、2 ビットを占めます;最後の F は禁止ビットで、1 ビットを占めます。具体的には次のとおりです:

3_1656856064741_0

  1. NALU タイプビットは NALU の 32 種類の異なるタイプの特徴を示すことができ、タイプ 1~12 は H.264 で定義され、タイプ 24~31 は H.264 以外に使用され、RTP ペイロード仕様はその中のいくつかの値を使用してパッケージの集約と分割を定義し、他の値は H.264 に予約されています。
  2. 重要性指示ビットは、再構築プロセス中に NAL ユニットの重要性をマークするために使用され、値が大きいほど重要です。値が 0 の場合、この NAL ユニットは予測に使用されていないため、デコーダーによって破棄されてもエラー拡散はありません;値が 0 より大きい場合、この NAL ユニットはドリフトなしの再構築に使用され、値が大きいほどこの NAL ユニットの喪失の影響が大きくなります。
  3. 禁止ビットは、エンコード時のデフォルト値が 0 であり、ネットワークがこのユニットにビットエラーがあることを認識した場合、1 に設定して受信者がそのユニットを破棄できるようにします。これは、異なる種類のネットワーク環境(例えば、有線と無線の組み合わせの環境)に適応するために主に使用されます。

264 の一般的なフレームヘッダーデータは:

00 00 00 01 67 (SPS)

00 00 00 01 68 (PPS)

00 00 00 01 65 (IDR フレーム)

00 00 00 01 61 (P フレーム)

上記の **67,68,65,61,** および 41 などは、NALU の識別レベルです。

F:禁止ビット、0 は正常、1 はエラー、通常は 0 です。

NRI:重要度レベル、11 は非常に重要です。

TYPE:この NALU のタイプを示します。

下の表を参照すると、7 はシーケンスパラメータセット(SPS)、8 は画像パラメータセット(PPS)、5 は I フレームを表します。1 は非 I フレームを表します。

4_1656856114733_0

これにより、61 と 41 は実際には P フレーム(タイプ値は 1)ですが、重要度レベルが異なります(それらの NRI は一つが 11BIN、もう一つが 10BIN です)。

H264 (NAL の概要と I フレームの判断)#

h264_1656856123091_0

最上部の図のビットストリームに対応するデータを段階的に分析していきます。00 00 00 01 で区切られた次のバイトは NALU タイプであり、これをバイナリデータに変換すると、

解読の順序は左から右に計算します。以下のようになります:

(1)第 1 ビットは禁止ビットで、値が 1 の場合は構文エラーを示します。

(2)第 2~3 ビットは参照レベルです。

(3)第 4~8 ビットは NAL ユニットタイプです。

例えば、上記の 00000001 の後に 67,68 および 65 があります。

0x67 のバイナリコードは:

0110 0111

4-8 ビットは 00111 で、10 進数に変換すると 7 になります。第二の図を参照すると、7 はシーケンスパラメータセット SPS に対応します。

0x68 のバイナリコードは:

0110 1000 4-8 ビットは 01000 で、10 進数に変換すると 8 になります。第二の図を参照すると、8 は画像パラメータセット PPS に対応します。

0x65 のバイナリコードは:

011 00101

4-8 ビットは 00101 で、10 進数に変換すると 5 になります。第二の図を参照すると、5 は IDR 画像のスライス(I フレーム)に対応します。

したがって、I フレームかどうかを判断するアルゴリズムは:

(NALU タイプ & 0001 1111) = 5 つまり (NALU タイプ & 31) = 5 例えば 0x65 & 31 = 5

RTP パッケージ送信 H264 の詳細なパッケージ化#

RFC3984 は H.264 のベースラインビットストリームを RTP 方式で伝送するための規範です。

H264 のビットストリーム構造

5_1656856166759_0

単一 NALU#

12 バイトの RTP ヘッダーの後には音声と映像データが続き、比較的シンプルです。単一 NAL ユニットを RTP の NAL ユニットストリームにパッケージ化する際、RTP シーケンス番号は NAL ユニットのデコード順序に従う必要があります。NALU の長さが MTU サイズ未満のパッケージでは、一般的に単一 NAL ユニットモードが採用されます。原始的な H.264 NALU ユニットは通常、[Start Code] [NALU Header] [NALU Payload]の 3 つの部分で構成され、Start Code は NALU ユニットの開始を示すために使用され、必ず “00 00 00 01” または “00 00 01” でなければなりません。NALU ヘッダーは 1 バイトのみで、その後は NALU ユニットの内容です。

パッケージ化する際には、“00 00 01” または “00 00 00 01” の開始コードを取り除き、他のデータを RTP パッケージに封入します。

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |F|NRI|  type   |                                               |
  +-+-+-+-+-+-+-+-+                                               |
  |                                                               |
  |               Bytes 2..n of a Single NAL unit                 |
  |                                                               |
  |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                               :...OPTIONAL RTP padding        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

例えば、H.264 の NALU が次のようなものであるとします:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F …]

これはシーケンスパラメータセット NAL ユニットです。[00 00 00 01] は 4 バイトの開始コードで、67 は NALU ヘッダー、42 から始まるデータは NALU の内容です。

RTP パッケージに封装すると次のようになります:

[RTP Header] [67 42 A0 1E 23 56 0E 2F]

つまり、4 バイトの開始コードを取り除くだけで済みます。

パッケージ集約#

NALU の長さが特に小さい場合、複数の NAL ユニットを 1 つの RTP パッケージに封入できます。

有線ネットワークと無線ネットワークの MTU の大きな差異に対応するため、RTP プロトコルはパッケージ集約戦略を定義しています:

  • STAP-A:集約された NALU のタイムスタンプは同じで、DON(デコーディング順序番号)はありません;
  • STAP-B:集約された NALU のタイムスタンプは同じで、DON があります;
  • MTAP16:集約された NALU のタイムスタンプは異なり、タイムスタンプの差を 16 ビットで記録します;
  • MTAP24:集約された NALU のタイムスタンプは異なり、タイムスタンプの差を 24 ビットで記録します;
  • パッケージ集約時、RTP のタイムスタンプはすべての NALU タイムスタンプの最小値です;
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |                                               |
+-+-+-+-+-+-+-+-+                                               |
|                                                               |
|             one or more aggregation units                     |
|                                                               |
|                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               :...OPTIONAL RTP padding        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 3.  RTP payload format for aggregation packets

STAP-A の例:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          RTP Header                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         NALU 1 Data                           |
:                                                               :
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               | NALU 2 Size                   | NALU 2 HDR    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         NALU 2 Data                           |
:                                                               :
|                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               :...OPTIONAL RTP padding        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 7.  An example of an RTP packet including an STAP-A
containing two single-time aggregation units

FU-A の分割形式#

データが比較的大きい H264 ビデオパッケージは、RTP で分割送信されます。12 バイトの RTP ヘッダーの後には FU-A 分割が続きます。NALU の長さが MTU を超える場合、NAL ユニットを分割してパッケージ化する必要があります。これをフラグメンテーションユニット(FUs)とも呼びます。

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator  |   FU header  |                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
|                                                               |
|                         FU payload                            |
|                                                               |
|                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               :...OPTIONAL RTP padding        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 14.  RTP payload format for FU-A

FU indicator の形式は次のとおりです:

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |
+---------------+

FU 指示バイトのタイプフィールド Type=28 は FU-A を示します。NRI フィールドの値は、分割された NAL ユニットの NRI フィールドの値に基づいて設定する必要があります。

FU ヘッダーの形式は次のとおりです:

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|  Type   |
+---------------+

S: 1 ビット、1 に設定されると NALU の最初のフラグメントであることを示します。続く FU ペイロードが分割 NAL ユニットの開始でない場合、開始ビットは 0 に設定されます。

E: 1 ビット、1 に設定されると NALU の最後のフラグメントであることを示します。続く FU ペイロードが分割 NAL ユニットの最後のフラグメントでない場合、終了ビットは 0 に設定されます。

R: 1 ビット、予約ビットは 0 に設定する必要があり、受信者はこのビットを無視する必要があります。

Type: 5 ビット、NAL ユニットペイロードタイプの定義は次の表を参照してください。

ユニットタイプおよびペイロード構造の要約

.Type   Packet      Type name                       
  ---------------------------------------------------------
  0      undefined                                    -
  1-23   NAL unit    Single NAL unit packet per H.264  
  24     STAP-A     Single-time aggregation packet    
  25     STAP-B     Single-time aggregation packet    
  26     MTAP16    Multi-time aggregation packet     
  27     MTAP24    Multi-time aggregation packet     
  28     FU-A      Fragmentation unit                
  29     FU-B      Fragmentation unit                 
  30-31  undefined                            

パッケージ化とデパッケージ化

パッケージ化:エンコーダがエンコード時に元の NAL を FU-A で分割する必要がある場合、元の NAL のユニットヘッダーと分割後の FU-A のユニットヘッダーの関係は次のとおりです:

元の NAL ヘッダーの最初の 3 ビットは FU indicator の最初の 3 ビット、元の NAL ヘッダーの後の 5 ビットは FU header の後の 5 ビットです。

FU indicator と FU header の残りのビット数は実際の状況に応じて決定されます。

デパッケージ化:受信側が FU-A の分割データを受信したとき、すべての分割パッケージを組み合わせて元の NAL パッケージに戻す必要があります。FU-A のユニットヘッダーと復元された NAL の関係は次のとおりです:

復元された NAL ヘッダーの 8 ビットは、FU indicator の最初の 3 ビットと FU header の後の 5 ビットから構成されます。すなわち:

nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)

libx264#

libx264 学習ノート

ffmpeg による libx264 の呼び出し

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。