詳しくはココ.
……後でぜったい内容忘れるから書いてあることをメモっておこう.
そもそもの問題点
VFW インタフェースと AVI コンテナは基本的に「Bフレーム」を扱えない. 古臭いテクノロジなので「Bフレーム」みたいな最新テクノロジには対応できないのだ.
「Bフレーム」を使いたかったら,できることといったらふたつくらい.
- んな古いテクノロジはさっさと捨てて,.MP4 を DirectShow 経由で使うとかする.
- 何とかして対応できるためにハックと開発をする.
ふたつのハックの方法
ハックとしては 2種類ありうる.
- エンコーダがうまいこと処理する(XviD で packed bitstream を使った場合,あと DivX5 も)
- デコーダで頑張る(packed bitstream を使ってない時の XviD)
基本的なトコ
まず,vfw/avi で Bフレームがどういう風に扱われてるのか理解しとこう.
通常,コンテナには「I P B B」の順でフレームが格納され,表示の際には「I B B P」の順で出力される.
vfw/avi は「1フレーム読んで 1フレーム出す(1 in, 1 out)」という仕組みになっていて, 1フレーム読み込んだら必ず 1フレーム出力しなきゃならない (エンコードもデコードも両方そう). Bフレームというのは前後ふたつのフレームの情報から間のひとつのフレームを作り出す技術なので, 「2 in, 1 out」という風に動けない vfw/avi ではうまくいかない.
今時の普通のデコーダの挙動を示す.
- まず Iフレームを普通に読んで出力する.
- 次に Bフレームを出力したいところだが,それには I/P のフレームが必要だ. I は既にデコード済みなので P までのフレームを読んできて Bフレームをデコードし出力. つまり「3 in, 1 out」となる.
- 同じように次の Bフレームを出力.
- 最後に Pフレームを出力する.
デコード時のハック
まず,やりかたその1.
avi/vfw の「1 in, 1 out」の法則があるので,まずはエンコーダ側で対応しとかなきゃならない. packed bitstream とか呼ばれる手法がこれだ. すなわち,最初の Bフレームが Pフレームと同じ 1フレームに入って, 「I P B B」が「I P+B B N」になるのだ. N というのはフレーム番号だけ持ってる空フレームだ.
その上で,デコーダの挙動はこうなる.
- まず Iフレームをデコード
- 次に Bフレームをデコード.これは I と P を必要とするが, P は B と一緒に入ってくるのでデコードできる. AVI的には両方で 1フレーム扱いとなっている.
- I と P は既に読み込んでるので 2番目の B もデコードできる
- 最後に P を出力.
このハックは,1 フレームに 2フレーム分の情報を送ることで, avi/vfw の「1 in, 1 out」の法則をうまく回避できる. が,普通の MPEG4 標準に従って書かれたデコーダは, この packed bitsream を扱うことができない.
やりかたその2.
コンテナには正しく「I P B B」の順にフレームが格納され,デコーダ側でこれを何とかする.
- デコーダはまず Iフレームを読み込むが,ここでは空フレームだけを出力する.
- 次に Pフレームが入力されるが,ここで最初の Iフレームを出力する. 「1 in, 1 out」の法則は,初回の空フレームも込みで維持されている.
- 次に Bフレームが入力されると,ここで I + B + P が揃うので,Bフレームをデコードできる.
- 2番目の Bフレームも同様にデコードできる.
- 最後に Pフレームを出力.
このハックだと,空フレームを作ることで「1 in, 1 out」のルールに対応できるが, デコーダは入力されたフレームと違うフレームを出力していることになる. が,packed bitsream と違って,MPEG4 標準ではこれを使用するよう定義している.
エンコード時のハック
というわけで,avi/vfw で Bフレームを扱うためのデコード時のハックは 2通りある. さらにエンコード時にもハックがある.
Bフレームをエンコードするには普通は以下の手順が必要となる.
- 最初のフレームを Iフレームにエンコードする.
- 2番目の,Bフレームとなるべきフレームが入力されるが, Pフレームが来るまでは Bフレームをエンコードすることができない.
- 3番目のフレームも同じようにエンコードできない.
- 4番目のフレームを Pフレームとしてエンコードする.
- I と P が揃ったので,Bフレームをエンコードできる.
- 同じように 2番目の Bフレームをエンコードできる.
もちろん,avi/vfw の「1 in, 1 out」の法則により, ステップ 2 と 3 の「何も出力しない」は不可能だ. そこで,エンコーダは「ディレイフレーム(delay frame)」と呼ばれる空フレーム(1バイトの 0x7F のみから成る)を出力する. このディレイフレームは,単に「1 in, 1 out」に従うためだけに出力されるもので, これが MPEG4 標準への準拠を不可能にする.
そこでどんな手段があるだろうか. Virtualdub(mod) は,エンコード中に得たディレイフレームをすべて捨てるという対処をしている. これにより,出力された AVI ファイルにはディレイフレームがなくなる. が,VFW が必ずしもこういうディレイフレームを捨てるフロントエンドで使われるとは限らない.
……AVI とか VFW,これマジどうよw
……けっきょく全部翻訳してしまったw