一台电脑同时连接多个相同的USB摄像头并根据USB口进行区分

一台电脑同时连接多个相同的USB摄像头并根据USB口进行区分

百度搜了下,

https://blog.csdn.net/kingston110/article/details/112060113?spm=1001.2014.3001.5506

这位老哥给的方案最靠谱,但是这老哥貌似有点保留,根据他的代码是没办法对相同摄像头by不同的USB口进行区分。

最后小研究了下找到解决方案。

1.OPENCV中打开摄像头都是打开摄像头的Index,这个Index是通过COM来遍历“CLSID_VideoInputDeviceCategory”,这里可以查询到不同Index的“DevicePath”。

比如:

Index: 0->"\\?\usb#vid_xxxx&pid_xxxx&mi_00#6&53e1f6&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"

这里用“#”作为字符串的分割点,取出“6&53e1f6&0&0000”作为后面USB端口比较的字符串

代码:

int listDevices(std::map<std::string,int>& list)
{
	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)
		{
			IMoniker *pMoniker = NULL;
			int iCamID = 0;
			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"DevicePath", &varName, 0);
				if (SUCCEEDED(hr))
				{
					_bstr_t bstr(varName);
					std::string strtmp = bstr;
					std::vector<std::string> listtmp;
					tool_StringA::split(strtmp, listtmp, '#');
					strtmp = listtmp[2];
					std::transform(strtmp.begin(), strtmp.end(), strtmp.begin(), ::tolower);
					list.emplace(strtmp,iCamID++);
					printf("ID:%d - %s\n", iCamID - 1, strtmp.c_str());
				}

				pPropBag->Release();
				pPropBag = NULL;

				pMoniker->Release();
				pMoniker = NULL;

				deviceCounter++;
			}

			pDevEnum->Release();
			pDevEnum = NULL;

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

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

	//comUnInit();

	return deviceCounter;
}

2. 根据USB口找到上面对应的信息:

这个位置可以通过SetupDiGetDevicePropertyW这个API 传入DEVPKEY_Device_LocationInfo得到,

对应的信息如下:

“USB\VID_xxxx&PID_xxxx&MI_00\6&53e1f6&0&0000”->"0000.0014.0000.005.000.000.000.000.000"

“USB\VID_xxxx&PID_xxxx&MI_00\6&53e1f6&0&0000”分割‘\\’,得到"6&53e1f6&0&0000",和上面取到的信息一样,当然大小写不一样需要转换下。

这段代码如下:

void EnumDevices(std::map<std::string, std::string> &listCamera)
{
	CONST GUID *pClassGuid = NULL;

	unsigned i, j;
	DWORD dwSize, dwPropertyRegDataType;
	DEVPROPTYPE ulPropertyType;
	CONFIGRET status;
	HDEVINFO hDevInfo;
	SP_DEVINFO_DATA DeviceInfoData;
	const static LPCTSTR arPrefix[3] = { TEXT("VID_"), TEXT("PID_"), TEXT("MI_") };
	TCHAR szDeviceInstanceID[MAX_DEVICE_ID_LEN];
	TCHAR szDesc[1024], szHardwareIDs[4096];
	WCHAR szBuffer[4096] = { 0 };
	LPTSTR pszToken, pszNextToken;
	TCHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];


	// List all connected USB devices  
	hDevInfo = SetupDiGetClassDevs(pClassGuid, ("USB"), NULL, pClassGuid != NULL ? DIGCF_PRESENT : DIGCF_ALLCLASSES | DIGCF_PRESENT);
	if (hDevInfo == INVALID_HANDLE_VALUE)
		return;

	// Find the ones that are driverless  
	for (i = 0; ; i++)
	{
		std::wstring strDevice_Friendly_Name, strDevice_Location_Info;
		DeviceInfoData.cbSize = sizeof(DeviceInfoData);
		if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
			break;

		status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0);
		if (status != CR_SUCCESS)
			continue;

		if (SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
			&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))
		{
			memset(szBuffer, 0, sizeof(WCHAR) * 4096);
			if (SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_FriendlyName,
				&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))
			{
				strDevice_Friendly_Name = szBuffer;
			}
			memset(szBuffer, 0, sizeof(WCHAR) * 4096);
			if (SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_LocationInfo,
				&ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))
			{
				strDevice_Location_Info = szBuffer;
			}

			std::string Location, FriendlyName;
			//Location = Cto_string(strDevice_Location_Info);
			//FriendlyName = Cto_string(strDevice_Friendly_Name);
			Unicode2ANSI(strDevice_Location_Info, Location);
			Unicode2ANSI(strDevice_Friendly_Name, FriendlyName);

			std::string::size_type pos = Location.find("0000.0014");
			if (pos != std::string::npos)
			{
				pos = FriendlyName.find("Camera");
				if (pos != std::string::npos)
				{
					std::string strtmp = szDeviceInstanceID;
					std::vector<std::string> listtmp;
					tool_StringA::split(strtmp, listtmp, '\\');
					strtmp = listtmp[2];
					std::transform(strtmp.begin(), strtmp.end(), strtmp.begin(), ::tolower);
					listCamera.emplace(Location, strtmp);
					printf("%s - %s\n", strtmp.c_str(), Location.c_str());
				}
			}
		}

	}
}

这样基本就可以了,可以把需要区分的usb端口号“0000.0014.0000.006.000.000.000.000”写入你的配置文件中即可~

std::map<std::string, int> camIDlist;
listDevices(camIDlist);

inih::INIReader r = inih::INIReader{ "./setting.ini" };

const auto& v3 = r.Get<std::string>("Setting", "CamUSBPortLocation");

std::map<std::string, std::string> camList;
EnumDevices(camList);

auto pos = camList.find(v3);
	decltype (pos->second) strDeviceID;
	if (pos != camList.end())
	{
		bFind = true;
		strDeviceID = pos->second;
	}
	else
	{
		printf("没有找到Setting.ini对应的USB摄像头!\n");
		return 0;
	}
	auto itFind = camIDlist.find(strDeviceID);
	if (itFind!=camIDlist.end())
	{
		iCamID = itFind->second;
	}
	else
	{
		printf("没有找到对应的USB摄像头!\n");
		return 0;
	}

 

 

  • 1
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值