嵌入式linux中V4L2应用程序开发

2019-07-12 22:22发布

嵌入式linux中有标准的V4L2协议,很多摄像头驱动和应用都是基于V4L2来进行的,一般情况下,摄像头的设备号为/dev/video0 #define DEVICE_NAME /dev/video0
一 、 打开设备 int fd;
void open_device(void)
{
    fd = open(DEVICE_NAME, O_RDWR /*| O_NONBLOCK */, 0);
}


二 、 ioctl命令控制函数 void v4l2_ioctl(int fd, int request, void * arg) { int r; r = ioctl (fd, request, arg); }
三 、 参数初始化 int v4l2_setpara(void) { struct v4l2_capability cap; struct v4l2_cropcap cropcap; struct v4l2_streamparm parm = {0}; struct v4l2_streamparm parm2 = {0}; struct v4l2_crop crop; struct v4l2_format fmt; unsigned int min; if (-1 == v4l2_ioctl (fd, VIDIOC_QUERYCAP, &cap)) // 查询v4l2驱动功能 { if (EINVAL == errno) //如果v4l2设备与内核驱动不兼容,则errno为EINVAL { printf("fd is no V4L2 device "); return -1; } else return -2; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { printf("fd is no video capture device "); return -3; } if (!(cap.capabilities & V4L2_CAP_STREAMING)) //判断设备是否支持视频流方式 { printf ("fd does not support streaming i/o "); return -4; } /* Select video input, video standard and tune here. */ memset(&cropcap,0,sizeof(cropcap)); cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (0 == v4l2_ioctl (fd, VIDIOC_CROPCAP, &cropcap)) // 查询裁剪能力,驱动会填充cropcap的其它成员 { crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect; // 恢复成默认值 if (-1 == v4l2_ioctl (fd, VIDIOC_S_CROP, &crop)) //重新设置裁剪参数 { switch (errno) { case EINVAL: /* Cropping not supported. */ break; default: /* Errors ignored. */ break; } } } memset(&fmt,0,sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = v4l2cappara.width; fmt.fmt.pix.height = v4l2cappara.height; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; //这种图像格式两个像素占四个字节,其中每Y分量占两个字节,即一个像素。每Cb,Cr分别占一个字节 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (-1 == xioctl (v4l2cappara.v4l2fd, VIDIOC_S_FMT, &fmt)) //设置视频捕获格式 { perror("VIDIOC_S_FMT:"); return -5; } /* Note VIDIOC_S_FMT may change width and height. */ /* Buggy driver paranoia. */ min = fmt.fmt.pix.width * 2; // 是16位 {MOD}的???????????????????? if (fmt.fmt.pix.bytesperline < min)fmt.fmt.pix.bytesperline = min; min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; if (fmt.fmt.pix.sizeimage < min)fmt.fmt.pix.sizeimage = min; /* parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (xioctl(v4l2cappara.v4l2fd, VIDIOC_G_PARM, &parm) == -1) { printf("set frame rate failed "); } printf("frame time1: %d/%d capturemode = %d capability = %d ",parm.parm.capture.timeperframe.numerator ,parm.parm.capture.timeperframe.denominator,parm.parm.capture.capturemode,parm.parm.capture.capability); parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; parm.parm.capture.timeperframe.numerator = 1001; parm.parm.capture.timeperframe.denominator = 20000; if (xioctl(v4l2cappara.v4l2fd, VIDIOC_S_PARM, &parm) == -1) { printf("set frame rate failed "); }*/ return 1; }
四 、 内存初始化 int v4l2_meminit(void) { struct v4l2_requestbuffers req; int count,count_max; memset(&req,0,sizeof(req)); req.count = 2; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == v4l2_ioctl (fd, VIDIOC_REQBUFS, &req)) // 向驱动申请分配缓冲区 { if (EINVAL == errno) { printf ("fd does not support memory mapping "); return -5; } else return -6; } if (req.count < 2) { printf ("Insufficient buffer memory on fd "); return -7; } count_max = req.count; if(req.count > V4L2BUFNUM)count_max = V4L2BUFNUM; for (count = 0; count < count_max; ++count) { struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = count; if (-1 == v4l2_ioctl (fd, VIDIOC_QUERYBUF, &buf)) { printf("fd VIDIOC_QUERYBUF error "); // 得到物理内存位置 return -9; } v4l2cappara.v4l2capturebuf[count].length = buf.length; v4l2cappara.v4l2capturebuf[count].start = mmap (NULL /* start anywhere */,buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */,v4l2cappara.v4l2fd, buf.m.offset); // 关联到用户空间 if (MAP_FAILED == v4l2cappara.v4l2capturebuf[count].start) { printf("encaputre fd init error mmap "); return -10; } } v4l2cappara.bufcount = count_max; int i; for (i = 0; i < v4l2cappara.bufcount; ++i) { struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == v4l2_ioctl (fd, VIDIOC_QBUF, &buf)) //将申请到的帧缓冲入队列,以便存放采集到的数据 { printf("encapture error VIDIOC_QBUF "); return -1; } } return 1; }
五 、 开始获取视频 int v4l2_startcapturing(void) { enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == v4l2_ioctl (fd, VIDIOC_STREAMON, &type)) //开始视频采集 { printf("encapture error VIDIOC_STREAMON "); return -2; } return 1; }
六、 结束获取视频 void v4l2_stop_capturing(void) { int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2_ioctl(fd, VIDIOC_STREAMOFF, &type); }