« エンコーダはフィルタでなくてもいい? | メイン | DirectShowのデバッグ支援 »

2005年10月16日

吉里吉里 ムービー拡張日誌2:: WMVからの読み出し

    

DirectShowには、フィルタを開発を行いやすくするためにいくつか基底クラスが用意されている。
ソースフィルタの開発用にはCSourceと言うフィルタ用の基底クラスとCSourceStreamと言う出力ピン用の基底クラスがある。
CSourceStreamのFillBufferをオーバーライドし、この中でダウンストリームに渡すIMediaSampleへ各フレームの画像などをコピーするようにすれば、楽にソースフィルタを作ることが出来る。(実際にはこれ以外にアロケーターの設定用と受け入れるメディアタイプの取得用のメソッドもオーバーライドする必要がある。後、CSourceの実装も)
また、CSourceStreamはワーカースレッドを持っており、内部で適切にFillBufferを呼び出すような実装になっている。

WMVファイルから各フレームの画像などを同期的に読み出すIWMSyncReaderインターフェイスには、GetNextSampleと言うメソッドがあり、これでサンプルを得ることができる。
このメソッドは指定したストリームのサンプルを得ることも出来るし、単純にファイルの中の並びでサンプルを取得することも出来る。
ムービーファイルの中にはビデオとオーディオがインターリーブされている(と思う)ので、ストリームを指定した呼び出しの場合、ファイルへのアクセスがシーケンシャルにならない場合も出てくる。(ビデオストリームかオーディオストリームの取得順がファイル中の並びと異なる場合)
これでは…… と書きかけて気付いた。(ちなみに、ここまでが説明のための長い前置き)
別にシークが発生してもそんなに大した負荷増にならないんじゃないかと。
内部でキャッシュするような構造になっていれば、関係ない話だし。
うーん……

フィルタにワーカースレッドを持たせて、各出力ピンへサンプルをプッシュするような構造にしようかと思っていたけど、CSource/CSourceStreamのように各出力ピンがワーカースレッド持ちプルするような構造の方がいい気がしてきた。
別にシーケンシャルじゃなくても問題なさそうと気付いた後、liboggVFAPIの仕様について確認してみた。
ビデオとオーディオがどういう順番で並んでいるかを得るのは、VFAPIでは無理っぽい。
また、liboggでも面倒くさそうだ。まあ、oggファイルフォーマットは仕様が公開されているので、自分で実装すれば何とでもなるが。

これを書く前にクラス構造などをある程度詰めていたが再考した方が良さそうだ。

追加説明
ソースフィルタは、画像を表示したり音を出したりするタイミングを考慮せずにひたすらサンプルをダウンストリームに送るような作りになっている。
では、どうやって同期を取るのかというと、それはレンダーフィルタに任されている。
レンダーフィルタは、適切なタイミングでサンプルをレンダリングする。
もし、レンダリング時間より早くサンプルが到達した場合は、それの受け取りを拒否する。(デコードの遅延などを考慮して、いくつかのサンプルをキャッシュしている場合もある)
ソースフィルタは、サンプルの受け取りが拒否されたらそこでレンダリングフィルタが受け取れるようになるまで待つ。(CSourceStreamではポーリングによる実装になっている)
このような作りになっているので、ビデオとオーディオの並びがどうなっているかわからなくても問題ない。
オーディオレンダラとビデオレンダラが暗にタイミングを調整してくれている。
つまり、各出力ピンがワーカースレッド持ちフィルタからサンプルをプルするような構造の方が望ましい。
と言うか、そうしないと並びがわからない場合、実装が難しそう。



投稿者 Takenori : 2005年10月16日 11:13




comments powered by Disqus
Total : Today : Yesterday : なかのひと