This site hosted by Free.ProHosting.com
Google

DirectShow の ページ


DirectShowとは、MSがDVプレイヤーを提供するために考えたというのは、 言い過ぎか(^_^;)、一応さまざまなメディアを扱うための、新しい技術だそうだ。
Video For Windowsなんかを置きかえる形になるようで、MediaPlayerなんかも この技術の一部です。

このDirectShowを使用したプログラミングに関して、わたしが得た情報等を、 書き留めてみました。結構不定期ですが、チョットずつでも更新していきたいです。

* DirectShowを使用して作成したアプリケーションは、このサイトにあるランタイム (DirectX Media 6.0 Run Time)をインストールする必要があります。

無くなっていますね(^_^;)
ここに飛ぶよう になっています。DirectMediaはDirectXに統合される運命の様ですね。
win98のSecond Editionでは、Runtimeをインストールしなくても動作するようですね。 w2000はどうなのだろう?
* ここにランタイムがありました。多分これでOKでしょう 2000/05/08確認
* さらにさらにDirectShow (DirectX Media)はPlatform SDKに存在している事が 判明しました。うーん、これでこのサイトも無駄にならないですむカモ(^^ゞ
ダウンロードはここから出来ます。 しかし、巨大だ。一応選択ダウンロードできますが、みなさん気をつけて下さいね(^^ゞ

DirectShowに関して思ったこと

DirectShowをちょっとだけ使っているが、本当に資料がないぞ。英語の重要性を説い ておきながら情けない次第だが、はっきりいって日本語の役立つ情報がない。 やはりサンプルを見て、試行錯誤するしかなさそうだ。
しかも、この技術が今後どのようになるのか、果たして生き残るのか、 まったく保証なく、身につける時間を費やしてまで、習得する必要があるのか。
ただ、わたしが思うのは、これはCOMの使い方を学ぶにはもってこいの技術だ ということ。

DirectDrawに関してわたしは何も知らないので、大きいことは言えないが、 これらDirectDraw、DirectX関連は生き残りそうには思える。今ならDirectDrawを 習得した方がいいのだろうが、DirectShowもなかなか面白い技術で、COMがベース にある為、COMを知らないとかなり苦労するが、フィルター・ピンの構成は他の アプリケーションにも応用できそうな考え方で、参考になる


DirectShowのサンプル

さてDirectShowはサンプルが唯一といっていいほどの情報源ですが、そのサンプルを コンパイルしたり、動作確認をすることすらできない場合がある。あるいは、VCのIDEで 動作確認しようにもmakefileでの提供の為、IDEでうまくビルドできないといった 問題もある。 DirectShowを勉強する前にmakefileの中身を知らなければいけないなどということでは、 なかなか先へ進むことができない。
ただ、この場合に参考にできるドキュメントが存在する。
DXMedia/samples/multimedia/dshow/vc5kit/vckit.txt
である。

ここで必要なことは、サンプルをコンパイルする時に必要なbox定義およびリンク時に 必要なライブラリです。
特にフィルタを作成する場合にはベースアドレスとエントリポイントが重要です。
また、デバッグ時には上記のファイルには記述されていませんが、define定義に DEBUG=1を追加することと、ライブラリをSTRMBASE.libではなく、 STRMBASd.libとすることです。
基本的に以上のことをすることで、VC-IDEにてサンプルの動作確認をすることができるでしょう。

(もしできなければお知らせください、BBSにて対応します。 (わたしがわかればですが))
追加 1999/10/15
timeGetTimeというAPIを使用するクラスがあるので、winmm.libもリンクする必要が ある場合がある。

2000/05/22
VC6に対応したウィザードを作成しました。上記の設定を簡単に行うことができます。
DirectShow開発用ウィザードをご利用ください


DirectShow GraphBuilder

基本的にDirectShowは様々なストリームを再生し表示することを容易にする為の ものと考えられる。
再生するには、あるストリームを解析し、絵と音に分離、絵はRGBへ変換し、 ディスプレイへ表示、音はWave(pcm)に変換し、スピーカーへと送られる。
その過程において、様々なフォーマットをあるフォーマットへ変換する必要があり、 それを行うのがフィルターの役目である。
windowsの場合一々ストリームを解析するのではなく、拡張子から様々なファイル 形式を分類し管理している。DirectShowも同様に、拡張子を元にレジスタから登録 済みの拡張子がどのストリームなのかを判断する。そしてそれに対応するフィルター を組み合わせるという動作を行う。
これらが正常に組み合わされると、再生できるわけだが、再生・一時停止・終了等の 動作をする事ができる。
これらの事をIGraphBuilderが受け持つのである。
IGraphBuilder->Renderは、GraphEditでファイルを読み込む時に表示されるフィルター の組み合わせと同じ事を行い、それを再生する場合には、IGraphBuilderから IMediaControlや、IMediaSeekingなどによって再生を制御する。
デフォルトでは対応していないストリームや、もっと高速な変換フィルターなど 独自のフィルターを使用したい場合には、IGraphBuilderIFilterGraph->AddFilter によってフィルターを登録しておき、Renderする事により、独自のフィルターを 使用する事が可能である。
フィルターの接続を制御するのがMediaTypeであり、独自フィルターでインプリメント するCBasePin.CheckMediaTypeにより、接続されるフィルターを制御できる。


VideoForWindowsとDirectShowとの比較

わたし自身はあまり深い知識があるわけではないので、その辺はお断りして おきます。
VideoForWindowsは以前からマルチメディアを扱う為のAPIとして提供されてきました。 DirectShowはDVを扱う事を前提に、新しい技術であるCOMと融合し、自由度が高く、 様々なストリームに対応しうる技術となっています。
DirectShowは新しい技術ですから、問題点もあり、DirectShowを使用する必要がない シーンもあります。
1.VFW対応のキャプチャデバイスからビデオ・あるいは音声のみ(両方でもOKの はずだが)キャプチャする場合
2.キャプチャデータが2Gを超えない
3.静止画キャプチャ
等の場合にはVFWのAPIを利用する方が簡単でしょう。
逆に2Gを超えるものや、DVを扱うものなどの場合にはDirectShowを使わざるを 得ません。
またある段階で固有の処理をしたい場合には、DirectShowのフィルタと言う概念 が有効です。


ICaptureGraphBuilder

このインターフェイスはヘルプに記述されている通り、キャプチャや、 プレビューあるいは再圧縮を容易に行う為のものとなっています。
キャプチャアプリケーションを作成するには必須のインターフェイスのようですが、 IGraphBuilderとの関係がよく分からん。
一応IGraphBuilderを取得する為のGetFiltergraphというメソッドがあるが、 何故QueryInterfaceを使用しなかったのか、わざわざメソッドを作成したの でしょうか?
まあ、それはよく分からないので置いておきます。(^^ゞ \おいおい
このインターフェイスに関するサンプルがAmCapです。これを参考にすれば、 ほとんどのメソッド使用方法が理解できるでしょう。
基本的にはRenderStreamを行い、IGraphBuilder->IMediaControlを取得して、 IMediaControl->Run()Stop()などで開始終了を制御します。
これだけではつまらないので、AmCapサンプルをMFCを使用したアプリケーションに 書き直す計画をはじめました。
「AmCap MFC化計画」 ってそのまんま
現在、プレビューのみOn/Offできる様にした物が置き多分ここにあります。 (一部メソッド等の訳があります。参考になるかは保証しません(^^ゞ)
基本方針としては、AmCapにあるgcap構造体を元にCCaptureクラスを作成します。 また、GUI部分はAmCapではダイアログベースの様な形になっていますが、 ステータスバーや、ツールバーが付いています。これをMFCのダイアログベースで 実現するには、MFCサンプルDLGCBR32という物を参考にすれば簡単にできますが、 VC6にはView/Doc構造を使用しないSDIテンプレートがありますので、 それを使っています。
コメント等は日本語で記述するようにしますが、あまり書いていません(^_^;)
最終的には、AmCapと同等な機能+αを考えていますが、いつになるやら。。。


MFCcap - AmcapをMFCで作成

さて、AmCap MFC化計画において、プレビューのみだった以前のバージョンからちょっと進展しました。と言いつつも基本的にはAmCapのキャプチャ部分をインプリメントしただけです。
しかも、以前のバージョンはまともにコンパイルできませんでした。(^^ゞ
恥ずかしいですが、この修正部分も含めてここに置きました。まだ問題もありますが、基本的な動作はするようです。
今のところAmCapというサンプルを参照すれば、この程度のものは出来るはずなのですが、時間がないとなかなかむずかしいね。チョットした違いが正常に動作しないという原因になるし、特にキャプチャアプリケーションの場合、間違ったことをすると、デバイスが正常に動作しなくなるようで、すぐリブートが必要だったりしますからね〜。
次からはいよいよAmCapとは違うことをしようと思っています。その内容に関しての解説もつける予定です。
また、Readme.txtにはキャプチャに関連したメソッドのヘルプを和訳しました。まだ5つだけですが、参考になるかもしれません。


MFCcap - 圧縮機能追加

キャプチャ機能が完成したので、次に実現したい機能として、圧縮取りこみをしたいと考えました。AVIファイルを選択して、プロパティを見ると、3つのタブがあり、詳細というタブを選択すると、AVIファイルの詳細情報が表示されます。さて、ここでビデオ形式という部分に注意すると、6つの情報を表示していることがわかります。
その中で最後の情報がビデオの圧縮形式をあらわしています。今回作成したキャプチャアプリケーションだけでなく、サンプルのAmCapによって作成されたAVIファイルも、この部分は未圧縮となっています。
しかし、通常MS-RLEやCinepak-Codecなどの形式で圧縮されています。
ちなみに、プロパティでは、不明なフォーマットと表示される場合があります。この場合には、圧縮されているストリームを復号するためのソフトウェアが登録されていないことが原因です。コントロールパネルの、マルチメディアを選択し、デバイスタブ中のビデオ圧縮 CODECという部分がそれに対応します。ここに登録されていなければ、プロパティで正常にフォーマットを表示できません。


MFCcap - 圧縮フィルタを適用可能か調査

圧縮するためにはどのようにすればいいのか調査をはじめる。
まずは、どのようなフィルタがあるのかを確認するために、GraphEditというツールを使用した。このツールはDirectShowを使用して何かを作成する場合とても役に立つツールであるので、操作方法や、利用方法を理解すべきだと思います。

このツールで具体的に何ができるかというと、実際にフィルタをつなぎ合わせてどのようなことができるか、ビジュアル的に確認できるということです。
起動してまず何をするかというと、GraphメニューのInsertFilterを選択することです。するとダイアログが現れ、カテゴリ毎のフィルタ一覧が表示されます。 もちろんキャプチャ時に必ず必要なVideoCaptureSourceなどもあります。オーディオをキャプチャする場合にはもちろんAudioCaptureSourceを使用するのだが、今回はVideoCaptureSourceを使用します。VFW対応のキャプチャ機器が、接続されていれば、そのドライバ名が表示されるはずです。
まあ、この辺りは適当にいじってもらうとして、特にVideoCompressorというカテゴリに注目してほしい。カテゴリの+印をクリックすると、そのカテゴリ内のフィルタが表示されるが、やはりみなれたcodecであるMS-RLEやIndeo Videoなどの名前もある。
これらのいずれかを選択して、うまくAVIファイルを作成できれば感じがつかめるだろうと考え、試行錯誤の上、下記のような構成でなんとか期待どおりのAVIファイルを作成することができた。

キャプチャソース -> Indeo Video 5.04 Compression Filter
 
 -> AVI Mux -> File writer
やはりねらいどおりVideoCompressorというカテゴリのフィルタが必要で、Render時にこのフィルタを追加しておく必要がありそうだということが認識できました。


MFCcap - 実際のCompressorフィルタ使用方法の調査

さて、次にこのCompressorをどのように扱う必要があるか、と考えたときに、AmCapサンプルの接続デバイスと同じような流れを踏襲し、メニューにGraphEditツールで表示されているようなCompressorフィルタ一覧が表示され、その中から必要なCompressorを選択するようにすればいいだろう、という構想にそって、アプリケーションにインプリメントしていこうと考えた。

それではどのような手順で進めたか、どうすれば実現できたかを、説明してみよう。

とにかく、Compressorと関係があるものを見つけることが必要だと思い、それにはまずGUIDを検索するのが一番だと考えました。
X:/DXMedia/include/uuids.hというファイルにはDirectShowで使用するGUIDが記述されているので、まずはこのファイルに対して、Compというキーワードで検索するとCLSID_VideoCompressorCategoryというGUIDが見つかった。いきなりビンゴです。これを使用すればCompressorの一覧が取得できそうな予感。しかも名前からすると、デバイス一覧を取得した方法と同じ流れで取得できるかもしれないと考えられます。
もちろん今度はDirectShowに付属のヘルプに対して上記のGUIDを検索します。しかし、これでは使い方は出ていません。
次はサンプルです。X:/DXMedia/samples/multimedia/dshow/src以下を検索してみると一つだけヒットしました。
X:/DXMedia/samples/multimedia/dshow/src/vidclip/setting.cppです。やはり考えていたとおり、デバイス名一覧を取得した方法とまったく同じように、Compressor一覧も取得できることがわかりました。なるほど、GraphEditのフィルタ挿入ダイアログに出ている一覧は、全てこの方法を使用して取得しているということがわかった(^o^)。上記のuuids.hの中でCategoryを含むGUIDは以下の10個。

CLSID_VideoInputDeviceCategory,
CLSID_LegacyAmFilterCategory,
CLSID_VideoCompressorCategory,
CLSID_AudioCompressorCategory,
CLSID_AudioInputDeviceCategory,
CLSID_AudioRendererCategory,
CLSID_MidiRendererCategory,
CLSID_TransmitCategory,
CLSID_DeviceControlCategory,
CLSID_DVDHWDecodersCategory,
GraphEditのダイアログのカテゴリも10個である。
しかし、名前を見るとちょっと対応が異なるものがある(^^ゞ
実際に上記のカテゴリを使用してどのように対応できるかを確かめてみればわかると思うが、そこまではやりませんでした(-_-;)。


CComPtrクラス 見つけた

ちょっと寄り道です。
いままでComReleaserという内部クラスを利用してCOMの参照カウンタを管理してきたが、CComPtr,CComQIPtrという便利なクラスを見つけたので、そちらを利用することにした。

また、VidClipサンプルソースを見ると、IMonikerを保存して、利用しているようなので、デバイス名やCompressor名だけでなく、IMonikerも含めて保存するようにした。

struct DevInfo
{
  std::string         name;      // Device name
  CComPtr <IMoniker>  pM;        // IMoniker pointer
};

typedef std::vector<DevInfo> DevInfos;
ただ、わたしが引っかかってしまった罠があった。
つまりpMをCComPtrとしたことで、生存期間をあまり気をつけないでいたために、CoUninitialize()の後でDevInfosのデストラクタが呼ばれ、pMが開放されるタイミングで落ちてしまうようになった。
これには結構はまってしまった。皆さんもお気を付けください。


MFCcap - 実際に使用しているフィルタおよび接続ピン

さて、圧縮フィルタを使用すれば、期待通りの動作をすることがわかった。そこで、今度はその圧縮フィルタを実際にどのように接続すれば良いかが問題である。さらにGraphEditでは圧縮フィルタをキャプチャソースに接続しただけでは、必要とする全てのフィルタを自動的に接続してくれるわけではなかった。ということは、圧縮フィルタを登録し、RenderStreamを行っただけでは、うまく行かないということが考えられる。

そのため、下準備としてキャプチャ時に使用しているフィルタや、どのピンがどのフィルタに接続されているかを確認しようと考えた。
そこで使用したのが、DisConnectAllメソッドで、これはAmCapサンプルのTearDownGraph関数に相当するものである。この機能は、接続されているピンを切り離すということを行っており、このときにフィルタ情報や、ピン情報を取得すれば、簡単に求める情報を得られると考えた。
以下のロジックにて行う。

FILTER_INFO finfo;
hr=pininfo.pFilter->QueryFilterInfo(&finfo);
if(SUCCEEDED(hr)) {
   finfo.pGraph->Release();   // <= これを忘れるとひどい目にあう
   TRACE("filter:%s %s",
        Helper::wstr2mstr(finfo.achName),
         ( (pininfo.dir==PINDIR_INPUT)?"<-":"->" ) );
}
TRACE(" pin:%s\n",Helper::wstr2mstr(pininfo.achName));
それにしても、この4行目のロジックが必要だとはどこにも書いていない。 まさかAddRefされているとは思わずに、使用していたため、本当に困った。
CComPtrを導入したための副作用かと考えてしまったため、余計に原因究明に時間がかかってしまった。


MFCcap - 圧縮フィルタの接続

いよいよ、肝心な部分である。が意外にあっさりできてしまった。スタンダードな方法がどのようなものかいまいち自信が無し。まあこんなものだろうと思う。

まずRenderStreamをする。これに関してはAmCapでも同じように行っているので説明は不要かと思うが簡単に言うと、必要なフィルタを接続するというものである。
その後に、以前調査したときに圧縮フィルタがどのように接続されるかは、わかっており、キャプチャソースとAVI Muxフィルタの間に接続してやれば良い。

キャプチャソース -> Indeo Video 5.04 Compression Filter
   -> AVI Mux -> File writer
まずAVI MuxフィルタをIGraphBuilder(IFilterGraph)から取り出し、そのフィルタの入力ピンを取得する。
ICaptureGraphBuilder->GetFiltergraph ==> IGraphBuilder
IGraphBuilder->FindFirstByName       ==> IBaseFilter(Mux filter)
IBaseFilter->FindPin                 ==> IPin -- (A)
さらにそのピンに接続されているピンを取得
IPin->ConnectedTo                    ==> IPin -- (B)
上記のピンを切断し、圧縮フィルタの入出力ピンに(A),(B)のピンをそれぞれ接続してあげれば良い。
IGraphBuilder->Disconnect
IGraphBuilder->Connect


MFCcap - 圧縮フィルタの接続 その2

結構無駄なことをしてしまった。RenderStreamの訳をしていながら、うっかり忘れてしまっていた。RenderStreamに圧縮フィルタを渡しておけば、面倒なこと抜きに簡単に圧縮フィルタの接続はできたようだ。
一つ注意が必要なことは、RenderStreamを行う前にIGraphBuilderに登録しておく必要があることだ。
ちょっと躓いたが何とか完成した。(^^ゞ
ソースと、バイナリ (56,991バイト)


静止画の取りこみ

いよいよ最終段階となりました。キャプチャに関して、私が考えているのは、 ここまでの予定です。では本題です。

まず静止画を取りこむ方法を考えてみます。

考え方としては、プレビュー時に取りこみボタンを押し、そのタイミングでプレビュー を一時停止させておき、画像データを取得、その後プレビューを再開するという感じ でしょうか。
この流れの中で一番の問題は、画像データを取得すると言うところですね。 どの様に画像を取り込めば良いのでしょうか。
今回はわたしが散々苦労して見つけ出した方法を使用します。と言っても、 別の方法があるのかはわたしにはわかりませんが(^_^;)。
まず、動画というのは、パタパタアニメのように一枚ずつその瞬間の画面が 集まったもので、一枚に対応するものを一フレームと言います。 (一秒あたりのフレーム数のことをフレームレートと言います)
さて、静止画を取り込むと言うのはその瞬間のフレームを取り出すと言うことですが、 DirectShowではフレームデータをIMediaSampleというインターフェイスで管理 しているようです。
このことは、DirectShowのサンプル(特にフィルタサンプル)を見ていて大体見当を 付けました。

さて、ここで話は変わりまして、キャプチャするときにレンダーされるフィルタの中で、 実際にフレームを取り出すインターフェイスなりが必ず取得できるかどうかは、 わかるのでしょうか?

後ほどフレームを取得する方法は述べますが、私が考えついた方法では必ず レンダーされるフィルタが取得できる条件を満たしているとは思えませんでした。
ということで、こちらの都合のよい条件を満足するフィルタを作成する事にしました。
フィルタを作成する方法が大きく2通りあります。それは、COMとして作成するか、 アプリケーション内部に作成するかです。
ちょっとわかりにくい表現で申し訳ありませんが、どちらの場合もわかってしまえば、 それほど難しいことはありませんし、作成するのも容易です。
DirectShowのサンプルはほとんどが COM として作成する場合に関してです。 ですから、恐らく最初に作成する場合には COM として作成したほうが わかりやすいかもしれません。
少なくとも私の場合はそうだったのですが、実はアプリケーション内部に 組み込んでしまったほうが、自由度が高く、作成も容易であることが 今回わかりました。(^^ゞ

このあたりはトレードオフの関係があるのですが、COMにしたほうがモジュール化 されている分汎用的に使える反面、拡張するのに面倒(COMインターフェイスを 定義したり)である。アプリ内部の場合には、通常のクラスのように使用でき、 容易に使用できる反面、COMのように汎用的に使用することはできない。 といったところでしょうか。

今回は、作成が容易であることと、サンプル自体が少ないことを考えて、 アプリ内部に作成する方法を取ってみました。

アプリ内部に自由度の高いフィルタを作成した場合には、苦労してDirectShowの 枠組みであるインターフェイスを使用する必要はなく、自由にメソッドを作成して 必要なデータを取得することができるように作成することができます。極端な話、 上記で見つけ出した
IMediaSampleを使用する必要もないのですが、そうすると、COM版にしたときに その方法を使用できなくなります。まあ、それようにインターフェイスを作成して あげればよいのですが、今回は止めます。
既存の枠組みであるDirectShowのインターフェイスを利用してフレームデータを 取得できるようにしてみます。

それでは、上記のIMediaSampleを取得するにはどのようにすれば良いのでしょうか。

ドキュメントからIMediaSampleを取得できるメソッドを片っ端から探してみました。 これは結構大変な作業でした。

その成果として、IMemAllocator::GetBufferメソッドはIMediaSampleを取得できる ことがわかった。(次はIMemAllocatorか(-_-;) )
さてIMemAllocatorを検索すると、CBaseInputPinおよびCBaseOutputPinが最初の ほうで見つかった。
ヘルプを見ると、とりあえずどちらもIMemAllocatorを取得できそうです。 それぞれよく見ると大きな違いがあります。それは、上記2つのクラスの派生元 クラスが違うのです。CBaseInputPinはIMemInputPin,CBaseOutputPinはIPinから CBasePinを介して派生されています。
IPinからはIMemAllocatorを取得できるインターフェイスはありません。 IMemInputPinからならば取得できるようです。IMemInputPin::GetAllocator
今回作成するフィルタは入力ピンとしてIMemInputPinを持っていなくてはならない。 それ以外には必要最小限の機能を持ったフィルタを作成する。
上記の条件を満たすようにフィルタを作成すればよいのだが、DirectShowには便利な クラスが提供されている。CTransformFilterである。これは入力ピンと出力ピンを 一つずつ持ち、CBaseInputPinとCBaseOutputPinである。ただし、5つのメソッドを オーバーライドする必要があると、ヘルプには記載されている。

実装に関しては、とりあえずサンプルを探してみることにした。CTransformFilterを キーにサンプルを探してみると、ありました。contrastやezrgb24などなど。

とりあえず、このフィルタをCStillFilterというクラス名にして、下記のように定義する。

class CStillFilter : public CTransformFilter
{
..
};
ezrgb24を参考にして、下記の5つのメソッドをインプリメントしてみましょう。

内容は、ほとんど同じです。ただ、メディアタイプに関しては以下のような考えの元で設定しました。
入力、出力ともにビデオでかつrgb24である。このようにしておけば原画をキャプチャするソースフィルタに直接接続してくれます。DVキャプチャとかMotionJpegなどのキャプチャでは、また別なメディアタイプを設定する必要があります。
もし、COM化するのであれば、ezrgb24と同じようにすれば簡単にCOMが作成できます。

さて、ここまでくれば準備はOKです。後は、作成したフィルタのインスタンスを作成して、RenderStreamをする前に、AddFilterで登録してあげます。

インスタンスを作成するときには、ちょっとわからない部分もあった。

クラスのコンストラクタは、COM化するのに比べ、簡単にすることができたのだ。
CTransformFilterのコンストラクタは、以下のようである。
CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);

一番目と三番目のパラメータは、タイプを見れば大体想像がつきますね。でも、二番目のパラメータはいったい何を渡せば言いのでしょう?
そもそもLPUNKNOWNとはなあに? そう、IUnknownのポインタだって。
実際上記で参照したezrgb24というサンプルを見るとCreateInstanceで指定されたIUnknownポインタを渡していた。
次にIClassFactory::CreateInstanceをヘルプで見ると答えが見つかった。

[in] If the object is being created as part of an aggregate, pointer to the controlling IUnknown interface of the aggregate. Otherwise, pUnkOuter must be NULL.
簡単に言うと、今回の場合NULLでいいってこと。


プレビュー中のみ静止画をキャプチャできるように、プレビューフィルタをレンダーするときに、以下のような感じで、自作フィルタの登録完成です。
このときに、IMemAllocatorインターフェイスを取得しておく。

  1. インスタンス作成
    CStillFilter * sf = new CStillFilter(_T("Still"),NULL,&hr);
  2. 参照カウンタ増加
    sf->AddRef();
  3. グラフビルダインターフェイス取得
    hr = mpCapBuilder->GetFiltergraph(&pFg);
  4. 登録
    hr=pFg->AddFilter(sf,L"StillFilter");
  5. レンダー
    hr=mpCapBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,mpVCap,NULL,NULL);
  6. 入力ピン取得
    CTransformInputPin * pinp=(CTransformInputPin *)sf->GetPin(PINDIR_INPUT);
  7. IMemAllocator取得
    hr=pinp->GetAllocator(&mpMemA);
  8. 参照カウンタ減少
    sf->Release();


次に実際にキャプチャするシーンです。
キャプチャボタンを押されたときに、一応プレビューをポーズさせています。ポーズさせなければいかないかどうかはわかりませんが、ポーズさせないでやってみていないのでわかりません。ポーズさせている間に以下のことを行います。

  1. IMediaSampleインターフェイスの取得 mpMemA->GetBuffer(&pms,NULL,NULL,0);
  2. 実データ長の取得
    unsigned long mFrameLength=(unsigned long)pms->GetActualDataLength();
  3. 実データポインタの取得
    hr=pms->GetPointer(&pbuf);
  4. フォーマット取得
    hr=mpVSC->GetFormat(&pmt);
  5. フォーマットに従いビットマップで書き出す
    ptr=(VIDEOINFOHEADER *)pmt->pbFormat;
やっとこさ、ビットマップへの書き出しが完成しました。パチパチo(^^ゞ
ソースと、バイナリ(273,847バイト)

さて、MFCcap(AMcap MFC化計画)も初志をあっさり捻じ曲げ、自分のやりたい部分だけをやってみて終わりとなりました。アプリ自体はまったく安定性がなく、こちらが想定していない動作をさせるとあっさり落ちるという面がありますが、DirectShowを使用したアプリケーションの作成という面で、何らかのヒントとなれば幸いですm(_"_)m

最初に書いたとおり、DirectShowに関してはまだまだ情報が少ないと感じているが、サンプルを含め、combase.h等のヘッダファイルに簡単な解説があり、これらを眺めるだけでも有用な情報が得られるし、自分の理解も深まると思う。


静止画の取りこみ その後

さて、このアプリケーションもうち止めと考えていたのですが、ある問題が発覚した為、ちょっと手直しをしてみました。(^^ゞ キャプチャ時のフォーマットタイプがRGB24以外の時に、何事もなくプレビューできるが、いざ静止画を取りこもうとすると、ハングアップしてしまうという問題があります。
これはエラー処理の不備もあるのですが、フィルタが接続できない為に発生してしまう事がわかった。もちろんアプリケーションの前提としてRGB24でキャプチャできるデバイス以外は対象外と考えてはいたのですが、それ以外の時の現象があまりにひどいと考えて、修正する事にしました(^^ゞ

修正の肝は、現在のデバイス状態をチェックし、ビデオフォーマットの圧縮されるのかを確認する。 VIDEOINFOHEADER:biCompression
非圧縮と判断すると接続し、一方フィルタの方は、RGB24だけではなく、メディアタイプがビデオならば接続できる様にした。
これにより、キャプチャできるかどうかを判断し、出来なければそれなりに、出来る場合は今まで通りビットマップに取り込む事が可能となった。

ソースと、バイナリ(76,927バイト)


質問はここのBBSへお願いします。
最近はMLの方がよろしいかも。MLの情報はTOPからどうぞ




counter
ahiru logo
Up Next Main