AMCap中的多个网络摄像头

时间:2010-01-17 04:51:46

标签: c++ sdk directshow

我在SDK中直接显示了AMCap示例。它能够处理2个或更多的网络摄像头,如何修改程序让我同时使用它们...比如按下一个“开始捕获”按钮并确保所有摄像机开始捕获并且一个按钮显示“停止”捕捉'停止所有相机。我希望不同相机的帧保存在不同的文件中。我是C ++的新手,感谢任何帮助!谢谢你的时间!

2 个答案:

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