前言
在使用USB摄像头经常遇到一些问题, 这种问题无论是驱动的稳定性还是硬件的小问题(采集异常),归根到底是设备节点/dev/video0
没有,又或者在某一时间片节点掉了后,又恢复了,节点编号变化了,因此导致应用层的服务中断。或者是 基于此, 做了如下几种方式解决。
一、采用udev规则
1)创建一个rules文件, 可以参照/etc/udev/rules.d/
下的文件创建,例如:
KERNEL=="video[02]", SUBSYSTEM=="video4linux", ATTRS{idVendor}=="114d", ATTRS{idProduct}=="8589", SYMLINK+="v4l/main"
KERNEL=="video[13]", SUBSYSTEM=="video4linux", ATTRS{idVendor}=="114d", ATTRS{idProduct}=="8589", SYMLINK+="v4l/main_video"
其中114d
和8589
修改为USB厂家的VID:PID
,如何查看?linux下使用命令lsusb查看,结果如下:
Bus 002 Device 002: ID 114d:8589 Alpha Imaging Technology Corp.
如果修改后立即生效, service udev reload;service udev restart
2)该方式会自动建立VID:PID
对应厂家的设备的一个软连接,使用如下命令查看:
root@ubuntu-desktop:/home/ubuntu/app# ls -l /dev/v4l/main
lrwxrwxrwx 1 root root 9 11月 17 2020 /dev/v4l/main -> ../video0
注意:
- 在某种情况下出现失效,比如USB总线上增加了
深度相机
,可能会失效(在NANO上接入深度相机确认失效了),因为深度相机也是采用该方式,所以可能有一定冲突,目前暂未解决该ISSUE
,因此有了其他替代方式。 - 该方式只在NVIDIA中尝试, 国产音视频芯片未做验证尝试。
二、检测USB设备的方式
该方式是备用方式,需要一直轮询设备是否存在,如果不存在,做一些去初始化的动作。
对于比较多的usb摄像头(在/dev/下有多个video),usb的设备如下:
crw-rw----+ 1 root video 81, 0 5月 25 09:38 /dev/video0 //采集卡
crw-rw----+ 1 root video 81, 3 5月 25 09:38 /dev/video1 //采集卡
crw-rw-rw-+ 1 root plugdev 81, 6 5月 25 09:38 /dev/video2 //深度相机
crw-rw-rw-+ 1 root plugdev 81, 7 5月 25 09:38 /dev/video3 //深度相机
crw-rw-rw-+ 1 root plugdev 81, 8 5月 25 09:38 /dev/video4 //深度相机
crw-rw----+ 1 root video 81, 9 5月 25 09:38 /dev/video5 //USB摄像头
如果只对USB监测,如下代码是发现USB摄像头是否存在的接口,返回0表示成功,非0表示失败,对应的错误码FISHEYS_NON_EXISTD
表示未发现USB摄像头,PIPE_READ_ERROR
PIPE调用失败。
MV_S32 FindFishEyeCamera(char *pName)
{
char videoInodeBuf[MIN_STRING] = {0}, cmdString[MIN_STRING] = {0};
char lsusbBuf[MAX_STRING*2] = {0};
std::string videoPath[5]={""};
static int flag = 1;
if(!pName){TRACK_LOG(LOG_ERROR, RED_START "ERROR:" COLOR_END); return MV_FAILURE;}
/* Find VID/PID */
FILE *pPipe = (FILE*)0;
if(!pPipe)
{
snprintf(cmdString, MIN_STRING, "lsusb");
pPipe = popen(cmdString, "r");
if(!pPipe)
{
TRACK_LOG(LOG_ERROR, RED_START "PIPE FAILURE!" COLOR_END);
}
fread(lsusbBuf, sizeof(MV_U8), MAX_STRING*2, pPipe);
pclose(pPipe); pPipe = (FILE*)0;
/**
* "0c45:6366" strings edit "0c45" because the fisheye camera when update version
cause "4366" become "4361".
*/
if(MV_NULL == strstr(lsusbBuf, "0c45"/*:6366*/))
{
TRACK_LOG(LOG_ERROR, RED_START "鱼眼镜头不存在!" COLOR_END);
return FISHEYS_NON_EXISTD;
}
// TRACK_LOG(LOG_INFO, GREEN_START "Fisheye camera exitstd." COLOR_END);
}
/*get inode*/
if(!pPipe)
{
//剔除RS2的设备节点
snprintf(cmdString, MIN_STRING, "ls -l /dev/video* |grep -v plugdev |awk '{print $10}'");
pPipe = popen(cmdString, "r");
if(!pPipe)
{
TRACK_LOG(LOG_ERROR, RED_START "PIPE FAILURE!" COLOR_END);
return PIPE_READ_ERROR;
}
// fread(videoInodeBuf, sizeof(MV_U8), MIN_STRING, pPipe);
int line = 0;
while(!feof(pPipe))
{
if(fgets(videoInodeBuf, MIN_STRING, pPipe))
{
videoPath[line] = videoInodeBuf;
if(flag){
TRACK_LOG(LOG_INFO, "video_path:%s", videoPath[line].c_str());
flag = 0;
}
line++;
}
}
pclose(pPipe); pPipe = (FILE*)0;
if(line >= 3 )
{
memcpy(pName, videoPath[2].c_str(), strlen(videoPath[2].c_str()));
}
else
{
return FISHEYS_NON_EXISTD;
}
}
return MV_SUCCESS;
}
展望
如果有其他更好的解决方案, 麻烦评论留言,互相讨论学习。