Linux v4l2编程API

在进行V4L2开发中,常用的命令标志符如下(some are optional): 
•    VIDIOC_REQBUFS:分配内存 
•    VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 
•    VIDIOC_QUERYCAP:查询驱动功能 
•    VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式 
•    VIDIOC_S_FMT:设置当前驱动的频捕获格式 
•    VIDIOC_G_FMT:读取当前驱动的频捕获格式 
•    VIDIOC_TRY_FMT:验证当前驱动的显示格式 
•    VIDIOC_CROPCAP:查询驱动的修剪能力 
•    VIDIOC_S_CROP:设置视频信号的边框 
•    VIDIOC_G_CROP:读取视频信号的边框 
•    VIDIOC_QBUF:把数据从缓存中读取出来 
•    VIDIOC_DQBUF:把数据放回缓存队列 
•    VIDIOC_STREAMON:开始视频显示函数 
•    VIDIOC_STREAMOFF:结束视频显示函数 
•    VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。

1  查询设备能力
struct v4l2_capability cap;
rel = ioctl(fdUsbCam, VIDIOC_QUERYCAP,&cap);
if(rel != 0)
{
    perror("ioctl VIDIOC_QUERYCAP");
    return -1;
}

2:查询当前捕获格式:
 memset(&fmt, 0, sizeof(structv4l2_format));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fdUsbCam, VIDIOC_G_FMT, &fmt)< 0)
{
     printf("get format failed\n");
     return -1;
}

3:设置当前捕获格式 
fmt.type      = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width =  640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field    = V4L2_FIELD_INTERLACED;
rel = ioctl(fdUsbCam, VIDIOC_S_FMT, &fmt);
if (rel < 0)
{
   printf("\nSet format failed\n");
   return -1;
}
4:读取Stream 设置。(主要是帧率)
struct v4l2_streamparm *setfps;
setfps=(struct v4l2_streamparm *) calloc(1, sizeof(structv4l2_streamparm));
memset(setfps, 0, sizeof(struct v4l2_streamparm));
setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
rel = ioctl(fdUsbCam,VIDIOC_G_PARM, setfps);
    if(rel == 0)
    {
           printf("\n  Frame rate:  %u/%u\n",
           setfps->parm.capture.timeperframe.denominator,
           setfps->parm.capture.timeperframe.numerator );
    }
    else
    {
       perror("Unable to read out current framerate");
       return -1;
    }

5:设置Stream参数。(主要是采集帧数)
struct v4l2_streamparm *setfps;
setfps=(struct v4l2_streamparm *) calloc(1, sizeof(structv4l2_streamparm));
memset(setfps, 0, sizeof(struct v4l2_streamparm));
setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
setfps->parm.capture.timeperframe.numerator=1;
setfps->parm.capture.timeperframe.denominator=60;
rel = ioctl(fdUsbCam,VIDIOC_S_PARM, setfps);
if(rel != 0)
{
       printf("\nUnable to Set FPS");
       return -1;
}

6 分配内存
接下来可以为视频捕获分配内存:
struct v4l2_requestbuffers  req;
req.count  = BUFFER_COUNT;//缓存数量,也就是说在缓存队列里保持多少张照片(3)
req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;//数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
req.memory = V4L2_MEMORY_MMAP;//V4L2_MEMORY_MMAP或V4L2_MEMORY_USERPTR
if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
      return -1;
}

7 获取并记录缓存的物理空间
使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:
typedef struct VideoBuffer {
    void   *start;
    size_t  length;
} VideoBuffer;
使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列: 
typedef struct VideoBuffer {
    void   *start;
    size_t  length;
} VideoBuffer;
v4l2_buffer     结构如下:
struct v4l2_buffer {
        __u32                 index;
        enum v4l2_buf_type    type;
        __u32                 bytesused;
        __u32                 flags;
        enum v4l2_field       field;
        struct timeval        timestamp;
        struct v4l2_timecode  timecode;
        __u32                 sequence;
        /* memory location */
        enum v4l2_memory      memory;
        union {
                __u32            offset;
                unsigned long  userptr;
        } m;
        __u32                   length;
        __u32                   input;
        __u32                   reserved;
};
VideoBuffer*    buffers = calloc( req.count, sizeof(*buffers) );
struct v4l2_buffer  buf;
for (numBufs = 0; numBufs < req.count; numBufs++) 
{
    memset( &buf, 0, sizeof(buf) );
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = numBufs;
    // 读取缓存
    if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
        return -1;
    }
    buffers[numBufs].length = buf.length;
    // 转换成相对地址
    buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
                                MAP_SHARED,fd, buf.m.offset);

//NULL起始地址,有huf.length这么长,fd是映射到的文件,offset被映射对象内容的起点。
—MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新
    if (buffers[numBufs].start == MAP_FAILED) {
        return -1;
    }
    // 放入缓存队列
    if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
        return -1;
    }
}
8 处理采集数据
V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=0;//读取缓存
if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) == -1)
{
    return -1;
}
//…………视频处理算法//重新放入缓存队列(重点图像处理)
if (ioctl(cameraFd, VIDIOC_QBUF, &buf) == -1) {
    return -1;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌上花开缓缓归以

你的鼓励将是我创作的最大动力,

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值