V4L2采集摄像头过程中的几点细节

本文主要分享了使用V4L2在Linux下进行摄像头图像采集时的一些重要细节,包括`v4l2_capability`结构体中`capabilities`字段的BIT0和BIT26的重要性,以及mmap在图像采集过程中的作用。通过mmap建立内核与用户空间的连接,实现高效的数据传输。同时,介绍了如何开始图像采集,以及在需要图像时如何从队列中获取和释放帧。附带了已测试成功的C++代码。
摘要由CSDN通过智能技术生成

 最近打算做一个H.264的图像传输设备,第一步当然是采集图像,了解过相关知识后得知图像采集需要用到V4L2,于是在网上找关于V4L2的资料,昨天终于把V4L2看的差不多,并且把网上的程序封装成了符合我的习惯的一个C++类。关于V4L2采集图像在网上有很多博客讲的都很详细,而我也水平有限,就不写V4L2的详细采集过程了,现在分享几点学习V4L2采集图像时遇到的一些不容易懂或者易错的地方,相信对于初学者来说这些困惑点也会遇到。
 首先放上一张V4L2采集图像的流程图,把这个图理解透了也就差不多了。
V4L2采集图像流程

 struct v4l2_capability里的capabilities的BIT0和BIT26很重要,这两个必须是1,否则是没法采集到图像的。可以使用这样的代码来验证一下:

//judge wherher or not to be a video-get device
if (!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE))
{
    printf("The Current device is not a video capture device\n");
    exit(EXIT_FAILURE);
}
//judge whether or not to supply the form of video stream
if (!(cap.capabilities & V4L2_CAP_STREAMING))
{
    printf("The Current device does not support streaming i/o\n");
    exit(EXIT_FAILURE);
}

 第二点要说的就是mmap这一步,这一步会建立起内核与用户之间的联系,在打开设备的视频流后,只要第四步里申请到的队列不是满的,设备就会采集图像并送到队列中,而用户是不能访问内核的,所以我们需要mmap来建立起这个联系,我们才能得到图像数据。当然可以用read来读取,但是操作IO效率是很慢的。

for (n_buffer = 0; n_buffer < reqbufs.count; n_buffer++)
{
    //stand for a frame
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = n_buffer;

    //check the information of the kernel cache requested 
    if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
    {
        perror("xioctl VIDIOC_QUERYBUF");
        exit(EXIT_FAILURE);
    }

    usr_buf[n_buffer].length = buf.length;
    usr_buf[n_buffer].start =
        (char *)mmap(
        NULL,
        buf.length,
        PROT_READ | PROT_WRITE,
        MAP_PRIVATE,
        fd,
        buf.m.offset
        );
    if (MAP_FAILED == usr_buf[n_buffer].start)
    {
        perror("mmap");
        exit(EXIT_FAILURE);
    }
}

 在开始采集图像这一步里,程序所做的工作有两点。
 一是把申请到的帧缓存区送到视频采集队列,也就是第四步申请到的帧缓冲区

//place the kernel cache to a queue
for (i = 0; i < n_buffer; i++)
{
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;

    if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)){
        perror("xioctl VIDIOC_QBUF");
        exit(EXIT_FAILURE);
    }
}

 二是打开视频流数据的采集,这个简单

enum v4l2_buf_type type;
//start capture data
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
{
    printf("i=%d.\n", i);
    perror("VIDIOC_STREAMON");
    close(fd);
    exit(EXIT_FAILURE);
}

 在我们需要得到图像的时候,首先要从队列中取出一帧,得到信息后再把这一帧放回队列中就行。

int CameraClass::GetOneImage(struct buffer_type *Image)
{
    struct v4l2_buffer buf;
    unsigned int i;
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    //put cache from queue
    if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
    {
        perror("xioct VIDIOC_DQBUF");
        exit
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值