之前在https://blog.csdn.net/fengbingchun/article/details/103507754 博文中介紹過如何在Linux獲取usb視頻設備的vendor id和product id,這裏介紹在Windows下獲取的方式:
1. 打開設備管理器,如下圖所示,內置攝像頭顯示名爲”Integrated Webcam”,插入的usb攝像頭顯示名爲”Logitech HD Webcam C310”:
選中其中一個,如”Logitech HD Webcam C310”,點擊右鍵,選中”屬性”點擊,-->詳細信息,-->屬性選擇”硬件id”,可獲取vid和pid值,如下圖所示,十六進制vid爲”046D”,pid爲”081B”:
2. 通過執行ffmpeg獲取,執行命令及執行結果如下圖所示:
3. 通過Windows的SetupDiGetDeviceInstanceId函數可以獲得所有usb設備的vid和vid,測試code如下:
int get_all_usb_devices_vid_pid()
{
GUID *guidDev = (GUID*)&GUID_DEVCLASS_USB;
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(guidDev, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE);
CHAR buffer[4000];
DWORD memberIndex = 0;
while (true) {
SP_DEVINFO_DATA deviceInfoData;
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex, &deviceInfoData) == FALSE) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
}
}
DWORD nSize = 0;
SetupDiGetDeviceInstanceId(deviceInfoSet, &deviceInfoData, buffer, sizeof(buffer), &nSize);
buffer[nSize] = '\0';
fprintf(stdout, "%s\n", buffer);
memberIndex++;
}
if (deviceInfoSet) {
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
return 0;
}
執行結果如下:
4. 提取FFmpeg源碼中部分code,測試code如下:
std::unique_ptr<char[]> dup_wchar_to_utf8(wchar_t *w, int& len)
{
len = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
std::unique_ptr<char[]> s(new char[len]);
WideCharToMultiByte(CP_UTF8, 0, w, -1, s.get(), len, 0, 0);
return s;
}
int parse_string(const std::string& src, std::string& vid, std::string& pid)
{
int pos = src.find("vid_");
if (pos == std::string::npos) return -1;
vid.assign(src, pos + 4, 4);
pos = src.find("pid_");
if (pos == std::string::npos) return -1;
pid.assign(src, pos + 4, 4);
return 0;
}
int get_usb_video_devices_vid_pid()
{
CoInitialize(0);
ICreateDevEnum *devenum = NULL;
int r = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&devenum));
if (r != S_OK) {
fprintf(stdout, "fail to CoCreateInstance: %d\n", r);
return -1;
}
IEnumMoniker *classenum = NULL;
r = ICreateDevEnum_CreateClassEnumerator(devenum, CLSID_VideoInputDeviceCategory, (IEnumMoniker **)&classenum, 0);
if (r != S_OK) {
fprintf(stdout, "fail to ICreateDevEnum_CreateClassEnumerator: %d\n", r);
return -1;
}
IBaseFilter *device_filter = NULL;
IMoniker *m = NULL;
while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) {
IPropertyBag *bag = NULL;
VARIANT var;
r = IMoniker_BindToStorage(m, 0, 0, IID_IPropertyBag, (void **)&bag);
if (r != S_OK) {
fprintf(stdout, "fail to IMoniker_BindToStorage: %d\n", r);
return -1;
}
var.vt = VT_BSTR;
r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
if (r != S_OK) {
fprintf(stdout, "fail to IPropertyBag_Read: %d\n", r);
return -1;
}
int length;
auto friendly_name = dup_wchar_to_utf8(var.bstrVal, length);
fprintf(stdout, "friendly_name: %s\n", friendly_name.get());
LPMALLOC co_malloc = NULL;
r = CoGetMalloc(1, &co_malloc);
if (r != S_OK) {
fprintf(stdout, "fail to CoGetMalloc: %d\n", r);
return -1;
}
IBindCtx *bind_ctx = NULL;
r = CreateBindCtx(0, &bind_ctx);
if (r != S_OK) {
fprintf(stdout, "fail to CreateBindCtx: %d\n", r);
return -1;
}
LPOLESTR olestr = NULL;
r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr);
if (r != S_OK) {
fprintf(stdout, "fail to IMoniker_GetDisplayName: %d\n", r);
return -1;
}
auto unique_name = dup_wchar_to_utf8(olestr, length);
/* replace ':' with '_' since we use : to delineate between sources */
std::for_each(unique_name.get(), unique_name.get() + length, [](char& ch) { if (ch == ':') ch = '_'; });
fprintf(stdout, "unique_name: %s\n", unique_name.get());
std::string src(unique_name.get()), vid, pid;
parse_string(src, vid, pid);
unsigned int value_vid, value_pid;
std::istringstream(vid) >> std::hex >> value_vid;
std::istringstream(pid) >> std::hex >> value_pid;
fprintf(stdout, "usb device name: %s, vid: %s, value: %d; pid: %s, value: %d\n",
friendly_name.get(), vid.c_str(), value_vid, pid.c_str(), value_pid);
if (olestr && co_malloc)
IMalloc_Free(co_malloc, olestr);
if (bind_ctx)
IBindCtx_Release(bind_ctx);
if (bag)
IPropertyBag_Release(bag);
IMoniker_Release(m);
}
IEnumMoniker_Release(classenum);
return 0;
}
執行結果如下: