在进行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;
}
还没有评论,来说两句吧...