这个子系统里需要实现摄像头的初始化,Epoll事件的添加,处理函数的编写以及开始采集函数,这里为了方便起见,先把处理函数设置为保存读取到的图片。

为了方便描述定义一个结构:

 

struct v4l2_dev{
	int fd;//设备文件fd
	__u8 name[32];//保存摄像头标签
	__u8 drv[16];//驱动名字
	struct buf *buf;//图片数据的指针
	struct event_ext *ev;//Epoll事件的附加结构
};

其中buf的结构如下:

 

 

struct buf{
	void *start;
	int len;
};

同时在v4l2中定义一个v4l2_dev结构:

 

 

struct cam
{
	struct v4l2_dev *v4_dev;
};


摄像头子系统的初始化需要完成以下处理:

 

1、打开摄像头

2、获取驱动信息

3、设置图像格式

4、申请图像缓冲区

5、把内核空间的图像缓冲区映射到用户空间

6、图像缓冲入队列

7、往Epoll池中加入事件

整理之后摄像头子系统的程序如下:

 

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <linux/videodev2.h>

#include "main.h"
struct buf{
	void *start;
	int len;
};

struct v4l2_dev{
	int fd;//设备文件fd
	__u8 name[32];//保存摄像头标签
	__u8 drv[16];//驱动名字
	struct buf *buf;//图片数据的指针
	struct event_ext *ev;//Epoll事件的附加结构
};

struct cam
{
	struct v4l2_dev *v4_dev;
};


/*事件处理函数*/
void cam_handler(int fd, void *arg)
{
	struct v4l2_buffer buf;
	struct v4l2_dev *v = arg;
	int file_fd;

	file_fd = open("test.jpg", O_RDWR | O_CREAT, 0777);

	//帧出列
	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buf.memory = V4L2_MEMORY_MMAP;
	ioctl(v->fd, VIDIOC_DQBUF, &buf);

	write(file_fd, v->buf[buf.index].start, v->buf[buf.index].len);
	close(file_fd);

	ioctl(v->fd, VIDIOC_QBUF, &buf);
}
/*初始化摄像头*/
struct v4l2_dev *v4l2_init()
{
	struct v4l2_dev *v;
	struct v4l2_capability cap;
	struct v4l2_format fmt;
	struct v4l2_requestbuffers req;
	int i;
	struct v4l2_buffer buf;

	//打开摄像头
	v = calloc(1, sizeof(struct v4l2_dev));
	v->fd = open("/dev/video0",O_RDWR|O_NONBLOCK);

	//获取驱动信息
	ioctl(v->fd, VIDIOC_QUERYCAP, &cap);
	if( !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
	{
		printf("this is not a video device\n");
		return -1;
	}
	strcpy((char *)v->name, (char *)cap.card);
	strcpy((char *)v->drv, (char *)cap.driver);

	//设置图像格式
	fmt.type 			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	fmt.fmt.pix.width 	= 1280;
	fmt.fmt.pix.height	= 1024;
	fmt.fmt.pix.field	= V4L2_FIELD_INTERLACED;
	fmt.fmt.pix.pixelformat	= V4L2_PIX_FMT_MJPEG;

	ioctl(v->fd, VIDIOC_S_FMT, &fmt);

	//申请图像缓冲区
	req.count		= 4;
	req.type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	req.memory		= V4L2_MEMORY_MMAP;
	ioctl(v->fd, VIDIOC_REQBUFS, &req);

	//把内核空间的图像缓冲区映射到用户空间
	v->buf = calloc(req.count, sizeof(struct buf));

	for(i=0; i < req.count; i++)
	{
		//获取缓冲区的信息
		buf.type 	= V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory 	= V4L2_MEMORY_MMAP;
		buf.index	= i;

		ioctl(v->fd, VIDIOC_QUERYBUF, &buf);

		v->buf[i].len = buf.length;
		v->buf[i].start = mmap(NULL,
								buf.length,
								PROT_READ | PROT_WRITE,
								MAP_SHARED,
								v->fd,
								buf.m.offset);
	}

	//图像缓冲入队列
	for(i=0; i<req.count; ++i)
	{
		buf.type 		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory 		= V4L2_MEMORY_MMAP;
		buf.index 		= i;
		ioctl(v->fd, VIDIOC_QBUF, &buf);
	}
	//往Epoll池中加入事件
	v->ev = epoll_event_create(v->fd, EPOLLIN, cam_handler, v);
	epoll_add_event(srv_main->epfd, v->ev);

	return v;
}

void v4l2_start_capture(struct v4l2_dev *v)
{
	enum v4l2_buf_type type;

	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ioctl(v->fd, VIDIOC_STREAMON, &type);
}
struct cam *cam_sys_init()
{
	struct cam *cam;
	cam = calloc(1, sizeof(struct cam));

	//初始化采集子系统
	cam->v4_dev = v4l2_init();

	//开始采集
	v4l2_start_capture(cam->v4_dev);
}


编译后复制到开发板上运行,如果采集到了正确的图片信息说明代码编写成功。

更多Linux资料及视频教程点击这里

 

 

 

 

Logo

更多推荐