一.V4L2操作流程
1.打开设备
2.配置(获取支持格式)
3.申请内核缓冲区队列
4.把内核的缓冲区队列映射到用户空间
5.开始采集
6.采集数据
7.停止采集
8.释放映射
9.关闭设备
二.打开设备
本次使用的是usb外接摄像头
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
//1.打开设备
int fd = open("/dev/video0", O_RDWR);
if(fd < 0)
{
perror("打开设备失败");
return -1;
}
//9.关闭设备
close(fd);
return 0;
}
三.获取支持格式
cd /usr/include/linux
vi videodev2.h
找到2179行
获取摄像头格式VIDIOC_ENUM_FMT--对应存储格式的结构体struct v4l2_fmtdesc
比如:VIDIOC_ENUM_FMT对应的是struct v4l2_fmtdesc
struct v4l2_fmtdesc {
__u32 index; /* Format number */
__u32 type; /* enum v4l2_buf_type */
__u32 flags;
__u8 description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
__u32 reserved[4];
};
enum v4l2_buf_type {
V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
V4L2_BUF_TYPE_VBI_CAPTURE = 4,
...
};
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
int main(void)
{
//1.打开设备
int fd = open("/dev/video0", O_RDWR);
if(fd < 0)
{
perror("打开设备失败");
return -1;
}
//2.获取摄像头支持的格式ioctl(文件描述符, 命令, 与命令对应的结构体)
struct v4l2_fmtdesc v4fmt;
v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int i=0;
while(1)
{
v4fmt.index = i++;
int ret = ioctl(fd, VIDIOC_ENUM_FMT, &v4fmt);
if(ret < 0)
{
perror("获取失败");
break;
}
printf("index=%d\n", v4fmt.index);
printf("flags=%d\n", v4fmt.flags);
printf("description=%s\n", v4fmt.description);
unsigned char *p = (unsigned char *)&v4fmt.pixelformat;
printf("pixelformat=%c%c%c%c\n", p[0],p[1],p[2],p[3]);
printf("reserved=%d\n", v4fmt.reserved[0]);
}
//9.关闭设备
close(fd);
return 0;
}
四.配置摄像头的采集格式
#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
struct v4l2_format {
__u32 type;
union {
struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
struct v4l2_sdr_format sdr; /* V4L2_BUF_TYPE_SDR_CAPTURE */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
struct v4l2_pix_format {
__u32 width;
__u32 height;
__u32 pixelformat;
__u32 field; /* enum v4l2_field */
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
__u32 colorspace; /* enum v4l2_colorspace */
__u32 priv; /* private data, depends on pixelformat */
__u32 flags; /* format flags (V4L2_PIX_FMT_FLAG_*) */
__u32 ycbcr_enc; /* enum v4l2_ycbcr_encoding */
__u32 quantization; /* enum v4l2_quantization */
__u32 xfer_func; /* enum v4l2_xfer_func */
};
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
int main(void)
{
//1.打开设备
int fd = open("/dev/video0", O_RDWR);
if(fd < 0)
{
perror("打开设备失败");
return -1;
}
//3.设置采集格式
struct v4l2_format vfmt;
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
vfmt.fmt.pix.width = 640;//设置宽(不能任意)
vfmt.fmt.pix.height = 480;//设置高
vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//设置视频采集格式
int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
if(ret < 0)
{
perror("设置格式失败");
}
memset(&vfmt, 0, sizeof(vfmt));
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);
if(ret < 0)
{
perror("获取格式失败");
}
if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 &&
vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
{
printf("设置成功\n");
}else
{
printf("设置失败\n");
}
//9.关闭设备
close(fd);
return 0;
}
五. 申请内核缓冲区队列
#define VIDIOC