December 26, 2004

シークと終端フレーム

シークのフラグでAM_SEEKING_NoFlush フラッシュしない。と言うのがある。
つまり、このフラグを指定しないとフラッシュされると言うことのようだ。
これで、少し安心だな。

で、シークに使っているSetPositions メソッドは、現在位置と停止位置を設定出来る。
そして、停止位置に来たらEC_COMPLETE を送ってくれるようだ。
EC_COMPLETE は普通のループでも使用している。
普通のループで確認すると、終端フレームの表示時間が取り立てて短いと言うことはないようだ。厳密には少し長くなっていると思われる。
つまり、これを使えばセグメントループもうまくいきそうだ。

メソッドはSetSegmentFrame と SetDefaultStopFrame を追加すればいいかな。
うん、うまくいきそうだ。

投稿者 Takenori : 11:01 PM | コメント (0) | トラックバック

再生できないMPEGファイルの調査

再生できないと言われたMPEGファイルを確認。
確かに再生できない。
エラーは、"これらのピンに共通するメディアの種類はありません。" だそうだ。
で、デバッガに各ピンがサポートするメディアの種類を出力するようにして、確認してみる。
問題のファイルの出力ピンのサブタイプはMPEG1Systemと出た。MPEG I Splitter はMPEG1System か MPEG1VideoCD、MPEG1Video、MPEG1Audio をサポートしている。 ( メジャータイプ、フォーマットは同一のため割愛 )
メディアタイプからするとつながるはずだが・・・

TMPGEncで問題のファイルを見てみる。
アスペクト比がその他(0.89)とか表示される。
何それ?
メディアプレーヤーでファイルを再生し、プロパティを表示、ビデオコデックのあたりをクリックするとアスペクト比が表示される。
それで、アスペクト比を見てみると1.19:1・・・ 何でそんなに変なアスペクト比を設定しているの?
問題なく再生できるほうを見ると4:3になっている。
PCで再生させるのなら1:1の正方画素にするのが良いと思うが・・・
うーん。
こんな変なアスペクト比のファイルは再生できなくてもいいような・・・
1:1になるように補正して表示しようとする段階で問題が生じそうな入力は、はじくようになっているのかな?
でも、グラフ自動生成やメディアプレーヤーでは再生されている。
さて、どうする?
個人的には1.19:1とか言う変なアスペクト比のMPEGファイルは再生できなくても良いと思うが。
非サポートの方向でいこう。

投稿者 Takenori : 09:48 PM | コメント (0) | トラックバック

DX9へ移行

新しいマシンのセットアップも完了したので、吉里吉里関係もそっちで行うようにするため、ビルドを行ってみる。
BCCは、boostを入れ、他に必要なインクルードファイルとライブラリをコピーしたらすんなりいった。
krmovieのビルドにはDirectShowが必要だが、DX8は入れていないので、DX9を使うことにしたが、DirectShow関係のは標準では入っていない。
DirectXのダウンロードページからExtrasをダウンロードし展開。
DX9 SDKが入っているところにコピーし、BaseClassesのライブラリをビルド。
krmovieのプロジェクトのインクルードディレクトリとライブラリを変更。
ビルドしたら、"krmovie fatal error LNK1181: 入力ファイル 'C:\Program.obj' を開けません。"と出る。
???
C:\Program.objって何?
どこかのライブラリで参照しているのか?
いろいろと調べるがわからず、ネット検索。
インクルードパスやライブラリを指定するとき""でくくらないといけないと言うことだ。
ああ、なるほど。
だから、C:\Program Files\Microsoft DirectX 9.0 SDK (October 2004)\Samples\C++\DirectShow\BaseClasses\Debug\strmbasd.lib の最初のスペースまでのC:\Programがリンク対象と認識されたのか。
って、DX9の標準インクルードディレクトリをProgram FilesにするなよMS。
今まで通りC:\DXSDKに入れてくれればいいものを。
で、ビルドすると今度はいくつかの関数などがかぶっていると出る。
LIBCMTDを除外する。
やっとビルドが通った。
動作も問題なし。

投稿者 Takenori : 07:29 PM | コメント (0) | トラックバック

終端フレーム関係の問題

IRCでDee氏から詳細な事情を聞いたところ、終端フレームの次のフレームが表示されてしまうと言うのではなく、終端フレームの表示時間が一定でないと言う問題の様子。
それはそうかも、終端フレームを表示した後すぐにシークをかけるので、シーク後のフレームが表示されるのは、デコードが完了したすぐ後になる。
でも、これはちょっといろいろと込み入っていて、対応するには問題が・・・
とりあえず、似たようなことについてログを残していたと思い、プログを読み返す。

ああ、プレゼンテーション時間を操作すればうまくいくかも。
でも、そしたらセグメントループは、フィルタの方で対応する必要があるかもしれないなぁ。
それと、プレゼンテーション時間はフィルタグラフがいい感じに設定するので、それをうまく操作できるかどうか・・・
ま、明日にでもコードとヘルプをにらめっこだな。

掲示板に書いた、終端フレームの次のフレームが表示されてしまうかもってやつも気になるので、シークについて少し調べたほうが良さそうだな。
シークを実行した時点でデータがフラッシュされるのなら問題は発生しないはずだし。

投稿者 Takenori : 01:04 AM | コメント (0) | トラックバック

December 07, 2004

ムービーセーブ仕様

保存する内容は次の通り。
オーバーレイかレイヤー描画か。
ループの有無
再生しているファイル
再生状態
対象レイヤー

なお、オーバーレイの時は保存/復元はしない。
保存するかしないかの指定は可能。

といった感じで良いかな。

投稿者 Takenori : 10:28 PM | コメント (0) | トラックバック

ムービーの栞への保存は厳しい?

レイヤー描画はピリオドイベントかセグメントループでシーンが遷移することを想定していた。
詳しく説明すると、ピリオドイベントは映画の字幕のように、ムービーに字幕を同期させたり、特定フレームでフラグによってムービーを分岐させたりするのに使用し、セグメントループは、選択肢やクリック待ちなどで、ムービーの指定範囲をループさせるのに使用し、クリックがあった時に、ループを解除するか、選択肢のときはループの終点のイベントでループの解除とムービーの遷移を行うような使用方法を考えて作っている。
上記のような用途に使うのなら、セーブポイントはシーン遷移後に置くことになる。
そして、栞がロードされた時、ムービーはそのシーンの開始フレームから開始されることを望む。
擬似スクリプトで表現するなら次のような感じ。
[ピリオド待ちorセグメントループ待ち]
[ジャンプ]
[ラベル]
[ムービーのフレーム移動]
って、再生しているムービーファイルとそのレイヤー、ループ状態を保存しておけば大丈夫か。
上記のように書いておけばロードされた時、移動させたいフレームに移動することになるし。

投稿者 Takenori : 09:54 PM | コメント (0) | トラックバック

ムービーの状態をセーブ

別にやらなくてもいいかと思ったけど、やっぱりやった方が良さそうなので検討することに。
で、栞関係のことをDee氏に聞くと、
MainWindow.tjs内のinternalStoreFlags で、栞へ現在の状態を保存。
internalRestoreFlags はその逆を行っている。
とのこと。
場所はわかった。
でも、仕様を考えないといけない。
さて、どういうのがいいかなぁ。

投稿者 Takenori : 12:48 AM | コメント (0) | トラックバック

December 02, 2004

theoraのサンプルコード

theoraのサンプルコードでいいのがない。
エンコードはffmpeg2theraがわかりやすそうだが、デコードはない。
DirectShowのならあるが、追うのが面倒臭い。
vorbisなら、SDKにサンプルが付いている。
α版の内は仕方ないのかな。
正式版がリリースされれば、サンプルコードも出てきて何とかなる?
面倒だから保留にしよう。
正式版が出た時に、気が向いたらやろうっと。

投稿者 Takenori : 07:58 PM | コメント (0) | トラックバック

theoraのビルド

ogg, vorbis, theoraのソースをDLし、順番にビルド。
って、theoraのプロジェクトファイル壊れてる!
VS 2003にコンバートするのが問題なのか?
でも、他のは出来たし。
どうしよう?
仕方がないので、新しくスタティックライブラリ用のプロジェクトを作り、libの中のソースを全部ぶち込んで、追加のインクルードパスにvorbisと同じものを追加。
ビルドしたらあっさり通る。
まあ、ライブラリだからね。

そうだ、デバッグ用のは末尾に_dを付けとかないと。

投稿者 Takenori : 02:57 PM | コメント (0) | トラックバック

theora使用感とか

Dee氏お勧めのプレーヤーVLC
確かに余計なもののインストールがなくていい感じです。

で、再生してみると・・・ シーンによって負荷が全然違う。
MPEG Iとかって、結構一定じゃなかったっけ?
最近のはだいたいこんな感じなのだろうか?
どういった圧縮アルゴリズムなんだろう?
少し気になる。

投稿者 Takenori : 02:31 PM | コメント (0) | トラックバック

ムービーのSave

すっかり忘れていた。
吉里吉里2/KAG3はレイヤー情報は自動的にセーブされ、ロードしたときは自動的に復元されるが、ムービーは何もしていないんで、白いレイヤーかゴミだったか忘れたけど、意図していないものが表示されるんだった。
まあ、セーブポイントをムービーの開始前に設定するようにすれば回避できるけど、忘れると変な画面になってしまう。
ムービーもセーブされるようにしたほうが良いかなぁ。
ムービーは途中のフレームから開始されるより、最初からの方がいいよなぁ。
ループ、セグメントループ、ピリオドイベントは復元しないとまずいよなぁ。
今夜また話してみよう。

投稿者 Takenori : 01:41 PM | コメント (0) | トラックバック

OggTheoraの追加

W.Dee氏も追加を予定しているそうな。
ならいいや、やらなくても。
たぶん、明日ぐらいに新マシン用のパーツが届いて組めるはずなので、3Dで遊んでようっと。

投稿者 Takenori : 01:54 AM | コメント (0) | トラックバック

November 30, 2004

OggTheoraのAPI

OggTheoraのAPIリファレンスを見ると、YUVでしか取得できない?
OggTheoraも、いわゆる人の輝度と色差の感度の違いを利用して圧縮するのだろうか?
だから、最初は輝度と色差になるから、それを直接利用できる環境だと効率がいいので、こうなっているのかな。
YUVからRGBへの変換
めんどいな。
そーだ、Playerのコードを参考にしよう。
YUVで吐いていたら、意味なしだけど。

投稿者 Takenori : 12:10 AM | コメント (0) | トラックバック

November 29, 2004

ビデオコーデックの内包

IRCで話していた時、吉里吉里にビデオコーデックを積むと言う話が出たので、少し調べてみた。
XviDが、オープンソースなんでいかなぁと思ったが、MPEG4自体にライセンスなどの問題があり、なんか避けた方がよさげな雰囲気。
Ogg Theoraってやつが良さそう。
作っているのは、Ogg Vorbis と同じところ。
他のも扱っているが、この解説ページがわかりやすい? ってか、ほとんど他のは読んでいなかったり。
でも、いろいろとあるなぁ・・・ 字幕や他言語サポート。
OGMはシークが速い。
それはいいな。
ちょっと遊んでみても楽しいかも。

投稿者 Takenori : 11:16 PM | コメント (0) | トラックバック

環境依存問題

W.Dee氏にマージをお願いしていたが、Dee氏の環境でうまく再生されないファイルがあることが判明。
Dee氏の協力を得て調査した結果、m_GraphBuilder->Connect( pIPinUpstream, pIPinDownstream)で、グラフビルダが途中のフィルタを検索かけた時に、変なフィルタがしゃしゃり出てきて、勝手に例外投げて、落ちるという、ちょっと待てよってことが起こっていた。
そこで、ConnectDirectで中間フィルタを入れずに接続するようにした。
これによって、検索しなくなり、変なのがしゃしゃり出てこなくなって問題解決。
この際、MPEG Audioデコーダーも固定とした。

まだ、AVIファイルが再生されない問題が残っているが、AVIはほとんど採用されていないようなので、非サポートってことで・・・

で、エラーの通知やオプションなどの追加はDee氏がやってくれるとのこと。
感謝。

投稿者 Takenori : 11:03 PM | コメント (0) | トラックバック

November 23, 2004

本体へ

今日、W.Dee氏へ、ムービー拡張の本体への組み込みをお願いした。
動作確認などはずっと前に終了していたのだが、引越しなどがあったので1ヶ月以上放置していた。
でも、これで本体へ組み込まれればめでたしめでたしだ。

投稿者 Takenori : 05:35 PM | コメント (0) | トラックバック

October 06, 2004

プロセスが残る問題への対処

以前、プロセスが残る問題の対処を行ったが、あれで完璧というわけではなかった。
まだ、タイミングによってプロセスが残ってしまうことが判明。
調査すると、DoRenderSample 内でフィルタグラフのIMediaSeeking を使用する箇所で返ってこなくなってしまうようだ。
フィルタグラフはマルチスレッドで動作しており、Stop がコールされても、タイミングによっては、DoRenderSample がコールされてしまうようだ。と言うか、ほとんどの場合、DoRenderSample がコールされてしまう。
そして、その中でフィルタグラフのIMediaSeeking を使うわけだが、すでにdelete中のため、何らかの理由でIMediaSeeking のメソッドがリターンしないようになってしまうようだ。(内部がどのようになっているかわからないので正確な理由は不明。)
そもそも、この時点では単にStopへステートの遷移中なのだから、IMediaSeeking のメソッドぐらい使えても良さそうなものだが、使えない。もしかしたら、デッドロックが発生しているという可能性もある。
レンダーフィルタは下記のようないくつかのクリティカルセクションを使用して動作しているが、それらの取得順序の違いによって・・・ いや、その可能性は低いか。
・m_InterfaceLock フィルタ状態のロック。
・m_RendererLock ストリーミングのロック。
それよりも、フラグの問題かもしれない。レンダーフィルタがもつフィルタは多い。っていうか、内部動作のシーケンス図クレーって感じだ。
BaseClassesはソースが公開されているので、CBaseRenderer などのシーケンス図を書こうと思えば書ける。でも、フィルタグラフのところは不明なので書けない。(もしかしてどこかにあるのかな?)
まあ、結局のところよくわからないのでいろいろと試したが、変なところでフリーズしたりしてうまく行かなかった。
なので、方法を変更することにした。

その方法は次の通り
ストリーミング開始時にコールされるメソッド内でフィルタグラフのIMediaSeeking を使用して、開始フレームを記録する。
レンダリング前にコールされるメソッド内で、自身のフィルタのIMediaSeeking を使用してストリーミングタイムを取得し、記録している開始フレームを加算したものを現在のフレームとみなし、メディアサンプルにメディアタイムとして設定する。もし、自身のIMediaSeeking が使用できない場合は、ストリーミングが開始されてからレンダリングしたフレーム数とドロップしたフレーム数を加算する。ただし、ドロップしたフレーム数はより上位のフィルタでドロップされたものまではわからないので、若干精度が劣る。
そして、DoRenderSample 内でメディアサンプルからメディアタイムを取得し、それを現在のフレームとして使用する。
以上のような処理に変更すると、プロセスが残る問題はなくなった。
ただし、現在のフレーム番号の精度は少し落ちているものと思われる。

この対処でも、完全にこの問題に対処できたとは限らない。
もし、CBaseRenderer::OnStartStreaming が別スレッドコールされてしまうと、同じような問題が発生する可能性がある。しかし、CBaseRenderer::OnStartStreaming を可能な限り追ったところ、CBaseRenderer::Run からコールされているようだ。これが同じスレッドなら・・・
そうだ、GetCurrentThreadId で調べればわかる。
調べるとPlayのコールもととOnStartStreaming のスレッドは異なる。
しかし、OnStartStreaming とレンダリングを行うスレッドも異なった。
結局わからないのか。
でも、フィルタグラフとOnStartStreaming のコール元スレッドが同じ可能性は少し高くなったかも。
もし、スレッドが異なっていたとしても、この問題が発生するのはごくまれだ。(と言っても、起こる可能性があるものは起こってしまうものだけど)
まあ、たぶん同じスレッドでしょう。
他に調べる方法は思い浮かばないし、この問題は解決としておこう。

投稿者 Takenori : 03:05 PM | コメント (0) | トラックバック

机上デバッグとコメント整備

机上デバッグしつつ、コメントを整備する。

机上デバッグで、以下のようなものを修正。
メモリリークが発生する可能性があったコードを修正。
冗長なコードを修正。
不要なコードを削除。
発生することはない不具合を修正。


修正後念のため、確認用スクリプトを走らす。
問題なし。


思い出した注意事項
セグメントループとピリオドイベント、ループ、モード、描画対象レイヤーはオープン時に初期化されない。

投稿者 Takenori : 12:06 AM | コメント (0) | トラックバック

October 05, 2004

position/frameプロパティの確認

position/frameプロパティへの値設定の確認を忘れていたので行う。
positionは何事もなかったが、frameはうまく行かなかった。
昨日のピリオドイベントの修正でデグレードしてしまったようだ。
修正して動作確認。
きちんと動作した。

後、pauseも確認していなかったので確認。
うまく行かない。
確認すると、pause状態の処理が全くなかった。
playで再開できるかなぁと、安易に考えていたのだが、TJSのコードを見るとそう言うわけにはいかないようだ。
resumeとかを追加してしまうかなぁ。それより、playの中にpause状態の扱いを追加した方が良いかも。
で、playの中にpauseの扱いを追加。
問題なく再開できるようになった。


うーん、やはり一気に全部チェックするスクリプトを書いておいた方が良いな。

ざっとスクリプトを書いた。
チェックした項目は次の通り
レイヤー描画
音あり/なし MPEG/AVI
close
open
play
stop
pause
rewind
prepare
segment loop
cancel segment loop
period event
cancel period event

loop プロパティの設定/取得
frame プロパティの設定/取得
position プロパティの設定/取得
fps プロパティの取得
numberOfFrame プロパティの取得
totalTime プロパティの取得

period event 待ち


オーバーレイ
上述のレイヤー描画と同等。
ただし、セグメントループとピリオドイベント、prepareは使用できないので確認していない。

投稿者 Takenori : 06:16 PM | コメント (0) | トラックバック

October 04, 2004

AVIの確認/オーバーレイの確認

音あり/なしのAVIファイルをレイヤー描画で確認した。
何事もなく再生できた。

音あり/なしのAVIファイル、音あり/なしのMPEGファイルをオーバーレイでも確認。
問題なく再生できた。
セグメントループと、ピリオドイベントはオーバーレイでは使えないので、確認はしていない。

とりあえず、これで一通りの基本動作は確認した。

投稿者 Takenori : 06:02 PM | コメント (0) | トラックバック

ピリオドイベントと無音MPEGの動作確認

まず、ピリオドイベントで忘れていたものを追加。
rewind がコールされた時か、frame にイベント発生フレームよりも小さい値がセットされた時に、イベント発生抑止を解除するようにした。
一度だけしかイベントを送らないというのも忘れていたので、追加した。

1分ぐらいの無音MPEG(.mpv)ファイルを再生して、ピリオドイベントで字幕を変化させるスクリプトをテストしてみる。
どうさせると、いきなりフィルター接続でエラーが返ってくる。
デバッガーで追うと最初のMPEG1スプリッターで、ピンを接続する際、適切な中間フィルタが見つかりませんでしたと言う、エラーが返ってきて失敗していた。
拡張子をmpgにし動作させると、そこは通り、DirectSoundフィルタを接続するところで失敗する。
どうやら、メディアタイプをMPEG1Videoとするのがまずいようだ。
なので、拡張子が.mpvとなっていても、MPEG1System とすることにし、DirectSoundフィルタの接続で失敗したら、音がないものとみなして、DirectSoundフィルタを接続しないような作りに変更した。
また、ついでにAVIの場合も同じような作りにしたので、音無しAVIにも対応したはず。
この修正によって、音があってもなくても拡張子は.mpgとして、内部で判断するようになった。
これで、.mpgでも、.mpvでもどっちでも良くなった。
ただし、MPEG1VideoCDの.datは確認していない。と言うか、ビデオCDは持っていないので確認できない。
ちなみに、MPEG1VideoはTMPGEncで作ったので、一般的なファイルになっているはず。

ピリオドイベントの方は1発でうまく動いた。

投稿者 Takenori : 04:33 PM | コメント (0) | トラックバック

ストリーム タイムを追う

時間について少し整理する

基準タイム
基準タイムは、基準クロックから返される絶対タイムである。

ストリーム タイム
ストリーム タイムは、グラフが最後に実行を開始したときを基準に定義される。
・グラフが実行しているときは、ストリーム タイムは、基準タイムから開始タイムを差し引いた値に等しい。
・グラフがポーズしているときは、ストリーム タイムはポーズされたときのストリーム タイムに留まる。
・グラフが停止しているときは、ストリーム タイムはゼロである。
・シーク処理後には、ストリーム タイムはゼロにリセットされる。

タイム スタンプ(サンプルタイム)
タイム スタンプは、ストリーム タイムで示されるサンプルの開始タイムと終了タイムを定義する。タイム スタンプは、プレゼンテーション時間と呼ばれることもある。

メディア タイム
メディア タイムは、シーク可能なメディア内のサンプルの本来の位置 (たとえばディスク上のファイル) を指定する。ビデオの場合、メディア タイムはフレーム番号を表す。


シーク処理後には、ストリーム タイムはゼロにリセットされるって、あかんやん。
でも、IMediaSeeking::GetCurrentPosition を使えば正しい位置が返ってくる。
だから、IMediaSeeking::GetCurrentPosition を使えればいいのだが・・・

調べるとちょうどいいのがあった。
CBaseRenderer::GetMediaPositionInterface
フィルタの IMediaPosition および IMediaSeeking インターフェイス ポインタを取得する。
前調べた時はフィルタグラフにばかり目がいって気付かなかった。
じゃ、さっそくこれを使ってみよう。

だめだ、CBaseRenderer::GetMediaPositionInterface で返ってくるインターフェイスからIMediaSeeking::GetCurrentPosition で時間を取得しても、ストリームタイムが返ってくる。

CBaseFilter.m_pGraph がフィルタグラフをおさえている。
このフィルタグラフにクエリーをかけてIMediaSeeking インターフェイスを取得すればうまくいきそうだ。
とりあえず、コンストラクタで・・・ って、コンストラクタがコールされる時にはまだフィルタグラフに参加していないからダメだ。
DoRenderSample で未取得なら取得するようにした。
で、動作チェック。
キターッ!
きちんと取得できた。
ループもきちんと行われている。

再生が終了してしまうと言う問題だが、あれは勘違いだった。
最終フレームに到達しても再生は終了しないんだった。
そして、シークしてまだ残りフレームがある位置に移動すると、再びヘッドが進み出す。
なんの問題もなかった。


2つほど不具合を発見し修正。
ダブルバッファリングにしたはずが、一部ずっと同じバッファを指していたために、無駄なメモリコピーが発生してしまっていた不具合を修正。
なんか重くなったような気がするなぁと思っていた原因はこれだったのか。

ループを設定して、KAGスクリプトが何もない状態になった時に終了するとプロセスが残ってしまう問題を発見。
tTVPDSMovie::ReleaseAll() のm_MediaControl->Stop(); が返ってこなくなっていた。
tTVPDSLayerVideo のデストラクタでもReleaseAll() をコールするようにしたらそのようなことはなくなった。
ReleaseAll() は何度呼んでも良いようにしているが、なんでそんなことが?
呼び出し過程で問題が発生するような呼び出し順序にしているつもりはなかったのだが・・・ 違う、デストラクタで消えていく順番が怪しい。
派生側が持っているメンバが先に消えてしまっていてどうしよう?状態になりそうだ。
そして、そのメンバにはフィルタグラフに参加しているグラフのインターフェイスもあるし。
でも、まあこれでプロセスが残る問題は解決。

以上で、セグメントループの基本的な動作確認は終了。

投稿者 Takenori : 01:49 PM | コメント (0) | トラックバック

IMediaSeeking::SetPositions の怪

IMediaSeeking::SetPositionsでシークした際、その移動先が0フレームでなくても、CBaseRenderer::GetSampleTimesで返ってくる位置は0からになっている様子。
そのせいで、途中のフレームにジャンプさせるとうまく行かないようだ。
でも、そしたら・・・ なんかおかしい。
ここはもっと調査しないといけないなぁ。

投稿者 Takenori : 12:50 AM | コメント (0) | トラックバック

October 03, 2004

BCBのコードをVCでデバッグしたい

デバッガはやっぱり、BCBではなく、VCの方を使いたい。
でも、いろいろと調べていくとBCBは独自のデバッグ情報を吐くらしい。
弱った。
無理なのだろうか?

ProgrammingのDebugging aidsにMs-dbgとか言うものがある。
これ使えないかなぁ?

pdbファイルを作ることは出来たけど、これはVCでは使えないのだろうか?
もっと調べないと良くわからない。

関係ないけどメモ
Open Watcom C/C++と言うのがあった。
消えたと思っていたWatcom C/C++はフリーになったのだろうか?

投稿者 Takenori : 11:20 PM | コメント (0) | トラックバック

セグメントループのテスト&デバッグ

だいぶ前に組み込んでおきながら今更動作確認。
いきなりTJSで引っかかる。
オブジェクト型を期待しているところに(int)0がきているとかどうとかでる。
初めKAGの方がおかしいのかと思ったが、コーンソールの表示を見るとMovie.tjsに問題がある様子。
オーバーライドしておきながら、親クラスのメソッドではなく、自分のを呼んでしまっている様子。
初めはよくわからなかったので、いろいろと調べていろいろと直す。(実はTJSについてあんまり知らなかったり)
そして、動いたと思ったら、今度はDLL側に問題があり、セグメントループがうまく動かず、調べる。
IMediaSeeking::SetPositions の使い方を勘違いしていたと思い直すが直らず、再度よく見るとそれは勘違いで元のがあっていたようなので、元に戻すと、なぜかうまく動くようになる。謎謎謎・・・
ビルドを忘れていたりしたのだろうか?
よくわからん。
でも、DirectShowは時々こういうことがあるような気がする。いったい何なんだろうか?

残っている問題
最終フレーム付近でセグメントループを使おうとしたら、シークさせるよりも先に再生が終了してしまい、うまくループさせられない。
これは、ダブルバッファリングしているので、内部処理よりも描画は1フレーム遅れている上に、内部的に数フレーム処理が進んでいることがあるようで、さらに先に進んでしまっているんが原因。
フレームを移動させた後、フィルタグラフの状態が再生中かどうかを確認して、再生中じゃない場合は、再度Playをコールした方が良さそう。
かと思ったが、どうやらそこが問題ではない様子。
上述の謎謎謎の部分がやっぱりおかしいようだ。
終了フレーム付近ではない位置でIMediaSeeking::SetPositions をコールして0位置へ移動した時、S_FALSEを返すが、なぜか位置移動は成功している。
なんだこれは?
自分でフレームから100ナノ秒単位に変換している部分がおかしいのだろうか?

IMediaSeeking::ConvertTimeFormat は例のごとく実装されていませんと返ってくる。
やはり期待できないヤツだ。

S_FALSEを返すかどうかはさして重要ではないようだ。
S_FALSEを返しても、シークはきちんと行われている。
最終フレーム付近でうまくいかないのは、SetFrameがコールされていないのが原因のようだ。
つまり、より上位の問題だ。
と言うことは、Builder側のソースなのだが・・・
Builder側のソースへOutputDebugStringを入れて、VCで拾ってみる。
ちょっと不安だったがうまく拾えた。
これで少しデバッグがやりやすくなるかも。

投稿者 Takenori : 09:59 PM | コメント (0) | トラックバック

オーバーレイでの動作確認

オーバーレイでも手動グラフ構築が問題ない確認した。
問題はなかったが、初めにちょっともたつくような印象を受けた。
まあ、構築プロセスが長くなっているので、少し時間がかかるようになってしまったのかもしれない。
リリースビルドにすれば大丈夫かな。

ちなみにオーバーレイ時のレンダーフィルタにはCLSID_VideoRenderer を使うようにした。
たぶんこれが標準だと思われる。
無意味にオーバーレイ ミキサー フィルタとかにしても良かったが、やっぱり変なことはしない方がいいだろうからね。

投稿者 Takenori : 03:48 PM | コメント (0) | トラックバック

October 02, 2004

フィルタグラフを手動で構築

DVDプレーヤーをインストールした特定の環境ではMPEGがうまく動作しない場合があるそうなので、フィルタグラフを手動で構築するように書き換えた。
とりあえず、レイヤー描画の方で確認したが、問題なく動作した。
オーバーレイの方はまだ確認していない。(2つ確認するのは面倒だなぁ・・・)

具体的には次のフィルタが使われるようにした。
CLSID_MPEG1Splitter
CLSID_CMpegVideoCodec
CLSID_DSoundRender
オーディオはCLSID_MPEG1Splitter とCLSID_DSoundRender を繋ぐ際、自動決定されるようにしているが、標準のCLSID_MPEG1Splitter を使用しているので、CLSID_CMpegAudioCodec が使われるはず。
これでも問題があるようなら、CLSID_CMpegAudioCodec も手動で繋がないといけないが、たぶん大丈夫だろう。(根拠なし)

今回の注意点
ヘルプのMPEGフィルタのクラスIDでCLSID_CMPEGVideoCodec と書かれているが、本当はCLSID_CMpegVideoCodec。
ハメられた。
なぜか、Audioの方はきちんとCLSID_CMpegAudioCodec と書かれている。

今回ふと気付いたこと
オーディオがないAVIファイルをレイヤー描画で再生しようとしたら、たぶん失敗する。
なので、これは非サポートとする。

投稿者 Takenori : 10:52 PM | コメント (0) | トラックバック

BRender.axの内包

BRender から必要なソースをコピーし、CBaseControlVideo を継承し作成したクラスを削除、IBasicVideo インターフェイスを取得できないようにする。
代わりにIRendererBufferVideo インターフェイスを作成し、それを継承するようにし、IBasicVideo が提供していたメソッドを実装する。

krlmovie 側では基底クラスでIBasicVideo のメソッドをラップし、IBasicVideo を使用している箇所から分離、そのメソッドを継承側でオーバーライドしてIRendererBufferVideo インターフェイスのメソッドをコールするようにする。
以上のようにすることで、IBasicVideo インターフェイスがなくても動くようにした。
これでクラスファクトリがどうとか言う問題はなくなる。
また、追加されたメソッドはインターフェイスを別にしたので、コードもなかなかスッキリした。
BRender.ax をアンインストールし、動作確認。
以前と同じように動作した。
これでBRender.axは必要なくなった。

にしても、次の2つは紛らわしい。
typedef LONGLONG REFERENCE_TIME;
typedef double REFTIME;
REFERENCE_TIMEは100ナノ秒単位、REFTIMEは普通に実数で時間を保持している。

次は特定の環境でMPEG再生がうまく行かない問題の対処だな。
フィルターをつなぎ合わせるメソッドは作ってあるので、ひたすらクエリーして接続していくだけのはず。

投稿者 Takenori : 07:41 PM | コメント (0) | トラックバック

September 23, 2004

BRenderをkrlmovie.dllへ移動する

幅と高さと平均時間を取得するメソッドを持ったインターフェイスを作る。
別モジュールではなくなるので、別にインターフェイスは作らなくてもいいのだが、作った方がスッキリするので作った。
後は、いろいろと削除したり、移動したり。でも、それは明日にしよう。

投稿者 Takenori : 09:47 PM | コメント (0) | トラックバック

KAG側仕様の検討

video タグに次の属性を追加
position : 再生時間を移動する場合
loop : ループをon/offする場合
frame : 再生フレームを移動する場合
mode : モード"overlay"か"layer"を指定する場合

新しいタグとして以下のようなものを追加
[videolayer layer=# page=fore channel=(1 or 2)] : channel はlayer1 かlayer2 を表す。
[clearvideolayer channel=(1 or 2)]

[pausevideo]
[preparevideo]
[rewindvideo]

[videosegloop start=# end=#]
[cancelvideosegloop]
[videoevent frame=#]
[cancelvideoevent]

[wv]でperiodも待つ。(すでに実装している)

以上のような感じかな。
で、書いてみて、デバッグする。
おお、KAGで動いた。
当たり前だけど、こっちの方がスッキリする。

投稿者 Takenori : 08:15 PM | コメント (0) | トラックバック

VideoOverlayクラスのドキュメントを書く

VideoOverlayクラスのドキュメントを書いてアップした。
次は、KAGの方を拡張しないと。
でも、どんな感じにするかなぁ。
と言うか、だいたい自然に決まってしまうけど。

レイヤー描画の機能がKAGから使えるようになれば、かなりお手軽になる。
サクサクですな。

投稿者 Takenori : 05:08 PM | コメント (0) | トラックバック

気になっているところ

prepareのperiodイベント発生付近がきわどいかも。
イベントがマルチスレッドでなければ問題ないが・・・ つーか、スレッドセーフにしておけよって感じか。
何らかのロック機構があった方が良いかも。

イベント、状態遷移まわりはきちんと整理しておいた方が良さそう。

AVIの動作確認。
音無しMPEGファイルの動作確認。
SetSegmentLoop、CancelSegmentLoop、SetPeriodEvent、CancelPeriodEvent の動作確認。
メソッドなどは一度テスト用のコードを書かないと。

SetPeriodEventで、再生位置が指定されたフレームより前に移動した時に、イベント発生抑止を解除するのを忘れていた。

投稿者 Takenori : 03:04 PM | コメント (0) | トラックバック

吉里吉里へのマージ

Dee氏に、リリースした時に吉里吉里へのマージなどしていただけるのでしょうか? と聞いたところ、
"そうですね、安定したものでkaedeさんの了承を得られればしたいと思います"と言う回答を頂けた。
安定したらっすね。(笑
BRenderは、いろいろと苦労した分かなり安定しているはず。
後は他の部分のテストだな。
その前に、追加したメソッド群をまとめておかないと。

投稿者 Takenori : 01:57 PM | コメント (0) | トラックバック

KAGの拡張

今はTJSを直接呼ぶことで、追加した機能を使用しているが、やはりKAGから指定できた方が楽だ。
で、拡張方法をDee氏に聞いたところ、
"MainWindow.tjsの最後の方に タグハンドラ群があって、全部 elm という引数をとっていますが、ここにタグの属性値が辞書配列で渡されてきます。
タグを追加したい場合はタグハンドラ群に、周りの関数に習って関数を追加すれば OK です。
タグハンドラの戻り値は基本的には次のタグへのms単位でのウェイトです。"
なるほどー。
簡単そうだ。

投稿者 Takenori : 01:54 PM | コメント (0) | トラックバック

トランジションについて

トランジションは完了時に表と裏のレイヤが入れ替わるだけとのこと。
それなら、オーバーレイでLayer1, Layer2と持っている分には問題ないはず。
良かった良かった。

投稿者 Takenori : 01:48 PM | コメント (0) | トラックバック

リリーサーの問題

以前、リリーサーを使ったら、うまく行かなかったのだが、Dee氏によると、
"単一の実行可能ファイルを作ろうとするとちょっとめんどうでsrc/core/environ/win32/optionarea.bin を tvpwin32.exe のお尻にくっつけて、くっつけた物の名前を krkr.exe としておいておかなければなりません。"とのこと。
そう言うことだったのか。
じゃ、copyでくっつければO.K.そうだな。

投稿者 Takenori : 01:46 PM | コメント (0) | トラックバック

MPEGの問題

Dee氏によると、DVD再生ソフトなどを入れると、MPEGのデコーダーが標準のものではなくなって、時々不具合が出るとか。
それならば、フィルタグラフを作る時にクラスIDを直指定して、作れば問題ないはず。
ついでに直すことにした。
たぶん、フィルタの追加をダウンストリームからやっていけば、自動的には繋がれないと思う。
と言うか、Renderとか呼ばなきゃ大丈夫か。
で、AVIはどうしよう?
面倒そうでなければAVIも直指定にしておくかなぁ? うーん、自動の方がいい気もする。AVIはコデックとかいろいろあって、何かありそうな予感するし。
QuickTimeは要らないと言うことなので、ほったらかしにしよう。

投稿者 Takenori : 01:37 PM | コメント (0) | トラックバック

BRenderのインストーラー

やはり、BRenderのインストールはない方が良いとのこと。
まあ、何となくはわかっていたんですけど・・・
だって、だってソースが汚くなるんだもん。とか言ってみたところで、始まらないので、なんとか、本体の方に吸収する方向で行こう。
と言っても、krmovie.dllとkrlmovie.dllを分離したので、少しはマシかもって、ダメだ。IBasicVideoは親が持っているんだった。
IBasicVideo *Video() を仮想にしてもいいけど、それよりも他の方法で解決したいなぁ。
IBasicVideoで使っているのは、
get_AvgTimePerFrame
get_SourceWidth
get_SourceHeight
の3つ。
で、get_SourceWidth と get_SourceHeight を使っているのは、GetVideoSize だけで、GetVideoSize は元々仮想なので、GetVideoSize を継承すれば問題ない。
じゃ、単にget_AvgTimePerFrameを仮想にすれば、O.K.かな。
意外とさっくり行くかも。
面倒なことは面倒だけど、簡単そうだな。たぶん。
三歩進んで二歩下がる~♪

投稿者 Takenori : 01:28 PM | コメント (0) | トラックバック

ついにサンプル公開

ムービー レイヤー描画サンプルに置いてあります。
いろいろと実験してみてください。
私は責任もてませんけど。

投稿者 Takenori : 01:13 PM | コメント (0) | トラックバック

September 22, 2004

本体側の修正

DLLが分離したのに伴い、本体側もそれに対応。
というか、ほとんど元の状態に戻したようなもの。
後、Flash側も要らなくなったものを削除。
それと、本体側でおかしかった部分を修正。
レイヤーサイズがムービーサイズと違う場合、強制的にムービーサイズに合わせるようにした。以前は、レイヤーが保持しているイメージサイズだけだった。

投稿者 Takenori : 03:29 PM | コメント (0) | トラックバック

インストーラーでタイムスタンプ忘れ

BRenderインストーラーでタイムスタンプをきちんとつけるのを忘れてた。
そのせいで、インストールした日付のファイルが出来てしまう。
そのうち直さないと。

投稿者 Takenori : 12:28 PM | コメント (0) | トラックバック

DLLの分離

レイヤー描画のDLLをkrlmovie.dll として分離した。
さくっと出来た。
これで、GetVideoOverlayObjectのパラメタ渡しバージョンが必要なくなり、modeを渡してDLL内で判断し生成するのではなく、外で判断し、DLLを使い分ける格好になった。
何となくシンプルになったかな。

次は本体の方で読み分ければ、分離は完成。
Flash側も少し修正しないといけないけど。

投稿者 Takenori : 08:21 AM | コメント (0) | トラックバック

September 21, 2004

BRenderアップロード

これだけあってもどうしようもないんだけど、取り合えず上げておく。
文書もいろいろ考えていたら短くなって、別ページにしなくても・・・ とかいろいろあるが、上げてしまう。
徐々に改善していこう。

投稿者 Takenori : 02:52 PM | コメント (0) | トラックバック

ドキュメントを書く

BRenderをアップするためにドキュメントを書いた。
ドキュメントは面倒だ。
GNUライセンスなどの汎用的なライセンス形態にするのもうなずける。
でも、いろいろと書いたんだけど。
結構疲れた。
アップロードはもう一度確認するためもう少し後の予定。
でも、アップした後も、初めのうちは何度も改版しそうだ。

投稿者 Takenori : 09:14 AM | コメント (0) | トラックバック

September 20, 2004

新 BRenderインストーラーの作成

msvcr71.dll を含んだインストーラーを作成した。
これでmsvcr71.dll がない環境でも問題なくインストールできるようになった。
後、ついでに少しソースの整理もした。

投稿者 Takenori : 09:46 AM | コメント (0) | トラックバック

続・BRender.axのインストール問題

msvcr71.dll がシステムディレクトリにない場合は、システムディレクトリにコピーしてしまおう。
そっちの方がよい。
で、ゲームのインストーラーを作る時は、ゲームをインストールしたディレクトリにもmsvcr71.dll を置くことにする。
これで文句ないだろう。
理屈上、msvcr71.dll のコピーは、実行可能プログラムと共にアプリケーション ディレクトリに保存してください。となっているので、msvcr71.dll を使用するアプリは、自分のディレクトリにmsvcr71.dll を置くだろうし、LoadLibraryで優先されるのはそちらになる。
つまり、システムディレクトリのmsvcr71.dll が使用されるのは、どこかの自分のようなお間抜けさんの場合で、きちんと理解してする人の場合は問題ない。
それに、お間抜けさんの場合も一応動くので万々歳?
ま、OSをクリーン インストールした状態でテストすれば、気付くんだけどね。
よし、コピーしてしまう方向で行こう。

投稿者 Takenori : 08:47 AM | コメント (0) | トラックバック

オーバーレイモードの確認

オーバーレイモードでもうまく再生されるかどうか確認。
問題ないようだが、時々msvcr71.dllが要求される。
レイヤー描画モード以外では必要ないはずなのだが・・・ なぜ?
これは問題だ。
従来との互換性の問題が出てしまう。
msvcr71.dll自体は再配布可能モジュールのはずなので、配布することは出来るのだが、手軽さが落ちてしまう。

ほぼ確実な解決策はkrmovie.dll を2つに分けてしまうことだ。
つまり、オーバーレイ時はkrmovie.dll、レイヤー描画時はkrlmovie.dllと言った感じだ。
構成としてはこの方が綺麗かもしれない。
機能的には結構違いがあるので、それを明確にする意味でも良いかもしれない。
ソースコードもさっぱりする。
でも、dllが増えると煩雑かなぁ?
・・・
ここは分ける方向かな。
さっぱりするし。
それで行こう。

投稿者 Takenori : 08:20 AM | コメント (0) | トラックバック

BRender.axのインストール問題

BRender.ax がインストール出来ないと言う問題が再現した。
次のようなメッセージが出た。
LoadLibrary("BRender.ax")に失敗しました - 指定されたモジュールが見つかりません。
リリース前に確認しようとなにげにやったら出来なくて、なんだなんだとなった。
検索したり実験したりしてなんとか解決。
解法は、次のページにあった。
独自ActiveXがregsvr32で登録できない
dllから他のdllを使用していて、それがないからLoadLibraryに失敗していたというわけか。
ちなみに、mfc71.dllは使用していなかったので不要だった。
後、初めはBRenderのリリース版の方でmsvcrtd.libをリンクしていたので、
msvcr71d.dllが読み込まれていた。
これは、msvcrt.libに変更した。

で、結局のところ、msvcr71.dllが必要と言うことだ。
これはインストーラを書き換えた方が良さそうだな。
msvcr71.dllも内部に持ち、システムディレクトリに見つからなかったらコピーするようにしないと。
MSDNによると・・・
-----以下、引用
アプリケーションでは msvcr71.dll を使用し、再配布する必要があります。システム ディレクトリには、msvcr71.dll のコピーを作成しないでください。また、既にコピーが存在する場合でも、使用しないでください。msvcr71.dll のコピーは、実行可能プログラムと共にアプリケーション ディレクトリに保存してください。/MD スイッチを使用して Visual C++ .NET で構築したアプリケーションはすべて msvcr71.dll を使用します。
-----引用終わり
つまり、マルチスレッドと動的リンクを使うアプリはmsvcr71.dllが必要なわけね。
それと、システムディレクトリにmsvcr71.dllをコピーするのはまずいのか。
じゃあ、インストーラーと同じディレクトリに置くようにしないといけないのか?
と言うことは、単にインストーラーと一緒に固めれば済みそうだけど、そうすると、インストーラーを作る時に問題が発生しそうだから、インストール時、msvcr71.dllをカレントディレクトリに書き出すようにするのが良さそうだな。

インストールの時だけでなく、レイヤー描画を使用する吉里吉里の実行時にも必要だ。やっぱり、システムディレクトリにコピーが必要かな。
この辺りはもう少し検討&検証しよう。

投稿者 Takenori : 01:23 AM | コメント (0) | トラックバック

September 19, 2004

すべてを追加してメイク

特殊再生のセグメントループとイベントフレーム設定機能を追加しメイク。
これで、一通りの機能は追加し終わったはず。

で、動作確認。
layerのvisible周りが変更になったので、prepareに書き換えておく。
ちょっと問題が発生したので、少し修正。
以前、prepareは
pause
rewind
play
1コマ描画
stop
rewind
のように処理すると、書いたが、
pause
rewind
play
1コマ描画
pause
rewind
に変更した。

セグメントループとイベントフレーム設定機能はまだ動作確認していない。
この動作確認はいろいろと準備が必要なので、もうちょっと後でテスト予定。

残りは、テストとドキュメントだな。

投稿者 Takenori : 06:14 AM | コメント (0) | トラックバック

Flash側DLLのメイク

DirectShow側のDLLに追加したメソッドなどをFlash側にも追加した。
と言っても、中身は空っぽ。
単に未サポートと返すだけだ。
いくつかのメソッドは簡単に実装できそうだったが、面倒なのでやめた。
そして、メイクするが、TShockwaveFlashがないと言われる。
よくわからん。とりあえず、クグってTShockwaveFlashを探す。
日本語ページで1個ヒットしたが、リンク切れだった。
仕方なく、googleのキャッシュを開いてみたら、なんとか読めた。ラッキー
Delphi 6の解説のようだったが、とにかく、ActiveXコンポーネントを取り込めると言うことのようだ。
で、C++ Builder 6でも似たようなものを探す。
コンポーネント->ActiveXの取り込みが同じもののようだ。
そして、Shockwave Flash (Version 1.0) を選択し、コンポーネントを追加、インストールする。
なんかうまくいった。
しかし、今度はリンク時にflashbpk.libがないと言われる。
flashbpk.libって?
クグるがヒットせず。
ふと気付き、以前Dee氏からもらったライブラリ類の中を検索。見つかった。
で、コピー。
メイクが通った。
これで、Flash側はO.K.かな。と言っても、何もしていないに等しいけど。

投稿者 Takenori : 05:49 AM | コメント (0) | トラックバック

September 18, 2004

prepareメソッドの追加

以前、変なフレームが表示される問題で、
open
pause
visible = true
play
のようにすれば、大丈夫だろうと書いたが、やっぱり準備メソッドを追加した。
内部的には
pause
rewind
play
1コマ描画
stop
rewind
のように処理する。
たぶん、
prepare();
[wv]
visible = true;
のような感じで書けばうまく行くはず。
動作確認は、セグメントループとイベント設定が出来た時に同時に行う予定。

投稿者 Takenori : 06:38 AM | コメント (0) | トラックバック

Visioを注文

以前からシーケンス図や状態遷移図を描きたいなぁと思っていて、IIOSSなどを使ってみたりしていたのだが、作図に限って言えば、Visioは使いやすい。
シーケンス図の編集は泣きそうになるのだが、その以外はいい。
で、最近お金が入ったので昨日Amazonで注文してしまった。
Vision Standard 2003 と Visio Professional 2003 Version/Product Upgrade だ。
なんでこんな構成になっているのかよくわからないが、Professionalを買うよりも安いので、まあいい。
到着予定は、1個が19日~21日、1個が22日~25日の予定だ。
なぜか分割発送を選んでしまった。
しかも、先に届くのはProduct Upgrade の方。
なんだかなぁと言う状況だ。

それはともかく、ビデオの再生でいろいろと機能追加して、複雑になってきているので、状態遷移図やシーケンス図で整理できるようになって、いい感じだ。
本当は先に図を描いておいた方がいいんだけど、Visioがなかったから仕方ない。
これからは先に描くだろうし。
状態遷移図とか描くのもなかなか楽しいしね。

投稿者 Takenori : 06:27 AM | コメント (0) | トラックバック

イベント発生の仕様

イベント発生の仕様はどのようにしたらよいだろう?
基本的には特定のフレームをセットしたら、再生中にそのフレームに来たら、periodイベントを投げるというものだが、問題はドロップフレームが発生する可能性があると言うことだ
つまり、if( curFrame == eventFrame ) ではなく、if( curFrame >= eventFrame ) としなければならないわけだが、そんなことをしてしまうと、指定フレーム以降毎フレームイベントを投げてしまう。
それならということで、フラグをもうけて1度しか投げないようにすれば良いかというと、そしたら、ループ中にイベントが発生するように設定したら、1回しか投げられなくて、期待したのと違うという事態にもなる。
じゃあ、指定したフレームより前のフレームに移動したらフラグを解除して・・・ と考えていったわけだが、ふと、利用する時はどのようなものが使いやすいか、と言うことについて考えてみた。
そして、そのフレームを通過した時、1回だけしか投げないと言う仕様にしてしまった方がスッキリするのではないかと思った。
たとえば、イベントを投げるとeventFrame=-1;などとして、イベントを投げるフレームを忘れてしまうわけだ。フラグも要らない。
ループなどでは何度も設定しないといけないわけだが、そう言う仕様だと言うことにすれば問題ないだろうし、ループ中で何度も投げることは少ないだろう。
ただ、問題点として、再生中のフレームより小さいフレーム番号にイベントを設定すると、設定した次のフレームにイベントが投げられてしまう。これはちょっと不便だ。
なら、ドロップフレームは10フレームまで考慮し、それよりフレーム番号が大きい場合は無視するように・・・ そしたら、取りこぼしが怖いなぁ。
設定した時のフレームの前後関係を保持し、現在のフレーム番号の方が大きい場合は、イベントが発生しないようにし、設定されているフレームよりも小さいフレーム番号へ移動した時にこの発生しないようにしたものを解除すると言うのが妥当だろうか。
ちょっと複雑になってしまったけど、仕方ないかな。
とりあえず、そんな感じにするか。

投稿者 Takenori : 05:57 AM | コメント (0) | トラックバック

September 16, 2004

特殊再生系I/Fの追加

VideoOvlIntf.cppへTJS用のクラスへマクロを使って、メソッドを追加。
VideoOvlImpl.h/.cppへ上記のところからコールする用のメソッドを追加。
DLLへも呼び出しが必要な場合は、さらにkrmovie.hへメソッドの追加が必要になる。(今回は必要ない)
うーん、深い。
まあ、よくあることだけどね。
で、コードジェネレーターみたいなのが欲しいと思ったりもするけど、今回はそんなに追加するわけじゃないので必要ないかなぁとか考える。
でも、もしかしたらすでに付いているかも。ま、もう予定しているのは追加したので、もういいんだけど。

で、次は実装。
指定フレーム間ループは、フレーム比較さえ気を付ければ簡単。
イベント発生はちょっと検討が必要かも。不用意にイベント送りまくらないように。

投稿者 Takenori : 11:21 PM | コメント (0) | トラックバック

September 15, 2004

追加したプロパティの確認

バリリアンと型にはtjs_uint64への変換がないのかな?
なぜかそこでエラーになったので、そこはtjs_int64とした。
そしたら、メイクが通ったので、動作確認。
とりあえず、コンソールに各プロパティの値を出すことにした。
で、実行。
なぜかエラー、よく見るとkrmovie.dllがエラーを出していた。
そうだ、krmovie.dllのビルド忘れていた。
ビルドして再度実行。
きちんとそれっぽい値が出ている。
よし、ここは大丈夫そうだな。
後でもう一度きちんと見た方がいいけど。

投稿者 Takenori : 11:55 PM | コメント (0) | トラックバック

September 14, 2004

未実装のプロパティ系を実装

まだ実装していなかった、次のプロパティ群を実装。
メイクはまだ。

組み込んだプロパティを列挙すると次の通り。
プロパティ
position ( 再生位置 )
frame (現在のフレーム)
fps (フレームレート)
numberOfFrame (全フレーム数)
totalTime (合計時間)

positionは迷ったが、ついでに組み込んだ。単位はミリ秒のまま。
totalTimeも単位はミリ秒とした。
positionやframeを使い、再生位置を設定した場合、完全に指定した位置になるわけではなく、指定した位置に最も近いキーフレームの位置に設定される。
これは、再生中に素早くシークできるようにするため。
なので、シークしたい位置には、ムービーを作る際にキーフレームを入れておく必要がある。
次は、特殊再生の実装だな。

これらプロパティはオーバーレイでも使用できるようになっているはず。
でも、特殊再生はレイヤー描画モード専用となる。
Flash, ビデオオーバーレイ, レイヤー描画モードで機能がだいぶ違う。
機能の多さは
Flash < ビデオオーバーレイ < レイヤー描画モード
となるのかな。
でも、サイズ指定などがレイヤー描画モードにはないので、必ずしも上記のようにはならないか。
各機能がどれで使えるかはまとめておかないと混乱の元だな。

ムービーの位置指定のSetLeft, SetTop, SetPositionとSetVisibleも実装した。
レイヤーへスルーさせただけだけど。
他の幅などを設定するものは、レイヤー描画モード時は何もせずにリターンさせた。

Visibleで思い出したが、1コマ目にゴミが表示される問題はどうしよう。
たぶん、
open
pause
visible = true
play
で、回避されるはずだが・・・
一回実験しないとな。

投稿者 Takenori : 03:04 AM | コメント (0) | トラックバック

EC_UPDATEイベントと共にフレーム番号を

なんとか、BRender側でEC_UPDATEイベントを送る時に、フレーム番号も一緒に送れるようになった。
また、忘れない内にBRenderのインストーラのリソースも更新しておく。
これで、BRenderは予定していた機能の組み込みは終了のはず。
次は、吉里吉里側でまだ実装していない機能の追加と、基底クラス書き換えによって増えたメソッドとDLLから出すメソッドのFlash側への実装だな。

投稿者 Takenori : 12:48 AM | コメント (0) | トラックバック

時間からフレーム番号へ

とりあえず、以下のようなコードで変換。

REFERENCE_TIME TimeStart;
REFERENCE_TIME TimeEnd;
GetSampleTimes( pSample, &TimeStart, &TimeEnd );
double renderTime = TimeStart / 10000000.0;
REFTIME AvgTimePerFrame;
CBaseControlVideo::get_AvgTimePerFrame( &AvgTimePerFrame );
EventParam1 = (LONG)(renderTime / AvgTimePerFrame + 0.5);

なぜか、REFERENCE_TIMEはLONGLONGで、REFTIMEはdouble。
とりあえず、doubleにあわせて計算。
最終的に四捨五入してフレーム番号とする。(レンダリング時間は処理時間を考慮して、少し遅く、もしくは早く設定されている。詳しく言えば、1フレーム目は少し遅く、それ以降は少し早くなっている。はず)
これで、だいたいいい感じのフレーム番号が出ているようだ。
でも、開始直後など時々ドロップフレームがある。
まあ、仕方ないでしょう。
このフレーム数を使って処理する部分は、ドロップフレームが発生する可能性を考慮して作らないといけない。
つまり、何フレーム目でと言う処理で、==とかで比較すると、一生一致しない可能性がある。
この点は気を付けないとな。

投稿者 Takenori : 12:29 AM | コメント (0) | トラックバック

September 13, 2004

現在のフレーム番号の取得

様々な場所でIMediaSampleからメディアタイムを得ようとするが、得ることは出来ず。
やはりデコーダーはメディアタイムを設定していないようだ。
ということは、レンダーは即座にレンダリングすることになる。
しかし、CBaseRenderer::Receiveがコールされてから実際にレンダリングされるまでには、一度イベント待ちがある。
つまり、このイベント待ちの直後の時間が、そのフレームの時間に近い。
そして、CBaseRendererでは、イベント待ちの後にOnWaitEnd がコールされるようになっているので、これをオーバーライドすれば、目的の時間に最も近い時間が得られるはずだ。
また、OnWaitStartと言うメソッドもある。
何となく、気になったので、この2つのメソッドを通過する時間をOutputDebugString でデバッガへ出力。すると、明らかにイベント待ちをしたような時間差がある。
イベントってレンダラー自身がIMediaSampleからメディアタイムを得て、IReferenceClock::AdviseTimeを使用し、そこからイベントが送られてくるのを待つんじゃなかったっけ?
調べると、やはりCBaseRenderer::ScheduleSample でスケジューリングされていた。
その中では、GetSampleTimesがコールされていて、そこから得た時間を元にスケジューリングしているようだ。
しかし、GetSampleTimesの中では、IMediaSample::GetTimeを使って時間を得ている。
以前、IMediaSample::GetTimeを直接コールしても、時間を得ることが出来なかったのだが・・・ なぜか出来ている。
あれ?っと思い、GetSampleTimes をコールしたら、時間を取得できた。
さらに、ありぃ?と思い、IMediaSample::GetTimeを直接コールしてみたら、またしても時間を取得できた。
なぜ?
私は幻を見たのだろうか? そんなことはないはずだが・・・
でも、100nsec単位の時間が返ってきている。確か、ビデオではフレーム番号がメディアタイムのはずだが。
GetSampleTimes はタイム スタンプを取得するとある。
って、あああぁぁぁぁぁぁぁぁ。
IMediaSample::GetTimeとIMediaSample::GetMediaTimeって、メソッド違うじゃないか!
IMediaSample::GetMediaTimeにしたら、やっぱり取得できなかった。
と言うことは、IMediaSample::GetTimeからフレーム番号に変換すれば何とかなりそうだ。
ここは意外と盲点かも。って、俺がアホなだけかな。

ちなみに、IMediaSeeking::SetTimeFormat( &TIME_FORMAT_FRAME )と設定しても、IMediaSample::GetMediaTimeでメディアタイムを得ることは出来なかった。

投稿者 Takenori : 10:55 PM | コメント (0) | トラックバック

September 11, 2004

特殊再生仕様

はじめは、事前に何らかのスクリプトをセットして再生する方法を考えていたが、次のようなメソッドを追加すれば、事足りそう。

SetSegmentLoop (指定フレーム間ループ) : 未実装。
CancelSegmentLoop (指定フレーム間ループ解除) : 未実装。
SetPeriodEvent (指定フレームでのイベント) : 未実装。
CancelPeriodEvent (指定フレームでのイベント解除) : 未実装。

Get系を追加するかどうかは検討中。

上記のようなメソッドとイベント待ちを使い、イベント後の振る舞いの設定で、多彩な再生が可能になるはず。
ムービーをつなげてストーリーが展開していくようなものも出来るだろう。

投稿者 Takenori : 08:15 PM | コメント (0) | トラックバック

仕様や進捗

とりあえず、新規追加部分について、進捗をまとめることに。

メソッド
pause (一時停止) : 組み込み済み
rewind (巻き戻し) : 組み込み済み
playSequence (特殊再生) : 未実装、仕様検討中。

プロパティ
position ( 再生位置 ) : 未実装。若干必要性が疑問。
loop (ループ ) : 組み込み済み。
frame (現在のフレーム) : 未実装。
fps (フレームレート) : 未実装。
numberOfFrame (全フレーム数) : 未実装。
totalTime (合計時間) : 未実装。
layer1 (描画レイヤー指定1) : 組み込み済み
layer2 (描画レイヤー指定2) : 組み込み済み
mode (オーバーレイorレイヤー描画) : 組み込み済み

イベント
onStatusChanged ( ステータスが変更された ) periodイベント追加 : 組み込み済み


オーバーレイの方にある、位置指定やサイズ、表示/非表示についてはどうするか検討中。
セットしたレイヤーに対して行うのと同じだし。
ただ、スルーするだけでも良いが・・・

投稿者 Takenori : 12:29 AM | コメント (0) | トラックバック

September 10, 2004

BRenderの拡張をしようとする

BRenderは画面更新時にEC_UPDATEイベントを送るが、そのとき同時に、何フレーム目かを送れるように変更しようとした。
IMediaSampleに問い合わせれば、フレーム番号が取得できるはずだから、簡単に出来ると思っていたのだが・・・
取得しようとしたら、"このサンプルにはメディア タイムがセットされていない。"って、返ってきた。
どうしよう。
これはまた大変そうだ。
他の方法をとるかなぁ。

まずは調査だ。

投稿者 Takenori : 11:47 PM | コメント (0) | トラックバック

エラーウィンドウ大量発生バグの解決

バグは、
kag.movie.layer1 = null;
としたら、エラーウィンドウが大量発生するというものだった。
で、この部分のコードはレイヤー(LayerIntf.cpp)のassignImagesのところをコピーしてきた。(同じようにレイヤーを引数にとるので)
コードは次のような感じ。

tTJSNI_BaseLayer *src;
tTJSVariantClosure clo = param[0]->AsObjectClosureNoAddRef();
if(clo.Object)
{
   if(TJS_FAILED(clo.Object->NativeInstanceSupport(TJS_NIS_GETINSTANCE,
           tTJSNC_Layer::ClassID, (iTJSNativeInstance**)&src)))
       TVPThrowExceptionMessage(TVPSpecifyLayer);
}
if(!src) TVPThrowExceptionMessage(TVPSpecifyLayer);
_this->AssignImages(src);

で、問題はsrcが初期化されていないこと。
*src = NULL;ってやった方が良さそう。
でも、そうすると下のif(!src)に引っかかって、エクセプション。
なので、(!src)の部分は上のif文の中に入れた。
で、自分のlayer1プロパティを設定するところは以下のような感じ。

tTJSNI_BaseLayer *src = NULL;
tTJSVariantClosure clo = param->AsObjectClosureNoAddRef();
if(clo.Object)
{
   if(TJS_FAILED(clo.Object->NativeInstanceSupport(TJS_NIS_GETINSTANCE,
               tTJSNC_Layer::ClassID, (iTJSNativeInstance**)&src)))
               TVPThrowExceptionMessage(TVPSpecifyLayer);
   if(!src) TVPThrowExceptionMessage(TVPSpecifyLayer);
}
_this->SetLayer1(src);

自分のところはこうしたが、レイヤーの方はいいのかな?
まあ、nullが引数であることはないのかも。
自分のところは、設定を解除するのに使っているので必要。
とりあえず、報告かな?
新しいのでは直っているのかもしれないけど。

投稿者 Takenori : 04:16 AM | コメント (0) | トラックバック

やっぱり、BCBがなんかおかしい

今日もなぜかブレイクポイントで止まらない。
全部消してやると動く。
さっぱりわからん。
ここに来ていったいなんだと言うんだ。
もっと片っ端から消してみるかな。

で、片っ端から削除したら動くようになった。
でもまだ油断は出来ない。
明日になったら、またうまくいかないようになっているかもしれない。
そう言えば、BCBのアップデートってやったっけ?
やったようなやっていないような。
一応もう一度やってみるかな。

投稿者 Takenori : 03:13 AM | コメント (0) | トラックバック

September 09, 2004

BCBでデバッグが出来なくなる

BCBで一度リリースビルドしたあと、デバッグビルドしたのだが、ブレークポイントで止まらなくなってしまった。
それで、再構築を何度もやったり、プロジェクトファイルを元に戻したり、したのだがうまくいかない。
BCBの問題かと思って、他ので試したらうまく行く。
VCで作ったDLLをデバッグ版にして、生成されるファイルを片っ端から削除しメイクしたらうまく動くようになった。
やっぱり、何かが残っていたのだろうか?
というか、それ以外はあんまり考えられないんだけど。
ま、解決して良かった。
今度、また同じようなことがあったら、まずは手作業で全部消してみよう。

投稿者 Takenori : 02:12 AM | コメント (0) | トラックバック

BRenderインストーラの作成

BRenderインストーラを作成した。
面倒なのでVCでMFCを使って組んだ。
MFCを使ってと言っても、書いたコードのほとんどはAPIコールだが。
にしても、面倒臭い。
基本的には、リソースに入れたファイルをシステムディレクトリに書き込んで、その書き込んだBRender.axをロードして、登録する関数ポインタを得て、それをコールするだけなのだが、きちんとエラーの処理などをしているのでコードがかなり多くなってしまっている。まあ、当然のことなのだが。

でも、これでBRender.axの公開にだいぶ近づいた。
後はドキュメントを書くだけ。面倒だけど。
そして、その次はレイヤー描画だ。
なんとか、来週ぐらいに一度リリース出来ると良いのだが・・・
まとまった時間がとれれば可能かな?

投稿者 Takenori : 01:46 AM | コメント (0) | トラックバック

September 08, 2004

インストーラを作ろうとする

regsvr32 BRender.ax
とやっても、コンポーネントを登録できない環境があるようです。
もしかしたら、操作上の問題かもしれないけど、インストーラを作ろうと思い立ち、VS.NET 2003でインストーラを作ろうとしてみる。
適当にやったけど、よくわからなかったのでヘルプを見る。
すると、コンポーネントだけをインストールするインストーラは、作れないとか。
アプリと同時インストールじゃないといけないらしい。
なんて不親切な。
そしてさらに、インストール (ActiveXコンポーネントを) と言う項を見ると、全部普通にコーディングしないといけないようなことが書かれていた。
面倒くせーと思ったが、ダイアログベースで、OK/Cancelのボタンだけ付けて、OKが押されたらコンポーネントをコピーしてDllRegisterServerをコールするだけだからそんなでもないかと思い直した。
まあとにかく、インストーラ作らないと。

投稿者 Takenori : 07:41 PM | コメント (0) | トラックバック

レイヤーへの描画サンプル

サンプルを置こうと思ったけど、いろいろいじっていたらちょっとまずい部分を発見したので、とりあえずやめにした。
まあ、激しいエラーが出て大慌ててでアプリ強制終了させると言うことがあったんですが。
原因は、フレームの更新部分にあったようで、レイヤーにnull設定したら、フレームの更新のたびにエラーが出て、毎秒30個エラーボックスが出るという悲惨なことに。

で、とりあえず画面イメージだけ。クリックすれば実寸になります。
layVideo.gif

どうしても、早く見たいって言う人がいたら言って下さい。
あげますんで。
でも、今のところ動作無保証です。
何があっても知りません。
まあ、他のアプリと同時に起動させていなければ大丈夫でしょう。
と言っても、その内リリースされると思うから別に今じゃなくてもいいんですけどね。

投稿者 Takenori : 07:18 PM | コメント (0) | トラックバック

リリースに向けて

まずはCOMコンポーネントを公開に向けて利用方法などの資料整理だな。
ムービー拡張を組み込んだ吉里吉里は、いろいろとやらないといけないことが残っているので、まずはそれを片づけないと。
それと、ブログを整理してDirectShowの解説ドキュメントも書いておきたいな。
ブログのままだとぐちゃぐちゃだし。というか、1から読まないとよくわからない状態。

吉里吉里でムービーの上に文字が表示されているサンプルって、早く見たいって人はいるのだろうか?
たぶん、リリースまでにはまだ時間がかかりそうだからこんな感じだ!って、置いておくのも良いかもしれない。
でも、その前にDee氏に一言断っておいた方がいいな。
一度またIRCに行こう。

さて、ここからが面倒臭い作業だが、リリースに向けてがんばらねば。

投稿者 Takenori : 02:05 AM | コメント (0) | トラックバック

使用感など

現時点では、KAGで直接記述することが出来ないので、KAGスクリプト内にTJSスクリプトを書くことになる。
で、初期化部分はこんな感じ。
[iscript]
kag.movie.loop = true;
kag.fore.layers[1].setSize(640,480); // ここは内部でムービーサイズを
kag.back.layers[1].setSize(640,480); // 割り当てるなどしないと
kag.movie.layer1 = kag.fore.layers[1];
kag.movie.layer2 = kag.back.layers[1];
kag.movie.mode = vomLayer; // オーバーレイはvomOverlay(default)
[endscript]
初期化さえ書いてしまえば、後はほとんどTJSで変更する部分はないかも。
たぶん、次のようにループをOFFにしたり、ONにしたりするぐらいだと思う。
[iscript]
kag.movie.loop = false;
[endscript]
そして、ムービーの位置などはレイヤーを使って操作する。(たぶん今はムービーのやつは効かないはず)
この辺りのオーバーレイモードとの違いなどはもう少し検証する必要がありそうだ。
後、レイヤーに描画されるので、トランジションなんかも出来るかもしれない。(未テスト)
にしても、意外と安定している。
まあ、サンプルでいろいろと実験してたからなぁ。
それにしても、なんか普通だな。
普通にムービーが再生されて文字が出ている。
元々こうだったんじゃないかとさえ思える。

それにしても、レイヤーに描画されるようになったことで、いじりがいがありそうだ。

投稿者 Takenori : 01:45 AM | コメント (0) | トラックバック

September 07, 2004

レイヤーへの描画、長かった・・・

ついにレイヤーにムービーが表示された。
テキストがムービーの上に出ている。
やったー。

でも、同時にいくつか問題が。。。

とりあえず解決したものとして、初めループ出来なかったのが直せた。
ただし、これでいいのかどうかは謎だ。
どういうことかというと、ループの終点でperiodイベントを送っているが、periodを送ったすぐ後で、playを送っている。
これはステータスをplayに戻すためだ。
単にStatusへplayを設定すればいいだけかもしれないが、とりあえずこのような実装にした。
ここはもう少し調査する必要がありそうだ。

もう一つは、ムービー開始点で一瞬ちらつくと言うことだ。
これは、ムービーが開始され、1フレーム目を描画し終わる前に画面が描画されてしまうために発生してしまう。
どうしてそうなるかと言うと、現在、描画後画像をレイヤーにアサインするような作りになっているのだが、初めは何も描画されていない真っ白な画像がレイヤーにアサインされている。
つまり、そのレイヤーを表示にした瞬間、この白い画像が描画されてしまう。
そして、1フレーム目が描画され、アサインされた瞬間に普通の絵が出る。
とりあえず、内部的にムービーの1フレーム目が描画され、アサインする時に表示にするようにしたが、本来は表示前にreadyか何かのメソッドを準備し、1フレーム目をレンダリングしレイヤーにその画像をアサインするようにした方が良いだろう。
そうすれば、表示にした時、1フレーム目が表示されるので特に問題ない。
しかし、そうすると1フレーム目が2回表示されて・・・というか、ダブルバッファリングだから表示が1フレーム遅れるのは仕方ないか。
ま、この辺りはもう少し考えて改善することにしよう。

何はともあれ表示されるようになったので、ちょっとこれで遊ぶぞーぅ。

投稿者 Takenori : 09:11 PM | コメント (0) | トラックバック

DLLへ公開メソッドの追加

tGetVideoOverlayObjectと同じ機能を持った構造体渡しバージョンを作った。
そして、元のtGetVideoOverlayObjectは、mode引数を削除し、従来のままの関数とした。
で、ビルド&実行。
うまくいった!
引数が7個とかになるとまずいのだろうか?
引数の制約でもあるのか?
でも、別にスタック渡しなら問題なさそうな気もするが・・・
よくわからないけどいいや、解決したし。
詳しく追ってもいいけど、そんなに引数が多い関数は滅多に作らないだろう。
ま、後で気が向いたら詳しく追おう。

そして、いよいよレイヤー描画の動作確認だ。
でもその前にTJSスクリプト書かないと。

投稿者 Takenori : 07:28 PM | コメント (0) | トラックバック

レイヤー描画を組み込んでビルド

レイヤー描画関連の機能を組み込んでビルド。
動作確認をしたら、なぜかDLL内の関数に渡される引数の一つがおかしなことに。
呼び出し方法も指定しているし・・・
引数が多いのが原因?というか、そう言うことってあるのか?
よくわからない。

BCBとVCでデバッグできないかなぁ。
BCBでデバッグ中だと、VCからそのプロセスにアタッチできなかった。
VCがBCBで吐いたコードのデバッグ情報を読み込んでくれれば楽なのだが・・・
VCのデバッガの方がいいし。
出来るかなぁ?

やっぱり、よくわからない。
もう一個メソッドをDLLから出してみるかなぁ。

投稿者 Takenori : 06:42 AM | コメント (0) | トラックバック

変更点など

変更点は署名(T.Imoto)入りのコメントで囲んでおくことにした。
後、出来る限りここに変更点を記しておくことに。
飽きて止めてしまいそうな気もするけど。

VideoOvlIft.cpp
ttstr tTJSNI_BaseVideoOverlay::GetStatusString() const にpauseとperiodを追加。
tTJSNC_VideoOverlay::tTJSNC_VideoOverlay() にメソッドとプロパティを追加。

SoundBufferBaseIntf.h
tTVPSoundStatusにssPauseとssPeriodを追加。

VideoOvlImp.h/.cpp
必要なメソッドとメンバ変数を追加。
必要な処理を追加 or 変更。

krmovie.h
iTVPVideoOverlay にインターフェイスを追加。

ScriptMgnIntf.cpp
TVPInitTJSScript にtTVPVideoOverlayModeを追加。

投稿者 Takenori : 06:00 AM | コメント (0) | トラックバック

krmovie.dllのビルド

クラス生成の切り替えを組み込んだのでビルドしたのだが・・・
tTVPBaseBitmapとtTJSNI_BaseLayerを使おうと、ヘッダーをインクルードしていたところで激しくコンパイルエラーが。
なんかいろいろと大変そうです。
DLLで使おうとするのがまずいのか、VCで使うのがまずいのか。
そんなpragmaないとかも言われたし。
なおすのはかなり大変なようなので、仕方なく現在の方法を断念。

初期化部分と、更新部分は相互扶助によって行うことに。
レイヤー描画用のメソッドがいっぱい増えてしまった。
ここいらは後でもう一度見直した方がよいかもしれない。

投稿者 Takenori : 04:29 AM | コメント (0) | トラックバック

September 06, 2004

レイヤー描画ビデオクラスの作成

オーバーレイとレイヤー描画の共通基底クラスへオーバーレイのIBasicVideoインターフェイスを移す。
共通基底クラスの純粋仮想関数を何もせずにリターンするように実装する。
これで、共通基底クラスの純粋仮想関数はなくなった。
まあ、それぞれのクラスで実装しないものを、何もしない関数として上位に実装しただけだが。
レイヤー描画ビデオクラスをコーディング。
まだ、ビルドしていないがとりあえずコーディング終了。
後は、生成部分でのクラス生成分けと、レンダーフィルターからの描画更新イベントに対応すれば、とりあえずはレイヤーに描画できるようになるはず。

CLSID_BufferRendererは手書きで定義したが、IDLにcoclassを記述して、MIDLに生成させた方が良いかもしれない。
ビルドしたところ、問題なかったのでそのままにした。

投稿者 Takenori : 02:56 AM | コメント (0) | トラックバック

September 05, 2004

ムービーレイヤー描画の制約

諸般の事情により、ムービーレイヤーはムービーの画像サイズを変更できないことにしたので、LayerVideoが持つBitmapはムービーのサイズと同一です。
描画対象レイヤーはそのBitmapと同一サイズである必要があります。
なので、レイヤーサイズがムービーのサイズを異なる場合、強制的にレイヤーサイズを変更してしまいます。(いいのかなぁ)
ムービーサイズとレイヤーサイズにはご注意を。
ムービーの画像サイズを変更出来るようにすれば、この問題は解消されるのだけれども、それは後で考えよう。

投稿者 Takenori : 05:09 PM | コメント (0) | トラックバック

コメント整備とコードの修正

ヘッダーコメントで欠けていた部分を追記。
コメント追記中に発見した不具合の修正。
メンバ名やパラメタ順序など統一性がとれていなかった部分を修正。
動作確認。

とりあえずは、これでこのフィルタコンポーネントは完成だ。
未テストな部分も多いけど、それはまたおいおいやることにしよう。リリース前とかに。
で、ここから吉里吉里への組み込みだな。
IBasicVideoをサポートしたので、両方で同じような処理に出来る部分が増えた。
平均レートの問題も解決した。
フィルタコンポーネント化したことで、すっきりする。
さあ、吉里吉里だ。

投稿者 Takenori : 03:28 PM | コメント (0) | トラックバック

September 04, 2004

プレーヤーもダブルバッファリングに対応

プレーヤーもフィルターの変更に伴いダブルバッファリング化した。
結構すんなり動作。
でも、ダブルバッファリング化されているのかどうかわかりづらいな。
片方だけを描画してみたり、入れ替えたりしてみたところ、少しカクカクした動作になった。
たぶん、うまくいっているのだろう。

これで、フィルタコンポーネント側はとりあえず完成かな。
一応、ソースの確認とコメントの整備、利用側へ提供するコードの整備を行う必要があるけど。

投稿者 Takenori : 09:22 PM | コメント (0) | トラックバック

ダブルバッファの実装

フィルタの方にダブルバッファの機能を追加。
バッファへアクセスする部分は、クリティカルセクションでロックするようにした。
で、ロックはCCritSec とCAutoLock を組み合わせることで、かなり楽に出来る。
CAutoLock のコンストラクタにCCritSec を渡せばロックされ、デストラクタでロックが解除される。
すごい楽チンです。
しかも、効率的なインラインコードに展開されるとか。
至れり尽くせりですな。

セマフォなんかもこういうふうに実装するといいのかもね。
解除し忘れとかなくなるし。

次はプレーヤー側の対応だな。

投稿者 Takenori : 08:53 PM | コメント (0) | トラックバック

アロケーターの集成化

アロケーターは今まで、newしていたが、集成にしても問題なさそうなので、集成にすることにした。
で、書き換えて動作確認。
問題なく動いた。

フィルタ側のソースコードを少し整理した。
次はダブルバッファリングの実装だな。
少し考えないと。

投稿者 Takenori : 04:54 PM | コメント (0) | トラックバック

終了時アクセス違反の調査

IGraphBuilderを最後にリリースしているのだが、どうやらこの部分でアクセス違反が起きているらしい。
なぜか、すでにリリースされてしまっているようだ。

集成の問題か!
もらったー!
やはり、集成の問題だった。
CBaseVideoRendererを継承したレンダーのコンストラクタで、CBaseControlVideoを継承したクラスをメンバに持っているので、CBaseControlVideo::CBaseControlVideo( NAME("Video properties"), pUnk, phr, &m_InterfaceLock, this ) と言うように初期化していた。
しかし、本来はCBaseControlVideo::CBaseControlVideo( NAME("Video properties"), GetOwner(), phr, &m_InterfaceLock, this ) と初期化しなければならない。
コンストラクタで渡されるpUnkは集成された所有者オブジェクトへのポインタと説明されている。
そして、pUnkがどこから渡されるかと言えばクラスファクトリだ。
さらに追うと利用者がCoCreateInstanceから渡たすものだ。
で、CoCreateInstanceではNULLと指定していた。集成なしということだ。
つまり、最初のように初期化すると集成なしとされる。
これがどういうことになるかというと、リリースした時メンバ変数をdeleteしようとしてしまう。
ま、おかしくなって当然ですな。
そして、本来は2番目の初期化方法のようにGetOwner()によって、集成もとのオブジェクトのポインタを得るわけだ。
そうすれば、参照カウンタは集成元のオブジェクトのものが使われるようになり、解放時もオーナーが解放されるようになる。
これで、万事O.K.と言うわけだ。


集成の説明 (間違っているかも)
複数のインターフェイスを1つのクラスに持たせる場合、多重継承が使われるが、多重継承を使いたくない場合というのは往々にしてある。
そんなとき、よくメンバにそのクラスを持ってしまうと言う方法がとられる。
そして、そのクラスが保持するインターフェイスが要求された時、そのメンバのポインタを返すことで要求を満たす。
これが集成である。
しかし、COMの場合、すべてのインターフェイスは参照カウンタを保持する。そして、参照カウンタが0になった時、そのオブジェクトはdeleteされる。
つまり、メンバ変数がdeleteされるという状況に遭遇してしまう。
このような状況を回避するため、集成されたオブジェクトはそのオブジェクトをメンバとして保持しているオブジェクトのポインタを保持し、参照カウンタへの操作は、その保持しているオブジェクトのものをコールされる。
つまり、集成する場合は、以上のようなルールに従わなければならない。
そして、このようなものを集成と言う。

以上のような形体以外の実装も存在するようだが、だいたい集成とはこんな感じです。

投稿者 Takenori : 02:06 PM | コメント (0) | トラックバック

DLL内の関数

DllGetClassObject や DllCanUnloadNow、エントリーポイントがないと思っていたら、BaseClassesの中にあった。
つまり、strmbasd.libの中に入っている。
この辺りは問題ないようだ。

COMのDLLサーバー内ではCoInitializeは使ってはいけない。(使っていなかった)

投稿者 Takenori : 01:17 PM | コメント (0) | トラックバック

September 03, 2004

プレーヤーの修正

今まで内部で持っていたレンダーフィルターをCoCreateInstanceで得るようにし、他にもいろいろと依存していた部分を書き換えた。
やっぱり、インターフェイスだけでつながるようにするとすっきりするなぁ。
で、デバッグは両方でいろいろとやらないといけないかと思いきや、プレーヤー側だけで出来る様子。(たぶん、レンダーフィルタがデバッグビルドだから)
でも、変。
うまくいかない。
これは少し時間がかかるかも。

ディスコネクトした時にデストラクタが呼ばれている。
なぜ?
と言うか、今まではなぜ動いていたんだ?
前はアロケーターをCComPtrで保持していたからか?
でも・・・
もう少し調査の必要がありそうだ。

アロケーターのReleaseがコールされる時の参照カウンタ値が違う。
CComPtrの場合、代入時にAddRefで参照カウンタがインクリメントされるが、アロケーターをCComPtrで保持しないようにしたから、Release時に参照カウンタ値がなくなり、Deleteされてしまうのか。
と言うことで、ピンのコンストラクタでアロケーターを生成した後、きちんとAddRefするように変更。
でも、newせずに単にメンバに持つって言うのはまずいのかなぁ。
いいような気もするけど。なんでこんな実装になっているのだろう? ピンはレンダーが普通にメンバとして保持しているのに。
ここから拾ってきた物をベースにしているのだが・・・
サンプルを見るとレンダーがアロケーターを持ってるしぃ。
まあ、だとしてもAddRefは必要なのかな。
でも、よく見るとnewしている意味がわからんな。

IBasicVideo::get_SourceHeightでアサートが出る。ピンが接続されていないとか。
レンダーのコンストラクタでCBaseControlVideo::SetControlVideoPinでレンダーの入力ピンを設定しておかなければいけないようだ。

とりあえず、シングルバッファーで普通に動くようになったが、CoUninitializeでアクセス違反が出る。
また、わかりづらいところで・・・
CoUninitializeの処理について調べないと。

投稿者 Takenori : 02:30 PM | コメント (0) | トラックバック

September 02, 2004

フィルタの修正

インターフェイスを追加しようとして、いろいろと入らないことが判明し、処理の書き換えを行った。
そのおかげでだいぶコードがすっきりした。
次はプレーヤー側の修正だ。
でも、そっちは結構大がかりかも。

投稿者 Takenori : 09:49 PM | コメント (0) | トラックバック

インターフェイスの変更(?)

レンダーからイベントを送るため、IMediaEventSinkをセットするメソッドを追加したいと思い、IDLファイルにメソッドを追記し、IMediaEventSink型を使うために、import "axextend.idl";を追加する。
と、やっていてふと気付く、フィルタはイベントを送るんだから、IMediaEventSinkははじめから持っているんじゃないかと。
調べると・・・あった。
CBaseFilter.m_pSinkだ。
IMediaEventSinkを設定する関数は無駄だったんですね。
で、作っていた物を書き換えて動作確認する。
問題なく動いた。
IMediaEventSink関連の処理は全くの無駄だった。(涙
無駄な処理を削除していくのもまた悲しい。
それはともかく、MediaTypeを取得する物もインターフェイスへ追加しようと思ったが、フィルターではなく、ピンの方のIPin::ConnectionMediaTypeで取得できることがわかったので、やめる。
まあ、これ関連の処理も全くの無駄だったんだけど、これはこれで処理は短くなっていたので良しとしよう。書き換えないといけないけど。
で、結局インターフェイスはそのままでいいことになった。

投稿者 Takenori : 09:32 PM | コメント (0) | トラックバック

September 01, 2004

とりあえずシングルバッファで作り、登録

とりあえず、シングルバッファで動作するようにし、フィルタをレジストリに登録する。
後、IBasicVideoの既定転送元矩形も作っておく。

登録は、
regsvr32 BRender.ax
と入力する。

ちなみに登録解除はこう
regsvr32 /u BRender.ax

で、CoCreateInstanceしてみたら、きちんとインターフェイスを取得出た。
でも、実際に使うにはいろいろと直さないといけないところがある。
いい感じになってきた。

投稿者 Takenori : 10:51 PM | コメント (0) | トラックバック

COM内でのメモリ割り当て

COM内でメモリの割り当てを行う場合は、CoTaskMemAlloc / CoTaskMemFree を使わないといけないようだ。

投稿者 Takenori : 10:33 PM | コメント (0) | トラックバック

IRendererBufferAcces関連仕様

Set系は、基本的にフィルタグラフを作ってから、再生を開始するまでに行うようにする。
再生中の呼び出しは動作保証されない。
再生が開始された時に、Setが呼ばれていない場合は、TBufferRendererが自分でメモリを割り当てる。
特にメモリを渡す必要がない場合はこの方法を使用する。
TBufferRendererが確保したメモリをGetし、そのメモリを再度Setしてはいけない。TBufferRendererは、Setによってメモリが設定されると、自分で確保したメモリは解放するので、不正アクセスが発生してしまう。
当然、TBufferRendererが確保したメモリをGetし、そのメモリを解放するなどという暴挙に出てはいけない。
buffにNULLを入れて呼び出すと、sizeに要求されているサイズが返ってくる。
TBufferRendererはフレームが更新された時、EC_UPDATEを投げる。利用者はEC_UPDATEを受け取ったら、GetFrontBufferし描画などの処理を行う。

投稿者 Takenori : 01:03 AM | コメント (0) | トラックバック

インターフェイスを加えてビルド

IRendererBufferAccesを継承するように書き換えて、メソッドを以下のように追加する。
STDMETHOD( SetFrontBuffer )( BYTE *buff, long *size);
STDMETHOD( SetBackBuffer ) ( BYTE *buff, long *size);
STDMETHOD( GetFrontBuffer )( BYTE *buff, long *size);
STDMETHOD( GetBackBuffer ) ( BYTE *buff, long *size);
STDMETHODと言うマクロは、CでもC++でも使えるようにする物だが、他が思いっきりC++で書かれているので、全然意味なしです。
完全に共通にするにはマクロ バリバリにしないといけません。
ま、特に気にしなくてもいいでしょう。Cで書くことはほとんどないでしょうし。
定義は、とりあえずS_OKを返すだけにしておきます。
HRESULT TBufferRenderer::SetFrontBuffer( BYTE *buff, long *size) { return S_OK; }
で、ビルド。
きちんとビルドされた。
次はいよいよ実装だ。

投稿者 Takenori : 12:46 AM | コメント (0) | トラックバック

August 31, 2004

多重継承

COMの場合、1つのクラスに複数のインターフェイスを持たせるのが一般的なようだが、そのためには多重継承をしなければならない。
しかし、すべてのインターフェイスはIUnknownを継承する。
つまり、QueryInterfaceやAddRedなどのメソッドがかぶってしまう。
おいおいどうするんだ?それってやばくないのか?と思っていたが、実は全然問題ないようだ。
そもそもCOMもそれを期待している節があるようだ。

多重継承を行った場合、基底クラスごとに仮想関数テーブルが作られる。
そして、共通の関数は両方のテーブルで同じ物を指す。
つまり、何の問題もないのだ。
ただし、複数の仮想関数テーブルが作られる関係上、キャストは慎重に行わなければいけない。
QueryInterfaceで返すインターフェイスは、要求された型に一度きちんとキャストする必要がある。
そうしなければ、仮想関数テーブルが別物になってしまい、うまく動作しなくなる。
また、仮想関数テーブルが違うと言うことは、ポインタが異なる。
つまり、同じクラスが持っているインターフェイスでも、QueryInterfaceで返ってきたインターフェイス同士を比較してはいけない。
まあ、利用者側としては、同じクラスかどうかなどわからないし、それを期待した実装はしてはいけないので、さして問題はない。
どうしても、比較したい場合は、そのインターフェイスにQueryInterfaceでIUnknownを要求し、そのIUnknownインターフェイスのポインタを比較するようにしないといけないようだ。と言っても、使わないけどね。

ここの説明は、C++がどのようにクラスを実現しているか、メモリ構造がどうなっているかを知っていないとかなりわからないかも。
まあ、C++のクラスのメモリ構造を知ってて、多重継承はどうなの?って説明だからなんだけど。
それと、図があった方がもっとわかりやすいっすね。
自分用の備忘録としてはこれで十分なんだけど。

投稿者 Takenori : 10:46 PM | コメント (0) | トラックバック

IDLの記述

新しいインターフェイスを作るのでIDLを書くことにした。
IDLを書けば、MIDLでヘッダーとか自動生成されるはず。
で、必要なメソッドはバッファの取得/設定のみかな。
とりあえず、書いてみるとこんな感じかな。
// IRendererBufferAccess.idl
import "oaidl.idl";
[
object,
uuid(2F8FFFC5-E7BE-497a-9254-DB97639131A6),
]
interface IRendererBufferAccess : IUnknown
{
HRESULT SetFrontBuffer( [in] BYTE *buff, [in,out] long *size );
HRESULT SetBackBuffer( [in] BYTE *buff, [in,out] long *size );
HRESULT GetFrontBuffer( [out] BYTE *buff, [in,out] long *size );
HRESULT GetBackBuffer( [out] BYTE *buff, [in,out] long *size );
}

このソースは、試していないのでうまく行くかどうかは不明。
さあ、MIDLだ。コマンドラインでVCのバッチを実行して

MIDL IRendererBufferAccess.idl

と入力する。
すると、いくつかソースが出力されるが、実際に使うのは、_i.cと.hのみ。
他はリモートコールなどの時に使用されるようだ。
とりあえずは、.hをインクルードして、インターフェイスを継承すればいい。

投稿者 Takenori : 10:40 PM | コメント (0) | トラックバック

August 28, 2004

フィルタDLLの作成

まずはプロジェクトを作成して、サンプルを参考にしてビルドオプションの設定を行う。
でも、いろいろとうまくいかない。
いろいろといじって、コンパイルは通るようになるが、リンクが通らない。
サンプルとは異なり、ATLを使用しているのが原因のようだ。
で、ATL用のライブラリatls.lib (atlsd.lib)を追加したら、とりあえずリンクが通った。
でも、"atlsd.lib(Externs.obj) : warning LNK4210: .CRT セクションが存在します。静的初期化子、または終末記号がハンドルされていない可能性があります。"などのwarningがたくさん出る。
これは、グローバルコンストラクタなどが使われていて、CRTが起動時に実行されないとでるwarningのようだ。
サンプルでも、出ていたが、サンプルでは1個だけだった。
ATLが使われているからなのだろうが、自分が作ったファイルのオブジェクトにまで出ているのが気になる。
CComPtrを使っているのが原因だと思うが・・・
とりあえず使わなくてもいいように書き換えて、ATLのライブラリとインクルードファイルを消した。
すると、ほとんどのwarningが消え、ほとんどサンプルと同じ状態になった。
2つ多くwarningが出ているが、それは#pragma warning(disable:4355)を追加していないためだ。(サンプルにはある)
なので、サンプルと同じ状態になった。
これで、ひとまずは完成だが、今のままだと使えない。
新しいインターフェイスの追加などが必要だ。

投稿者 Takenori : 09:30 PM | コメント (0) | トラックバック

フィルタのCOMコンポーネント化

とりあえず、ヘルプのCOMコンポーネントやDLL化の項を読んだ。
ほぼサンプルの通りやれば出来そうだ。

DLLとして作られたフィルタはRegsvr32.exeユーティリティを使って登録することができるらしい。
テストなどはこれでいけそうだ。

DLL化した時の振る舞いを考えてみる。
インストーラがある場合は、インストーラによって登録/解除する。
実行時に見つからない場合は、実行時に登録し終了時に登録解除する。ただし、この場合、エラーなどで落ちた時、レジストリに情報が残ってしまう。登録/解除ツールというか、Regsvr32.exeを呼ぶバッチファイルを用意しておけば良いか。

投稿者 Takenori : 06:44 PM | コメント (0) | トラックバック

August 27, 2004

IBasicVideoの実装

サンプルを見ながらクラスを作成。
CBaseControlVideo::NonDelegatingQueryInterfaceとCBaseControlVideo::GetVideoFormatさえ作れば、目的を達成できるが、他にいろいろ純粋仮想関数があるので、それも実装しないといけない。
ほとんどはE_NOTIMPLエラーを返すだけだが。

とりあえずは、今までグローバルにあったMediaTypeをBufferRendererに保存するように変更。動作確認。
IBasicVideoをサポートするクラスを作成し、追加したらクラスファクトリ系のグローバル変数が必要だと言われる。
つまり、CBaseControlVideoを継承したクラスを作ると
Textures error LNK2001: 外部シンボル ""class CFactoryTemplate * g_Templates" (?g_Templates@@3PAVCFactoryTemplate@@A)" は未解決です。
Textures error LNK2001: 外部シンボル ""int g_cTemplates" (?g_cTemplates@@3HA)" は未解決です。
などが出るようだ。

CBaseControlVideoを継承したクラスを持ったフィルタを作ると、IBasicVideoがフィルタグラフから使われる(検索される)ようになるわけで、そしたらフィルタが登録されていないといけないと言うわけだろうか。
これは、どんどん本格的なフィルタになっていく・・・。と言うか、クラスファクトリを実装してレジストリの登録とかをやったら、もう普通のフィルタです。
でも、そうなると独自メソッドはインターフェイスとして実装しないといけないことになって・・・。
ちょっと大変です。
しかも、レジストリへ登録とかになってくると、インストーラがどうとか言うことになって・・・
IBasicVideoはもういいか。
とりあえずは、LayerDrawとOverlay別々の処理にしておいて、将来的にきちんとしたフィルタとして実装する?
と言っても、かなり近い将来になりそうだけど。
とりあえず、その方針にして、両方を平行で進めることにしよう。
よし、ローカルの実験用リポジトリをブランチだ。

投稿者 Takenori : 10:34 PM | コメント (0) | トラックバック

August 26, 2004

現在の時間とフレーム

再生中にIMediaSeeking::SetTimeFormatを使って、タイムフォーマットを頻繁に切り替えると再生が乱れる。どうやら、タイムフォーマットを変更すると何らかの初期化が行われているようだ。
そうすると、再生中にはタイムフォーマットの変更は出来なくなる。

IMediaSeeking::ConvertTimeFormatを使用すれば、他のフォーマットへ変換できるが、自分の環境では、フレームからメディアタイムへの変換は出来たが、メディアタイムからフレームへの変換は実装されていないと出た。
どうやら、IMediaSeeking::ConvertTimeFormatは万能ではないようだ。
FPSを使用すれば、ある程度は自前で変換できる。
出来る限り厳密な設定を望むのなら、タイムフォーマットはメディア タイムを設定しておくべきだが、私の個人的な見解では、設定はフレームで行いたい。
でも、取得は時間の方が都合が良さそうだ。
さて、どうしたものか。
タイムフォーマットにフレームが設定可能であればフレームを、そうでなければメディア タイムとしておくかな。
つまり、フレームを基準として動作させることにする。
細かい時間での制御が出来なくなるが、フレーム以上の精度で何かを制御することはあまりないであろう。
よって、以下のような仕様とする。

合計時間と合計フレーム数はグラフ構築時に取得し、保持しておく。また、同時にFPSも計算し保持する。
タイムフォーマットもグラフ構築時に問い合わせを行い、フレームが利用可能であればフレームに設定。利用できない場合はメディア タイムに設定。もし、両方が利用できない場合は、現在時間の取得や設定は利用できない物とする。
フレームが利用できない場合は、合計フレーム数やFPS、現在のフレームの取得/設定は利用できない。つまり、メディア タイム(100ナノsec単位)での制御となる。

以上のような仕様にするのはいいものの、フレームが利用できないといろいろと痛い。ムービー内ループが利用できなくなる。
FPSが他の方法によって取得できれば何とかなるのだが・・・
もう少し調べてみなければならなそうだ。

AM_MEDIA_TYPEのVIDEOINFOHEADERにはビデオ フレームの平均表示時間がある。これを利用すればFPSを得られる!
オーバーレイの場合は、IBasicVideoを取得すればビデオ フレームの平均表示時間が得られる。
でも、出来れば独自レンダーの方も同じようにIBasicVideoを使用したい。調べるとCBaseBasicVideoというベースクラスがあった。しかし、これは少々ややこしそうだ。もう少し見るとCBaseControlVideoが見つかった。こちらの方が簡単に実装できそうだ。
しかし、実装したとしても、どうやればグラフビルダのQueryInterfaceで返されるようになるのかは現在不明。
良いサンプルがあるといいが。

Filters/SampVidが役に立ちそうだ。
でも、単にクエリーの時に返しているような感じだな。
次はCBaseControlVideoの実装だ。
にしても、独自レンダーは次々に拡張されていくなぁ・・・

投稿者 Takenori : 11:36 PM | コメント (0) | トラックバック

各種ビデオパラメータの取得

合計時間や合計フレーム数はIMediaSeekingインターフェイスを利用すれば、得られるが、フレームレートはIBasicVideoの各フレームの平均時間からと思ったけど、この文章を書いてすぐに気付いた。
合計フレーム数を合計時間で割れば出るんじゃないか。FPSなんて。
独自レンダーはIBasicVideoをサポートしていないから・・・って悩む必要なんてなかった。
ただし、これらの値は参考値でしかない。
出来る限り誤差が少なくなるように実装するが、誤差が出ることはあるし、仕方がない。
クロックの同期化などの問題もあるし。
まあ、合計時間や合計フレーム数、FPSを他のところで使うことはあまりないでしょう。
でも、これを元に他のところを制御されたらどうしよう・・・
知ーらないっと。
ま、出来る限りやるってことで。

調べていると、再生レートの操作、コマ送り、音のパンポットの設定等々、いろいろと出来ることがわかる。
でも、一気にいろいろと追加するとややこしいし、使わないからそんなのは無視。

投稿者 Takenori : 04:21 PM | コメント (0) | トラックバック

August 25, 2004

オーバーレイ機能の実装

基底クラス(dsmovie)からオーバーレイ用のクラスを派生して作る。
とりあえずは、基底クラス側で作ったPauseとRewindだけが機能拡張されている状態。
いくつかのインクルードディレクトリとライブラリをプロジェクトに追加しておく。
で、動作を確認すると従来と同じように動いていることを確認。
また、DLLのデバッグが出来るように、VCで設定を行っておく。
デバッガで追えることも確認した。

pauseとrewindをTJSからコールできるようにし、動作確認。動いているようだ。
とりあえず、rewindがあれば、KAGを書き換えてループさせることが出来る。
まあ、TJSのVideoOverlayクラスでサポートされるから意味ないんだけど。
でも、pauseやrewindをしていると時々ムービーがウィンドウに追従しないという問題(バグ?)に気付いた。メニューで何か操作するときちんと合うようになる。
そうか、tTJSNI_VideoOverlay::WndProcで状態がStopになるからだ。たぶんそれで、どこかでイベントが堰き止められているか、コールしなくなっているのだろう。
本来、EC_COMPLETEが来た時点ではムービーは停止状態ではない。ただ最後まで行っただけ。ここで、ムービーの位置を最初に戻すと、何もしなくても再び再生が始まる。でも、Stop状態だから・・・と言うわけだろう。
ま、ループなどが下位でサポートされれば解決するだろう。
あっ、でも、ここの処理は考えておかないとなぁ。

とりあえずここまでをコミットしておく。

投稿者 Takenori : 10:48 PM | コメント (0) | トラックバック

基底クラスの作成

OverlayとLayerDrawの両方で使うインターフェイスとメソッドをまとめたクラスを作った。
でも、LayerDrawの矩形設定どうしよう。
レイヤーに対して行えば同じなのだが・・・
内部でもレイヤーに対して処理するだけでうまく行かな。
もう少し調べてみる必要がありそう。

投稿者 Takenori : 10:23 PM | コメント (0) | トラックバック

インターフェイスの拡張

iTVPVideoOverlayにインターフェイスを追加しようとして気付く。
純粋仮想関数にしたらFlash側にも実装の変更が及ぶ。と言っても、まだサポートしていないってエラーメッセージを返すだけなのだが・・・
むぅ。
Flash側もそれだけやるか。

投稿者 Takenori : 04:52 PM | コメント (0) | トラックバック

August 23, 2004

modeにいて

modeはopen前に設定されていた物を有効とすることにした。
それは、open時のクラス生成時に生成するクラスを振り分けることにしたからだ。
OverlayとLayerDrawの共通部を基底クラスにし、それを継承してOverlayとLayerDrawの各クラスを作ることにした。
動的再接続を使用して2つを切り替えるのは少々厳しそうだから諦めることにした。MPEG SplitterかDecoderのどちらか忘れた(あるいは両方)が、再接続に必要なインターフェイスを備えていないので、再接続しようとしたらかなり面倒だ。

メモ
デフォルトのフィルターなどもCOMだから、包含することで独自に機能拡張することも可能だ。
つまり、デフォルトのオーバーレイをラップして機能拡張が出来る・・・調べてみるとやりたいことは無理そうだ。

メモ2
フィルタグラフはIReferenceClock を使用して同期をとるようだ。
IReferenceClockではセマフォを使って同期をとるようだ。
DirectXのヘルプ"DirectShow のタイムとクロック"の項を読むとよいようだ。
時間は100ナノ秒単位。
10,000,000 = 1秒。
でも、返される値は意味がない。それは、基準クロックに依存するから。つまり、100ナノ秒単位できちんと増加するわけではない。
制御しづらそう。サウンドがある場合は、サウンドフィルタのクロックに同期化されるんだろうなぁ。
IMediaSample::GetMediaTimeを使えば、そのサンプルのフレーム番号がわかる。
IBasicVideo::get_AvgTimePerFrameを使えば、100ナノ秒単位のフレームレートが得られる。
IVideoFrameStep を使えばコマ送りが出来る。

投稿者 Takenori : 11:57 PM | コメント (0) | トラックバック

メソッドとプロパティの追加

TJS2 基本的な使い方のネイティブクラスの項を読む。
以前も一度読んだのだが、また頭がこんがらがる。
クラス、インスタンス、オブジェクトと言う言葉が出てくるが、これらの言葉は状況によって取り方が変わる。それに、C++の方かTJSの方かがすぐに判断できなくて、さらにこんがらがる。
まあ、よく読めばわかるんだけど。。。
もう一度読んだらまた???ってなりそうだ。

それはさておき、とりあえず、Overlayにメソッドとプロパティを追加。
VideoOvlIntf.cppですな。
他のをコピペしてただ書き換えるだけ。単純作業だ。
マクロが少し気になるが、たぶん登録処理だろう。

で、メイク。
すんなりいった。
じゃ、次は実際の処理の記述ですな。
でも、I/FにはすでにPause()が入っているけど、実装されていない。
なぜだろう?
ま、考えても仕方ない。追加していこう。
でも、その前にテスト用のTJSスクリプトを書いておいた方がいいかな。

投稿者 Takenori : 06:57 PM | コメント (0) | トラックバック

ムービー拡張仕様(仮)

VideoOverlayクラスのインターフェイスの拡張仕様を考える。
次のような物にしようと考えているが、追加削除がありそうな臭いぷんぷん。

メソッド
close ( メディアを閉じる )
open ( メディアを開く )
play ( 再生開始 )
setBounds ( 再生矩形の位置とサイズを指定 )
setPos ( 再生矩形の左上位置を指定 )
setSize ( 再生矩形のサイズを指定 )
stop ( 再生停止 )
pause (一時停止) : 新規追加
rewind (巻き戻し) : 新規追加、positionに0を設定するのと同意だが・・・
playSequence (特殊再生) : 新規追加、特定フレーム間ループなどを行えるようにしたい

プロパティ
height ( 再生矩形の縦幅 )
left ( 再生矩形の左端位置 )
position ( 再生位置 ) : 未実装なのを実装する。でも、msecじゃないかも。
top ( 再生矩形の上端位置 )
visible ( 可視かどうか )
width ( 再生矩形の横幅 )
loop (ループ ) 新規追加 : ループの有効/無効を取得/設定。
frame (現在のフレーム) 新規追加 : フレーム番号で取得/設定。使えない時もあるかも。
fps (フレームレート) 新規追加 : 読み込みのみ、実装できないかも
numberOfFrame (全フレーム数) 新規追加 : 読み込みのみ、実装できないかも
totalTime (合計時間) 新規追加 : 読み込みのみ、実装できないかも
layer1 (描画レイヤー指定1) : 新規追加
layer2 (描画レイヤー指定2) : 新規追加
mode (オーバーレイorレイヤー描画) : 新規追加

イベント
onCallbackCommand ( コールバックコマンドが発生した )DirectShow側では使用されない?
onStatusChanged ( ステータスが変更された ) イベント追加 : period (ループ時にループの終点に達した時に発生)

layer1, layer2と言うプロパティを持つ仕様はちょっと格好悪いだろうか?
まあいいか、比較的簡単直せるだろうし。
気にしない気にしない。

まだ書きかけです。

投稿者 Takenori : 06:50 PM | コメント (0) | トラックバック

なにげにFlashの方も見てみる

COM ( ActiveX ) ですな。
メッセージはサブクラス化(?)しているように見えたが、コメントアウトされている。
でも、これがフックって言っていたやつですな。
フックという呼び方の方が正確なのだろうか?
Codianではフックと書かれている。
サブクラス化とフックは厳密には異なるのだろうか?
何となく違うようだが今は細かいことは気にしないことにした。
っていうか、これはまた面倒ですな。
Flashのレイヤー描画は考えないことにしよう。

投稿者 Takenori : 06:43 PM | コメント (0) | トラックバック

次は? メモ

TJSのクラスの追加の仕方を再度熟読。
オーバーレイミキサーの説明を読む。
メソッドなどを追加してみる。
激ねむなので、ここにメモっておこう。

投稿者 Takenori : 12:30 AM | コメント (0) | トラックバック

August 22, 2004

ムービー内移動

連続再生は止めて、ムービー内の任意のフレームへ移動できる機能を実験してみた。
単純に一部の区間をループし、クリックされると次へ移行、また次の区間でループするという物。
複数ムービーをつなげるよりもスムーズにつながった。
まあ、元々一つのムービーなんだから当然と言えば当然かもしれないが。
ただ、かなり離れたフレームへ移動する場合もうまく行かどうかは不明。
でも、たぶんなんとかなるでしょう。(根拠なし)

ただし、この実験では独自レンダーから、フレームごとにイベントを発行しているので、フレームの切り替わりを取得できるけど、オーバーレイのレンダーを使った場合は取得できない。
たぶん、なんとかできそうな気がするけど、今のところ不明。

投稿者 Takenori : 09:44 PM | コメント (0) | トラックバック

吉里吉里をメイク

kirikiri2/src/core/environ/win32/bcb6/tvpwin32.bprを使ってメイクしてみる。
インクルードファイルがいくつか足りないと出た。
前もらったやつからコピーし忘れていたようだ。
再度メイク。
ライブラリがいくつか足りないと出た。
コピーし忘れていたようだ。
再度メイク。
boost関連でリンクエラーが出る。
1.31.0にパッチを当てずにライブラリを作っていたので、今度はパッチを当てて、makeしインストール。
しかし、やはりboost関連でリンクエラーが出る。
なんだろう?
バージョン違いかな?

---以下追記
バージョン管理されている最新のソースのmakeにはboost 1.30が必要なようだ。
1.31.0だとなぜか通らない。
なお、このときの最新のリリースバージョンは吉里吉里 2.23 β3。

投稿者 Takenori : 12:48 PM | コメント (0) | トラックバック

August 21, 2004

ダブルバッファリングの実験

CMediaSample::SetPointerを使えば出来そうだ。

ヘルプには、
このメソッドは IMediaSample インターフェイスを通しては使えない。サンプルを作成したオブジェクトは (CMediaSample を通して) このメソッドにアクセスできるが、他のオブジェクトはアクセスできない。
とある。

そこで、自前のアロケーターにCMediaSampleを保持しておくようにし、新しいバッファを設定する関数を追加した。
そして、CBaseRenderer::DoRenderSampleで、サンプルのポインタをすげ替えたら、うまくいったようだ。
描画部分はダブルバッファにしていないが、交互にバッファが使われているのを確認した。
これでダブルバッファリングの問題は解決した。

投稿者 Takenori : 07:10 PM | コメント (0) | トラックバック

August 20, 2004

ダブルバッファリング

最新の吉里吉里をチェックアウトして、メイクしている間、どのような仕様にするか考えていて思い出す。
デコーダーに直接レンダリングさせるのならダブルバッファリングしないといけないんだったと。
でも、どうやればいいのだろう?
たぶん、メディアサンプルかアロケーター辺りをいじればいいんだろう。
で、また実験することになった。

投稿者 Takenori : 10:26 PM | コメント (0) | トラックバック

オーバーレイの対応

レンダーがデフォルトの物でいいので、グラフ作成部分がすごい簡略化された。
で、再生!
・・・ ウィンドウが4つ出来た!!
やったね!っておい。
オーナーウィンドウや位置を設定しとかないといけないようだ。
設定すると問題なく表示できた。
これでとりあえず目標は達成だな。
次は吉里吉里への組み込みだ。
でも、その前にどのような構成にするか検討しないと。

なんとなく、KAGのソースを見てみる。
ウィンドウがムービーオブジェクトを持っているんすね。
KAGの方の改造はそれほど大変ではなさそうだ。
そして、ふと気付く。
KAGに構文を追加しようと思ったらパーサーをいじらなければならないのではと。
でも、ほとんど予約語追加と対応する処理を記述するだけとかで出来るんじゃないかなぁと期待を抱く。
何となく見た感じだとbisonは使っているけど、flexは使っていないような感じだったけど・・・
ま、その辺は追々だな。
初めはKAGでTJS直打ちすれば済むし。

投稿者 Takenori : 09:28 PM | コメント (0) | トラックバック

フィルタグラフの複数生成

ヘルプを見ていると、どうもフィルタグラフは複数存在していても良いようだ。
それなら、初めに複数のフィルタグラフを生成しておき、順番に再生していけばうまくいきそうだ。
で、早速試す。
うまくつながっているけど、完璧につながっているかどうかはわからないなぁ。
そこで、アニメのOPを5秒ずつに分けた3つのムービーを準備し、再生してみた。
が、やっぱりつなぎ目で音がとぎれるし、絵も一瞬ぼやける。しかし、MPEGなんだから、その絵が完璧に一致しないのは仕方ないだろうと思う。
問題は音だが・・・やっぱり一瞬とぎれてしまうよなぁ。
完全に繋ごうと思ったら、ソースフィルタからデコーダーへ流れるデータをとぎれないようにしないといけない。
そうするとソースフィルタを工夫しないといけないのだろうか?
そもそもそこまで必要かどうかと言う問題がある。
ムービーをつなげて作る場合、シーンが切り替わるところにムービーの接続点を持ってくるだろう。そうすれば、たいして違和感なく表示される。
また、バックに音楽を流す場合は、ムービーとは別に音楽を流せば何とかなるのではないだろうか。
つまり、完全につながっていなくても大丈夫な気がする。
ま、作り手の工夫次第っすね。

投稿者 Takenori : 09:10 PM | コメント (0) | トラックバック

グラフの再構築

再接続は少し面倒そうなので、もう一度一から作る方法を試してみることにした。
作ってみてみると・・・つながっているけど、隙間が空いていないのかどうかわからない。
まあ、つながっていないムービーをつなげてもわかるわけないか。
まずはつながっているムービーを分割して用意する必要がありそうだ。
バックに音楽が流れていたらなおよしだが、それはかなり厳しそうだ。
音楽がとぎれなく聞こえるようにするのは可能なのだろうか?
専用の物を作らないと厳しそうだが・・・最近のPCなら難なくやってのけてしまうのだろうか?
とにかくやってみないことにはわからないな。

次に全体をループさせる(1->2->3->1・・・と言う感じ)ように作ってみるが、なぜか同じ物を使おうとしたら適切な中間フィルタがないと言ってくる。
フィルタグラフが削除された時に何かされているのだろうか?
自分で事前にグラフからフィルタを削除したり、Disconnectしたり、いろいろとやってみるが結果は変わらず。
少し考えてふと気付く、ファイルの位置が終端に達しているからでは?と。
とりあえず、IStream::Seekで位置を先頭に移動させる。
が、効果なし。
IMediaPosition::put_CurrentPositionで先頭に移動させても効果なし。
なんなんだろうか?

投稿者 Takenori : 09:00 PM | コメント (0) | トラックバック

August 19, 2004

ソースフィルタの動的再接続

ヘルプの動的再接続のソースを参考に、と言うかほとんどそのまま実装してみる。
が、いきなりQueryInterfaceでインターフェイスがないと返ってきて終了。
何ーぃ。
まあ、サンプルはソースフィルタではなく、途中のエフェクトフィルタだったので若干異なるのかもしれない。
でも、このIPinFlowControlがないと動的再接続が出来ないのだが・・・
ヘルプを読むと次のように書かれている
---以下引用
フィルタ開発者へ : 動的な再接続をサポートするパーサー フィルタとキャプチャ フィルタでは、その出力ピン上でこのインターフェイスをサポートしなければならない。通常、その他のタイプのフィルタでは、このインターフェイスを実装する必要はない。
---引用終わり
ソースフィルタはサポートしていなくても良いと言うことだろうか?
そもそも、ソースフィルタを差し替えるには他の方法があるような気がしてならない。
さてどうしたものか。

基本的にソースフィルタを差し替えたい場面はムービーの終点になる。
つまり、すでにストリームにはデータは流れていないはずだ。
なら、そのままはずしてしまえばよいのではないだろうか?
とはいうものの、やっぱり危険な香りがするので、IMediaControl::Stop()を事前に呼び出し、フィルタを停止状態にしておくことにする。
しかし、この場合ムービーのつなぎ目に隙間が生じてしまう可能性がある。
まあ、隙間が出来たら、ソースフィルタのみを停止し、つなぎかえれば何とかなるのではないだろうか。そのときはそのときにいろいろと考えよう。
で、IMediaControl::Stop()を呼び、IPinFlowControl::Block()は呼ばずにIGraphConfig::Reconnectを実行してみたのだが、入力ピンがIPinConnectionをサポートしていないと返ってきて終了。
・・・
なんですとー。
まあ、毎度のことなんだけど・・・
よし、自分でDisconnectを呼んで、その後また自分で繋ごう。
で、やってみたらなんかうまく再生されない。
GraphEditで見てみると・・・
20040819graph.gif
めためたです。(涙
本来は次のようにきれいにつながっています。
20040819graph02.gif
でも、よく見てみると、スプリッターから先がぶった切れているだけのようだ。
なら面倒だが、再度繋げば大丈夫なんだろうか?
でも、そうすると一から構築するのと大差ない気がするのだが・・・
さてどうした物か。
とりあえず、どの辺りでぶった切れているのか調べると、ソースフィルタをDisconnectした後にすでに切れてしまっているようだ。
うーん・・・
明日考えよう。

投稿者 Takenori : 08:48 PM | コメント (0) | トラックバック

接続しているピンの取得

接続しているピンを取得するには、IPin::QueryInternalConnectionsではなくIPin::ConnectedToを使えばいいようだ。
QueryInternalConnectionsはインプリメントされていない場合があるが、ConnectedToにはそのようなエラーは定義されていない。
たぶん下位の部分で実装されているのだろう。
これで、スプリッターのピンの問題は解決した。
次はソースフィルタを差し替えれば、次のムービーが再生されるはず。

投稿者 Takenori : 07:54 PM | コメント (0) | トラックバック

August 18, 2004

ある程度整理できた

一通り整理して、ビルドが通り、動くところまでいく。
でも、いくつか問題が。
ソースフィルタにQueryInternalConnectionsがインプリメントされていないので、そこからスプリッターが取得できない。
とりあえずは問題ないが、再接続時に困る。
フィルターを列挙してそれで何とかなるのかな。
まあ、やってみよう。

他にもまだまだきちんとしていないところが・・・
MPEGに依存している部分や、関連が混み合っている部分がある。
まあ、ビルドが通るようになったので、少しずつ整理していこう。

投稿者 Takenori : 10:53 PM | コメント (0) | トラックバック

August 17, 2004

ソースの整理2

エクセプションクラスは組み込めた。
そのおかげで例外処理部がきれいになった。

ユーティリティー的なのは全部CPlayerに入れてしまうことにした。
そして、MPEG依存部分 ( フィルタ名を直指定で検索している箇所がある ) をなくしていく。
しかし、ソースの整理と同時にやると面倒なことになる可能性があるので、とりあえずは従来の処理を有効にしておく。#if #else #endifで分けておく。(リファクタリング時に機能追加しないのは基本らしいし)

ソース整理はもう少しかかりそうだ。
ビルドして動かす間でしばらくかかるので、時々中だるみする。
やっぱり、細かくやっていった方がいいな。

投稿者 Takenori : 10:29 PM | コメント (0) | トラックバック

CComPtrの代入時の振る舞い

COMのインターフェイスを管理する時はATLのCComPtrを使うと楽だ。
ソースはatlcomcli.hにある。
で、代入時の振る舞いがちょっと気になったので調べてみた。
中ではAtlComPtrAssignが呼ばれている。
その中を見ると次のような感じ。

if (pp == NULL)
   return NULL;

if (lp != NULL)
   lp->AddRef();
if (*pp)
   (*pp)->Release();
*
pp = lp;
return lp;

やっぱ代入元もAddRefされてるんすね。
と言うことは、呼び出し元管理のインターフェイスは代入後Release呼んどいた方が良さそうだ。

投稿者 Takenori : 02:16 PM | コメント (0) | トラックバック

August 16, 2004

ソース整理・構成の変更

CIStreamProxy、CIStreamReader、IStreamはCMovieに、グラフ系のはCPlayerに入れる。
HRESULTからAMGetErrorTextでエラーメッセージを作ってくれるexceptionクラスも作っておくことに。
でも、まだ整理中。
さっさときれいにしないとねぇ。
と言うか、もっと早くやっとけよ。って気が。

でも、他のユーティリティー的なのはどうするか?
グラフ関連のが多いから、そう言うクラスを作ってまとめるかな。
うーん、行き当たりばったりだけどいいのかなぁ。
少し、きちんとモデリングした方がいい気がする。
まあ、吉里吉里に組み込む時にやるか。
そうしよう。

投稿者 Takenori : 07:55 PM | コメント (0) | トラックバック

August 15, 2004

連続再生について

今日はとあるイベントに行った後、アキバへ行ったりしていたので進捗がないが、昨日考えたことをここに記しておく。

遅延なく連続再生するためにメモリ上にデータを置こうと思っていたが、そんなことをしなくても、ディスクに一度アクセスすればキャッシュがきいてほとんどの場合遅延なく読み込めるのではないかと思う。NT系のディスクキャッシュは強力だし。
で、それより問題になると思われるのはグラフの再構築だ。
もし一から構築しなおすと、完全につながらないのではないかと考えられる。
何となくだが、グラフの構築はそこそこ時間のかかる処理のように見える。
そこで、どうするか? だ。
簡単に思い付くのはフィルタグラフを複数作っておくという物だが・・・ 複数作っても大丈夫なのだろうか? また、うまく切り替えられるのだろうか?
次善の策としてはソースフィルタの差し替えだ。
すべてを作り直すのではなく、次のムービーのソースフィルタのみを事前に準備しておき、切り替え時にその部分のみつなぎかえると言う方法だ。
どっちにしても、ソースコードを整理しないといけないので、どちらを選択してもいいのだが、ソースフィルタの差し替えで済むのならそれが一番なので、まずは差し替えを試してみることにする。

投稿者 Takenori : 10:09 PM | コメント (0) | トラックバック

August 14, 2004

ソースフィルタの変更

asyncio.h/.cppとasyncrdr.h/.cppをそのままコピーしてきて、吉里吉里のCIStreamReaderとCIStreamProxyを別ファイルに分離して、それをインクルード。
VC.NET 2003でビルドするとasyncio.cppでビルドエラーが。
単に型チェックが厳しくなっただけのようだ。
asyncio.cppの422行目のCreateThreadへ渡す関数ポインタを(LPTHREAD_START_ROUTINE)にキャストしたらビルドが通る。たぶん、これで大丈夫だろう(あまりこういうことはしない方がいいけど)。

ビルドが通ることを確認したので、ソースフィルタを変更する。
と言っても、AddFilterでCIStreamReaderをグラフに追加し、その出力ピンとレンダーをつなぐだけ。
IStreamはとりあえずSHCreateStreamOnFileでお手軽に生成。
でも、SHCreateStreamOnFileに渡すファイル名はなぜかマルチバイト文字セット。
仕方なく、WideCharToMultiByteで変換する。
なんで、ワイド文字列(Unicode)じゃないのだろうか?
シェル系はワイド文字列が多かったはずだが・・・あれ?逆だったかな?
まあ、いいか。どっちでも。面倒だけど。
で、前回と同じように再生されることを確認。
なんか、かなりあっさりと出来た。

次はいよいよメモリからの再生。
でも、そんなに難しくはなさそう。
IStreamを継承したクラスを作って、ぽんっと渡せば済みそうだし。

投稿者 Takenori : 07:25 PM | コメント (0) | トラックバック

MSDNをインストール

COMの部分が日本語化されていないかなぁと言う淡い期待を抱きながらMSDNの2004/07をインストール。
やっぱり、英語のままだった。
仕方ない、英語を読むか。

吉里吉里のコードを見て、IStreamについてはだいたいわかったが、IMonikerについては手掛かりがない。
MSDNを入れるついでに一緒に入っているSampleソースもコピーしておいたので、Grepをかけるが、それっぽいのは見つからなかった。
ふと思い立ち、DirectShowのサンプルに対してGrepをかけたら、いっぱい出てきた。
モニカはCOMオブジェクトを一意に識別する仕組みっぽい。
で、マルチメディア ストリーミングで使われるモニカはデバイス モニカかファイル モニカとなっている。
モニカはよくわからないし、いろいろと面倒だなぁ。
とりあえず、マルチメディア ストリーミングはほっとくか。

メモ (ちょっと関係ない)
DirectShowのビデオキャプチャプログラミング

投稿者 Takenori : 01:23 PM | コメント (0) | トラックバック

August 13, 2004

Asyncサンプル

メモリから読み込む場合、このサンプルがほとんどそのままっぽい。
Base部分は吉里吉里と同じ?
とりあえず、memfileのソースを読むが、やっぱり簡単そうだ。
でも、BaseやFilterを見ると・・・って、いつものようになるのだろうか?

Filterを軽く見た感じではそうでもなさそうだ。
Baseがいろいろとやってくれているのだろう。
でも、Baseのソースを見ると・・・いろいろとややこしそうなことをしている。
面倒だなぁ。
Baseはあんまり見ずに、そのまま流用でいいかな。

吉里吉里ソースを見直すとIStreamを渡すようになっている。
つまり、メモリ用のIStreamのなんかを作ればいけるのか?
ファイル用のIStreamはSHCreateStreamOnFileをコールするだけでいけるようだ。
でも、COMってどうやって作るんだっけ?
すっかり忘れてしまった。

投稿者 Takenori : 09:23 PM | コメント (0) | トラックバック

IDLファイル

COMのインターフェイスを定義(宣言?)したIDLファイルがあることを思い出した。
IMpegVideoDecoderのインターフェイス定義もあるかと思い、grepをかけたが見つからなかった。
IMpegVideoDecoderに関する情報は全くないなぁ。

投稿者 Takenori : 06:27 PM | コメント (0) | トラックバック

マルチメディア ストリーミング

IDirectDrawMediaSampleAllocatorのことについて調べていて、
IDirectDrawMediaStreamを発見する。
どうやら、IDirectDrawMediaSampleAllocatorを使うには、IDirectDrawMediaStreamを使わなければならいなような雰囲気だ。
しかし、IDirectDrawMediaStreamはインターフェイス一覧にない。
なぜだ?
うーん、MicrosoftのDirectDrawをなくしたいと言う思惑だろうか?
まあ、使用禁止インターフェイス一覧になかったら気にせずに使おう。

そして、IDirectDrawMediaStreamの項を見ているとマルチメディア ストリーミングへのリンクがあった。
マルチメディア ストリーミング?
そんなのあったっけ?と思ったら、ヘルプ付録にあった。
うーん・・・普通のところに書いていて欲しかった。
まあ、とにかくマルチメディア ストリーミングの項を読まねば。
・・・
例によって例のごとくよくわからない。
いや、よくわからないと言うか、今回のような構成で使用できるのかどうかがわからない。
マルチメディア ストリーミングはどうやらファイルを与えて、任意のサンプルを得るための仕組みのようだ。
つまり、適当につなげて・・・と言うような用途には利用できないのかもしれない。

マルチメディア ストリーミングの入力はファイルかモニカを使用するようだ。
モニカについてはよくわかっていない。

調べた結果、オーバーレイかマルチメディア ストリーミングを使用しないとDirectDrawへ直接書き込めなさそうだ。
しかし、MPEG-1 ビデオ デコーダ フィルタの
> このフィルタは、DirectDraw サーフェスへのデコードも可能である。
と言う一文がかなり気になる。
何らかの方法でDirectDraw サーフェスへ直接書き込めそうなのだが・・・
とりあえずは、そのことを気にとめておいて、メモリ上からの再生とオーバーレイの切り替えを先にやろう。
オーバーレイ、マルチメディア ストリーミング、モニカはその過程でわかっていくだろう。


メモ
DirectShow の ページ

投稿者 Takenori : 09:40 AM | コメント (0) | トラックバック

August 12, 2004

DirectDrawSurfaceへの描画方法の調査

ビデオレンダリングフィルタを使えば、DirectDrawSurfaceに描画出来るようだが、そうしてしまうと、描画タイミングを得る方法がわからない。
あるのかもしれないが、調べた限りではわからなかった。

IDirectDrawMediaSampleAllocatorとIDirectDrawMediaSampleを使えば、デコーダーにDirectDrawSurfaceへ直接描画させられそうであるが、これはどうすればいいのだろうか?
どのメディアタイプで接続すれば良いのかがわからない。
アロケーターに呼び出しがかかるのは、レンダー接続時のCheckMediaType呼び出しより後だったはず。
つまり、その時点で受け入れるメディアタイプをどうするかが問題だ。
いや、他ので実験してみればよいのか。
いけるかも。

投稿者 Takenori : 07:09 PM | コメント (0) | トラックバック

Oleview

IMpegVideoDecoderのことが気になったので、OLEViewで調べてみるが、インターフェイスが見つからなかった。
ハテ?
DirectShowのインターフェイスはどこにあるんだろう?
もちっと真剣に探すかな。
うーん、IMpegVideoDecoderにはそれほど関心がないので、ほっとくか。

OLEViewのことはすっかり忘れていたが、なぜか突然思い出した。
COMのことに関しては、Visual C++プログラマのためのCOM入門がそこそこわかりやすいかも。
まあ、私はmacromedia DirectorのMOAで泣いたので、COMについてはそこそこ知っていたから、本当にわかりやすいかどうかはわからなかったり。
でも、OLEViewについての解説があるので、それはそれで良いかも。って言うか、この本の存在自体しばらく忘れていたんですが。

次こういうことがあったときにOLEViewをすぐ思い出せるようにここにメモ。
って、そん時はこの文書も忘れてそう。

投稿者 Takenori : 06:56 PM | コメント (0) | トラックバック

Namazu Perl5.8で動かず

DLしたメーリングリストログにNamazuをかけようとしたが、すぐ落ちてしまった。
やはり、Perl 5.8系では動かないのだろうか?
いろいろと調べたりするのが面倒なので、Perl 5.6系が入っている方のマシンでインデックスを作ることにした。
インデックスさえ作ってしまえばこっちのものだしね。

投稿者 Takenori : 11:42 AM | コメント (0) | トラックバック

メーリングリストのログDL

やはり、DirectShowのメーリングリストのログから検索したくなり、メーリングリストのログをDLすることに。
DLするために簡単なPerlスクリプトを書く。
以下のような感じ。

※このままでは実行できません。
これでしばらく実行しておけばローカルにログのコピーが置ける。
ローカルにたまったらNamazuでインデックスを作ろう。


$target_url = 'www.freeml.com';
$base_url = 'http://www.freeml.com/message/directshow@freeml.com/';
$target_object = 'message/directshow@freeml.com/';
$start_num =;
$end_num =;

use Win32::Internet;

local $INET = new Win32::Internet();    # WinInetのインスタンスを得る
if( defined( $INET ) ) {        # 成功
   local $HTTP;
   $INET->HTTP( $HTTP, $target_url );  # HTTPのインスタンスを得る
   if( defined( $HTTP ) ) {            # 成功
       $HTTP->ConnectBackoff(2000);    # リトライの間隔 (in milliseconds)
       $HTTP->ConnectRetries(100);
       $HTTP->ConnectTimeout(10000);   # in milliseconds
       $HTTP->ControlReceiveTimeout(10000);
       $HTTP->ControlSendTimeout(10000);
       $HTTP->DataReceiveTimeout(10000);
       $HTTP->DataSendTimeout(10000);
       for( $i = $start_num; $i <= $end_num; $i++ )
       {
           print "Reading    page - $i\n";
           $send_command = sprintf("%07d",$i);
           {
               my $REQ;
               $ref_page = "http://" . $target_url . "/" . $target_object . $send_command;
               print "Open " . $ref_page ." ... ";
               $HTTP->OpenRequest( $REQ, $target_object . $send_command, "GET","", "","text/*\0image/gif\0image/jpeg\0\0",INTERNET_FLAG_RELOAD );  # HTTPのリクエストを生成
               if( defined( $REQ ) ) {                     # 成功
                   print "Success.\n Reading...";
                   sleep(1);
                   $REQ->SendRequest();        # リクエストを送る
                   $file = $REQ->ReadEntireFile();         # 返ってきたデータを読む
                   $REQ->Close();                          # リクエストを閉じる
                   {
                       open( FOUT, ">$send_command.html" ) or die "cannot open file!";
                       print FOUT $file;
                       close( FOUT );
                   }
               }
               else {
                   print "Fail.\n"
               }
           }
       }
       $HTTP->Close();
   }
   $INET->Close();
}

投稿者 Takenori : 09:20 AM | コメント (0) | トラックバック

August 10, 2004

高速化への実験

今までのことを整理していてふと気付く。
DirectDraw Surfaceを使えばさらに高速化できるのではないかと。
とは言っても、直接使うことは出来ない。
吉里吉里の仕様上、最終的にはメモリ上にイメージがなくてはならない。
しかし、これは最終的にメモリ上にあれば良いと言うことでもある。
つまり、DirectShowにDirectDraw Surfaceへレンダリングさせ、それを再びメモリへコピーしてこようという作戦だ。
明らかに非効率的な方法のように感じるが、これによって少しCPU負荷が下がる可能性がある。

最近のグラフィックスカードはMPEG再生支援機能という物がだいたい搭載されている。
MPEGのデコードは前フレームとの差分や逆離散コサイン変換などがあり結構重い処理だ。
そして、MPEG再生支援機能とは動き補償やIDCTなどをさすようだ。
当然、MPEGムービーは入力データ量よりも出力データ量のほうが遙かに大きくなる。
あくまで推測だが、、MPEG再生支援機能によって、この少ないデータ量をグラフィックスカードへ送り、グラフィックスカード内で伸張されるのではないかと考えられる。(このようになっていればかなり効率が良い)
つまり、CPUの処理量とメモリコピーの量がかなり軽減されるわけだ。(推測だけど)
しかし、この後でVRAMからメインメモリへのコピーを行わなければならない。
当然これは負荷がかかる。しかも、その後またメインメモリからVRAMへのコピーが発生する。
結局のところハードウェアによってなくなった分とVRAMからメインメモリへのコピーでどちらが重いかと言うことになる。

うーん、微妙ですね。
たいして速くならない気もする。
まあ、興味があるのでちょっとやってみようって感じですね。

投稿者 Takenori : 08:22 AM | コメント (0) | トラックバック

August 09, 2004

ファイルの差し替え

複数ファイルの連続再生だが、どうやらメモリ上からの再生と同時にやった方が簡単そうだ。
ファイルグラフを再構築するのであれば、話は違うかもしれないが、ファイルを切り替えるにはソースフィルタを作らなければならなそうだ。
まあ、メモリ上からの再生もあるので、このあたりのことはあまり調べていないんだけど。
と言うわけで、次はメモリ上からの再生(ソースフィルタ)の作成に移ることにする。
ソースはAsync フィルタ サンプルと吉里吉里のが参考になりそうだ。

ループ再生はイベントさえ実装してしまえば全然余裕と言うか、すでにループ再生しているので、もう、やってもやらなくてもどっちでも同じだ。

何というか、DirectShow一巡りという感じがしてきた。
パーサー、スプリッター、デコーダーは作らないが、両端のフィルタは作る(作った)ので、だいたいの用途では事足りそうだ。

投稿者 Takenori : 06:15 PM | コメント (0) | トラックバック

ソースの整理とイベント化

上下反転の実験用コードの削除と、連続再生用に少しだけコードを整理する。
Texture3Dでは再描画がメッセージではなく、メッセージループでメッセージがないときに描画&Sleepと言う構成だったので、レンダーのDoRenderSampleがコールされ、サンプルが得られた時点でIMediaEventSinkインターフェイスを使ってメッセージを送信するように変更した。( メッセージはOnRenderEndで送る方が良いかも )
なお、定義済みのイベントではそのような目的の物はなかったので、独自に定義した。
ヘルプに独自定義に関する文章は見つからなかったが、DirectShowのイベントが定義してあるEvcode.hにEC_USERが定義してあったので、たぶんこれを使ってユーザーイベントを定義することになっているのだろうと勝手に解釈し、#define EC_UPDATE (EC_USER+1)と定義した。(ウィンドウメッセージにもWM_USERって言うのがあるし)

よく調べるとDirectX8.1の英語ヘルプのには次のように書かれていた。
Filters can define custom events with event codes in the range EC_USER and higher.
どうやら、上記のような使い方で問題ないようだ。

投稿者 Takenori : 04:38 PM | コメント (0) | トラックバック

August 08, 2004

DirectShowメーリングリスト

DirectShowについて語ろうと言う、DirectShow関連の開発に関するメーリングリストがあった。
とりあえず登録しておく。
でも、ログに検索機能がないのですごい見づらい。
途中まで順番に見て行っていたが、見つからずやめた。

何で検索がないんだろう?
MyPageとかに登録すれば使えるのか?
過去ログ全部落として、ローカルでインデックス作って検索するかなぁ・・・かなり嫌だけど。

投稿者 Takenori : 02:40 PM | コメント (0) | トラックバック

デコーダーで上下反転

BITMAPINFOHEADERのbiHeightの項を見ると、
ビットマップの高さをピクセル単位で指定する。biHeight の値が正である場合、ビットマップはボトムアップ DIB であり、左下隅が原点となる。biHeight の値が負である場合、ビットマップはトップダウン DIB であり、左上隅が原点となる。
と書かれている。
つまり、VIDEOINFOHEADERのメンバ、bmiHeader.biHeightをマイナス値にすれば、上下反転は実現できそうだ。
でも、BITMAPINFOHEADERの説明の最初に『AVI RIFFファイルの・・・』とか書かれているが、気にしない。
とにかくやってみよう。

と書いたものの、どこでAM_MEDIA_TYPEを設定すればいいのかよくわからない。
レンダーのSetMediaTypeで指定してみるがうまくいかず。って、よく考えたら、レンダーは自前で用意しているんだから当然か。
他に、レンダーのCheckMediaTypeの中に入れてみたり、アロケーターのAllocでMediaSampleに設定してみたり、GetBufferの中でやってみたり、独自のMediaSampleを作ったりしたがどれもうまくいかない。
ネットでいろいろ検索するも有用な情報は得られない。
で、再度いろいろと考えてみる。
Allocの中やCheckMediaTypeの中で行われるのはおかしい。
接続時か、それより前に設定されるべきだ。
そうしないと使えるかどうかわからないはずだ。
そして、ピンのところを見ていると・・・Connectの引数にAM_MEDIA_TYPEを渡せるようになっている!これだ!

途中の試行錯誤は割愛して、手順を説明すると次のようになる。
まずは、普通に接続する。
CheckMediaTypeの時に渡されるMediaTypeで、OKを返した物のコピーを取っておく。
接続が完了したら、デコーダーとレンダラーの接続を切る。
コピーしておいたMediaTypeのVIDEOINFOHEADERのメンバ、bmiHeader.biHeightを *= -1;してマイナスにする。
そして、このMediaTypeを使い、Connectする。
すると、上下が反転された(画面上では反転していない)画像が出てくる。※普通のBMPは上下が逆に格納されている。つまり、上下反転したら反転していないBMPが得られる。

同じ箇所でrcTargetを使えば、拡大縮小なども出来るかと思ったが、うまくいかなかった。
このあたりはまだまだ調査が必要そうだ。もしかしたら、デコーダーでは出来ないかもしれない。でも、効率面を考えると出来るようにしてあってもおかしくないが・・・
まあ、とりあえずは上下反転できたのでよしとしよう。
次は複数ファイルの連続再生だな。
グラフを一から再構築すればすぐに出来そうだが、そうせずに出来ないかなぁ。
ま、いろいろ調べよう。

投稿者 Takenori : 02:03 PM | コメント (0) | トラックバック

August 07, 2004

デコーダーがダイレクトSurfaceに書き込み

アロケーターをCBaseAllocatorから継承するように書き換え、いくつかのメソッドを変更。
なんとか、デコーダーがダイレクトにSurfaceへ書き込んでくれるようになった。
負荷もだいぶ軽くなった。
まあ、640*480*32bppのコピーが1回減ったので当たり前と言えば当たり前。
でも、出力はBmp形式なので、上下逆だ。
吉里吉里はどうなんだろう?
たぶん、上下反転にはなっていないだろうなぁ。
ドキュメントを見た感じもそうはなっていなさそうだし。
吉里吉里より先にDirectShowで上下反転せずに出力できないか調べるか。
出力先の矩形のTopとBottomを入れ替えると逆転しないかな。
マイナス値を使ったり、上のような方法で反転する仕様って言うのは時々あるし。
StretchBltとかそうだし。

で、いろいろ試すが、どこでメディアタイプを設定するのかよくわからない。
もちっと真剣にヘルプを読むかな。

投稿者 Takenori : 10:08 AM | コメント (0) | トラックバック

ピンとアロケーターの実装

参考ソースを今まで作ってきた物にあうように若干修正して(ほとんどそのまま、でも、オーバーライドした関数は単にスルーようにした)、ビルド。
デバッガで動きを追ってみる。

次は、アロケーターがDirect Draw Surfaceを返すように改造だ。
いよいよ核心ですな。
でも、CMemAllocatorではなく、CBaseAllocatorを継承した方がよい気がするなぁ・・・
メモリは確保せず、持っているサーフェイスのポインタを渡すだけだし。
でも、要求されたサイズがサーフェイスのサイズを上回っていたらどうするか・・・
エラーにするか、それともメモリ確保をして、多段コピーするようにするか。
デコーダーに渡す時に丸める処理を入れるから、上回ることはそんなに多くないだろうし、エラーにしても他のアロケーターが使われるだけだろうから、たいして問題はないでしょう。まあ、そのときは多段コピーで性能が落ちるけど致し方ない。

投稿者 Takenori : 08:36 AM | コメント (0) | トラックバック

さくっと分離

レンダーを別ファイルに分離して、ソースの整理を行って、ビルドが通った。
グローバル変数はそのまま。
やっぱめんどうだし、そんなに多くないから今はいいやって感じで。
で、次はアロケーターとピンですね。

投稿者 Takenori : 07:50 AM | コメント (0) | トラックバック

August 05, 2004

ソースの整理

レンダーを別ファイルに分離して、ソースの整理を行う。
でも、サンプルとはいえ、グローバル変数多すぎ。
ちょっと考えないと。
リファクタリング・リファクタリング。

投稿者 Takenori : 10:05 PM | コメント (0) | トラックバック

最適化にハマる

このページこのページを読みながら最適化について少しはまる。
と言うか、元々そう言うことにハマりやすいたちで、今回も例に漏れずハマりかけております。
でも、まだ傷は浅くもう元の道に戻っています。
と言うより、コード量が少なくて最適化の余地がまだあまりなかったり。

投稿者 Takenori : 09:33 AM | コメント (0) | トラックバック

ピン、アロケーターの振る舞いの確認

次の手順で進める。
Texture3Dのフィルター部のソースを分離&整理し、ピンとアロケーターを実装する。
ただし、まずは分離&整理を行う。
次に何もしないラッパーとして働く ( オーバーライドするが何もしない ) ピンとアロケーターを作り、動作を確認する。
後、もしかしたら、メディアサンプルも実装する必要があるかもしれない。

投稿者 Takenori : 06:50 AM | コメント (0) | トラックバック

August 04, 2004

Texture3D(改)をメインに

サンプルのTexture3Dを改良していった方が簡単だと思い、その方向で行くことにした。
DirectDrawでいろいろやったのは何だったんだろうと言う考えが、頭をよぎるが気にしないことにする。
で、まずは必要のない3D関連の処理を取り、TextureをSurfaceにする。
デコーダーの出力形式をRGB32にするのは以外と簡単で、CheckMediaType内で受け入れる形式をRGB32にすれば、RGB32で出力してくれるようになった。
それと、MPEGファイル名が直値だったのをプログラムの実行ディレクトリ+ファイル名(直値)とした。
とりあえず、これでだいたい準備は整ったかな。
ヘルプも読んでだいたい理解したので、次はピンとアロケーターの作成だな。

投稿者 Takenori : 09:50 PM | コメント (0) | トラックバック

バージョン管理

サンプルをいろいろといじるようになってきたので、バージョン管理でもしようと思い立ち、TortoiseSVNをさわる。
リポジトリの内容を見やすいようにViewCVSを入れようとここここを見る。
参考にしてインストール。
おお、いい感じに表示された。
RapidSVNも入れようとしたが、なぜかDL出来なかった。後でまた試すことにする。
WinMergeをまだ入れていなかったので、ついでにインストール。
マージするときのプログラムに設定しておく。

メモ
TortoiseSVN ユーザガイド

投稿者 Takenori : 10:38 AM | コメント (0) | トラックバック

拡縮デコード

デコーダーに直接指定したバッファへ書き込みを行ってもらうことは可能なようだ。
それには、自前のアロケーターを準備すれば良いようだ。
任意位置への拡大縮小描画もできそうだ。
でも、任意位置って使えるのかなぁ・・・
まあ、使う場面はあることはあるか。
別にそうしなくてもいいような気もしないでもないが。

投稿者 Takenori : 09:17 AM | コメント (0) | トラックバック

シーケンス図が書きたい

DirectShowのヘルプのデータフローの項を読みながら思う。シーケンス図が書きたい。

Visioがあれば、あまり好きではないがVisioでさくっと書くのだが、あいにく持っていない。
で、やっぱIIOSSかなと思い。
おもむろに最新版JavaをDL。もちろんSDKの方。
で、次にIIOSSをDL。
Javaをインストールした後、IIOSSのインストール方法を見ながらインストールする。
IDEはヒープサイズの初期化のところでエラーが出て起動できなかったが、とりあえずはMEFが使えたらよいので気にしないことにした。
これで、いろいろと図が描けるぞぅ。

投稿者 Takenori : 08:45 AM | コメント (0) | トラックバック

August 03, 2004

Texture3D(改)の最適化

Texture3D(改)は重い。
MPEG Video Decoderから得たIMediaSampleをテクスチャにコピーし、それをまたバックバッファーにコピーしているので、かなり重いだろう。
でも、吉里吉里でも似たようなことになる。

まずは、テクスチャへのコピー処理を小手先で最適化する。少し軽くなった。でも、それほど軽くない。と言うか、重い。
MPEG Video DecoderからRGB24で受け取り、それをX8R8G8B8にコピーしている。
はじめから、MPEG Video DecoderにX8R8G8B8で吐いてもらえば、もっと処理を軽くできるのではないだろうか?
ヘルプのMPEG-1 ビデオ デコーダ フィルタ項を読む。
MEDIASUBTYPE_RGB32がサポートされている。
と言うことは、何とかなりそうだ。
さらに次のような記載がある。
このフィルタは、DirectDraw サーフェスへのデコードも可能である。
DirectDraw サーフェスが使えれば、このコピー処理の固まりは全部すっ飛ばせるのか・・・でも、今回は出来ない。ささっと諦める。

さらによく考えると、MPEG Video Decoderに途中のバッファに書いてもらえばよいのではないだろうか?
そうすれば1回コピーがなくなる。つまり、コピー処理が2/3になる。これはいい。
MPEG Video DecoderにRGB32で中間バッファに書き込んでもらえれば、ほとんどの処理はしなくていい。
吉里吉里ではこの中間バッファがレイヤーに当たるだろうから、かなり手間いらずだ。
でも、拡縮する場合は・・・ぐぉ、中間バッファに書き込んでもらう部分は複雑になりそうだ。
しかし、コピー回数を1回増やすのは避けたい。
まずはMPEG Video Decoderに直接書き込んでもらう方法を調査だ。
軽く調べるがこれはちょっと本腰を入れてヘルプを読まねばならなそうだ。
がんばって読むか。

投稿者 Takenori : 08:45 AM | コメント (0) | トラックバック

DirectShow 実験プログラム第1段階 - 3

長くなったので、またまた分割。
ある程度やった内容に沿って、分けた方が良かったのではないかと、反省を始める。
まあ、今後はそうしようと言うことで今回はもう気にしない。
でも、この実験プログラムうんたらの前は分けている。
おいおい退化かよ。

投稿者 Takenori : 08:23 AM | コメント (0) | トラックバック

DirectShow 実験プログラム第1段階 - 2

かなり長くなってしまったので分離する。
なんか計画性は皆無だな。

メモ
超高速描画の謎--以前読んだ気もする・・・

DirectShowを扱う部分のコードを吉里吉里のからコピペして、改良していく。
とその前に、コメントとルールを決めておくことにした。
基本的にはDoxygenで自動的にドキュメント(関数リファレンス)を吐かせたいから、Doxygenの書き方には従う。
で、後は項目や細かい書き方だな。
以前、会社で作ったものを参考にしながら、自分の書きたいように作り直す。(こうゆう規約を作るのは、自分が多かったなぁ・・・)
ヘッダーコメントは//スタイルよりも/**/の方が書く量が減るし、書き始めが左に少しずれるので/**/を使うことにした。
そんな感じでだいたい決めた。
そのうち内規として上げておこう。

で、早速コーディングだと意気込んで。
まずはプロジェクトにDirectShowに必要なライブラリなどを加える。
そして、コーディング・・・よくわからない。
ヘルプとサンプル、ソースコードを何度も見直す。
そのうち何とかわかってきた。
とりあえずここにある程度まとめる。

吉里吉里のコードIStream周りを追う。深い。止める。
今回は、ファイルが独立しているので、IFileSourceFilterですませることにした。
ここでふと、Texture3Dを改良したプログラムで音が鳴っていなかったことに気付く。
そこで、GraphEditでシミュレートしようと思うが、独自に拡張したフィルタを追加する方法がわからない。GraphEditのヘルプを見ればいいんだろうが面倒だなぁと思っていると、実行中プロセスのフィルタグラフを見る方法があると書かれている。
そのためには、実行中オブジェクト テーブル (ROT)にプログラムで登録する必要があるらしい。
ここってハッと気付く、Texture3DのソースでなんとかROTと言う関数があって、よくわからない処理をしていたことを。
そう言うことだったのか。
今後は、DirectShowのプログラムを書くときは、デバッグ用にROTへの登録処理を書くことにする。
ちょっと話がそれたが、Texture3Dではそのままでグラフを見ることが出来るようなので、GraphEditで見る。
サウンドの出力がない。
とりあえず、練習用にこれにサウンドの出力を追加してみるか。

まず、DirectSoundのフィルターがなんかよくわからなかったので、IAMDirectSoundかな?と思い、おもむろにグラフビルダーにQueryInterfaceしてみる。後で気付くが、これははっきり言ってアホな行為です。
たぶん、IAMDirectSoundはフィルターではありません。DirectSoundフィルタのインターフェイスの一つです。
しかも、IGraphBuilderにQueryInterfaceしても見つからないと思われる。
まあ、このあたりのことはさらに理解が深まったときに書くとして、結果としてどうやったかを書きます。
CoCreateInstanceでCLSID_DSoundRenderを使い、DirectSoundフィルターを生成します。
フィルタグラフにDirectSoundフィルタを追加します。
MPEG-I Stream SplitterフィルタをフィルタグラフにFindFilterByNameで見つけます。
後は、両者のピンで合致するものを検索してつなげればできあがりです。
見事に音が鳴りました。
にしても、インターフェイスの継承関係を表したクラス図と、各インターフェイスが所持しているインターフェイスがわかる図がほしいなぁ。
どこかにないだろうか?
昔、macromedia DirectorのXDKを使ってXtra(プラグイン)を作るために、そんな感じの図を書いた記憶が・・・
DirectShowで似たようなものを書くのはちょっとしんどいな。便利そうだけど。
落ちていないかなぁ・・・うーむぅ。
まあ、それはいいとして、この実験でDirectShowについての理解がかなり深まった。

続く・・・

投稿者 Takenori : 07:00 AM | コメント (0) | トラックバック

August 02, 2004

DirectShowっていったい・・・

私は馬鹿なのだろうか?
DirectShowのヘルプとサンプルを見ると何となくわかったような気になる。
でも、コーディングの時になると、やっぱりわからない。
たぶん、それでもほぼ期待した動作をするコードを書くことは出来るだろう。
何かが引っかかる。

グラフビルダーにムービーファイルを渡すと、最も基本的な構成でフィルタグラフを構築してくれる。
自分で構築したいときは、AddFilterを使ってフィルタを追加し、ピンを接続する。
でも、ピンの接続先は指定しない。勝手につないでくれる。
よくヘルプを見るとメディアタイプを指定することで、グラフビルダは正しい位置にフィルタを挿入できるとある。

GraphEditを少しいじってみて、ヘルプを読み直す。
ああ・・・、了解了解。
よく見ると接続先を指定している。
もう少し実験すれば確証が得られそうだ。

Texture3Dサンプルの場合
まず自作のCTextureRendererをグラフビルダーにAddFilterで追加している。
次にグラフビルダーのAddSourceFilterをコールすることで、ファイルを渡されたグラフビルダーがメディアを理解し、残りのフィルタグラフを自動的に構築するようにしている。この時点ですべてつながっているのではないかと思われるが、サンプルを見た感じでは、つながっていないようだ。
そして、CTextureRendererの入力ピンをCTextureRendererからFindPinで取得、ソースフィルタの出力ピンをソースフィルタからFindPinで取得し、その2つのピンをグラフビルダーのConnectでつなげている。Connectは必要であれば、間に適切なフィルタを挿入する。
つまり、グラフビルダーがどこまで自動的に構築できるかをよく認識し、自動的に出来ない部分を手動でつないでやる。と言うことのようだ。

IGraphBuilderとIFilterGraphで、フィルタグラフへのフィルタ追加&グラフ構築ができる手は限られている。
IFilterGraphはAddFilterとConnectDirectの2つ。
IGraphBuilderはConnect、Render、RenderFileとAddSourceFilterだ。

ちょっとメモ
メリット値
モニカ
続く・・・

投稿者 Takenori : 05:29 PM | コメント (0) | トラックバック

August 01, 2004

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 : 07:10 AM | コメント (0) | トラックバック

バージョン管理システムについてのメモ

使ったことがあるものと、これから使おうとしているものを比較してみる。
ただ、使ったことがあるものは少々バージョンが古かったりするので、現在のものとは違うかもしれない。
後、あんまり詳しく比較はしない。
と言うか、最もよく使う、チェックイン、チェックアウト、ロック、ロック解除ぐらいしか比較していない。

Visual SourceSafe 6.0
チェックアウト&ロック、チェックイン&ロック解除を持つ。
チェックアウトするとロックがかかり、チェックインするとロックが解除される。
チェックアウト以外に取得というものがあり、ソースはこれで取ってくる。
取得したソースは読み取り専用属性が付く。
編集する際はチェックアウトする。すると、ソースの読み取り専用属性が解除され、リポジトリ上のソースはロックされる。
編集が終わったらチェックインする。すると、ソースに読み取り専用属性が再び付き、ロックが解除される。
読み取り専用属性はローカルで簡単に解除できるけど、そんなことをしてもあんまり意味がないのでしない。
説明を読んでわかる通り、小規模開発向け。
でも、作りがシンプルな分使いやすい。
チェックアウト&ロックをした人と管理者が休むと作業が止まってしまうこともある。あんまりないけど、その時はとりあえず叫ぶ。
ただ、マージがほとんど発生しないので、精神的に良い。
マージは非生産的な作業の雰囲気を漂わせている上に、かなりの集中力がいるので、ファイル数が多いと相当辛い。

StarTeam 4.2
チェックイン、チェックアウト、ロック、ロック解除を持つ。
チェックイン、チェックアウトとロック、ロック解除が独立している。
当然、ロックしていないと、他の人が同じソースをチェックインして、マージが発生することがある。
ただし、生産性を下げないためにロックはあまりしない。
そのためマージ作業に遭遇するが、それは諦めるしかない。
もし、他の人が同じファイルをいじっているのを発見したら、出来るだけ早くmakeが通る状態にしてチェックインするのが吉。
そうすればマージ作業から逃れられる。チェックインは早い者勝ちなのだ。とにかく細かく早くリリースしよう。
ただ、焦って致命的なバグを入れてしまわないようにしよう。そんなことをしたら、かなり非難されてしまう。それと、チェックインを急いでいるのは出来るだけ周りに悟らないようにしよう。何食わぬ顔をしながら、素早くコーディングするのだ。
また、周りがどのような作業をしていて、どのファイルをさわっているかに常に気をつけておこう。同じファイルをいじる時期は出来たらずらしたい。かち合う場合はとにかく素早くコーディングだ!
また、ロック機構があるので、担当者に休まれたら叫ぶという状況は発生しうる。
なんか、いいとこなしのような印象を与えてしまうかもしれないが、実際はそんなことはない。
いろいろと機能盛りだくさんだし、それほど悪くはないシステムだ。
にしても、StarTeamってBorlandだったのか。違ったような気がしたが。
そもそも私が使っていたのは4.2とだいぶ古かったので、変わってしまったのかもしれない。

Subversion, CVS
コミット(チェックイン)、チェックアウトを持つ。
まだ使ったことはないので、よく知らない。
ただ、ロック機構がないので担当者不在で叫ぶことはない。
それに、フリーだ。
ただし、CVSはテキストを扱うことを主眼に作られているため、制止画や動画などの扱いは苦手らしい。
Subversionはマニュアルによるとバイナリファイルもうまく扱うようだ。
なお、この項は今後使っていくことで書き換えるかもしれない。

マージへの福音
辛く不毛なマージ作業。そのマージ作業を劇的に楽にしてくれるツールがある。
WinMergeだ。日本語版はこちら
このツールがあるとマージはかなり楽だ。一度使うとやめられない。
とりあえず、マージする予定があるのならインストールしておこう。
テキストのdiffをとるにも使えるし。

投稿者 Takenori : 05:57 AM | コメント (0) | トラックバック

boost regex++をBCB6に入れる

boostを取ってくる。
展開して、libs/regex/build に移動して、

make -fbcb6.mak
make -fbcb6.mak install

boost以下のインクルードファイル類はBCBのIncludeディレクトリーへ手でコピー。(なぜmake installでやってくれないのだろうか)

でも、makeはBorlandのやつが使われるようになっていたのか。って、他のmakeはまだ入れていないか。
後、実際に使うのはもう少し先になりそうだ。

投稿者 Takenori : 12:58 AM | コメント (0) | トラックバック

ファイルの解凍

+Lhacaは時々解凍できずに落ちることがある。
今日はbz2を解凍しようとしたら落ちた。
少し前は1GB超のファイルを解凍しようとしていたら落ちた。

で、cygwinでも入れるかー、とやや落胆しながら考えていたのだが、ふとeoを入れてみた。
すると難なく解凍できた。
解凍はこれからeoにするかな。
+Lhacaは圧縮用だ。

ファイルが壊れていないかどうか確かめるためにMD5を確認する必要があった。
特に何もツールを入れていなかったので、Perlで組むかと、やや面倒臭げに考えるが、以前コマンドラインのツールを会社でDLして使ったことを思い出す。
早速ググって見つける。
これ
出来た出来た。

投稿者 Takenori : 12:47 AM | コメント (0) | トラックバック

July 31, 2004

Subversionのインストール

ダウンロードしたのはsvn-1.0.6-setup.exe。
インストールページを探すが、Windows上でのSubversionのインストールを解説したよさげなページは見つからなかった。
でも、インストーラーがあるので実行すればよいかと思い実行。
Nextを押しまくっていたらインストール終了。
で、どうするのさ?
このページを見て、自分のPC内のコンフィグを探すが、見つからず。
C:\Documents and Settings\ユーザ名\Application Data\Subversionってフォルダなんてないぞ。
よくわからないがSubversion によるバージョン管理のインストールの部分から少し読んで、おもむろにリポジトリを作る。
そしたら、C:\Documents and Settings\ユーザ名\Application Data\Subversionが出来ていた。
これで上のページと同じようになったのでこのまま進められる。

Apacheの設定をしてブラウザから見られるようになった。
ただし、Subversionの後半の設定はまだ。
TortoiseSVNをインストール。
ViewCVSも入れたいと思うが・・・Pythonが必要なのか。
面倒なのでまた今度にする。
Pythonも面白そうなので一度遊んでみたいが・・・

とりあえずはこんなところか。
DirectShowで遊びたいし。

投稿者 Takenori : 06:49 PM | コメント (0) | トラックバック

バージョン管理について悩む

別に適当にやっていても良いのだが、後のことを考えるときちんとやっておいた方がよいだろうということで、バージョン管理ソフトを入れることを考える。
真っ先に思いついたのは、やっぱりCVSだ。
でも、subversionも気になる。
Apache2も入れていることだし、subversionにするか。(すごい安直です)

そういえば、Apache2なんかのインストールメモを残しておくのを忘れていたのでここにメモ。まあ、こういうのはいっぱいあるから別にここに書いとかなくてもいいけど、自分が一番忘れそうだからね。
Perl
Namazu, kakashi, seach-s
MySQL
WinへのApacheインストール方法
mod_phpインストール方法

後は関連する記事などを
Apache2.0関連記事
WebDEV関連記事
Subversion関連記事
別に一覧にしなくても、リンクはつながっているんだけど、一応。

Apache2を使う時、Perlは5.8系を使わないといけないようだ。
で、Perl 5.8系とApache2をインストールした。
NamazuはPerl5.6以上と書いてあるが、以前上位バージョンを使った時はうまく動かなかったのだが、大丈夫だろうか?
まだNamazuでインデックス作っていないので何とも言えないが・・・、うまくいかなかった時はどうするかなぁ。
------以前のメモ書きコピー終わり

で、まずはWebDAVを試してみる。
とりあえず、このページを参考に設定してみる。
日本語ファイル名対応(mod_encodingの導入)だが、何もしなくてもうまくいった。
インストールしてあるApache 2.0.50なら大丈夫なのだろうか?
それとも、利用環境がWinだけだから大丈夫なのか。
@ITの記事にもうまくいく場合といかない場合があると書いてあるし細かいことは気にしない。
mod_encodingの最新版がApache2.0.48用となっていて、バージョンが少し異なるのも気になるので、とりあえず入れないことにする。
まあ、subversionとか入れて問題が出てきたらインストールすることにしよう。

そして、WebDAVを使ってみた感じだが、いい感じだ。
普通にWebフォルダに設定して使ったのだが、ローカルと同じような感覚で使える。
Windowsの共有じゃなくて、こっちをメインに使った方がよいかなぁと思ったりもするが、よく考えるとどっちも同じだな。

次にsubversionインストールするためにをここからDL。

投稿者 Takenori : 05:47 PM | コメント (0) | トラックバック

DirectShow 実験プログラム作成開始

DirectShow 実験プログラム作成開始

Direct Showのヘルプで関係有りそうなところを読んでみた。
何となくわかったので、次は実践。
で、これから作るプログラムの簡単な使用を書いてみる。

---第1段階---
Direct DrawとDirect Showを使う。
Direct Drawのバックサーフェイスに直描きする。

---第2段階---
複数のMPEGファイルをつなげて再生する。(出来れば切れ目なく)

---第3段階---
[通常再生|2回ループ再生|通常再生]と言った感じで、ループさせる。

---第4段階---
オーバーレイとサーフェイス直描きの切り替えが出来るようにする。

---第5段階---
メモリ上へのプリロードしてから再生を開始する。


とりあえずは、上記のような仕様で徐々に拡張しながら実験(学習用)プログラムを作っていく。
まあ、上記のようなのが作れれば、そこそこDirect Showに関する知識も深まっていることでしょう。

投稿者 Takenori : 05:46 PM | コメント (0) | トラックバック

July 29, 2004

IRC チャンネル?

IRC チャンネルとはなんだろう?
初めて聞く言葉。とりあえず、ググる。
上2件のページで調べてみる。
IRC普及委員会
IRC users in Japan Home Page
どうやら、インターネットを使ったチャットシステムのようだ。
httpとかtelnetとかftpとかそんなのの一種だろう。細かいことは気にしない。
次にクライアントソフトを落とす。
TakIRCをインストールして使ってみる。
なんかよくわからない。というより、私が全然理解していないようだ。
吉里吉里のページでは、irc:#kirikiriirc にリンクが張られている。
だから、サーバーにirc:#kirikiriircやirc.kirikiriircなどいろいろと試すがうまくいかない。
よくわからないので、もう一個ダウンロードしてみた。
CHOCOA
そして、さらに調べる。
国内サーバーリストというものがあった。
irc.huie.hokudai.ac.jp
irc.media.kyoto-u.ac.jp
irc.tokyo.wide.ad.jp
irc.fujisawa.wide.ad.jp
irc.nara.wide.ad.jp
irc6.nara.wide.ad.jp
wwwの部分をircに変えたアドレスが基本のようだ。より正確に言うなら、サブドメインで切り替えているようだ。
で、#kirikiriirc はどこかのサーバーのチャンネルらしい。
上のアドレスのいくつかと、TRPG.NETのサーバーに#kirikiriircというチャンネルがないか探すが見つからず。
吉里吉里ページのアドレスにIRCをつけてirc.kikyou.infoとしてみるがつながらず。
いったいどこのサーバーに#kirikiriircはあるのだろうか?
---ちょっと追記
コメントにも書いたのですが、よくよく考えたらここにも書いといた方が良いと思ったのでここに追記。
irc.*.wide.ad.jp は相互接続していますので、どれにつないでも #kirikiriirc チャンネルに入れるはずです。
chocoaならサーバを適当に選びまして「コマンド」から「チャンネルに入る」で「#kirikiriirc」と打ち込みますと吉里吉里チャンネルに入れます。
とのこと、なるほど。
上に書いたアドレスの2個目までしか試していなかったかも。
もう1個試していれば見つかっていたのか。
確認すると、irc.tokyo.wide.ad.jpは試していた。
といっても、チャンネルリストを表示で見ただけだった。
で、チャンネルリストでは表示されていない。
チャンネルへ入るで#kirikiriircと入力すれば入れた。
なるほど、そういうことだったのか。

投稿者 Takenori : 09:25 PM | コメント (3) | トラックバック

DirectShowで実験-サンプルの改造

Texture3Dサンプルとヘルプでしばらく格闘したところ、DirectShowはDoRenderSampleを勝手に呼び出すようだ。(CTextureRendererはCBaseRendererを継承しているので)
そして、CTextureRenderer::DoRenderSampleではテクスチャをロックしてビデオの画像をテクスチャへコピーしている。
つまり、テクスチャをバックバッファにコピーするようにすれば、とりあえず目的は達成できそうだ。
とりあえず、あんまり何も考えずにIDirect3DTexture8*をIDirect3DSurface8*にキャストして、CopyRectsでコピー。
エラー。
当たり前か。
次にLockRectでちまちまコピーすることにする。
試してみると、バックバッファのサーフェイスがロックできない。
BeginScene - EndSceneの中でやっても、外でやってもできない。
if( pBackBuffer->LockRect( &lrDest, NULL, D3DLOCK_NOSYSLOCK ) == D3D_OK ) ってやっても if( pBackBuffer->LockRect( &lrDest, NULL, 0) == D3D_OK ) ってやってもできない。
何か特殊な方法があるのだろうか?
ふと、IDirect3DSurface8::LockRectとIDirect3DTexture8::LockRectの引数が違うことが気になる。
IDirect3DTexture8はテクスチャのレベルを指定するパラメタが多い。
そして、IDirect3DTexture8::GetSurfaceLevelというメソッドに気付く。
IDirect3DTexture8::GetSurfaceLevelを使えば、、IDirect3DSurface8*が得られるようだ。
早速、取得してCopyRectsを試す。
エラー。
フォーマットが違うとでている。
バックバッファーはD3DFMT_X8R8G8B8だが、テクスチャはD3DFMT_A8R8G8B8。
面倒なのでテクスチャをD3DFMT_X8R8G8B8にしてしまう。
で、実行。
うまく表示されたが、上下逆だ。
DoRenderSampleの引数のIMediaSampleからGetPointerを使って得られるポインタはビットマップ形式のようだ。(つまり上下逆)
反転させるためにIMediaSample::GetMediaTypeを使って、サイズを得ようといろいろやるが、画像サイズは元々メンバにあった。
m_lVidHeightやm_lVidPitchを使えばよいようだ。
で、ビットマップの方を下からコピーするようにして反転させる。
表示させてみると・・・うまく表示された。
とりあえず、こんなもんかな。
謎がいくつかあるが気にしない。
バックバッファがロックできないのは結構気になるが。
でも、それよりもう少しDirectShowをさわる部分をいじっていかねば。

投稿者 Takenori : 06:25 PM | コメント (0) | トラックバック

DirectShowで実験-サンプルのビルド

実際に実験を行ってから、少し時間が経ってしまったが、メモしておくのを忘れていたので、ここに追加しておく。

まず、やりたいことはオーバーレイを使わずにDirectShowを使ってビデオを再生することだ。
オーバーレイは以前に一度、DirectX7かその辺りの時に、何となく遊んでみたことがある。とは言っても、そのころのことはほとんど忘れてしまった。
そんな感じなので、とりあえずは良さそうなサンプルをDirectX8.1 SDKの中からか探してみる。(DirectX9でもいいのだが、入れてあったのが8.1だったので、そのままにした)
いろいろと見てみたところTexture3Dが一番近そうだ。
Texture3Dはムービーをテクスチャとして使うサンプルだ。
とりあえず、MovTexture3Dと言うフォルダを作り、そこにこの中身をコピーする。
プロジェクトはVC++6の物のようだ。
気にせずダブルクリックしてVC++.NET 2003を立ち上げる。
プロジェクトを変換するかとどうか聞かれたので、すべて変換する。
何はともあれビルド。
> Textures fatal error LNK1104: コンパイラは、ファイル 'libci.lib' を開くことができません。
と出て、失敗。
旧プロジェクトから変換した時、よく出るエラーだ。
LIBCIをリンクしないようにして、再度ビルド。
> Textures error LNK2001: 外部シンボル "_CLSID_FilterGraph" は未解決です。
> ・・・
なんか、リンク時にいっぱいないと言われる。
いろいろと調べたところstrmiids.libを追加する必要があるようだ。
で、追加したらうまくいった。
そうそう忘れていた。
上記のこと以外に、XSDK/samples/Multimedia/DirectShow/BaseClassesをビルドしてライブラリを作っておく必要がある。
これを忘れているとさらにエラーが出たはず。
以上で、とりあえずビルドが通ったので、改良にかかる。

投稿者 Takenori : 05:07 PM | コメント (0) | トラックバック

こういう仕様にしましょう

----以下、W.Dee氏の返答から引用
もし吉里吉里本体に手を加えられるならば、VideOverlayにレイヤへの画像出力機構を持たせるようになるのかな、とか思っています。
VideoOverlay のなんらかのプロパティにレイヤオブジェクトを指定するとそのオブジェクトに動画が出力されるようになると。
いわゆる「オーバーレイ」では無くなるので VideoOverlay という名前とはちょっと乖離してしまいますが、レイヤの指定領域にビデオを勝手に表示する(結果もともとレイヤのそこの領域にあった画像は上書きされる)という意味ではオーバーレイという意味があり、名前はこのままでかまわないとも思います。
----以上、引用終わり
W.Dee氏の考えに沿う形にしよう。
より詳細な仕様は、もうちょっと調査してから決めることにする。

投稿者 Takenori : 01:05 AM | コメント (0) | トラックバック

July 28, 2004

新構成を検討

W.Dee氏の回答を受けて新たに構成を考える。
って、よく考えたら、初期の構成と同じじゃないのかとふと思ったが、気にしないことにする。

1. 関数のプラグインを作ってTJS2のクラスでラップする。
2. 本体に改良を加える。
以上のどちらかで作成することにした。
で、気分的に心地よいのは、やっぱり2.かな。
とりあえずは、本体に改良を加えると言う方向で行こうと決める。

投稿者 Takenori : 11:26 PM | コメント (0) | トラックバック

プラグインのライセンスに関して

いずれlicense.txtに追加されることになりそうですが、念のためここにメモしておく。
------以下、引用
license.txtの「● オープンソース」のにある「ここで流用とは、このソフトウェアの一部が他のソフトウェアに組み込まれること」(tp_stub.h / tp_stub.cpp が他のソフトウェアに組み込まれること)に該当しますが、プラグインについては特にそこで求められているような「このソフトウェアに含まれるソースを使用している旨をドキュメント等に表記することか、あるいは、このソフトウェアの作者に配布を行う旨を事前に連絡し確認をとることの、どちらかあるいは両方」は求めない方向で行こうかな、と思います。
ただし、tp_stub.h や tp_stub.cpp 以外の 吉里吉里のソースコードを流用する場合は別です。

ライセンスに補足が必要ですね。入れておこうとおもいます。

ただプラグインをGPLも適用可能なライセンスにしておかないと、吉里吉里のライセンスとしてGPLが選択されたときにその吉里吉里とはリンクできないことになりますのでご注意ください。
もっともGPLを選択可能にするのは強制ではありませんし、プラグインのソースを公開することでさえ強制ではありません。

# 吉里吉里のライセンスとしてGPLが選択された事例は未だ見かけた事はありませんが

投稿者 Takenori : 11:23 PM | コメント (0) | トラックバック

クラスプラグインに関するW.Dee氏の考え

可能ですが、かなり面倒です。
ソースのtjsNative.hや「TJS2リファレンス」の「基本的な使い方」が参考になるといえばなりますが、これはTJS2をアプリケーションなどに組み込む際の話で、吉里吉里用プラグインではかなり勝手が違います。

ArrayとかDictionaryとかを作るメソッドはプラグイン側に提供されているのですが、
クラスそれ自身、それとクラスからオブジェクトを作る際のベースとなるtTJSCustomObject (TJSにおける生の"Object") がプラグイン側に提供されていないのでかなり難しいです。

# tTJSCustomObject と同じ動作の物をプラグイン側で実装してしまうならば別ですが...

プラグイン側でクラスを実装できるようにするのは、TJS2に予定しているクラス関連の仕様の改良が済んでからと思っていたので、ちょっと現状では簡単にはできないかな、と思います。スミマセン。
--------以上、引用終わり

つまり、止めた方が良いと言うことのようです。
自分がこう返答する場合は、「十中八九、私ならしない」と考えている場合なので、クラスプラグインはあきらめることにする。

投稿者 Takenori : 11:10 PM | コメント (0) | トラックバック

クラスプラグインは可能?

ソースやTJS2のドキュメントを見ていて気付いたのだが、関数プラグインだけではなくて、クラスプラグインも作れるのではないだろうか?
関数プラグインはtTJSDispatchを継承して作る。
実際の処理はFuncCallをオーバーライドする。
そして、それをバリリアント型に変換する。
iTJSDispatch2かそれから派生したグローバルオブジェクトを取得し、そのメンバ関数のPropSetを使い、バリリアント型に変換したクラスを登録する。
そうすることで、グローバルな関数として使えることになるようだ。

そして、ここからはソースやドキュメントからの予想。
PropSetは字句を登録しているのではないだろうか?
登録した字句をnewするとiTJSDispatch2のCreateNewがコールされる。
生成されたオブジェクトのメソッドをコールするとiTJSDispatch2のFuncCallがmembernameを伴ってコールされる。
と言うことは、クラスプラグインも何とかなるのではないだろうか?
ただ、組み込みクラスは継承図の構成が異なっているのが気になる。
ファクトリーパターンやプロキシのような作りになっていると言うことだろうか?
やはり、もう少しコードを追わないと可能かどうかわからないなぁ。

クラスプラグインが使えるのなら、関数をまとめたクラスをTJSで作ると言うことはしなくても良くなる。
当然、その方が自然だし、処理も軽くなるだろう。

ソースを追ってもいいが、聞いた方が早いか。

投稿者 Takenori : 02:05 PM | コメント (0) | トラックバック

関数プラグインの作り方

吉里吉里の関数プラグインの作り方をすでにあるプラグインのソースを追って調べていたのだが、tvp2win32/base/win32/plugin_kit/basetest/Main.cpp を見ると作り方が解説してある。
しかも、Readmeをよく見ると "/base/win32/plugin_kit/basetest/ は、吉里吉里で使用可能な関数を増やすサンプル" と書いてある。
Readmeは読んだつもりだったのだが・・・もっとよく読んだ方が良さそうだ。

投稿者 Takenori : 02:01 PM | コメント (0) | トラックバック

Doxygen

DoxygenGraphvizをインストール。
Latexはインストールが面倒なので入れなかった。
まあ、数式を書かないのであれば、Latexは必要ないのでしばらくは大丈夫だろう。

吉里吉里のソースにDoxygenをかけてみるが結構な量だなぁ。
ある程度分割してかけた方が良かったかも。

投稿者 Takenori : 01:56 PM | コメント (0) | トラックバック

DirectShow

はじめは言いたいことはわかるが・・・なんか漠然としているなぁと思っていたが、ヘルプを読み進んで何となく理解した。
DirectShowは与えられたファイルを元に最も適切だと思われるグラフを構築する。
もし、特殊な用途で使用する時は、グラフから一度フィルタやピンの接続を解除し、再度目的のフィルタやピンを接続する。
と言うことか。

ゲームなどの用途でDirectShowを利用するという似たような状況を解説したページを発見。
軽くふれる程度の内容だが、なかなか良い。

投稿者 Takenori : 01:48 PM | コメント (0) | トラックバック

July 26, 2004

構成

拡張方法としては、次の2つが考えられる。
・本体に変更を加える
・プラグインを作る

しかし、W.Dee氏は定期的に本体の拡張をされているようなので、あまり本体に変更を加えたくない。
そうなるとプラグインとなるのだが、今回のような用途の物はあまり想定されていないようだ。
吉里吉里で使えるプラグインの種類は次の3つ。
・Susie Plug-in (画像読み込みとアーカイブアクセス)
・WaveSoundBufferで再生可能な形式を拡張するためのプラグイン
・そのほかの吉里吉里専用のプラグイン

そして、そのほかの吉里吉里専用のプラグインは次の2つにわかれている様子。
・トランジション用
・関数追加用

以上のことから考えると、
プラグインで提供する。
プラグインはTJS関数追加プラグイン。
となりそうだ。
後は、利便性を考えて、TJSでクラスを作り、KAGプラグインとして提供するとなるだろうか。
なんか、Cで組まれたライブラリのラッパークラスを作るような感じだなぁ。
組込型に比べれば少し重いかもしれないが、たぶん大丈夫でしょ。(根拠なし)

投稿者 Takenori : 05:33 PM | コメント (0)

懸念事項

吉里吉里の掲示板を見ていて気付いたのだが、W.Dee氏も最前面以外にも表示出来るようにすることを検討されているとか。
微妙だなぁ。
まあ、かち合ってもいいか。
気にせず前進あるのみ。

投稿者 Takenori : 05:25 PM | コメント (0)

制限

吉里吉里2/KAG3のムービー機能では次のような制限がある。

・ムービーは常に最前面に表示される。つまり、テキストなどをそれより前に表示することが出来ない。
・通常再生のみサポート。ループ、途中から再生などが出来ない。

基本的に上記制限を解消するために開発を行う。

投稿者 Takenori : 05:16 PM | コメント (3)

Total : Today : Yesterday :