- ベストアンサー
VC++でDirectShowのグラフにフィルターを追加する方法
- VC++でDirectShowを使用して、ビデオキャプチャデバイスからファイルに保存する方法について説明します。
- 保存する際には、圧縮を行いたい場合はMicrosoft Video 1というフィルターを追加する必要があります。
- 初心者の方には、MSDNなどの情報が理解しにくい場合もあるため、簡単なサンプルがあれば助かるでしょう。
- みんなの回答 (1)
- 専門家の回答
質問者が選んだベストアンサー
こんばんは。以下のURLが参考になります。 http://msdn.microsoft.com/ja-jp/library/cc973418.aspx http://msdn.microsoft.com/ja-jp/library/cc353106.aspx http://www.codeguru.com/forum/showthread.php?t=392724 圧縮コーデックの一覧から、Microsoft Video 1を探し出して見つかればフィルタを作成して、SplitterとMuxの間に挟み込めばOK見たいです。 大分乱暴なコードですが、以下で圧縮が出来ました。参考程度に。 #include <stdio.h> #include <dshow.h> #include <qedit.h> #pragma comment(lib, "strmiids.lib") //コーデックを探す static IBaseFilter* FindCodec(BSTR bstrDesire) { ICreateDevEnum *pSysDevEnum = NULL; IEnumMoniker *pEnum = NULL; IMoniker *pMoniker = NULL; IBaseFilter *pFilter = NULL; HRESULT hr = ::CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum); if(FAILED(hr)) return pFilter; hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnum, 0); if(hr != S_OK) return pFilter; while (S_OK == pEnum->Next(1, &pMoniker, NULL)) { IPropertyBag *pPropBag = NULL; pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag); VARIANT var; ::VariantInit(&var); hr = pPropBag->Read(L"FriendlyName", &var, 0); if(SUCCEEDED(hr)) { ::wprintf(L"[codec %s]\n", var.bstrVal); //見つかったのでフィルタを作成する if(::lstrcmp(var.bstrVal, bstrDesire) == 0) { pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter); } } ::VariantClear(&var); pPropBag->Release(); pMoniker->Release(); //見つかっているのでループから抜ける if(pFilter)break; } //最後の後始末 pSysDevEnum->Release(); pEnum->Release(); return pFilter; } int main() { IGraphBuilder *pGraph = NULL; IMediaControl *pControl = NULL; IMediaEvent *pEvent = NULL; ::CoInitialize(NULL); //グラフの作成 ::CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); //コントロールとイベントの作成 pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl); pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent); //グラフビルダーの作成 ICaptureGraphBuilder2* pBuilder = NULL; ::CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&pBuilder); //フィルタの作成 IBaseFilter *pFileSource; pGraph->AddSourceFilter( L"test.avi", L"Source", &pFileSource); IBaseFilter *pAviSplit; ::CoCreateInstance(CLSID_AviSplitter, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pAviSplit); IBaseFilter *pAviMux; ::CoCreateInstance(CLSID_AviDest, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pAviMux); IBaseFilter *pWriter; ::CoCreateInstance(CLSID_FileWriter, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pWriter); IBaseFilter *pMSVideo1 = ::FindCodec(L"Microsoft Video 1"); //出力先の設定 IFileSinkFilter *pSink= NULL; pWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pSink); pSink->SetFileName(L"testresult.avi", NULL); pSink->Release(); //フィルタを追加 pGraph->AddFilter(pFileSource, L"AVI Source"); pGraph->AddFilter(pAviSplit, L"AVI Splitter"); pGraph->AddFilter(pAviMux, L"AVI MUX"); pGraph->AddFilter(pWriter, L"AVI Writer"); pGraph->AddFilter(pMSVideo1, L"Microsoft Video 1"); //フィルタ同士の接続 pBuilder->SetFiltergraph(pGraph); pBuilder->RenderStream(0, 0, pFileSource, 0, pAviSplit); pBuilder->RenderStream(0, &MEDIATYPE_Video, pAviSplit, pMSVideo1, pAviMux);//split⇔mux間にMS Video1を挟み込む pBuilder->RenderStream(0, &MEDIATYPE_Audio, pAviSplit, 0, pAviMux); pBuilder->RenderStream(0, 0, pAviMux, 0, pWriter); //書き込みスタート pControl->Run(); //達成まで待つ long evCode; pEvent->WaitForCompletion(INFINITE, &evCode); //停止 此れがないと駄目 pControl->Stop(); //始末 pControl->Release(); pEvent->Release(); pGraph->Release(); pFileSource->Release(); pAviSplit->Release(); pAviMux->Release(); pWriter->Release(); pMSVideo1->Release(); pBuilder->Release(); return 0; }
お礼
大変細かな親切なご回答本当にありがとうございます。 とても分かりやすく、すぐにできました。 ありがとうございました。