在使用usb摄像头获取视频时,有时需要获取此摄像头供应商ID(vendor id, vid)和产品ID(product id, pid),这里在Linux下提供获取vid和pid的8种方法:
1. 通过v4l2中结构体v4l2_capability的成员变量card:此变量中会包含设备名、vid、pid信息,其内容例如为“UVC Camera (046d:081b)”,其中”:”前四个字符为vid,”:”后四个字符为pid,代码段如下:其中str存放card的值
std::string str = (*it).second;
auto pos = str.find(":");
if (pos != std::string::npos) {
std::string vid_str = str.substr(pos-4, 4);
std::string pid_str = str.substr(pos+1, 4);
std::istringstream(vid_str) >> std::hex >> vid_value;
std::istringstream(pid_str) >> std::hex >> pid_value;
fprintf(stdout, " vid: str: %s, value: %d; pid: str: %s, value: %d\n", vid_str.c_str(), vid_value, pid_str.c_str(), pid_value);
}
2. 通过解析/sys/class/video4linux/xxxx/device/modalias文件,其中xxxx为video0或video1等,当有usb camera插入到Linux上时,则会有此文件,其内容例如为” usb:v046Dp081Bd0012dcEFdsc02dp01ic0Eisc01ip00in00”,其中”usb:v”后四个字符为vid,”usb:v046Dp”后四个字符为pid,代码段如下:其中str为设备地址,如"/dev/video0"
str = (*it).first;
pos = str.find_last_of("/");
if (pos == std::string::npos) {
fprintf(stderr, " fail to get vid and pid\n");
}
std::string name = str.substr(pos+1);
std::string modalias;
vid_value = 0; pid_value = 0;
if (!(std::ifstream("/sys/class/video4linux/" + name + "/device/modalias") >> modalias))
fprintf(stderr, " fail to read modalias\n");
if (modalias.size() < 14 || modalias.substr(0,5) != "usb:v" || modalias[9] != 'p')
fprintf(stderr, " not a usb format modalias\n");
if (!(std::istringstream(modalias.substr(5,4)) >> std::hex >> vid_value))
fprintf(stderr, " fail to read vid\n");
if (!(std::istringstream(modalias.substr(10,4)) >> std::hex >> pid_value))
fprintf(stderr, " fail to read pid\n");
fprintf(stdout, " vid value: %d, pid value: %d\n", vid_value, pid_value);
3. 通过解析/proc/bus/input/devices文件,输入设备名可以获取对应的vid和pid,代码段如下:其中bus_line为"I: Bus=0003 Vendor=046d Product=081b Version=0012"
auto pos = bus_line.find("Vendor");
if (pos != std::string::npos) {
std::string str = bus_line.substr(pos+7, 4);
std::istringstream(str) >> std::hex >> vid;
} else {
fprintf(stderr, "not found vid\n");
return -1;
}
pos = bus_line.find("Product");
if (pos != std::string::npos) {
std::string str = bus_line.substr(pos+8, 4);
std::istringstream(str) >> std::hex >> pid;
} else {
fprintf(stderr, "not found pid\n");
return -1;
}
4. 通过设备的event可以直接读取vid和pid,如event为event6,则为/sys/class/input/event6/device/id/vendor和/sys/class/input/event6/device/id/product,可通过解析/proc/bus/input/devices得到指定设备的event,代码段为:其中event_line为"H: Handlers=kbd event6"
auto pos = event_line.find(search_event_line);
if (pos != std::string::npos) {
std::string str = event_line.substr(pos, std::string::npos);
str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
std::string vid_str, pid_str;
std::string prefix = "/sys/class/input/" + str + "/device/id/";
if (!(std::ifstream(prefix +"vendor") >> vid_str)) {
fprintf(stderr, "not found /device/id/vendor\n");
return -1;
}
if (!(std::ifstream(prefix + "product") >> pid_str)) {
fprintf(stderr, "not found /device/id/product\n");
return -1;
}
std::istringstream(vid_str) >> std::hex >> vid;
std::istringstream(pid_str) >> std::hex >> pid;
}
5. 通过解析/sys/kernel/debug/usb/devices可获取vid和pid,但是好像需要root权限。
6. 通过在Linux上安装libusb,然后调用其库提供的相应接口来获取vid和pid。
7. 可以通过执行lsusb命令获取vid和pid,执行结果如下:其中红框标注的为真实usb摄像头信息

8. 可以通过执行v4l2-ctl --list-devices命令获取vid和pid,执行结果如下:

以下是上面1--4种方法实现的完整C++代码:
#include "funset.hpp"
#include
执行结果如下:从结果可知,这四种方法与通过命令行获取到的pid和vid是一致的。

GitHub:https://github.com//fengbingchun/OpenCV_Test