3

There having these two ways to open the camera cv::VideoCapture:

CV_WRAP virtual bool open(const String& filename)

CV_WRAP virtual bool open(int index)

Is possible open the camera using the index and get the filename(device name) from the VideoCapture object?

or How to find the device name of a USB webcam in Windows which pass to open function?

JustWe
  • 4,250
  • 3
  • 39
  • 90

2 Answers2

1

From my knowledge, OpenCV does not provide such functionality. To get the names of the attached devices, you'll need to go lower and use the DirectShow or WMF API to get the device enumeration list.

Here is a good answer which will help you to do what you want, but not with OpenCV. Pasting the same code from the post.

#pragma once
#include <new>
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <Wmcodecdsp.h>
#include <assert.h>
#include <Dbt.h>
#include <shlwapi.h>
#include <mfplay.h>

#include <iostream>


const UINT WM_APP_PREVIEW_ERROR = WM_APP + 1;    // wparam = HRESULT

class DeviceList
{
    UINT32      m_cDevices; // contains the number of devices
    IMFActivate **m_ppDevices; // contains properties about each device

public:
    DeviceList() : m_ppDevices(NULL), m_cDevices(0)
    {
        MFStartup(MF_VERSION);
    }
    ~DeviceList()
    {
        Clear();
    }

    UINT32  Count() const { return m_cDevices; }

    void    Clear();
    HRESULT EnumerateDevices();
    HRESULT GetDevice(UINT32 index, IMFActivate **ppActivate);
    HRESULT GetDeviceName(UINT32 index, WCHAR **ppszName);
};




#include "DeviceList.h"

/*
* A templated Function SafeRelease releasing pointers memories
* @param ppT the pointer to release
*/

template <class T> void SafeRelease(T **ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = NULL;
    }
}



/*
* A function which copy attribute form source to a destination
* @ param pSrc is an Interface to store key/value pairs of an Object
* @ param pDest is an Interface to store key/value pairs of an Object
* @ param GUID is an unique identifier
* @ return HRESULT return errors warning condition on windows
*/

HRESULT CopyAttribute(IMFAttributes *pSrc, IMFAttributes *pDest, const GUID& key);




/*
* A Method form DeviceList which clear the list of Devices
*/

void DeviceList::Clear()
{
    for (UINT32 i = 0; i < m_cDevices; i++)
    {
        SafeRelease(&m_ppDevices[i]);
    }
    CoTaskMemFree(m_ppDevices);
    m_ppDevices = NULL;

    m_cDevices = 0;
}


/*
* A function which enumerate the list of Devices.
* @ return HRESULT return errors warning condition on windows
*/
HRESULT DeviceList::EnumerateDevices()
{
    HRESULT hr = S_OK;
    IMFAttributes *pAttributes = NULL;

    this->Clear();

    // Initialize an attribute store. We will use this to
    // specify the enumeration parameters.
    std::cout << "Enumerate devices" << std::endl;
    hr = MFCreateAttributes(&pAttributes, 1);

    // Ask for source type = video capture devices
    if (SUCCEEDED(hr))
    {
        std::cout << "Enumerate devices" << std::endl;
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }
    // Enumerate devices.
    if (SUCCEEDED(hr))
    {
        std::cout << "Enumerate devices:" << m_cDevices << std::endl;
        hr = MFEnumDeviceSources(pAttributes, &m_ppDevices, &m_cDevices);
    }

    SafeRelease(&pAttributes);

    return hr;
}


/*
* A function which copy attribute form source to a destination
* @ param index the index in an array
* @ param ppActivate is an Interface to store key/value pairs of an Object
* @ return HRESULT return errors warning condition on windows
*/


HRESULT DeviceList::GetDevice(UINT32 index, IMFActivate **ppActivate)
{
    if (index >= Count())
    {
        return E_INVALIDARG;
    }

    *ppActivate = m_ppDevices[index];
    (*ppActivate)->AddRef();

    return S_OK;
}


/*
* A function which get the name of the devices
* @ param index the index in an array
* @ param ppszName Name of the device
*/


HRESULT DeviceList::GetDeviceName(UINT32 index, WCHAR **ppszName)
{
    std::cout << "Get Device name" << std::endl;
    if (index >= Count())
    {
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;

    hr = m_ppDevices[index]->GetAllocatedString(
        MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
        ppszName,
        NULL
        );

    return hr;
}


#include <iostream>
#include "DeviceList.h"

HRESULT UpdateDeviceList()
{
    HRESULT hr = S_OK;
    WCHAR *szFriendlyName = NULL;

    DeviceList g_devices;


    g_devices.Clear();

    hr = g_devices.EnumerateDevices();

    if (FAILED(hr)) { goto done; }
    std::cout << "Nb devices found:"<< g_devices.Count() << std::endl;

    for (UINT32 iDevice = 0; iDevice < g_devices.Count(); iDevice++)
    {
        //std::cout << "" << std::endl;
        hr = g_devices.GetDeviceName(iDevice, &szFriendlyName);
        if (FAILED(hr)) { goto done; }
        std::cout << szFriendlyName << std::endl;
        // The list might be sorted, so the list index is not always the same as the
        // array index. Therefore, set the array index as item data.
        CoTaskMemFree(szFriendlyName);
        szFriendlyName = NULL;
    }
    std::cout << "End of EnumDeviceList" << std::endl;
done:
    return hr;
}



int main()
{
    std::cout <<"Main" << std::endl;
    UpdateDeviceList();
    while (1);
    return 0;
}
Rahat Zaman
  • 1,322
  • 14
  • 32
0

This is more close to what you want(Note that, all STRING types are std::string):

int _GetUSBCameraDevicesList(std::vector<__STRING__>& list, std::vector<__STRING__>& devicePaths)
{
    //COM Library Initialization
    //comInit();

    ICreateDevEnum* pDevEnum = NULL;
    IEnumMoniker* pEnum = NULL;
    int deviceCounter = 0;
    CoInitialize(NULL);

    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
        CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
        reinterpret_cast<void**>(&pDevEnum));


    if (SUCCEEDED(hr))
    {
        // Create an enumerator for the video capture category.
        hr = pDevEnum->CreateClassEnumerator(
            CLSID_VideoInputDeviceCategory,
            &pEnum, 0);

        if (hr == S_OK) {

            printf("SETUP: Looking For Capture Devices\n");
            IMoniker* pMoniker = NULL;

            while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {

                IPropertyBag* pPropBag;
                hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
                    (void**)(&pPropBag));

                if (FAILED(hr)) {
                    pMoniker->Release();
                    continue;  // Skip this one, maybe the next one will work.
                }


                // Find the description or friendly name.
                VARIANT varName;
                VariantInit(&varName);
                hr = pPropBag->Read(L"Description", &varName, 0);

                if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0);

                if (SUCCEEDED(hr))
                {

                    hr = pPropBag->Read(L"FriendlyName", &varName, 0);

                    int count = 0;
                    char tmp[255] = { 0 };
                    //int maxLen = sizeof(deviceNames[0]) / sizeof(deviceNames[0][0]) - 2;
                    while (varName.bstrVal[count] != 0x00 && count < 255)
                    {
                        tmp[count] = (char)varName.bstrVal[count];
                        count++;
                    }
                    list.emplace_back(tmp);
                    //deviceNames[deviceCounter][count] = 0;

                    //if (!silent) DebugPrintOut("SETUP: %i) %s\n", deviceCounter, deviceNames[deviceCounter]);


                    // then read Device Path
                    {
                        VARIANT DP_Path;
                        VariantInit(&DP_Path);

                        hr = pPropBag->Read(L"DevicePath", &DP_Path, 0);

                        if (SUCCEEDED(hr))
                        {
                            int __count = 0;
                            char __tmp[255] = { 0 };
                            while (DP_Path.bstrVal[__count] != 0x00 && __count < 255)
                            {
                                __tmp[__count] = (char)DP_Path.bstrVal[__count];
                                __count++;
                            }

                            devicePaths.emplace_back(__tmp);
                        }
                    }
                }

                pPropBag->Release();
                pPropBag = NULL;

                pMoniker->Release();
                pMoniker = NULL;

                deviceCounter++;
            }

            pDevEnum->Release();
            pDevEnum = NULL;

            pEnum->Release();
            pEnum = NULL;
        }

        //if (!silent) DebugPrintOut("SETUP: %i Device(s) found\n\n", deviceCounter);
    }

    //comUnInit();

    return deviceCounter;
}

Just pass two std::vectorstd::string() to get the list of all connected devices and their paths(Paths may be used to compare device identity if two device have the same friendly name).