【原文】http://forum.doom9.org/showthread.php?s=&threadid=80430
【概要】
ここでは主にXviDのBフレームを、AVIに入れるためにWin界で編み出された技法が紹介されています。
手許では、Mac OSX 上でx264.mp4を作成する際、MEncoder,ffmpeg,x264cliでBフレームを使ったものは、いずれもQuickTime Player で再生すると冒頭に白紙フレームが入ります。
これは以下で言及されている"Delay Frame"である可能性があります。
再生に関しては問題ありませんが、以下のような症状が発生します。
- 冒頭で(白紙フレーム)を表示させた状態でシークするとムービー終端に飛ぶ。
- QuickTime Playerで映像情報が一部表示できない。
- QuickTime Player Proで.mp4へ「そのまま」書き出しできない。
b-frameがどのように .aviに収められ、vfwでのエンコード/デコード過程で使われるかについて、一部の人たちには説明して来たが、一度簡単な説明を書いて公開しておいた方が良いと思った。
内容は以下の通り。
第一の問題
"video for windows" (VFW) コデック・インターフェイス (virtualdub(mod)が使う) とそのコンテナ (AVI) は b-frameを扱えない、それどころか、このタイプのフレームの存在すら認識出来ないのだ!
b-frameのようなモダンテクノロジーを扱えないという事は、これらは時代遅れのテクノロジーと言う事ができる。
b-frameを使いたければ可能性は二つある:
1)b-frameを扱えないような 時代遅れの技術を捨てる(そして DirectShow や .MP4 のような新しいものを使う)。
2) 時代遅れの技術を開発と裏技でなんとかする。
2種類の裏技
現在、 2) のb-frames をavi と vfwで扱う方法は2種類ある。
a) エンコーダ側で扱う (xvid と divx5がデフォルトで使うpacked bitstream)
b) デコーダ側で扱う (xvidが packed bitstream をオフにした時に使う)
基本
aviとvfwでb-frameを使う裏技を理解するには、まず次の理解が必要だ。
通常、コンテナの中のフレームは次のように配置されている:
I P B B
ディスプレイは次の順番だ:
I B B P
VFW と AVI が使うのは " 1 フレーム イン・1 フレーム アウト " 方式 (それがこのテクノロジーの基礎)、これは 1フレームのインプットがある度に、1フレーム出力しなければならない事を意味する(エンコードでもデコードでも)。
これはb-frameと互換性がない。b-frame は 前後のi/pフレームとセットで使うべく作られているからだ。しかし vfw/avi は " 2 フレーム イン・1 フレーム アウト" といった事を許さない。 (モダンな directshow や .mp4はできる。)
通常 (モダンなテクノロジーを使った場合)デコーダはデコード中に次のような事を行う:
1) I-フレームを表示
2) 次に B-frameを表示するが、Bフレームは前後の I/P-frameが必要なので、既にデコード済みのIフレームをキープしておき、さらにPも読み込む。これで B もデコードできるわけだ (これは "3 フレーム イン・1 フレーム アウト" の場合)
3) 2番目のBフレームも同様に処理
4) 次に P-フレームの表示
デコードの裏技
では裏技に行こう:
a) AVI and VFW は" 1 フレーム イン・1 フレーム アウト " しかできないので、以下の処理をエンコーダで行う方法 ( packed bitstream と呼ばれる):
最初のBフレームは1フレームとしてPフレームとパックされる。
I P B B
は次のようになる
I PB B N
(*訳注:半角スペースに注意*)
(N フレームナンバー維持の為の、符号化されていない代替フレーム)
次に、デコーダは以下の処理をする:
1) I をデコード
2) 最初の B-フレームをデコードするには (前述のように) I と P が要る。最初の B は Pとパックされているので、彼は "公式には" 1フレームとカウントされる ( PB が1フレームしか無いように見える)が、実際にはP+Bの2フレームだ。これで最初のBはデコードできる。
3) デコーダは既に I と P を持っているので2番目の B もデコードできる。
4) 次に、 Pをディスプレイ。
まとめると、avi/vfwは" 1 フレーム イン・1 フレーム アウト " 方式しか使えないので、2フレームをパックして、これは1フレームですよと偽って処理に流し込むというものだ。
開発者の中には(ffmpegのミヒャエル=ニーダーマイヤーのように)2フレームを1フレームにパックするとMPEG-4規格との互換性が無くなるとする人もいます!また、MPEG-4規格を遵守する通常のMPEG-4デコーダはpacked bitstreamなんか知らないのでデコードもできない。
(*訳注:MEncoder -xvidencopts の(no)closed_gop, divx5bvopあたりが相当すると思われる*)
b) 2番目の案はストリームはaviの中に正しく配置(I P B B)しておいて、デコーダ側に裏技を用意するというものだ。
1) デコーダは先ずI-フレームを取得する。しかしディスプレイしない。代わりに例えば、有名なxvidの"decoder lag"メッセージを表示する!
2) 次に、デコーダはPを入力として取得する。そして、最初のIフレームだけを表示--" 1 フレーム イン・1 フレーム アウト " は遵守されるが、1フレームぶんのタイムラグがある。
3) 3番目、デコーダは最初のB-フレームを取得する。既にデコーダの手許には必要なIとPがあるので、このBもデコードできる。
4) 既にデコーダの手許には必要なIとPがあるので、2番目のBもデコードできる。
5) Pをディスプレイ
この裏技は、avi/vfwは" 1 フレーム イン・1 フレーム アウト " 方式しか使えないので、ラグを作って、デコーダがこの方式に従いつつも、取得したフレームを吐き出さないようにするもの。
packed bitstreamとの違いは、ストリームがMPEG-4規格準拠の方式で記述される事。
(*訳注:そういえばXvid+mp3.avi再生時、冒頭の一瞬は、素材と異なる真っ白のフレームだった記憶が…*)
エンコードの裏技
ここまでが、デコード側で時代遅れのvfw/aviでB-フレームを使うための2個の裏技。
さらに、エンコード側にも裏技がある(もちろん、ここでも" 1 フレーム イン・1 フレーム アウト " 方式に従う必要がある)。
B-フレーム エンコードの為には、エンコーダに2フレームを送り込ま無ければならない:
エンコーダは以下の作業をする:
1) 第一フレームをエンコーダに送り込む -> これはI-フレームとして符合化される。
2) 第二フレームを入力 -> これはB-フレームに符号化するべきだが => その為にはP-フレームも見る必要があるのでできない。
3) 第三フレームの入力 -> B => これも不可能。Pがまだ無い。
4) 第四フレームの入力 -> P-フレームに符号化
5) (IとPが準備完了している)=> 最初のBが符号化
6) (IとPが準備完了している) => 2番目の Bが符号化
さてvfw/aviの" 1 フレーム イン・1 フレーム アウト " 方式で、どうやって2) と 3) を行うか?
1 フレーム イン・1 フレーム アウトなので、いわゆるディレイ・フレーム (1-byte 0x7f frames)を書き出す。
VFWはなにか書き出せば良いのでディレイ・フレームでも良い訳だ!しかし、それは入力の中に存在するものではないし、しかも、MPEG-4規格との互換性は破壊される!
ではどうしよう?
AVI と VFW がトラブルを起こした時、我々がいつもしている事は、 -> 裏技を探す、だ。:
=> virtualdub(mod)にこうした"ディレイ・フレーム"をドロップさせればいい。これで最終的な出力ストリームの中には"ディレイ・フレーム" はなくなる。
しかし、vfwコデックを使う他のツールでは"ディレイ・フレーム"が残ってしまう可能性がある。注意してくれ。
AVI と VFW って、いいもんだろ?