linux v4l2 摄像头采集视频的方法

Linux上用v4l2函数接口获取视频主要是一个步骤流程,一步步做就很容易,现已我在qt下编写的一个读取摄像头视频的程序中的相关代码为例。

首先打开视频设备,比如/dev/video0,

[cpp]  view plain  copy
  1. fd = open(dev_name.toStdString().c_str(), O_RDWR/*|O_NONBLOCK*/, 0);  
  2.   
  3.     if(-1 == fd)  
  4.     {  
  5.         emit display_error(tr("open: %1").arg(QString(strerror(errno))));  
  6.         return -1;  
  7.     }  
然后初始化设备
[cpp]  view plain  copy
  1. v4l2_capability cap;  
  2. v4l2_cropcap cropcap;  
  3. v4l2_crop crop;  
  4. v4l2_format fmt;  
  5.   
  6. if(-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))  
  7. {   //查询设备功能  
  8.     if(EINVAL == errno)  
  9.     {  
  10.         emit display_error(tr("%1 is no V4l2 device").arg(dev_name));  
  11.     }  
  12.     else  
  13.     {  
  14.         emit display_error(tr("VIDIOC_QUERYCAP: %1").arg(QString(strerror(errno))));  
  15.     }  
  16.     return -1;  
  17. }  
  18.   
  19. if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))  
  20. {   //视频采集  
  21.     emit display_error(tr("%1 is no video capture device").arg(dev_name));  
  22.     return -1;  
  23. }  
  24.   
  25. if(!(cap.capabilities & V4L2_CAP_STREAMING))  
  26. {   //视频流  
  27.     emit display_error(tr("%1 does not support streaming i/o").arg(dev_name));  
  28.     return -1;  
  29. }  
  30.   
  31. CLEAR(cropcap);  
  32.   
  33. cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  34.   
  35. if(0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap))  
  36. {  
  37.     CLEAR(crop);  
  38.     crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  39.     crop.c = cropcap.defrect;  
  40.   
  41.     if(-1 == ioctl(fd, VIDIOC_S_CROP, &crop))  
  42.     {  
  43.         if(EINVAL == errno)  
  44.         {  
  45.             emit display_error(tr("VIDIOC_S_CROP not supported"));  
  46.         }  
  47.         else  
  48.         {  
  49.             emit display_error(tr("VIDIOC_S_CROP: %1").arg(QString(strerror(errno))));  
  50.             return -1;  
  51.         }  
  52.     }  
  53. }  
  54. else  
  55. {  
  56.     emit display_error(tr("VIDIOC_CROPCAP: %1").arg(QString(strerror(errno))));  
  57.     return -1;  
  58. }  
  59.   
  60. CLEAR(fmt);  
  61.   
  62. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  63. fmt.fmt.pix.width = 640;  
  64. fmt.fmt.pix.height = 480;  
  65. fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//YUV4:2:2  
  66. fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;//隔行扫描  
  67.   
  68. if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))  
  69. {  //设置视频格式  
  70.     emit display_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));  
  71.     return -1;  
  72. }  
  73.   
  74. if(-1 == init_mmap())  
  75. {  //初始化mmap,内存映射  
  76.     return -1;  
  77. }  
初始化mmap   
[cpp]  view plain  copy
  1. v4l2_requestbuffers req;  
  2. CLEAR(req);  
  3.   
  4. req.count = 4;  
  5. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  6. req.memory = V4L2_MEMORY_MMAP;  
  7.   
  8. if(-1 == ioctl(fd, VIDIOC_REQBUFS, &req))  
  9. {   //请求buf  
  10.     if(EINVAL == errno)  
  11.     {  
  12.         emit display_error(tr("%1 does not support memory mapping").arg(dev_name));  
  13.         return -1;  
  14.     }  
  15.     else  
  16.     {  
  17.         emit display_error(tr("VIDIOC_REQBUFS %1").arg(QString(strerror(errno))));  
  18.         return -1;  
  19.     }  
  20. }  
  21.   
  22. if(req.count < 2)  
  23. {  
  24.     emit display_error(tr("Insufficient buffer memory on %1").arg(dev_name));  
  25.     return -1;  
  26. }  
  27.   
  28. buffers = (buffer*)calloc(req.count, sizeof(*buffers));//分配内存大小  
  29.   
  30. if(!buffers)  
  31. {  
  32.     emit display_error(tr("out of memory"));  
  33.     return -1;  
  34. }  
  35.   
  36. for(n_buffers = 0; n_buffers < req.count; ++n_buffers)  
  37. {  
  38.     v4l2_buffer buf;  
  39.     CLEAR(buf);  
  40.   
  41.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  42.     buf.memory = V4L2_MEMORY_MMAP;  
  43.     buf.index = n_buffers;  
  44.   
  45.     if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))  
  46.     {   //获取buf信息起始位置,长度等  
  47.         emit display_error(tr("VIDIOC_QUERYBUF: %1").arg(QString(strerror(errno))));  
  48.         return -1;  
  49.     }  
  50.   
  51.     buffers[n_buffers].length = buf.length;  
  52.     buffers[n_buffers].start =  
  53.             mmap(NULL, // start anywhere  
  54.                  buf.length,  
  55.                  PROT_READ | PROT_WRITE,  
  56.                  MAP_SHARED,  
  57.                  fd, buf.m.offset);//映射  
  58.   
  59.     if(MAP_FAILED == buffers[n_buffers].start)  
  60.     {  
  61.         emit display_error(tr("mmap %1").arg(QString(strerror(errno))));  
  62.         return -1;  
  63.     }  
  64. }  
开始捕获视频
[cpp]  view plain  copy
  1. int VideoDevice::start_capturing()  
  2. {  
  3.     unsigned int i;  
  4.     for(i = 0; i < n_buffers; ++i)  
  5.     {  
  6.         v4l2_buffer buf;  
  7.         CLEAR(buf);  
  8.   
  9.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  10.         buf.memory =V4L2_MEMORY_MMAP;  
  11.         buf.index = i;  
  12. //        fprintf(stderr, "n_buffers: %d\n", i);  
  13.   
  14.         if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))  
  15.         {   //把buf排成一列  
  16.             emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));  
  17.             return -1;  
  18.         }  
  19.     }  
  20.   
  21.     v4l2_buf_type type;  
  22.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  23.   
  24.     if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))  
  25.     {  
  26.         emit display_error(tr("VIDIOC_STREAMON: %1").arg(QString(strerror(errno))));  
  27.         return -1;  
  28.     }  
  29.     return 0;  
  30. }  
获取一帧图像
[cpp]  view plain  copy
  1. int VideoDevice::get_frame(void **frame_buf, size_t* len)  
  2. {  
  3.     v4l2_buffer queue_buf;  
  4.     CLEAR(queue_buf);  
  5.   
  6.     queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  7.     queue_buf.memory = V4L2_MEMORY_MMAP;  
  8.   
  9.     if(-1 == ioctl(fd, VIDIOC_DQBUF, &queue_buf))  
  10.     {   //从队列中取出一个buf  
  11.         switch(errno)  
  12.         {  
  13.         case EAGAIN:  
  14. //            perror("dqbuf");  
  15.             return -1;  
  16.         case EIO:  
  17.             return -1 ;  
  18.         default:  
  19.             emit display_error(tr("VIDIOC_DQBUF: %1").arg(QString(strerror(errno))));  
  20.             return -1;  
  21.         }  
  22.     }  
  23.   
  24.     *frame_buf = buffers[queue_buf.index].start;  
  25.     *len = buffers[queue_buf.index].length;  
  26.     index = queue_buf.index;  
  27.   
  28.     return 0;  
  29.   
  30. }  
获取完后,将这一帧图像的buf放回去
[cpp]  view plain  copy
  1. int VideoDevice::unget_frame()  
  2. {  
  3.     if(index != -1)  
  4.     {  
  5.         v4l2_buffer queue_buf;  
  6.         CLEAR(queue_buf);  
  7.   
  8.         queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  9.         queue_buf.memory = V4L2_MEMORY_MMAP;  
  10.         queue_buf.index = index;  
  11.   
  12.         if(-1 == ioctl(fd, VIDIOC_QBUF, &queue_buf))  
  13.         {   //将buf放入队列  
  14.             emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));  
  15.             return -1;  
  16.         }  
  17.         return 0;  
  18.     }  
  19.     return -1;  
  20. }  
停止视频捕捉
[cpp]  view plain  copy
  1. int VideoDevice::stop_capturing()  
  2. {  
  3.     v4l2_buf_type type;  
  4.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  5.   
  6.     if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))  
  7.     {  
  8.         emit display_error(tr("VIDIOC_STREAMOFF: %1").arg(QString(strerror(errno))));  
  9.         return -1;  
  10.     }  
  11.     return 0;  
  12. }  
卸载摄像头设备
[cpp]  view plain  copy
  1. int VideoDevice::uninit_device()  
  2. {  
  3.     unsigned int i;  
  4.     for(i = 0; i < n_buffers; ++i)  
  5.     {  
  6.         if(-1 == munmap(buffers[i].start, buffers[i].length))  
  7.         {  
  8.             emit display_error(tr("munmap: %1").arg(QString(strerror(errno))));  
  9.             return -1;  
  10.         }  
  11.   
  12.     }  
  13.     free(buffers);  
  14.     return 0;  
  15. }  
关闭视频设备文件
[cpp]  view plain  copy
  1. int VideoDevice::close_device()  
  2. {  
  3.     if(-1 == close(fd))  
  4.     {  
  5.         emit display_error(tr("close: %1").arg(QString(strerror(errno))));  
  6.         return -1;  
  7.     }  
  8.     return 0;  
  9. }  
这就是完整的采集视频的流程,当然可以多增加配置采集的视频格式的代码。
  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值