我在SDK中直接显示了AMCap示例。它能够处理2个或更多的网络摄像头,如何修改程序让我同时使用它们...比如按下一个“开始捕获”按钮并确保所有摄像机开始捕获并且一个按钮显示“停止”捕捉'停止所有相机。我希望不同相机的帧保存在不同的文件中。我是C ++的新手,感谢任何帮助!谢谢你的时间!
答案 0 :(得分:0)
使用GraphEdit工具。在那里,您可以构建自己的图表,连接所有视频输入设备。请参阅http://en.wikipedia.org/wiki/GraphEdit
答案 1 :(得分:0)
如果您刚刚开始使用DirectShow编程,这可能会有点攀爬,但我希望它有所帮助,或指向正确的方向。
M $ DN有一个描述how to select a capture device的页面。这个例子有点薄,所以我在下面提供了一个简单的实现。
理论上,您需要枚举CLSID_VideoInputDeviceCategory中的所有设备,并尝试为该类别中的每个有效项创建渲染图。
首先,我将向您展示迭代类别中设备名称的代码。下面是3个静态函数,可用于迭代类别中的设备。将这些功能添加到项目后,可以通过调用以下功能列出视频输入设备类别中的设备:
ListDevicesInCategory(CLSID_VideoInputDeviceCategory);
好的,这是三个功能。 ListDevicesInCategory()是工作发生的地方。它取决于其他两个函数,FindDeviceInCategory()和CountDevicesInCategory()
#define RFAIL(x) { HRESULT hr = x; if(FAILED(hr)) {return hr;} }
static HRESULT FindDeviceInCategory(IBaseFilter** pSrc, const IID& cls, wstring& wFilterName,int devNum)
{
CComPtr<ICreateDevEnum> spDevEnum;
CComPtr<IEnumMoniker> spEnum;
int i;
RFAIL( spDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum) );
RFAIL( spDevEnum->CreateClassEnumerator(cls, &spEnum, 0) );
if(spEnum == 0)
return E_FAIL;
for(i = 0; i >= 0; i++)
{
CComPtr<IMoniker> spiMoniker;
if( spEnum->Next(1, &spiMoniker, 0) != S_OK )
return E_FAIL;
if( devNum == i)
{
CComVariant varName;
CComPtr<IPropertyBag> spiPropBag;
RFAIL(spiMoniker->BindToStorage(0, 0, IID_IPropertyBag,reinterpret_cast<void**>(&spiPropBag)));
RFAIL(spiPropBag->Read(L"FriendlyName", &varName, 0));
RFAIL(spiMoniker->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(pSrc)));
wFilterName = V_BSTR(&varName);
varName.Clear();
return S_OK;
}
}
return E_FAIL;
}
static HRESULT CountDevicesInCategory( int *pCount, const IID& categoryClass )
{
// pass in a category class like CLSID_VideoInputDeviceCategory, writes the count of the number of filters in that category
// available on the local machine
HRESULT hr = S_OK;
CComPtr<ICreateDevEnum> spIDevEnum;
CComPtr<IEnumMoniker> spIEnum;
CComPtr<IMoniker> spIMoniker;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&spIDevEnum));
if( ! SUCCEEDED(hr) || hr == S_FALSE )
{
*pCount = 0;
return hr;
}
hr = spIDevEnum->CreateClassEnumerator( categoryClass, &spIEnum, 0 );
if( ! SUCCEEDED(hr) || hr == S_FALSE )
{
*pCount = 0;
return hr;
}
if( spIEnum )
{
while( spIEnum->Next(1, &spIMoniker, 0) == S_OK )
{
(*pCount) ++;
spIMoniker.Detach();
}
}
return S_OK;
}
static HRESULT ListDevicesInCategory( const GUID & cls )
{
CComPtr<IBaseFilter> spSource;
wstring * psNextFilter = NULL;
int nDeviceNum = 0;
int nTotalNumDevices = 0;
HRESULT hr = S_OK;
bool bComplete = false;
DeviceNames CaptureDeviceNames;
if( FAILED(CountDevicesInCategory( &nTotalNumDevices, (IID)cls )) )
bComplete = TRUE;
if( nTotalNumDevices == 0 )
bComplete = TRUE;
while( ! bComplete )
{
psNextFilter = new std::wstring;
hr = FindDeviceInCategory( &spSource, (IID)cls, *psNextFilter, nDeviceNum++ );
if( SUCCEEDED(hr) && spSource )
{
if ( *psNextFilter )
{
wcout << *psNextFilter << endl;
delete *psNextFilter;
psNextFilter = NULL;
}
spSource.Release();
spSource = NULL;
}
else
bComplete = TRUE;
}
return S_OK;
}
一旦您确定了您感兴趣的类别中的某个项目,就可以使用IGraphBuilder::AddFilter调用将其添加到图表中。
要在图表中添加过滤器,首先需要为该过滤器获取IBaseFilter *。我还有一个功能可供您使用。
定义IBaseFilter智能指针:
CComPtr<IBaseFilter> spSource;
附加到过滤器:
m_spSource.Attach(
GetFilter(CLSID_VideoInputDeviceCategory, CComBSTR(L"Osprey-450e Video Device 1A"))
);
这是最后一个函数 - GetFilter:
static IBaseFilter * GetFilter( REFCLSID clsidDeviceClass, CComBSTR & sName )
{
HRESULT hr;
IBaseFilter * pRetFilter = NULL;
ICreateDevEnum * pSysDevEnum = NULL;
IEnumMoniker * pEnum = NULL;
IMoniker * pMoniker = NULL;
int nSameSrcCounter = 0;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum);
if( pSysDevEnum )
hr = pSysDevEnum->CreateClassEnumerator(clsidDeviceClass, &pEnum, 0);
if (hr != S_OK)
return NULL;
USES_CONVERSION;
while ( pEnum->Next(1, &pMoniker, NULL) == S_OK )
{
IPropertyBag *pPropBag = NULL;
VARIANT var;
VariantInit(&var);
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
hr = pPropBag->Read(L"FriendlyName", &var, 0);
if (SUCCEEDED(hr))
{
if(sName == OLE2T(var.bstrVal))
{
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pRetFilter);
if (FAILED(hr))
pRetFilter = NULL;
VariantClear(&var);
pPropBag->Release();
pMoniker->Release();
break;
}
}
VariantClear(&var);
pPropBag->Release();
pMoniker->Release();
}
pSysDevEnum->Release();
pEnum->Release();
return pRetFilter;
}