毕设系列之Linux V4L2(图形图像采集篇)
来源:互联网 发布:mac怎么删除应用程序 编辑:程序博客网 时间:2024/05/13 02:09
#PS:要转载请注明出处,本人版权所有
#PS:这个只是 《 我自己 》理解,如果和你的
#原则相冲突,请谅解,勿喷
开发环境:Ubuntu 16.04 LTS
1 虽然介绍Linux V4L2的文章已经满大街了,但是这里我也还要讲一些基本的东西。
1. v4l2 是Video for Linux 2的简称。 2. v4l2 不仅仅支持图像类设备,还支持音频等设备类型。 3. 能够使用v4l2的前提是Linux内核已经识别并注册了了相关的设备,常见的就是/dev/videox类似的设备文件存在。(如果是做图像类的采集,说白了你得有个摄像头,这个摄像头还得被Linux 内核识别) 4. 从上文可知,一个设备要被内核识别必须要由驱动才行,而对于我们常用的图像采集来说,就是要有一个摄像头驱动才行。对于这个问题,linux内核工作者根据UVC这个标准开发了一个通用的驱动程序,并且整合到linux内核中。只要是支持UVC这个通用标准的摄像头芯片,就能够使用这个驱动。(非图像类也有类似的存在,具体这里不做多余阐述) 5. 一般来说,常用的Linux平台是的内核是已经编译进去了UVC驱动的。如果是自己移植的嵌入式Linux 内核,请在配置内核选项时候打开UVC驱动的选项。如下图:
2 V4L2这个框架的原理简述(这里我们只需要关注几个结构体就可以,要深入,去看内核源代码)
1. struct v4l2_device v4l2框架中的根节点,主要是用来管理和遍历其它子节点。2. struct v4l2_subdev v4l2框架中的子节点,在v4l2_device下可以有多个v4l2_subdev存在,这里主要是区分设备类型,如图像或者音频等等。3. struct video_device 具体设备的结构体,并在/dev/下创建相关的设备文件。4. struct v4l2_buffer 为设备数据交换提供空间。
原理(这里以USB摄像头为例):当一个设备接入内核,首先根据USB标准协议对USB进行初始化,最终完成USB设备信息探测。根据USB设备信息,内核给其分配相应的驱动。这里内核知道我们的USB设备是一个图像设备,这时内核开始初始化v4l2_subdev结构体,并且类型设置为图形图像设备。当初始化好后,内核继续初始化一个video_device结构体,并插入到v4l2_subdev的管理链表中。这里的初始化过程中,就要涉及摄像头驱动的加载,设备文件的创建等等。到这里,整个注册环节就结束了,意味着我们可以使用v4l2框架来操作我们的设备。操作的话,就是各种ops的调用就ok了。(这里涉及到usb设备驱动的初始化和字符型设备驱动等等相关知识,需要更多,自行查阅资料)
3 V4L2的使用(没啥可讲的,各种资料烂大街了,我直接贴源代码)
ym_v4l2.c文件
/* FileName:m_v4l2.c Version:1.5 Description: Created On: 2017-2-21 Modified date:2017-3-14 Author:Sky*/#include <ym_v4l2.h>int yInitMV4l2(const char * pathname, yMV4L2 * mv4l2){ //mv4l2 = mvl; //request alloc IMG_BUFF_NUM DATA_BUF size mem if ( (mv4l2->img_buf = (IMG_BUF *)calloc(IMG_BUFF_NUM, sizeof(IMG_BUF))) == NULL){ printf("calloc failed\n"); return -1; } if ( (mv4l2->camera_fd = open(pathname, O_RDWR | O_NONBLOCK)) < 0){//open video device perror("Open video device faild"); return -1; } return 0;}int yIoctlV4l2(enum yV4l2Cmd cmd,...){ va_list arg; va_start(arg,cmd); yMV4L2 *mv4l2; mv4l2 = va_arg(arg,yMV4L2 *); va_end(arg); switch(cmd){ case yVIDIOC_QUERYCAP: { if ( ioctl(mv4l2->camera_fd, VIDIOC_QUERYCAP, &mv4l2->cap) < 0){ perror("QUERY VIDEO CAP FAILED"); return -1; } printf("DriverName:%s/nCard Name:%s/nBusinfo:%s/nDriverVersion:%u.%u.%u\n",mv4l2->cap.driver,mv4l2->cap.card,mv4l2->cap.bus_info,(mv4l2->cap.version>>16)&0XFF,(mv4l2->cap.version>>8)&0xFF,mv4l2->cap.version&0xFF); if ( !(mv4l2->cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE) ){ printf("The device is not a video capture\n"); return -1; } if ( !(mv4l2->cap.capabilities & V4L2_CAP_STREAMING) ){ printf("The device can not support streaming i/o\n"); return -1; } break; } case yVIDIOC_ENUM_FMT: { CLEAR_MEM(mv4l2->desc_fmt); mv4l2->desc_fmt.index = 0; mv4l2->desc_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; while( ioctl(mv4l2->camera_fd, VIDIOC_ENUM_FMT,&mv4l2->desc_fmt) == 0 ){ printf("index : %d, format:%s \n", mv4l2->desc_fmt.index,mv4l2->desc_fmt.description); mv4l2->desc_fmt.index++; } break; } case yVIDIOC_S_FMT: { // set data format for dev mv4l2->stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->stream_fmt.fmt.pix.width = IMAGE_WIDTH; mv4l2->stream_fmt.fmt.pix.height = IMAGE_HEIGHT; mv4l2->stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //mv4l2->stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; mv4l2->stream_fmt.fmt.pix.field = V4L2_FIELD_ANY; if ( ioctl(mv4l2->camera_fd, VIDIOC_S_FMT, &mv4l2->stream_fmt) ){ perror("Set data format failed"); return -1; } break; } case yVIDIOC_G_FMT: { CLEAR_MEM(mv4l2->stream_fmt); mv4l2->stream_fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(mv4l2->camera_fd,VIDIOC_G_FMT,&mv4l2->stream_fmt); printf("Currentdata format information: width:%d height:%d\n",mv4l2->stream_fmt.fmt.pix.width,mv4l2->stream_fmt.fmt.pix.height); break; } case yVIDIOC_REQBUFS: { //bzero(&reqbuf, sizeof(reqbuf)); CLEAR_MEM(mv4l2->reqbuf); mv4l2->reqbuf.count = IMG_BUFF_NUM; mv4l2->reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->reqbuf.memory = V4L2_MEMORY_MMAP; if ( ioctl(mv4l2->camera_fd, VIDIOC_REQBUFS, &mv4l2->reqbuf) < 0 ){ perror("ioctl REQBUFS failed"); return -1; } break; } case yVIDIOC_STREAMON: { mv4l2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if ( ioctl(mv4l2->camera_fd, VIDIOC_STREAMON,&mv4l2->type)< 0){ perror("Failed to ioctl:VIDIOC_STREAMON"); return -1; } break; } case yVIDIOC_STREAMOFF: { mv4l2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if ( ioctl(mv4l2->camera_fd, VIDIOC_STREAMOFF,&mv4l2->type)< 0){ perror("Failed to ioctl:VIDIOC_STREAMOFF"); return -1; } break; } case yVIDIOC_S_PARM: { CLEAR_MEM(mv4l2->stream_parm); mv4l2->stream_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->stream_parm.parm.capture.timeperframe.numerator = 1; mv4l2->stream_parm.parm.capture.timeperframe.denominator = 10; if ( ioctl(mv4l2->camera_fd, VIDIOC_S_PARM, &mv4l2->stream_parm) < 0){ perror("Failed to ioctl:VIDIOC_S_PARM"); return -1; } break; } case yVIDIOC_G_PARM: { CLEAR_MEM(mv4l2->stream_parm); mv4l2->stream_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if ( ioctl(mv4l2->camera_fd, VIDIOC_G_PARM, &mv4l2->stream_parm) < 0){ perror("Failed to ioctl:VIDIOC_G_PARM"); return -1; } if ( mv4l2->stream_parm.parm.capture.capability == V4L2_CAP_TIMEPERFRAME ){ printf("This Video Support Set Fps,Now-Fps is : %d\n",mv4l2->stream_parm.parm.capture.timeperframe.denominator); } else{ printf("This Video Un-Support Set Fps\n"); } break; } case yVIDIOC_DQBUF: { //bzero(&normal_buf, sizeof(normal_buf)); CLEAR_MEM(mv4l2->normal_buf); mv4l2->normal_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->normal_buf.memory = V4L2_MEMORY_MMAP; if ( ioctl(mv4l2->camera_fd, VIDIOC_DQBUF, &mv4l2->normal_buf) < 0){ perror("Failed to ioctl:VIDIOC_DQBUF"); return -1; } break; } case yVIDIOC_QBUF: { if ( ioctl(mv4l2->camera_fd, VIDIOC_QBUF, &mv4l2->normal_buf) < 0){ perror("Failed to ioctl:VIDIOC_QBUF"); return -1; } break; } case yMMAPTOVEDIOBUF: { for ( int i=0; i < IMG_BUFF_NUM; i++ ){ //bzero(&normal_buf, sizeof(normal_buf)); CLEAR_MEM(mv4l2->normal_buf); mv4l2->normal_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->normal_buf.memory = V4L2_MEMORY_MMAP; mv4l2->normal_buf.index = i; //get kernel cache information if ( ioctl(mv4l2->camera_fd, VIDIOC_QUERYBUF,&mv4l2->normal_buf) < 0){ perror("Failed to ioctl:VIDIOC_QUERYBUF"); return -1; } mv4l2->img_buf[i].len = mv4l2->normal_buf.length; mv4l2->img_buf[i].start = mmap(NULL,mv4l2->normal_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED,mv4l2->camera_fd, mv4l2->normal_buf.m.offset); if ( MAP_FAILED == mv4l2->img_buf[i].start){ perror("Failed to mmap"); return -1; } } break; } case yPUTVEDIOALLBUFTOQUEUE: { //bzero(&normal_buf, sizeof(normal_buf)); for ( int i = 0; i < IMG_BUFF_NUM;i++){ CLEAR_MEM(mv4l2->normal_buf); mv4l2->normal_buf.index = i; mv4l2->normal_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mv4l2->normal_buf.memory = V4L2_MEMORY_MMAP; if ( ioctl(mv4l2->camera_fd, VIDIOC_QBUF,&mv4l2->normal_buf) < 0){ perror("Failed to ioctl:VIDIOC_QBUF"); return -1; } } break; } case yUNMMAPTOVEDIOBUF: { for (int i = 0; i < IMG_BUFF_NUM; i++){ if ( munmap(mv4l2->img_buf[i].start,mv4l2->img_buf[i].len) < 0){ perror("Failed to munmap"); return -1; } } break; } default : { return -1; break; } } return 0;}int yDestroyMV4l2(yMV4L2 *mv4l2){ //StopStream(); yIoctlV4l2(yVIDIOC_STREAMOFF,mv4l2); //UnMMapToVedioBUf(mv4l2); yIoctlV4l2(yUNMMAPTOVEDIOBUF,mv4l2); close(mv4l2->camera_fd); free(mv4l2->img_buf); return 0;}
ym_v4l2.h
/* FileName:ym_v4l2.h Version:1.5 Description: Created On: 2017-2-21 Modified date:2017-3-14 Author:Sky*/#ifndef _YM_V4L2_H#define _YM_V4L2_H#ifdef __cplusplus#if __cplusplusextern "C"{#endif#endif /* __cplusplus */#include <ym_v4l2_config.h>//open#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>//memset#include <string.h>//v4l2#include <linux/videodev2.h>//errno#include <errno.h>//perror#include <stdio.h>//calloc,free#include <stdlib.h>//close#include <unistd.h>//ioctl#include <sys/ioctl.h>//mmap,munmap#include <sys/mman.h>#include <stdarg.h>#define CLEAR_MEM(x) memset(&(x),0,sizeof(x))enum yV4l2Cmd{ yVIDIOC_QUERYCAP = 0,//Get Camera Capability yVIDIOC_ENUM_FMT = 1,//Get Camera all support-format yVIDIOC_S_FMT = 2,//Set Img Format yVIDIOC_G_FMT = 3,//Get Img Format yVIDIOC_REQBUFS = 4,//Req Video buf yVIDIOC_STREAMON = 5,//Start stream yVIDIOC_STREAMOFF = 6,//Stop stream yVIDIOC_S_PARM = 7,//Set Fps info yVIDIOC_G_PARM = 8,//Get Fps info yVIDIOC_DQBUF = 9,//delete buf from out queue yVIDIOC_QBUF = 10,//put buf to in queue yMMAPTOVEDIOBUF = 11, yUNMMAPTOVEDIOBUF = 12, yPUTVEDIOALLBUFTOQUEUE = 13,};typedef struct { void * start; long len;} IMG_BUF;typedef struct ymv4l2{ int camera_fd;//camara file descriptor IMG_BUF *img_buf;//img buf head struct v4l2_buffer normal_buf; struct v4l2_fmtdesc desc_fmt; struct v4l2_capability cap; struct v4l2_format stream_fmt; struct v4l2_requestbuffers reqbuf; struct v4l2_streamparm stream_parm; enum v4l2_buf_type type;}yMV4L2; int yInitMV4l2(const char * pathname, yMV4L2 * mvl);int yDestroyMV4l2(yMV4L2 * mvl);int yIoctlV4l2(enum yV4l2Cmd cmd,...);//int OpenCamera(const char * pathname);//int GetCapability(void);//int GetAllSupportFormat(void);//int SetFrameInfo(void);//to set fps//int GetFrameInfo(void);//int SetImgFormat(void);//int GetImgFormat(void);//int RequestVedioBuf(void);//int MMapToVedioBuf(void);//int PutVedioBufToQueue(void);//int UnMMapToVedioBUf(void);//int StartStream(void);//int StopStream(void);//int ConfigV4l2(void);//int GetVedioBufFromQueue(void);//int PutVedioBufToQueue(void);#ifdef __cplusplus#if __cplusplus}#endif#endif /* __cplusplus */ #endif
#PS:请尊重原创,不喜勿喷
#PS:要转载请注明出处,本人版权所有.
有问题请留言,看到后我会第一时间回复
阅读全文
0 0
- 毕设系列之Linux V4L2(图形图像采集篇)
- Linux 之V4L2图像采集程序设计
- linux 视频采集v4l2
- Linux V4L2摄像头采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- Linux V4L2 摄像头视频采集
- linux下usb camera图像采集(V4l2)
- linux下usb camera图像采集(V4l2)
- PAT乙级 1055. 集体照 (25)
- Android Base64处理数据
- 以博客系统为例的数据库分析与设计之设计篇1
- Python探索记(04)——运算符
- 用redis实现一个投票(java版)
- 毕设系列之Linux V4L2(图形图像采集篇)
- bzoj[1855] [Scoi2010]股票交易 ,[2826]Minecraft的世界末日
- Android Base64Encoder
- VB.net计算二维数组的行列式
- Python数据分析——基于CART决策树的用户识别
- jQuery页面加载初始化的3种方法
- Atcoder ARC 077 D
- 动态规划:硬币凑值
- 常用正则表达式大全