2010-01-17 176 views
0

我在SDK中直接显示时构建了AMCap示例。它能够处理2个或更多的网络摄像头,我如何修改程序让我同时使用它们...就像按下一个按钮,说'开始捕捉'并确保所有相机开始捕捉,一个按钮说'停止捕捉'来停止所有的相机。我希望来自不同相机的帧可以保存在不同的文件中。我是C++的新手,任何形式的帮助都会被赞赏!谢谢你的时间!AMCap中的多个网络摄像头

回答

0

使用GraphEdit工具。您可以在连接所有视频输入设备的情况下创建自己的图表。请参阅http://en.wikipedia.org/wiki/GraphEdit

+0

的GraphEdit是创建一个良好的原型开发工具图表,但我认为OP想要在代码中实现这一点。 GraphStudio是GraphEdit的更好选择;)http://blog.monogram.sk/janos/tools/monogram-graphstudio/ – 2010-11-29 21:46:45

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; 
}