【发布时间】:2010-01-17 04:51:46
【问题描述】:
我在 SDK 中直接显示下构建了 AMCap 示例。它能够处理 2 个或更多网络摄像头,我如何修改程序以让我同时使用它们……比如按下一个显示“开始捕捉”的按钮,并确保所有相机开始捕捉和一个显示“停止”的按钮捕获”以停止所有摄像机。我希望来自不同相机的帧保存在不同的文件中。我是 C++ 新手,任何形式的帮助都将不胜感激!感谢您的宝贵时间!
【问题讨论】:
标签: c++ sdk directshow
我在 SDK 中直接显示下构建了 AMCap 示例。它能够处理 2 个或更多网络摄像头,我如何修改程序以让我同时使用它们……比如按下一个显示“开始捕捉”的按钮,并确保所有相机开始捕捉和一个显示“停止”的按钮捕获”以停止所有摄像机。我希望来自不同相机的帧保存在不同的文件中。我是 C++ 新手,任何形式的帮助都将不胜感激!感谢您的宝贵时间!
【问题讨论】:
标签: c++ sdk directshow
使用 GraphEdit 工具。在那里,您可以构建自己的图形,并连接所有视频输入设备。请看http://en.wikipedia.org/wiki/GraphEdit
【讨论】:
如果您刚开始使用 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;
}
【讨论】: