Linux下基于V4L2 USB Camera操作

转:http://www.openhw.org/module/forum/thread-586794-1-1.html

 一直在做的视频流硬件加速工作基本结束, 最后验证的时候发现一个问题,为了计算视频流加速的加速比打算采用1920x1080的分辨率,买的USB camera是1080P的,在window下也正常工作; 但是我用的opencv的VideoCap类打开摄像头的, 发现其不能设置分辨率(HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP),导致摄像头的分辨率一直是640x480的。因为Opencv摄像头才做也是基于UVC驱动,利用V4L2 API数据采集的, 所以自己根据V4L2重写了摄像头操作相关的API, 发现可以调节分辨率和帧率等信息的, Opencv的驱动应该没写好。

 
      LInux UVC是视频设备驱动,使用前应确保将其加入到linux kernel中(可参考 [RSun +手记6]解决OpenCV不能在目标板中打开摄像头问题),配置完成后,目标板上电后插入USB摄像头, 如果有/dev/video0出现,说明UVC驱动应该没问题。V4L2是linux下根据UVC驱动开发的API,核心是通过ioctl函数实现的。 ioctl是设备驱动程序中对IO通道进行管理的函数,主要是对设备控制/数据寄存器等的读写控制。现在USB摄像头一般都支持iotcl管理的。参考博客:Linux2.6.33下ZC301USB摄像头使用教程
    我将摄像头的操作封装成v4l2cap类(见附件源码)的,具体的操作和注意事项如下:
一:打开摄像头
  linux下驱动设备与文件设备类似,也是可以通告open函数打开的:
vd_info->camfd = open(device, O_RDWR | O_NONBLOCK, 0);
这里需要注意的是打开方式, 加 O_NONBLOCK表示非阻塞方式打开,否则为阻塞方式打开。这一点对摄像头数据采集速度非常重要。非阻塞方式在不主动询问时,会自动采集数据,但是阻塞方式只有在询问后才开始采集。当用定时器进行数据采集时,如果使用阻塞方式,将会额外消耗(800 x 600) 30ms时间(实验测量),非阻塞方式就基本不用等待时间了。所以建议大家使用非阻塞方式。
二:获取摄像头属性
    memset(&vd_info->cap, 0, sizeof(struct v4l2_capability));
    if ( -1 == ioctl(vd_info->camfd, VIDIOC_QUERYCAP,&(vd_info->cap)))
  摄像头属性在v4l2_capability中定义(videodev2.h),包含了driver, bus_info, version等信息。
三:摄像头视频格式
   摄像头视频格式定义在v4l2_format中,在videodev2.h中可以看到几十种视频格式,包括RGB, MJPG,YUYV等,但是常见的摄像头一般只支持V4L2_PIX_FMT_MJPEG和V4L2_PIX_FMT_YUYV格式,为了得到RGB格式图像,MJPG需要解码, YUYV需要YUV到RGB的转换。获取视频格式操作:
   memset(&vd_info->fmt,0,sizeof(struct v4l2_format));
    vd_info->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == ioctl(vd_info->camfd, VIDIOC_G_FMT, &(vd_info->fmt)))

设置摄像头格式类似, 只需将VIDiO_G_FMT改为VIDIOC_S_FMT(G=>Get, S=>Set)
四:设置帧率
    struct v4l2_streamparm *parm = new struct v4l2_streamparm;
     memset(parm,0,sizeof(struct v4l2_streamparm));
     parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//     parm->parm.capture.capturemode = V4L2_MODE_HIGHQUALITY;
     parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
     parm->parm.capture.timeperframe.denominator = 40 ;
     parm->parm.capture.timeperframe.numerator = 1;
     if(-1 == ioctl(vd_info->camfd,VIDIOC_S_PARM,parm))
帧率信息定义在v4l2_streamparm结构体中,parm.capture.timeperframe.denominator就是帧率(frame/s),每帧的时间是1000ms/parm.capture.timeperframe.denominator。帧率的设置不是随意的,各个分辨率下硬件支持的分辨率各不相同,硬件会选择最接近的帧率。比如640*480帧率33,800*600只有15,1920*1080只有5了。
五:抓取帧数据
 摄像头正常打开后,需要设置存储b帧数据的buffer等信息,之后就可以抓取帧数据:
    memset(&vd_info->buf, 0, sizeof(struct v4l2_buffer));
    vd_info->buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    vd_info->buf.memory = V4L2_MEMORY_MMAP;

    if (-1 = ioctl(vd_info->camfd, VIDIOC_DQBUF, &vd_info->buf))
 当采用非阻塞方式打开摄像头时, 不是每次抓取帧数据都会成功, 因为时间不够或者冲突等,但是多抓几次总能抓的到的。
 
除了上面讲的基本操作,还有许多相关的配置, 我将其封装在附件的v4l2cap类中,希望对大家有所帮助。
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读