Windows下摄像头采集驱动(DirectShow)

  枚举摄像头设备(不论设备能否被使用都会被枚举出来):

int EnumDevices()

 int id = 0;
 
 //枚举视频扑捉设备
 ICreateDevEnum *pCreateDevEnum;
 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);
 if (hr != NOERROR)
  return -1;
 
 CComPtr pEm;
 hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);
 if (hr != NOERROR)
  return -1;
 
 pEm->Reset();

 ULONG cFetched;
 IMoniker *pM;
 
 while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK) 
 {
  IPropertyBag *pBag;
  hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
  if(SUCCEEDED(hr))
  {
   VARIANT var;
   var.vt = VT_BSTR;
   hr = pBag->Read(L"FriendlyName", &var, NULL); //you can get other info by first parame
   if (hr == NOERROR)
   { 

        id++;
        SysFreeString(var.bstrVal);
   }
   
   pBag->Release();
  }
  
  pM->Release();
 }
 
 return id;
}

 

启动摄像头:

HWND m_hWnd;
IGraphBuilder *m_pGB;
ICaptureGraphBuilder2* m_pCapture;
IBaseFilter* m_pBF;
IMediaControl* m_pMC;
IVideoWindow* m_pVW;
CComPtr m_pGrabber;

1.初始化GraphBuilder

CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB); 
CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &m_pCapture);  
m_pCapture->SetFiltergraph(m_pGB); 
m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);  
m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *) &m_pVW); 

2.绑定一个设备到InputFilter

CComPtr pCreateDevEnum;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum);  
CComPtr pEm;
pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0); 

pEm->Reset(); 
ULONG cFetched;
IMoniker *pM; 
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
  IPropertyBag *pBag; hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
  if(SUCCEEDED(hr))
  {
   VARIANT var;
   var.vt = VT_BSTR;
   hr = pBag->Read(L"FriendlyName", &var, NULL);
   if (hr == NOERROR)
   { 
    pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter); 
    SysFreeString(var.bstrVal); 
   } 
   pBag->Release();
  }
  pM->Release(); 
 }

3.创建一个OutputFilter

m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );
CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase( m_pGrabber );

4.设置SampleGrabber的视频格式

AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24; //这里只是设置输出的图像数据类型(24bit,32bit,...),directshow会对自动的对采集到的图像数据做转换
m_pGrabber->SetMediaType(&mt);

5.将2个Filter添加到GraphBuilder

m_pGB->AddFilter(m_pBF, L"Capture Filter"); 
m_pGB->AddFilter( pGrabBase, L"Grabber" );

6.尝试去RenderStream,失败则表示该设备无法使用(比如被其他应用程序所占用)

hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
 if( FAILED( hr ) )
  hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
 if( FAILED( hr ) )
 {
  AfxMessageBox(L"Can’t build the graph");
  return hr;
 }

7.配置SampleGrabber

m_pGrabber->SetBufferSamples( FALSE ); //如果设置true,SampleGrabber会创建一个内部的buffer,可以通过GetCurrentBuffer获得当前帧数据
m_pGrabber->SetOneShot( FALSE ); //如果设置成true,表示只会进入callback函数一次
m_pGrabber->SetCallback( &mCB, 1 );//设置callback,第2个参数如果设置成0,则第一个参数必须是IMediaSample指针

8.开始视频捕获

m_pMC->Run();

 

枚举,设置InputFilter的数据格式:

CComPtr pam;
m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,    m_pBF, IID_IAMStreamConfig, reinterpret_cast(&pam));
int nCount = 0;
int nSize = 0;
pam->GetNumberOfCapabilities(&nCount, &nSize);

AM_MEDIA_TYPE* pmmt = NULL;
VIDEO_STREAM_CONFIG_CAPS scc;

if (sizeof(VIDEO_STREAM_CONFIG_CAPS) == nSize) {
  for (int i=0; i    pmmt = NULL;

   hr = pam->GetStreamCaps(i, &pmmt, reinterpret_cast(&scc));
   if (FAILED(hr))
   {
    continue;
   }

   if ( pmmt->majortype == MEDIATYPE_Video && pmmt->formattype == FORMAT_VideoInfo )
   {
    pam->SetFormat(pmmt);

    break;
   }
  }
 }

 

释放AM_MEDIA_TYPE类型资源:

void FreeMediaType(AM_MEDIA_TYPE& mt)
{
 if (mt.cbFormat != 0)
 {
  CoTaskMemFree((PVOID)mt.pbFormat);
  
  // Strictly unnecessary but tidier
  mt.cbFormat = 0;
  mt.pbFormat = NULL;
 }
 
 if (mt.pUnk != NULL)
 {
  mt.pUnk->Release();
  mt.pUnk = NULL;
 }
}

 

绑定视频输出窗口:

创建一个picture空间,设置其属性(Type: Rectangle,Color:Gray)

m_pVW->put_Owner((OAHWND)m_hWnd);  
m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);  
 Rect rc; 
::GetClientRect(m_hWnd,&rc); 
float fk = (float)mCB.lWidth / (float)mCB.lHeight;
long rw = fk * rc.bottom;
int off_x = (rc.right - rw)/2;
m_pVW->SetWindowPosition(off_x, 0, rw, rc.bottom);//让捕获到的视频居中显示
m_pVW->put_Visible(OATRUE);

 

解绑视频输出窗口:

m_pVW->put_Visible(OAFALSE);
m_pVW->put_Owner(NULL);

你可能感兴趣的:(C/C++)