« バージョン管理システムについてのメモ | メイン | ファイルの解凍 »

2004年08月01日

吉里吉里2/KAG3ムービー拡張日誌:: DirectShow 実験プログラム第1段階

    

とりあえずは、以前自分が作ったDirectDrawのプログラムと吉里吉里のソースとDirectShowを使った動画再生とフレームビットマップ取得方法のサンプルソースを参考に作る。

まずは、VCでプロジェクトを作って、draw.libをリンクに加え、Direct Drawの初期化部分を作る。
でも、なんでVCはあんなにAboutダイアログ好きなのだろう。私は、ほとんどの場合使わないのだが。。。
コーディングしながらふと気付く。DirectX5ぐらいのヘルプはないだろうか?
VC.NETのヘルプを見ても、そのあたりの関数は消えている。MSDNを入れれば復活するかなぁ。
そうだ、Cマガの付録から探せばいいんだ。
で、探すとあった。
DX5.2とDX7のヘルプとサンプルソースを入れる。
でも、DX5.2の日本語ヘルプはなくて、なぜかDX3のが入っていた。
まあ、DX7のヘルプがメインになるだろうから大丈夫だろう。

サンプルなどを見ていて思い出してきた。
このころはCOM丸出しだったんだった。

DX7使うにはdxguid.libも必要な様子。
フルスクリーンじゃないとバックバッファ使えないんだった。(本当にそうだったかなぁ?)
とりあえずは、DirectDrawを初期化してから、オフスクリーンバッファのポインタを取得して、そこへ書き込むまでは出来た。
予想外に手こずるなぁ。

DXMediaSDKのヘルプも必要そうなのでコピーしておく。
でも、英語版しかなかった。
まあ、それはともかく次はDirectShowだ。
上述のページによると・・・
streams.hとそれに必要なライブラリがサンプルのディレクトリ内にあり、ビルドするにはSDK内のdxsdk\samples\Multimedia\DirectShow\BaseClassesをINCLUDEディレクトリに追加し、 baseclasses.dswをビルドして得られるstrmbase.libとstrmbasd.libをリンクできるようにしておかなければならない。
・・・とある。
本当なの?と言うか、これ使ってしまっていいの?
後、吉里吉里は固めたファイル内からムービーを読み込むためにMicrosoftから提供されているasyncio.h/.cppとasyncrdr.h/.cppを使っているとか。
吉里吉里のkrmovieのプロジェクトを見てみると、strmbasd.libをリンクしていた。
それに、streams.hもインクルードしている。
やっぱり、必要なようだ。
よくヘルプを見ると、8以前のバージョンでは上記ライブラリはバイナリで提供されていたようだ。

DirectShowについて再びいろいろと調べる。少し理解が深まった。
そして、出来れば、吉里吉里の実装に近い形態で作りたいと思い、コードを追う。
IDirectDrawSurfaceが取得できれば・・・と思って、いろいろと調べるがよくわからず。と言うか、取得方法がない気がする。
結局、Dee氏に質問することにした。
結論はメモリへのポインタとして取得することしかできないとのこと。
まあ、DirectDrawだけだと自由度が低いし、Lock遅いって言うし、そう言う実装になりそうだなぁ。
---それといろいろと聞いたのでメモ
聞いたときのバージョンは吉里吉里2 2.22 rev.2/ KAG3 3.22 rev.2

オーバーレイクラスにレイヤーを渡し、そのレイヤーへビデオを書いてもらうような作りにする予定だが、そのレイヤーを渡すメソッドでは、TJSオブジェクトが渡されることになる。
つまり、実体はiTJSDispatch2。
そこから、tTJSNI_Layerを得るには、iTJSDispatch2::NativeInstanceSupportをコールする。
paramがプロパティに渡されたtTJSVariant型のオブジェクトだとしてparam.AsObjectNoAddRef()->NativeInstanceSupport(TJS_NIS_GETINSTANCE, tTJSNC_Layer::ClassID, (iTJSNativeInstance**)& tTJSNI_Layer型変数);でtTJSNI_Layerを取得できる。

tTJSNI_Layerで画像そのものへのポインタを得るには、
const void * GetMainImagePixelBuffer() const;
void * GetMainImagePixelBufferForWrite();
tjs_int GetMainImagePixelBufferPitch() const;
などを使う。

レイヤそのものは画像バッファしか持っていないし、DIBセクションであることもDirectDrawのSurfaceであることも期待できない。
ピクセルバッファのみへのアクセスしかtTJSNI_BaseLayerを通じては提供されていない。
DirectDrawは画面解像度の切り替えの時に使用して、あとは最終的な画像を画面に転送する際に(指定によっては)使用するが、そうでもなければ吉里吉里はいっさい使っていない。

レイヤには画像を書いただけだと何も起こらないので、書き込んだ後はtTJSNI_BaseLayer::Updateをコールしなければならない。
tTJSNI_BaseLayer::Updateはメインスレッドから呼ばないと変になるので、メインスレッドから呼ぶような実装にしなければならない。
つまり、別スレッドからイベントを投げて、ウィンドウのメッセージキューで処理すると良い。
TimerImpl.cpp (タイマ) で UtilWindow というのを使って実際にそういうことをやっているので、参考にすると良い。
tTJSNI_BaseLayer::Updateレイヤに変更が有ったという通知をするだけで、実際に描画が行われるのはその後、すべてのイベントが処理し終わった後になる。
イベントがほとんどない場合で、十分高速なPCだと、Updateを30fpsでコールすれば、描画サイクルも30fpsになる。

KAG のクリック待ちのアニメーションや文字表示のタイミングでタイマは使われている。そうでもなければKAGだとタイマは動いてないはず。

吉里吉里の Timer クラスで実装されているタイマーはWindowsの物ではなく、スレッドが一つ立ち上がってて複数のタイミングを管理しており、スレッドは次のタイマのイベントの時間が来るまでSleepで眠ってる。ただ、それだと精度が妖しいので timeGetTimeで補正している。
---メモ終わり
吉里吉里の実装に関するメモは分離して保存しておいた方がよいかも。

続く・・・



投稿者 Takenori : 2004年08月01日 07:10




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