i.MX6 V4L2编程学习记录之初始化(二)

关于如何启用内核对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;
		}
	}
}
发布了62 篇原创文章 · 获赞 106 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/lang523493505/article/details/82883462