编写C++程序使DirectShow进行视频捕捉

2020-01-06 14:51:47于海丽


HWND hList;     //Handle to the list box 
IMoniker *pMoniker = NULL; 
while(pEnum->Next(1, &pMoniker, NULL) == S_OK) 
{ 
  IPropertyBag *pPropBag; 
  hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag)); 
  if(FAILED(hr)) 
  { 
    pMoniker->Release(); 
    continue;    //Skip this one, maybe the next one will work 
  } 
  VARIANT varName; 
  hr = pPropBag->Read(L"Description", &varName, 0); 
  if(FAILED(hr)) 
  { 
    hr = pPropBag->Read(L"FriendlyName", &varName, 0); 
  } 
  if(SECCEEDED(hr)) 
  { 
    //Add it to the application's list box 
    USES_CONVERSION; 
    (long)SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)OLE2T(varName.bstrVal)); 
    VariantClear(&varName); 
  } 
 
  pPropBag->Release(); 
  pMoniker->Release(); 
} 

 
如果用户选中了一个设备调用IMoniker::BindToObject为设备生成filter,然后将filter加入到graph中。


IBaseFilter *pCap = NULL; 
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); 
if(SECCEEDED(hr)) 
{ 
  hr = m_pGraph->AddFilter(pCap, L"Capture Filter"); 


为了创建可以预览视频的graph,可以调用下面的代码:


ICaptureGraphBuilder2 *pBuild;   //Capture Graph Builder 
//Initialize pBuild(not shown) 
... 
IBaseFilter *pCap;                 //Video capture filter 
hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, 
                        pCap, NULL, NULL); 
} 

 

如何捕捉视频流并保存到文件(Capture video to File)

1 将视频流保存到AVI文件

AVI Mux filter接收从capture pin过来的视频流,然后将其打包成AVI流。音频流也可以连接到AVI Mux Filter上,这样mux filter就将视频流和视频流合成AVI流。File writer将AVI流写入到文件中。
可以像下面这样构建graph图


IBaseFilter *pMux; 
hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,      //Specifies AVI for the target file 
                L"C:Example.avi",       //File name 
                &pMux,                  //Receives a pointer to the mux 
                NULL);    //(Optional)Receives a pointer to the file sink 

 
 
第一个参数表明文件的类型,这里表明是AVI,第二个参数是制定文件的名称。对于AVI文件,SetOutputFileName函数会创建一个AVI mux Filter 和一个 File writer Filter ,并且将两个filter添加到graph图中,在这个函数中,通过File Writer Filter 请求IFileSinkFilter接口,然后调用IFileSinkFilter::SetFileName方法,设置文件的名称。然后将两个filter连接起来。第三个参数返回一个指向 AVI Mux的指针,同时,它也通过第四个参数返回一个IFileSinkFilter参数,如果你不需要这个参数,你可以将这个参数设置成NULL。