V4L2总结(1)- 编程使用总结
V4L2 编程使用总结说明 V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。流程 内存映射方式打开设备文件。 int fdopen(”/dev/video0″,O_RDWR);取得设备的capability看看设备具有什么功能比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability设置视频的制式和帧格式制式包括PALNTSC帧的格式个包括宽度和高度等。 VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format向驱动申请帧缓冲一般不超过5个。struct v4l2_requestbuffers将申请到的帧缓冲映射到用户空间这样就可以直接操作采集到的帧了而不必去复制。mmap将申请到的帧缓冲全部入队列以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer开始视频的采集。VIDIOC_STREAMON出队列以取得已采集数据的帧缓冲取得原始采集数据。VIDIOC_DQBUF将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF停止视频的采集。VIDIOC_STREAMOFF关闭视频设备。close(fd);关于视频采集方式操作系统一般把系统使用的内存划分成用户空间和内核空间分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址而内核空间存放的是供内核访问的代码和数据用户不能直接访问。v4l2捕获的数据最初是存放在内核空间的这意味着用户不能直接访问该段内存必须通过某些手段来转换地址。一共有三种视频采集方式使用read、write方式内存映射方式和用户指针模式。read、write方式:在用户空间和内核空间不断拷贝数据占用了大量用户内存空间效率不高。内存映射方式把设备里的内存映射到应用程序中的内存控件直接处理设备内存这是一种有效的方式。本文就是。首先让驱动申请一个缓存空间使用命令然后获取缓存空间的地址之后再将这个缓存转换到用户按空间的地址和长度记录在用户空间直接读取即可用户指针模式内存片段由应用程序自己分配。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。处理采集数据V4L2有一个数据缓存存放req.count数量的缓存数据。数据缓存采用FIFO的方式当应用程序调用缓存数据时缓存队列将最先采集到的 视频数据缓存送出并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUFstructv4l2_buffer buf; memset(buf,0,sizeof(buf)); buf.typeV4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memoryV4L2_MEMORY_MMAP; buf.index0;读取缓存if(ioctl(cameraFd, VIDIOC_DQBUF, buf) -1) { return-1; }重新放入缓存队列if(ioctl(cameraFd, VIDIOC_QBUF, buf) -1) { return-1; }还需要使用munmap方法。//作者zzhere2007 //时间2013.08.27 /************************************************ **设备的打开和关闭 *************************************************/ #include fcntl.h int open(const char *device_name, int flags); #include unistd.h int close(int fd); //例 int fdopen(“/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.version16)0XFF, (cap.version8)0XFF,cap.versionOXFF); /*************************************************************************************** **查询或设置帧格式 ** 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.index0; fmtdesc.typeV4L2_BUF_TYPE_VIDEO_CAPTURE; printf(Support format:/n); while(ioctl(fd,VIDIOC_ENUM_FMT,fmtdesc)!-1) { printf(/t%d.%s/n,fmtdesc.index1,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.typeV4L2_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.typeV4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.pixelformatV4L2_PIX_FMT_RGB32; if(ioctl(fd,VIDIOC_TRY_FMT,fmt)-1) if(errnoEINVAL) 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);
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2444699.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!