V4L2总结(1)__使用说明经典_zzhere2007

/**********************************************************************************************************/
//作者:zzhere2007
//时间:2013.08.27
/**********************************************************************************************************
V4L2 编程使用总结

说明:
		V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。    
 
流程:  内存映射方式
 
		1.打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
		2.取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
		3.设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
				VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
		4.向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
		5.将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap
		6.将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
		7.开始视频的采集。VIDIOC_STREAMON
		8.出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
		9.将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
		10.停止视频的采集。VIDIOC_STREAMOFF
		11.关闭视频设备。close(fd);


头文件:V4L2 的相关定义包含在头文件<linux/videodev2.h> 中.
***********************************************************************************************************/
/*关于视频采集方式
操作系统一般把系统使用的内存划分成用户空间和内核空间,分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存放的是供内核访问的代码和数据,用户不能直接访问。v4l2捕获的数据,最初是存放在内核空间的,这意味着用户不能直接访问该段内存,必须通过某些手段来转换地址。
一共有三种视频采集方式:使用read、write方式;内存映射方式和用户指针模式。
read、write方式:在用户空间和内核空间不断拷贝数据,占用了大量用户内存空间,效率不高。

内存映射方式:把设备里的内存映射到应用程序中的内存控件,直接处理设备内存,这是一种有效的方式。本文就是。
              首先让驱动申请一个缓存空间(使用命令),然后获取缓存空间的地址,之后再将这个缓存转换到用户按空间的地址和长度,记录在用户空间,直接读取即可

用户指针模式:内存片段由应用程序自己分配。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。
	处理采集数据
	V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的 视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:
	structv4l2_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;
	}	
	关闭视频设备
	使用close函数关闭一个视频设备
	close(cameraFd)
还需要使用munmap方法。
*/
/******************************************************************************
**设备的打开和关闭:
*******************************************************************************/  
	#include <fcntl.h>   
	int open(const char *device_name, int flags);     
 
	#include <unistd.h>   
	int close(int fd);   

//例:  
	int fd=open(“/dev/video0”,O_RDWR);// 打开设备  
	close(fd);// 关闭设备   
	
/*****************************************************************************
**查询设备属性: VIDIOC_QUERYCAP   查询设备属性命令
************************************************************************************************************/
	struct v4l2_capability   
	{   
		__u8 driver[16]; 	// 驱动名字  
		__u8 card[32]; 	    // 设备名字 
 
		__u8 bus_info[32];  // 设备在系统中的位置  
		__u32 version; 		// 驱动版本号  
		__u32 capabilities; // 设备支持的操作      //常用值:    V4L2_CAP_VIDEO_CAPTURE // 是否支持图像获取 
		__u32 reserved[4];  // 保留字段  
	};   
	int ioctl(int fd, int request, struct v4l2_capability *argp);   

 
//例:获取并显示设备信息   
	struct  v4l2_capability   cap;   
	ioctl(fd,VIDIOC_QUERYCAP,&cap);   
	printf(“Driver 
			Name:%s/nCard 
			Name:%s/nBus 
			info:%s/nDriver 
			Version:%u.%u.%u/n”,
			cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&OXFF);  
/****************************************************************************************************************
**查询或设置帧格式
**           VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式命令
**           VIDIOC_G_FMT:    读取当前驱动的频捕获格式命令
**           VIDIOC_S_FMT:    设置当前驱动的频捕获格式命令
*****************************************************************************************************************/
// 显示所有支持的格式  
	struct v4l2_fmtdesc   
	{   
		__u32 index;             // 要查询的格式序号,应用程序设置  
		enum v4l2_buf_type type; // 帧类型,应用程序设置  
		__u32 flags;             // 是否为压缩格式  
		__u8 description[32];    // 格式名称  
		__u32 pixelformat;       // 格式  
		__u32 reserved[4];       // 保留  
	};  
	int ioctl(int fd, int request, struct v4l2_fmtdesc *argp);   

//例:
	struct v4l2_fmtdesc fmtdesc;   
	fmtdesc.index=0;   
	fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;   
	printf("Support format:/n");   
	while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)   
	{   
			printf("/t%d.%s/n",fmtdesc.index+1,fmtdesc.description);   
			fmtdesc.index++;
	}  
/**********************************************************************    
** 查看或设置当前帧格式  
** VIDIOC_G_FMT, VIDIOC_S_FMT   
** 检查是否支持某种格式  
** VIDIOC_TRY_FMT   
************************************************************************/
struct v4l2_format   
{   
	enum v4l2_buf_type type;				// 帧类型,应用程序设置  //数据流类型,必须永远是//V4L2_BUF_TYPE_VIDEO_CAPTURE 摄像头:视频捕捉设备
	union fmt  
			{   
				struct v4l2_pix_format pix;// 视频设备使用(见下面定义) 
				struct v4l2_window win;   
				struct v4l2_vbi_format vbi;   
				struct v4l2_sliced_vbi_format sliced;   
				__u8 raw_data[200];  
			};   
};      
struct v4l2_pix_format     
{   
	__u32 width; 		// 帧宽,单位像素  
	__u32 height; 		// 帧高,单位像素  
	__u32 pixelformat;  // 帧格式  V4L2_PIX_FMT_MJPEG
	enum v4l2_field field;   
	__u32 bytesperline;   
	__u32 sizeimage;   
	enum v4l2_colorspace colorspace;   
	__u32 priv;   
};   
int ioctl(int fd, int request, struct v4l2_format *argp);   


//例:显示当前帧的相关信息   
struct v4l2_format fmt;  
 
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;   
ioctl(fd,VIDIOC_G_FMT,&fmt);   
printf(“Current data format information:/n/twidth:%d/n/theight:%d/n”,fmt.fmt.width,fmt.fmt.height);   

//例:检查是否支持某种帧格式   
struct v4l2_format fmt;  
 
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;   
fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_RGB32;   
if(ioctl(fd,VIDIOC_TRY_FMT,&fmt)==-1)   
if(errno==EINVAL)   
printf(“not support format RGB32!/n”);
/**************************************************************************************************************
**  为视频捕获分配内存:VIDIOC_REQBUFS
***************************************************************************************************************/
struct v4l2_request buffers
{
		__u32               count;     //缓存数量,也就是说在缓存队列里保持多少张照片
		enum v4l2_buf_type   type;      //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
		enum v4l2_memory     memory;    // V4L2_MEMORY_MMAP或 V4L2_MEMORY_USERPTR
		__u32               reserved[2];
};

//例:为视频捕获分配内存:
structv4l2_requestbuffers  req;
if(ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
return-1;
}

	//获取并记录缓存的物理空间
	//使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,
	//然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:
/****************************************************************************************************************
**  使用mmap函数转换成应用程序中的绝对地址,视频数据
*** 获取分配的内存的地址命令:VIDIOC_QUERYBUF
*****************************************************************************************************************/
typedef struct VideoBuffer
{
		void*start;
		size_t  length;
} VideoBuffer; 
VideoBuffer*       buffers= calloc( req.count, sizeof(*buffers) );                 //1、定义用户的缓存空间

structv 4l2_buffer    buf;                                                         //2、定义问询的数据格式
 
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;                                                      //3、填充问询数据
		//读取缓存
		if(ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1)                                 //4、获取分配的内存的地址
		{                                      
		return-1;
		}
		buffers[numBufs].length= buf.length;                                       //5、将驱动的数据内存地址和长度,转换到用户空间
		buffers[numBufs].start= mmap(NULL, buf.length,PROT_READ| PROT_WRITE,MAP_SHARED,fd, buf.m.offset);//转换成相对地址
				/**********************************************************************************
				void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);   
					//addr   映射起始地址,一般为NULL ,让内核自动选择  
					//length 被映射内存块的长度 
					//prot   标志映射后能否被读写,其值为PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE   
					//flags  确定此内存映射能否被其他进程共享,MAP_SHARED,MAP_PRIVATE   
					//fd,offset, 确定被映射的内存地址 
                ***********************************************************************************/
		if(buffers[numBufs].start== MAP_FAILED) { return-1; }
 
       //放入缓存队列
       if(ioctl(fd, VIDIOC_QBUF, &buf) == -1) { return-1; }                        //6、读取一帧放入缓冲队列
}

/****************************************************************************************************************************
** 启动或停止数据流  
** 命令:VIDIOC_STREAMON, VIDIOC_STREAMOFF 
*****************************************************************************************************************************/  
int ioctl(int fd, int request, const int *argp);
 
//例:  
	enum  v4l2_buf_type  type; 
	
	type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;   
	ioctl (fd, VIDIOC_STREAMON, &type);  




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值