AOYAMA KOJI's PROGRAMMING BLOG

NAL Unit取得【mp4ファイル生成解説】プログラマー向け実装解説

2025/05/04
NAL Unit取得【mp4ファイル生成解説】

 mp4動画ファイル生成について、プログラマー向けに解説します。 大まかな流れとしては、各フレーム画像をエンコードし、mp4フォーマットに合わせてまとめます。 本記事では、全4工程中2番目の、エンコード結果から NAL Unit を取得する処理について、詳述します。
 なお、実際にこれを用いて作られたWebアプリケーションがこの記事などにありますので、 プログラマー以外の方も、ぜひお試しください。
NAL Unit取得【mp4ファイル生成解説】 fig.2

[PR]

mp4動画ファイル生成の工程


 当ブログにおける、mp4動画ファイルを生成する工程は、以下の4ステップです。
 本記事では「2.エンコード結果から NAL Unit を取得」を解説します。
  1. WebCodecsのVideoEncoderで各フレーム画像をエンコードWebCodecsのVideoEncoderで各フレーム画像をエンコード
  2. エンコード結果から NAL Unit を取得 ← 本記事で解説
  3. NAL Unit 等からボックス形式のmp4ファイルバイナリーデータを生成
  4. ボックス形式のバイナリーデータ生成
  5. バイナリーデータを保存バイナリーデータを保存

VideoEncoderのエンコード結果


NAL Unit取得【mp4ファイル生成解説】 VideoEncoderのエンコード結果
 前工程で、VideoEncoderを使用してエンコードすることで、フレームごとのバイナリーデータが取得でき、それを配列に保存していました。
 各フレームのバイナリーデータを詳細に確認すると、図のように、それぞれ複数の「NAL Unit」と呼ばれるもので構成されています。 mp4動画ファイル生成のためには、この解析が必要です。

NAL Unit


NAL Unit取得【mp4ファイル生成解説】 NAL Unit  NAL Unit には、複数のフォーマットがあり、 今回は annexb を指定しました。
 この形式は、スタートコードと呼ばれる「00 00 00 01」または「00 00 01」 が区切りになります。 データ長がすぐにはわからず、今回の用途では扱いづらいです。 そのため、1回だけ内容を解析して、内容の長さがわかる AvcC 形式に変換しておきます。
 AvcC形式の「データ長」には、NAL Unit ヘッダーの1バイトと、データ本体のバイト数の合計値を入れます。 データ長を収める自身のバッファサイズ(基本4バイト)は含めません。
 注意点として、スタートコードのサイズが可変で、AvcC形式のデータ長は固定のため、AnnexB形式をAvcC形式に変換すると、サイズが変わる可能性があります。 そのため、スタートコードをデータ長に書き換えるのではなく、新たにバイナリーデータを作る必要があります。

NAL Unit ヘッダー


NAL Unit取得【mp4ファイル生成解説】 NAL Unit ヘッダー
 次に、各 NAL Unit を解析するために、まず、先頭1バイトのNAL Unit ヘッダーを解析します。
 ここで必要な情報は、 NAL Unit タイプ、つまり下位5ビットです。 具体的には 0x1f で & を取り、その値により処理を分岐します。

NAL Unit ヘッダー解析プログラム例


switch( iNalUnitHeader & 0x1f ) {
  // Instantaneous Decoding Refresh (IDR) picture
  case 0x05:
      // キーフレーム保存コード(略)
  // Non Instantaneous Decoding Refresh (Non-IDR) picture
  case 0x01:
      // フレームデータ保存コード(略)
      break;
  // Sequence Parameter Set (SPS)
  case 0x07:
      // SPS保存コード(略)
      break;
  //  Picture Parameter Set (PPS) 
  case 0x08:
      // PPS保存コード(略)
      break;
}

NAL Unit タイプ


NAL Unit タイプ
内容
0x01
差分フレームデータ
0x05
キーフレームデータ
0x07
Sequence Parameter Set (SPS)
0x08
Picture Parameter Set (PPS)

 NAL Unit タイプは数種類ありますが、当ブログのアプリケーションでは表の4種類のみ取り出します。

0x01 と 0x05 フレームデータ


 動画圧縮には、画像をそのまま圧縮エンコードするキーフレームと、前画像からの差分を取得して圧縮エンコードする差分フレームがあります。
 それぞれ対応する NAL Unit があり、0x01なら差分フレーム、0x05ならキーフレームです。 この2種類の NAL Unit は1フレームに必ず1つ含まれているので、確保して、配列に保持しておきます。
 また、キーフレームのフレーム番号は、次の工程で必要になるため、別途保持しておきます。 上記コード例で case 0x05 に break が無いのは意図的で、キーフレーム専用処理のあと、フレーム共通処理を行っています。

0x07 と 0x08 パラメーターセット


 NAL Unit には、エンコードのパラメーターが収められた、 0x07 SPS と、0x08 PPS も存在します。 1フレーム目のエンコードデータの中に含まれています。
 この2つのパラメーターセットは、mp4動画ファイルに必須の情報のため、別途保管しておきます。
 なお、このパラメーターセットは、VideoEncoder に annexb フォーマットを指定することで、取得できます。 それ以外のフォーマットでは、エンコードデータに含まれているかは不定のようで、手元で試したところ、含まれる環境と含まれない環境がありました。

その他


 その他の NAL Unit は破棄します。
 例えば、筆者が確認した範囲では、各フレームの最初に 0x06 (Supplemental Enhancement Information [SEI]) が来ますが、無視して問題ありません。 もしかしたら、筆者の知識不足で、必要なものがある可能性はありますが、破棄して動いていますので、現時点では問題無さそうです。

結果


NAL Unit取得【mp4ファイル生成解説】 NAL Unit ヘッダー  これらの処理をして、図のように、フレームデータの配列と、SPSとPPSが取得できていれば、この工程は完了です。
 次の工程では、主にこの情報を用いて mp4のフォーマットであるボックス形式のファイルを生成します。 そちらは次回の記事で詳細に解説予定ですので、少々お待ち下さい。
 なお、キーフレームは1フレーム目の他、途中で再度現れる場合もあります。

実践コード


 本記事で解説した内容は、概念はmp4ファイルフォーマットに特有のものですが、 プログラミングは一般的な範囲のため、ソースコード例はほとんど載せていません。
 もし、本記事に関する実際のコードを参考にされたい場合は、 この記事など、各mp4クリエイター記事のソースから、import 先を調べてみてください。 プログラムを読める方に限定するため、ここではあえて不親切にさせていただきますが、コードの再利用は、悪意の無い範囲でしたら、まったく問題ありません

[PR]

まとめ


 本記事では、mp4動画ファイルを生成する工程のうち、エンコード結果から NAL Unit を取得する処理について解説しました。 次は、これを用いて mp4のフォーマットであるボックス形式のファイルを生成します。 詳細は解説記事の公開までお待ち下さい。

補足

  • 画像内のラスタライズ文字フォントにOpen Font LicenseNoto Sans Japaneseを使用しております。
  • (本記事公開後)本記事公開後に公開された記事へのリンクを追加しております。
カテゴリー:プログラミング解説,mp4ファイル生成解説
[PR]