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
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
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
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum);
CComPtr
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
m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pBF, IID_IAMStreamConfig, reinterpret_cast
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
hr = pam->GetStreamCaps(i, &pmmt, reinterpret_cast
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);