fwrite

fwrite

好好生活
twitter
github
email

画像と動画

画像エンコーディング#

1 枚の画像は 2 次元の行列で表現でき、行列の各点はピクセルと呼ばれます。各ピクセルの色は三原色で表現され、すなわち赤、緑、青です。

bafkreifxg6vo5wnigcns2fokhhyxu6kg6y5zb4wtu4tmdignqnkyw3jqqy

各ピクセルは異なるビット数で表現でき、一般的な量子化ビット数には 16 ビット、24 ビット、32 ビットなどがあります。

  • 24 ビットビットモード:各ピクセル 24 ビット(bits per pixel、bpp)でエンコードされた RGB 値:赤、緑、青の強度を表すために 3 つの 8 ビットの符号なし整数(0 から 255)を使用します。
  • 16 ビットビットモード:各原色に 5 ビットが割り当てられ、緑は 6 ビットです。これは人間の目が緑の色調をより正確に識別できるためですが、特定の状況では各原色が 5 ビットずつ割り当てられ、残りの 1 ビットは使用されません。
  • 32 ビットビットモード:24 ビットビットモードと同様で、残りの 8 ビットはピクセルの透明度(アルファ)を表します。

画像にはもう 1 つ重要な属性があり、それは解像度で、幅 × 高さで表されます。

bafkreiah5ux6zbguyiokny6fgwcdeqkcswsuetjgtdxntwbpee6yeytg5u

画像や動画を処理する際のもう 1 つの属性はアスペクト比で、これは画像やピクセルの幅と高さの比率を示します。一般的な比率には 4:3、16:9、21:9 があり、通常は表示アスペクト比(DAR)を指します。同様に、ピクセルにも異なるアスペクト比があり、これをピクセルアスペクト比(PAR)と呼びます。

bafkreiewwvii2dpjlsifsxqn74wlyiuzmi6djeojorkczkftfgsfhmlbsy

YUV カラーモデル#

RGB は人間の目による色彩の感知に訴えかけ、YUV は視覚の明るさに対する感度に重点を置いています。Y は明るさ(輝度、ルミナンス)を表し、UV は色度(クロミナンス / クロマ)を表します(したがって白黒映画では UV を省略でき、RGB に近くなります)。それぞれ Cr と Cb で表されるため、YUV の記録は通常 Yの形式で表示されます。

bafkreia2dsmley7477h4uua4kvxbpklg2d57pqszxqyjdwehebsmoyab3u

帯域幅を節約するために、ほとんどの YUV フォーマットは平均して各ピクセルのビット数が 24 ビット未満です。主要なサンプリング(サブサンプル)フォーマットには YCbCr 4:2:0、YCbCr 4:2:2、YCbCr 4:1:1、YCbCr 4:4:4 があります。YUV の表記法は A:B表記法と呼ばれます:

  • 4:4:4 は完全サンプリングを示します。
  • 4:2:2 は 2:1 の水平方向のサンプリングで、垂直方向は完全サンプリングです。
  • 4:2:0 は 2:1 の水平方向のサンプリングで、垂直方向は 2:1 のサンプリングです。
  • 4:1:1 は 4:1 の水平方向のサンプリングで、垂直方向は完全サンプリングです。

RGB と YUV の変換#

# 最初のステップは明るさを計算します
Y = 0.299R + 0.587G + 0.114B
# 明るさが得られたら、色(青色と赤色)を分割できます:
Cb = 0.564(B - Y)
Cr = 0.713(R - Y)
# YCbCrを使用して変換することもでき、RGBを得ることもできます
R = Y + 1.402Cr
B = Y + 1.772Cb
G = Y - 0.344Cb - 0.714Cr

サンプリングレート、ビットレート、フレームおよびフィールドの概念#

画像はアナログ信号をサンプリング量子化して得られ、動画は一連の画像で構成されています。収集時に画像の解像度や量子化ビット数が高いほど、表現できる情報が多く、画面はより鮮明になります。動画にはサンプリング周波数の属性があり、単位時間あたりのサンプリング回数を示します。動画のサンプリング周波数は人間の目の制限を受け、通常は 1 秒あたり 20〜30 フレームの範囲です。サンプリング周波数が 1 秒あたり 10〜20 フレームの場合、速い動きの画像では人間の目には滑らかさが感じられず、サンプリング周波数が 20〜30 フレームに上がると、目には比較的滑らかに見えます。サンプリング周波数をさらに上げると、人間の目にはその差を感じることが難しくなります。これが現在の映画撮影で 24 フレームまたは 30 フレームのサンプリング周波数が使用される理由です。

動画を表示するために必要な毎秒のビット数はビットレートと呼ばれ、またはコーディングレートとも呼ばれます。計算式はビットレート=幅 高 深度 毎秒フレーム数です。例えば、圧縮を一切行わない場合、毎秒 30 フレーム、各ピクセル 24 ビット、480x240 解像度の動画は 82,944,000 ビット / 秒または 82.944 Mbps(30x480x240x24)を必要とします。

ビットレートがほぼ一定の場合は恒常ビットレート(CBR)と呼ばれますが、変動する場合は可変ビットレート(VBR)と呼ばれます。下の図は制限された VBR を示しており、フレームが黒のときにはあまりビットを消費しません。

bafkreid3gdtk6unvikp5pei4sdzpm75eghi4ikjyrigb7skimxou7sp77a

動画サンプリングで逐次スキャンによって得られた完全な画像は 1 フレームと呼ばれ、通常のフレームレートは 25 フレーム(PAL 方式)、30 フレーム毎秒(NTSC 方式)です。インターレーススキャン(奇数、偶数行)を使用すると、1 フレームの画像が 2 つのフィールドに分割され、通常のフィールドレートは 50Hz(PAL 方式)、60Hz(NTSC 方式)です。これは初期にエンジニアが提案した技術で、追加の帯域幅を消費せずにディスプレイの知覚フレームレートを倍増させることができます。この技術はインターレース動画と呼ばれ、基本的には 1 フレームで画面の半分を送信し、次のフレームで残りの半分を送信します。

bafkreifpux2p2edxpebxghyrps5cgfiqcpzvnag5cbxc6ghbysd5bw6hpe

H264 の概要#

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 単位にカプセル化されて初めて、転送または保存に使用できます。

bafkreiaefcxhtams7qptc46er22wucl4iv6kxnkfffpem4z75kk7hhpyq4

H.264 のエンコード動画シーケンスは一連の NAL 単位を含み、各 NAL 単位は RBSP を含みます。エンコードされたスライス(データ分割スライス IDR スライスを含む)とシーケンス RBSP の終了符号は VCL NAL 単位として定義され、残りは NAL 単位です。典型的な RBSP ユニットシーケンスは図 2 に示されています。

bafkreidubua2emr4jzasebschjflriqryrganel7embopfmydtgkngnouq

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

NAL 単位#

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

NALU ヘッダーは 1 バイトで構成され、その文法は次のようになります:

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

bafkreickxngl7hldegdehuumtirvpbfu2c7isj3pfh3nlxnuepv52mofye

  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 フレームを表します。

{% asset_img h264-header.png h264-header %}

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

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

bafkreia4uo4h67h5jks4gzfzd4v5pzjmynjmdgcoeecnnevsjwee74birq

私たちは最上部の図のビットストリームに対応するデータを段階的に分析し、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、図 2 を参照すると:7 はシーケンスパラメータセット SPS に対応します。

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

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

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

011 00101

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

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

(NALU タイプ & 0001 1111) = 5 すなわち (NALU タイプ & 31) = 5 例えば 0x65 & 31 = 5

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

RFC3984 は H.264 のベースラインビットストリームが RTP 方式で送信される規範です。

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

bafkreiaes3rw3r4hxrwkq5hhnlmjojg3wy2duroaypfwzagybmv3vcgnxa

単一 NALU#

12 バイトの RTP ヘッダーの後に音声データが続き、比較的シンプルです。単一 NAL 単位を RTP の NAL 単位ストリームにパッケージ化する場合、RTP シーケンス番号は NAL 単位のデコード順序に従う必要があります。NALU の長さが MTU サイズ未満のパッケージでは、一般的に単一 NAL 単位モードが使用されます。原始的な H.264 NALU 単位は[開始コード] [NALUヘッダー] [NALUペイロード]の 3 つの部分で構成され、開始コードは 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ヘッダー] [67 42 A0 1E 23 56 0E 2F]

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

パッケージ集約#

NALU の長さが特に短い場合、いくつかの NALU 単位を 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 を超える場合、NALU 単位を分割してパッケージ化する必要があります。これをフラグメンテーションユニット(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 インジケーターは以下の形式です:

+---------------+
|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 の最後のフラグメントを示します。すなわち、ペイロードの最後のバイトも分割 NAL 単位の最後のバイトです。続く 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 インジケーターの最初の 3 ビットであり、元の NAL ヘッダーの後の 5 ビットは FU ヘッダーの後の 5 ビットです。

FU インジケーターと FU ヘッダーの残りのビット数は実際の状況に応じて決定されます。

** 解凍:** 受信側が FU-A の分割データを受信した場合、すべての分割パッケージを組み合わせて元の NAL パッケージに戻す必要があります。FU-A の単位ヘッダーと復元された NAL の関係は次の通りです:

復元された NAL ヘッダーの 8 ビットは FU インジケーターの最初の 3 ビットと FU ヘッダーの後の 5 ビットで構成されます。すなわち:

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

参考資料#

動画技術紹介

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