Directshow 能很方便的獲取連接的 視頻和音頻設備的名稱。本篇文章同時介紹如何判斷獲取的攝像頭是否正在佔用。
代碼如下:
(1) 獲取攝像頭音視頻設備名稱
void CDeviceTree::EnumDevices()
{
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum);
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
//將CLSID_VideoInputDeviceCategory 改成 CLSID_AudioInputDeviceCategory 即能獲取音頻設備
if (FAILED(hr))
{
return;
}
if(hr == S_OK)
{
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
if(SUCCEEDED(hr))
{
VARIANT varName;
varName.vt=VT_BSTR;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
USES_CONVERSION;
LPTSTR lpstrMsg = W2T(varName.bstrVal);
if(SUCCEEDED(hr))
{
//videoDev[videoIndex]=lpstrMsg;
//videoIndex++;
//此處即得到獲得的視頻設備名稱 你可以將它打印出來 或者存入隊列
}
pPropBag->Release();
}
pMoniker->Release();
}
}
}
(2) 判斷攝像頭是否佔用。
int DeviceIsBusy(char *videoName,char *audioName)
{
//輸入設備的音視頻名稱
HRESULT hr;
HRESULT hhr;
int ret=0;
int videoBusy=1;
int audioBusy=1;
CoInitialize(NULL);
ICreateDevEnum* pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum);
IEnumMoniker* pEnumCat ;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
if(hr == S_OK)
{
IMoniker* pMoniker = NULL;
IMoniker* pm1=NULL;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
if(SUCCEEDED(hr))
{
VARIANT varName;
varName.vt=VT_BSTR;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
USES_CONVERSION;
LPTSTR lpstrMsg = W2T(varName.bstrVal);
if(SUCCEEDED(hr))
{
if (!strcmp(videoName,lpstrMsg))//存在設備
{
LPBC *pbc=NULL;
IBaseFilter *P_VCamTrans=NULL;
IBaseFilter *pCap=NULL;
CreateBindCtx(0,pbc);
hr=pMoniker->BindToObject((IBindCtx *)pbc,0,IID_IBaseFilter,(void **)&pCap);
ICaptureGraphBuilder2 *m_pCapGB;
IGraphBuilder *m_pGB;
IMediaControl *m_pMC;
IVideoWindow *m_pVW;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB);
if (FAILED(hr)) return hr;
m_pGB->AddFilter(pCap,NULL);
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&m_pCapGB);
if (FAILED(hr)) return hr;
m_pCapGB->SetFiltergraph(m_pGB);
IAMCrossbar *pXBar1 = NULL;
hr=m_pCapGB->FindInterface(&LOOK_UPSTREAM_ONLY,NULL,pCap,IID_IAMCrossbar,(void **)&pXBar1);
if (SUCCEEDED(hr))
{
long OutputPinCount;
long InputPinCount;
long PinIndexRelated;
long PhysicalType;
long inPort = 0;
long outPort = 0;
pXBar1->get_PinCounts(&OutputPinCount,&InputPinCount);
//對於存在輸入輸出引腳的攝像頭。此處採用輪詢所有的引腳
for(int i =0;i<InputPinCount;i++)
{
pXBar1->get_CrossbarPinInfo(TRUE,i,&PinIndexRelated,&PhysicalType);
if(PhysConn_Video_Composite==PhysicalType)
{
inPort = i;
break;
}
}
for(int i =0;i<OutputPinCount;i++)
{
pXBar1->get_CrossbarPinInfo(FALSE,i,&PinIndexRelated,&PhysicalType);
if(PhysConn_Video_VideoDecoder==PhysicalType)
{
outPort = i;
break;
}
}
for (int i=0;i<InputPinCount;i++)
{
for (int j=0;j<OutputPinCount;j++)
{
if(S_OK==pXBar1->CanRoute(j,i))
{
pXBar1->Route(j,i);
m_pGB->AddFilter(pCap, L"Capture Filter");
m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
hr = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
hr = m_pCapGB->RenderStream(NULL, NULL, pCap, NULL, P_VCamTrans);
hr = m_pVW->put_Owner((OAHWND)NULL);
hr = m_pVW->put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN);
hr = m_pVW->put_Visible(OAFALSE);
hr=m_pVW->put_AutoShow(OAFALSE);
hhr=m_pMC->StopWhenReady();
if (SUCCEEDED(hhr))
{
videoBusy=0;
}
}
}
}
if (videoBusy == 1)
{
ret=-1; //視頻設備佔用
}
}
else
{
m_pGB->AddFilter(pCap, L"Capture Filter");
m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
hr = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
hr = m_pCapGB->RenderStream(NULL, NULL, pCap, NULL, P_VCamTrans);
hr = m_pVW->put_Owner((OAHWND)NULL);
hr = m_pVW->put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN);
hr = m_pVW->put_Visible(OAFALSE);
hr=m_pVW->put_AutoShow(OAFALSE);
hhr=m_pMC->StopWhenReady();
if (FAILED(hhr))
{
ret=-1; //視頻設備佔用
}
}
}
}
pPropBag->Release();
}
pMoniker->Release();
}
}
//判斷音頻的方法和上面的一樣 重複。
hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnumCat, 0);
if(hr == S_OK)
{
IMoniker* pMoniker = NULL;
IMoniker* pm1=NULL;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
if(SUCCEEDED(hr))
{
VARIANT varName;
varName.vt=VT_BSTR;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
USES_CONVERSION;
LPTSTR lpstrMsg = W2T(varName.bstrVal);
if(SUCCEEDED(hr))
{
if (!strcmp(videoName,lpstrMsg))//存在設備
{
LPBC *pbc=NULL;
IBaseFilter *P_VCamTrans=NULL;
IBaseFilter *pCap=NULL;
CreateBindCtx(0,pbc);
hr=pMoniker->BindToObject((IBindCtx *)pbc,0,IID_IBaseFilter,(void **)&pCap);
ICaptureGraphBuilder2 *m_pCapGB;
IGraphBuilder *m_pGB;
IMediaControl *m_pMC;
IVideoWindow *m_pVW;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB);
if (FAILED(hr)) return hr;
m_pGB->AddFilter(pCap,NULL);
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&m_pCapGB);
if (FAILED(hr)) return hr;
m_pCapGB->SetFiltergraph(m_pGB);
IAMCrossbar *pXBar1 = NULL;
hr=m_pCapGB->FindInterface(&LOOK_UPSTREAM_ONLY,NULL,pCap,IID_IAMCrossbar,(void **)&pXBar1);
if (SUCCEEDED(hr))
{
long OutputPinCount;
long InputPinCount;
long PinIndexRelated;
long PhysicalType;
long inPort = 0;
long outPort = 0;
pXBar1->get_PinCounts(&OutputPinCount,&InputPinCount);
for(int i =0;i<InputPinCount;i++)
{
pXBar1->get_CrossbarPinInfo(TRUE,i,&PinIndexRelated,&PhysicalType);
if(PhysConn_Video_Composite==PhysicalType)
{
inPort = i;
break;
}
}
for(int i =0;i<OutputPinCount;i++)
{
pXBar1->get_CrossbarPinInfo(FALSE,i,&PinIndexRelated,&PhysicalType);
if(PhysConn_Video_VideoDecoder==PhysicalType)
{
outPort = i;
break;
}
}
for (int i=0;i<InputPinCount;i++)
{
for (int j=0;j<OutputPinCount;j++)
{
if(S_OK==pXBar1->CanRoute(j,i))
{
pXBar1->Route(j,i);
m_pGB->AddFilter(pCap, L"Capture Filter");
m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
hr = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
hr = m_pCapGB->RenderStream(NULL, NULL, pCap, NULL, P_VCamTrans);
hr = m_pVW->put_Owner((OAHWND)NULL);
hr = m_pVW->put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN);
hr = m_pVW->put_Visible(OAFALSE);
hr=m_pVW->put_AutoShow(OAFALSE);
hhr=m_pMC->StopWhenReady();
if (SUCCEEDED(hhr))
{
audioBusy=0;
}
}
}
}
if (audioBusy == 1)
{
ret=-1; //音頻設備佔用
}
}
else
{
m_pGB->AddFilter(pCap, L"Capture Filter");
m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
hr = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
hr = m_pCapGB->RenderStream(NULL, NULL, pCap, NULL, P_VCamTrans);
hr = m_pVW->put_Owner((OAHWND)NULL);
hr = m_pVW->put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN);
hr = m_pVW->put_Visible(OAFALSE);
hr=m_pVW->put_AutoShow(OAFALSE);
hhr=m_pMC->StopWhenReady();
if (FAILED(hhr))
{
ret=-1; //音頻設備佔用
}
}
}
}
pPropBag->Release();
}
pMoniker->Release();
}
}
pSysDevEnum->Release();
CoUninitialize();
return ret;
}
(3)頭文件
#include "windows.h"
#include "stdio.h"
#include "string.h"
#include <string>
#include "Dshow.h"
#include "atlconv.h"
#pragma comment(lib,"Strmiids.lib")
#pragma comment(lib,"Quartz.lib")