关于如何启用内核对USB摄像头的支持可移步:imx6平台V4L2编程学习记录之内核对usb摄像头的支持(一)
首先需要介绍的是有个V4L2官方手册,可以帮助学习V4L2编程。虽然是英文版的,但是不难理解。
地址: https://download.csdn.net/download/lang523493505/10692686
本文记录的是我自己摸索学习、实现功能的过程,其中可能有些地方理解不正确,还望指出。
根据手册说明V4L2编程支持两种数据采集方式:内存映射和直接读取。而我目前只实现过通过内存映射的方式采集数据,如果有尝试直接读取的方式后再记录。
初始化的流程:
1、打开USB摄像头设备,Linux下外设以“设备文件”的形式存在。
2、设置视频数据的格式,其中包括图像的宽高、视频的格式,使用的摄像头不同设置可能有所不同。
3、申请n块帧缓冲区
4、映射到应用内存。
使用:
1、获取单张图像数据。
2、获取视频流储存为视频格式,暂时没干过这事。
步骤(函数上方的宏及全局变量为参数说明)
1、打开设备
#define CAMERA_DEVICE "/dev/video0" /* 摄像机设备路径 */
static int video_fd; /* 摄像头设备文件描述符 */
/*******************************************************************
** 函数描述: 打开摄像头设备
********************************************************************/
static void open_device()
{
video_fd = open(CAMERA_DEVICE, O_RDWR, 0);
if (video_fd < 0) {
printf("Open %s failed\n", CAMERA_DEVICE);
}
}
2、获取及设置视频格式
static int video_fd; /* 摄像头设备文件描述符 */
static struct v4l2_fmtdesc fmtdesc; /* V4L2的视频格式描述 */
static struct v4l2_format fmt; /* V4L2的视频数据格式 */
/*******************************************************************
** 函数描述: 获取视频数据格式
********************************************************************/
static void get_data_format()
{
int ret;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(video_fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
printf("VIDIOC_G_FMT failed (%d)\n", ret);
return;
}
}
/*******************************************************************
** 函数描述: 设置视频数据格式
********************************************************************/
static void set_data_format()
{
int ret;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = VIDEO_WIDTH;
fmt.fmt.pix.height = VIDEO_HEIGHT;
fmt.fmt.pix.pixelformat = fmtdesc.pixelformat;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(video_fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
printf("VIDIOC_S_FMT failed (%d)\n", ret);
return;
}
}
3、申请帧缓冲区
#define BUFFER_COUNT 3 /* 缓存区数量 */
static struct v4l2_requestbuffers reqbuf; /* 初始化内存映射的请求缓存 */
/*******************************************************************
** 函数描述: 申请V4L2视频驱动内存
********************************************************************/
static void request_buf()
{
int ret;
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.count = BUFFER_COUNT;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(video_fd, VIDIOC_REQBUFS, &reqbuf);
if(ret < 0) {
printf("VIDIOC_REQBUFS failed (%d)\n", ret);
return;
}
}
4、内存映射
#define BUFFER_COUNT 3 /* 缓存区数量 */
static int video_fd; /* 摄像头设备文件描述符 */
static app_buffer_t app_buffer[BUFFER_COUNT]; /* 应用层缓冲区映射 */
static struct v4l2_buffer buf; /* 缓冲区 */
/*******************************************************************
** 函数描述: 映射内存并放置缓冲区
********************************************************************/
static void mmap_map_qbuf()
{
int i, ret;
for (i = 0; i < BUFFER_COUNT; i++){
memset(&buf, 0, sizeof(buf));
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(video_fd, VIDIOC_QUERYBUF, &buf);
if(ret < 0) {
printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret);
return;
}
app_buffer[i].length = buf.length;
app_buffer[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE,
MAP_SHARED, video_fd, buf.m.offset);
if (app_buffer[i].start == MAP_FAILED) {
printf("mmap (%d) failed: %s\n", i, strerror(errno));
return;
}
}
}