DirectShowで動画を表示するには?


KT06  2005-10-20 14:06:41  No: 59330  IP: 192.*.*.*

VC++6.0でUSBカメラからの画像を取得しています。
そのプログラムをDLL化して、VBで表示できるようにしたいのですが、
新しいWindowが開いてしまいます。
VBのフォーム上に画像を表示させることはできないのでしょうか?

_declspec(dllexport) int preview()
{
 IGraphBuilder *pGraphBuilder;
 ICaptureGraphBuilder2 *pCaptureGraphBuilder2;
 IMediaControl *pMediaControl;

 // 補足情報)英単語の日本語訳
 //   Enumerate : 列挙、一覧
 //   Moniker   : あだ名
 ICreateDevEnum *pCreateDevEnum = NULL;
 IEnumMoniker *pEnumMoniker = NULL;
 IMoniker *pMoniker = NULL;

 ULONG nFetched = 0;
 IBaseFilter *pDeviceFilter;

 // COMを初期化
 CoInitialize(NULL);

 // FilterGraphを生成
 CoCreateInstance(CLSID_FilterGraph,
  NULL,
  CLSCTX_INPROC,
  IID_IGraphBuilder,
  (LPVOID *)&pGraphBuilder);

 // CaptureGraphBuilder2というキャプチャ用GraphBuilderを生成する
 CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, 
   IID_ICaptureGraphBuilder2, 
   (LPVOID *)&pCaptureGraphBuilder2);

 // FilterGraphをセットする
 pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder);

 // MediaControlインターフェース取得
 pGraphBuilder->QueryInterface(IID_IMediaControl,
  (LPVOID *)&pMediaControl);

 // デバイスを列挙するためのCreateDevEnumを生成
 CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, 
   IID_ICreateDevEnum, (PVOID *)&pCreateDevEnum);
    
 // VideoInputDeviceを列挙するためのEnumMonikerを生成 
 pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
   &pEnumMoniker, 0);
 if (pEnumMoniker == NULL) {
   // 接続された映像入力デバイスが一つも無い場合にはこのif文に入ります
   printf("no device\n");
   return 0;
 }

 // EnumMonikerをResetする
 // Resetすると、先頭から数えなおします
 pEnumMoniker->Reset();

 // 最初のMonikerを取得
 pEnumMoniker->Next(1, &pMoniker, &nFetched);

 // MonkierをFilterにBindする
 pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pDeviceFilter );

 // FilterGraphにデバイスフィルタを追加する
 pGraphBuilder->AddFilter(pDeviceFilter, L"Device Filter");

 // この時点でMoniker系、Enumerate系は用済み
 pMoniker->Release();
 pEnumMoniker->Release();
 pCreateDevEnum->Release();

 // Graphを生成する
 pCaptureGraphBuilder2->RenderStream(&PIN_CATEGORY_PREVIEW,
   NULL, pDeviceFilter, NULL, NULL);

 // 再生開始
 pMediaControl->Run();

 // 再生中にプログラムが終わってしまわないように
 MessageBox(NULL,
  "Block Execution",
  "Block",
  MB_OK);

 // 資源を解放
 pMediaControl->Release();
 pCaptureGraphBuilder2->Release();
 pGraphBuilder->Release();

 // COM終了
 CoUninitialize();

 return 0;
}

編集 削除
ボコノン教徒  2005-10-21 09:17:16  No: 59331  IP: 192.*.*.*

表示したいVBのフォームのWindow Handleをどっかから(具体的な方法は知らん)取り出して

HWND hwnd = "フォームのハンドル";
IVideoWindow::put_Owner((OAHWND)hwnd);
IVideoWindow::put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

とかすれば、フォームに描画できるはずだが。

編集 削除
KT06  2005-10-28 10:15:55  No: 59332  IP: 192.*.*.*

ボコノン教徒さん、返事が遅くなってすみません。

教えていただいた通りにやってみたのですが、Formに表示されませんでした。
VBのFormのハンドルは取れていると思うのですが・・・
下のプログラムでは実行されないのでしょうか?
よろしくお願いします。


 pCaptureGraphBuilder2->RenderStream(&PIN_CATEGORY_PREVIEW,
   NULL, pDeviceFilter, NULL, NULL);

 struct HWND__ * hwnd;

 hwnd=FindWindow(NULL,"Form1");
 char buf[32];

 sprintf(&buf[0], "%d", hwnd);
 //ハンドルの表示
 MessageBox(NULL,buf,"hwnd",MB_OK);

 pGraphBuilder->QueryInterface(IID_IVideoWindow,
  (LPVOID *)&pVideoWindow);
 pVideoWindow->put_Owner((OAHWND)hwnd);

 pVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS);

 // 再生開始
 pMediaControl->Run();

編集 削除
ボコノン教徒  2005-10-31 09:55:00  No: 59333  IP: 192.*.*.*

put_Owner()、put_WindowStyle()の戻りはちゃんとチェックしてますね?

> // 再生中にプログラムが終わってしまわないように
>  MessageBox(NULL,
>     "Block Execution",
>     "Block",
>     MB_OK);

これではなく、
IMediaEvent   *pEvent;
pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
.....
pMediaControl->Run(); // Run実行
.....
long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);//終了を待つ

を使ってください。モーダルだと、Formの画面が更新されないかもしれない。
画面更新がうまくいかず、マウスで画面をつつくと描画開始されることもあります。
put_WindowStyle()で WS_CLIPCHILDRENも追加する必要があるかも。

Formがだめなら、PictureBoxをはりつけ、Formのハンドルの変わりに
PictureBoxのハンドルを使って試してみては。

編集 削除