logo资料库

linux v4l2视频采集教程.doc

第1页 / 共5页
第2页 / 共5页
第3页 / 共5页
第4页 / 共5页
第5页 / 共5页
资料共5页,全文预览结束
#include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include //V4L2 的相关定义包含在头文件 中 int cam_fd; struct v4l2_capability cam_cap; struct v4l2_fmtdesc fmtdesc; v4l2_std_id std; struct v4l2_format fmt; struct v4l2_requestbuffers struct v4l2_buffer buf; req; struct VideoBuffer{ void *start; size_t length; }; struct VideoBuffer *buffers; const int bpp = 24; int main(int argc,char **argv) { int w = 176; int h = 144; int ret; int numBufs = 0; cam_fd = open("/dev/video2" ,O_RDWR,0);
if(cam_fd < 0){ printf("can not open driver!! \n"); exit(1); } printf("cam_fd = %d\n",cam_fd); // VIDIOC_QUERYCAP:查询驱动功能 if( ioctl(cam_fd,VIDIOC_QUERYCAP,&cam_cap )< 0){ printf("cam_cap is fail!! \n"); exit(2); } printf("Driver name:%s \ndevice name: %s \n",cam_cap.driver,cam_cap.card); //检测视频支持的制式,连驱动代码都查了,还是不知道 do{ ret = ioctl(cam_fd, VIDIOC_QUERYSTD, &std); }while(ret == -1 && errno == EAGAIN); printf("v4l2_std_id is:%x\n",std); switch(std){ case V4L2_STD_NTSC: printf("format is V4L2_STD_NTSC"); break; case V4L2_STD_PAL: printf("format is V4L2_STD_PAL"); break; default: printf("i can not find!!\n"); } //设置帧格式 memset(&fmt,0,sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; V4L2_BUF_TYPE_VIDEO_CAPTURE // 数 据 流 类 型 , 必 须 永 远 是 fmt.fmt.pix.width = 176; fmt.fmt.pix.height = 144; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //要与摄像头相对应, 视频数据存储 类型,例如是 YUV4:2:2 还是 RGB fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if(ioctl(cam_fd, VIDIOC_S_FMT,&fmt) < 0){ printf("set format is fail!! \n"); exit(4); }
if(ioctl(cam_fd,VIDIOC_TRY_FMT,&fmt) <0){ printf("not support format V4L2_PIX_FMT_YUYV!\n"); } //接下来可以为视频捕获分配内存(向驱动申请帧缓存,为 mmap 映射做准备。),使用 VIDIOC_REQBUFS,我们获取了 req.count 个缓存 //v4l2_requestbuffers 结构中定义了缓存的数量,驱动会据此申请对应数量的视频缓存。 多个缓存可以用于建立 FIFO,来提高视频采集的效率。 req.count = 2; 就是说在缓存队列里保持多少张照片 // 缓存数量,也 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 数 据 流 类 型 , 必 须 永 远 是 // V4L2_MEMORY_MMAP 或 V4L2_BUF_TYPE_VIDEO_CAPTURE req.memory = V4L2_MEMORY_MMAP; V4L2_MEMORY_USERPTR,与后面的读取方式有关 if(ioctl(cam_fd,VIDIOC_REQBUFS,&req) ==-1){ printf("VIDIOC_REQUFS is fail!! \n"); exit(5); } //printf("req.count is %d\n",req.count); //申请缓冲区个数:2 //获取并记录缓存的物理空间,调用 VIDIOC_QUERYBUF 命令来获取这些缓存的地址 buffers = (struct VideoBuffer *)calloc(req.count,sizeof(*buffers)); 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; //要获取内核视频缓冲区的信息编号 //目的只为了获取 buf.length 和 buf.m.offset 进行映射 if(ioctl(cam_fd, VIDIOC_QUERYBUF,&buf) < 0){ printf("VIDIOC_QUERYBUF is fail!! \n"); exit(6); } buffers[numBufs].length = buf.length; buffers[numBufs].start= mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,cam_fd,buf.m.offset); if(buffers[numBufs].start == MAP_FAILED){ printf("MMAP is fail!! \n"); exit(7); } printf("Buffer size:%d -------Offset:%d\n",buf.length,buf.m.offset);
//放入缓存队列 if(ioctl(cam_fd,VIDIOC_QBUF,&buf) < 0){ printf("VIDIOC_QBUF is fail!! \n"); exit(8); } } /*以上步骤完成了视频采集的准备工作,但驱动还没有启动采集过程, 应用程序需要调用 VIDIOC_STREAMON ioctl 系统调用驱动才会开始采集数据。 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl (fd, VIDIOC_STREAMON, &type);*/ //开始采集视频 int buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(ioctl(cam_fd,VIDIOC_STREAMON,&buf_type) < 0){ printf("VIDIOC_STREAMON is fail!! \n"); exit(9); } /*采集过程开始以后,驱动会不停地将数据写入分配的缓冲区内, 当一个缓冲区的数据准备就绪后,驱动就会将其放入输出队列,等待应用程序的处理。 当所有的缓冲区都进入输出队列后,驱动将停止采集,并等待缓冲区重新放入采集队列。 读取数据时,首先需要将一个缓冲区出队列: struct v4l2_buffer buf; ioctl (fd, VIDIOC_DQBUF, &buf);*/ //取出 FIFO 缓存中已经采样的帧缓存, struct v4l2_buffer buf_2; memset(&buf_2,0,sizeof(buf_2)); buf_2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf_2.memory = V4L2_MEMORY_MMAP; //buf.index = 0; 由 VIDIOC_DQBUF 返回 if(ioctl(cam_fd,VIDIOC_DQBUF,&buf_2) < 0){ printf("VIDIOC_DQBUF is fail!! \n"); exit(10); } printf("buf.index =%d \n",buf_2.index); /*驱动会从输出队列取出一个缓冲区,并将其序号赋值给 buf.index, 应用程序可以通过 buffers[buf.index].start 来访问缓冲区的数据。 当处理完成后,需要将其重新放入采集队列。*/ //---根据返回的 buf.index 找到对应的 mmap 映射好的缓存,取出视频数据。 /******* 进行数据处理
*****/ //将刚刚处理完的缓冲重新入队列尾,这样可以循环采集 if(ioctl(cam_fd, VIDIOC_QBUF,&buf_2)<0){ printf("VIDIOC_QBUF is fail!! \n"); exit(11); } //停止视频的采集 if(ioctl(cam_fd,VIDIOC_STREAMOFF,&buf_type) < 0){ printf("VIDIOC_STREAMOFF is fail!! \n"); exit(12); } close(cam_fd); return 0; }
分享到:
收藏