« MPEG I デコードでもとのソースから変えているところ | メイン | Vorbis のデコーダ »

2007年11月19日

動画再生エンジン開発日誌:: Ogg ( Theora + Vorbis ) で音が出るように

    

やっぱり音がないとさびしいということで、音を鳴らすことにした。
今のマシンには HD Audio が付いているので、それが使えないかなぁと思ったけど、どのように使うのか調べてもすぐには見つからなかったので止めた。
DirectSound や OpenAL、 ASIO などどうするか考えて、とりあえずは DirectSound でいいやと DirectSound にした。
昔、DirectSound を使う何かを書いたような気がするけど、見付からなかったのでサンプルをベースに書き起こした。
ストリーミング再生のサンプルは、イベント通知があると、WAVE ファイルから読み込んでからバッファに書き込んでいるけど、ムービーでは直接読めないので、バッファへの書き込み関数だけ提供して、バッファに書き込めるかどうかの判定や、無音でのフィルは外に出した。
外と言っても、オーディオレンダラーというのがいて、それで処理するんだけど。
オーディオ側も、ビデオと同じようにサンプルのアロケートによってデコードの進み具合を調整するようになっている。

最初は、プチプチ言ってすぐに鳴り止んでなんだと思ったら、サウンドのループ再生を指定していなかった。
だから、バッファを確保している1秒ぐらいで停止してしまっていた。
で、ループするようにしたら音は鳴るんだけど、まともに再生できていない。
ビデオとオーディオのスレッドが共通なので、Ogg ファイルでのインターリーブのされ方によって、オーディオが間に合わないようだ。
0.5 秒分ぐらい先にオーディオを詰めておいてくれればまともに鳴るのだが、そのようにはなっていない。
と言うことで、やはりオーディオのスレッドを分離することにした。

分離すると、libogg は少し扱いづらいので、Ogg から読む部分は以前自分で作ったものを直して、ビデオストリーム、オーディオストリームと派生して、それぞれのストリームで読めば、そのパケットが得られるようにした。
で、うまく鳴るようになったのだが、Release ビルドにすると音か絵のどちらかが止まってしまう。
なんだろう? と考えていて、なんかうまくならないと書いた時に気付いた。
IStream を共通にしているので、別スレッドにするのなら、シークした後からリードするまでをクリティカルセクションなどで保護しないといけない。
でないと、その間でスレッドスイッチが起こると期待した位置から読めない。
と言うことで保護するようにした。
が、絵が遅れる。
ロックされている期間が長すぎるのか……
クリティカルセクションを使う前のデバッグバージョンではうまくいっていたのだが……
と言うことで、IStream を 2つ作ることにした。
シーク位置などは、やはり IStream に覚えてもらっていた方が手軽。
で、うまくいった。
でも、かなり釈然としない。
この部分に関してはもっと検討する必要がありそうだ。

後、現在 Ogg からはパケット単位で読むようにしているが、これはセグメント単位にした方が良さそうだ。
パケットは、複数のセグメントから構成されているが、theora のデコードはセグメント単位で行われる。
なので、一気にパケット単位で読み込むのではなく、セグメント単位で読み込んだ方がキャッシュ効率が上がり高速化が少し見込めるのと、読み込みでロックする期間が短くなるので、音と絵の同時デコードがやりやすくなるはずだ ( 今までの感覚では、読み込みは一気にやった方が速いような気がするが、どうも少しずつ ( 処理単位で ) 読んだ方が速いようだ。OS の HDD からの読み込み時のキャッシュが賢いのか、そこはそれほど気にする必要はなさそう。とは言っても、ディスクアクセスが頻発している時は引きずられるので、何か考えた方が良いとも言えるのだが。まあ、ここも検討する必要がある )。

他に、フォーカス移動したら音が止まってしまうのが気になったので、調べるとバッファ作る時に DSBCAPS_GLOBALFOCUS フラグをつけないといけなかったようだ。
これをつけると、フォーカスがなくても音が鳴る。



投稿者 Takenori : 2007年11月19日 18:55




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