モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

H.264 について(まとめ) 【H.264/Annex B/NAL file format/AVC/rtmp】

 こんにちは、モノトーンです。

 Windows ストア アプリでの、H.264 の映像再生に成功し、ちょっとテンション高いモノトーンです。私の集大成といいますか、H.264 における日本語資料が極端に少ない (実装する人が少ないのか、それともそういうのに取り組む日本人がいないのか…) ので、ここに記述しておきます。(なお、中国語の資料はいっぱいでてきましたね)

 まとめなのでかなり長くなります。おつきあいください。

概要

  1. H.264 について
  2. コンテナーとコーデック
  3. データ形式ついて
  4. NALUs について
  5. rtmp や FLV でのデータの扱い
  6. まとめ

1. H.264 について

 そもそも規格書では「ITU-T Rec. H.264 | ISO/IEC 14496-10 Advanced Video Coding」という呼び方をします。ITU-T (国際電気通信連合の電気通信標準化部門) と ISO/IEC (国際標準化機構/国際電気標準会議) の両方で標準化されています。基本的に略す場合 H.264 や AVC、H.264/AVC と略すことが多いかと思います。

 H.264 はコーデックです。良く x264 がコーデックって思われているのですが、x264 は“エンコーダー名”ですね。では、今回は H.264/MPEG-4 AVC について詳細を追っていきたいと思います。

2. コンテナーとコーデック

 そもそもコンテナーとコーデックの違いが判ってない人が多いかと思います。実は私も間違っているかもしれませんね。間違いがあったら突っ込んでほしいです。

 コンテナーとは、入れ物ですね。箱を想像してください。たとえば FLV や F4V、MP4、MKV、AVI、3GPP3GPP2、WebM などがコンテナーです。いろいろなフォーマットが入ると思っているでしょ? 単なる箱なんですね。

 一方、コーデックはデータの符号化方式です。デジタル化したデータをそのまま保存するとデータは非常にでかいです。そこで何らかの変換をかけてデータを小さくする必要があります。たとえば、音声では MP3、AACApple LosslessFLAC、OGG、また映像では H.263、On2 VP6H.264/AVC、H.265/HEVC、VP8 などがそうです。H.265/HEVC は次世代フォーマットとしてまだ一般ではありませんが、将来的には上記に上げたコンテナーに入れて当たり前に使われる日が来るでしょう。

 なぜ、このようなことが行われるのか? それは抽象化して考えを簡単にするためですね。ネットワーク通信もそうですが、有線接続と無線接続で何で同じようなパケットを投げつければ通信が成立するのですか? そうですね、物理でやり取りする部分以外はデータ形式が同じなんですね。この場合物理層 (空中を伝播する規則と同船を伝播する規則) は別物ですが、それ以外は同じということです。

 つまり、抽象化をすればいろいろ再利用ができるから、必然として抽象化が行われているということです。

3. データ形式について

3.1. Byte stream format (Annex B) について

 MPEG2-TS などはこの形式で H.264/AVC を扱います。NAL file format は次のような形式でデータが並んでいます (これは一例です):

f:id:mntone:20130903170838p:plain

図3.1-1 Byte stream format におけるデータ配置例

 単純でしょ? NALU とは Network Abstraction Layer Unit と呼ばれ、ネットワークで扱いやすい形式になっています。H.264/AVC 以外に H.265/HEVC でもこの形式で扱うことが可能です。具体的には:

f:id:mntone:20130903171314p:plain

図3.1-2 Byte stream format におけるデータ構造
(f(n) は fixed-pattern n-bits のこと, ISO/IEC 14496-10 Annex B.1.1 で定義)

 しかし、このままでは NALUs について何もわかっていないことになります。そうなんですね。ただ、この項目では取り上げません。詳細は 4 をご覧ください。

 ちなみに、このデータ列を見たい場合 ffmpeg や x264 で .264 ファイル (H.264 raw file) を生成してみてください。このように 0x000001 または 0x00000001 のスタートコード (以後 sc) で始まっていることがわかります。

3.2. NAL file format について

 この形式では、stream 以外にも別のデコード情報が必要です。たとえば、AVCDecoderConfigurationRecord データなどです。まずは「AVCDecoderConfigurationRecord」について見てみましょう。

f:id:mntone:20130903172138p:plain

図3.2-1 AVCDecoderConfigurationRecord
(ISO/IEC 14496-15 5.2.4.1.1 で定義)

 これには 2 つの NALUs が含まれていると思われます (H.264/AVC ではたぶん 2 つしかないと思われる)。SPS と PPS という情報がここには含まれており、通常 Annex B format ではファイルの冒頭に sc | NALU (SPS) | sc | NALU (PPS) と並んでいることがわかります。(rtmp では AVCDecoderConfigurationRecord が含まれていますから、これから SPS と PPS を NALUs として扱えばいいわけです。)

 ここで AVC format において、もっとも注目して一つを解説します。lengthSizeMinusOne というのがあります。これは 2b の unsigned interger で表されています。変数名からわかるように 1 引いた数値が入ってます。なお、このデータには 0b00 (0)、0b01 (1)、0b11 (3) だけ使われ、0b10 (2) は不正です。つまり 1、2、4 が正しい情報になります。

 上で表されたデータ長 (Big Endian) 分がその次から NALU 1 つ分を構成することになります。たとえば lengthSizeMinusOne が 3 となっていれば、次のように構成されます:

f:id:mntone:20130903173339p:plain

図3.2-2 NAL file format

3.3. Byte stream format から NAL file format への変換

 図を見て気づきませんでしたか? そうです、長さをいれる or スタートコードを入れるの違いですね。変換は単純にそれの置き換えでかまいません。

4. NALUs について

 NALU の構造も難しくありません。まずはこの図をご覧ください:

f:id:mntone:20130904112617p:plain

図4-1 NALU のデータ構造例

 NALU は NALU header と RBSP (Raw Byte Sequence Payload) EBSP (Encapsulated Byte Sequence Payload) で構成されます。EBSP についての詳細は今回は取り上げません。(調べたい人は自力で調べてね) 詳細データ構造について見ていきましょう:

f:id:mntone:20130910090949p:plain

図4-2 NALU のデータ構造
(ISO/IEC 14496-10 7.3.1 で定義)

 ここにおいて、nal_unit_type について取り上げます。

f:id:mntone:20130910091803p:plain

図4-3 nal_unit_type
(ISO/IEC 14496-10 7.4.1 Table 7-1 で定義)

 1 つ 1 つ見ていけばそれほど難しくありませんね?

5. rtmp や FLV でのデータの扱い

 rtmp や FLV ではこれらの形式を理解すれば、「Byte stream format で食ってくれる H.264 ハードウエア デコーダーが使えるんだけど…」、などという案件もこなせることになります!

 まずは VIDEODATA についてみていきましょう (rtmp ではヘッダー後にこの情報が入ります)。

 

f:id:mntone:20130903175200p:plain

図5-1 VIDEODATA
(Adobe Video File Format Spec V1.0 で定義)

 CodecId が 7 の場合、H.264/AVC です。この場合についてさらに詳細を見ていきましょう:

f:id:mntone:20130903175422p:plain

図5-2 AVCVIDEOPACKET
(Adobe Video File Format Spec V1.0 で定義)

 ここを見ると、上に上げた AVCDecoderConfigurationRecord や NALUs (AVC format で格納されています) が含まれていることがわかります。ただ、AVC end of sequence という項目が引っ掛かりますが、これは NALUs に相当するものがあるので、それに変換しておけばいいでしょう。

6. まとめ

 いかがでしたでしょうか? 今回は H.264/AVC に限定して、パックし直す (Byte stream to/from NAL file format) 場合について取り上げました。ここまで情報を取り上げて書いた資料は日本語にはたぶんないと思っていいと思います (だれかもっときれいにまとめて)

 なお今回取り上げた資料 (参考文献) について書いておきます。

そーかつ

 疲れた。やっぱり文章書くの嫌いだ! 時間かかる。

 でも、映像が出たときは感動したね。

 以上!

2013 年 9 月 4 日追記

 muken さん、ありがとうございます。

 指摘されているところをわかる範囲で直してみた。AVCDecoderConfigurationRecord についても近いうちに差し替えておきます…。私も勘違いしてたので少しまとめておきます。

  • AVCDecoderConfigurationRecord について、
    私は ffmpeg や FME などを相手に戦うので、たぶん誤った情報からの変換が必要な気がします… このあたりは誤ってる相手のデータを読んでどんな情報が来るか推測できればいいんでしょうね。
  • データの扱いやすさについて、
    実は読み直したときいろいろと不適切かな~ と思ったのですが、そのままにしていました。コメントに書いてあるように Byte stream format はランダムアクセスに不向きです。
  • RBSP と EBSP について、
    コメントで指摘があるように、EBSP は RBSP とは明確に違います。私の認識では 0x000000 を 0x00000300、0x000001 を 0x00000301、0x000002 を 0x00000302、0x000003 を 0x00000303、という感じにすればいいと思っています。

 追記分の補足に関してはこんな感じです。RBSP と EBSP に関して認識し間違っていたので、もしかしたらこれがデコードプロセスでエラーを起こしているのかもしれません。調べてみたいところ。