TA的每日心情 | 慵懒 2024-5-31 23:20 |
---|
签到天数: 302 天 连续签到: 2 天 [LV.8]以坛为家I
|
本帖最后由 day_day 于 2020-12-13 21:59 编辑
V4L2 是 linux 下的通用视频框架,板子上的opencv没有适配v4l2,因此视频采集需要直接操作V4L2。
(一)V4L2采集
V4L2是作为通用视频框架,操作和 linux 各类设备驱动有点像,都是打开/dev下的设备文件,通过ioctl控制。
1-打开设备文件
- int fd=open("/dev/video2",O_RDWR);// 打开设备
- init_uvc(fd);
复制代码
2-查询设备属性
- ioctl(fd,VIDIOC_QUERYCAP,&cap);
- printf("DriverName\t%s\r\nCard Name\t%s\r\nBus info\t%s\r\nDriverVersion\t%u.%u.%u\r\n",
- cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF,(cap.version>>8)&0XFF,(cap.version)&0xFF);
复制代码
3-帧格式-显示所有支持的格式
- struct v4l2_fmtdesc fmtdesc;
- unsigned int min = 0;
- fmtdesc.index=0;
- fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- printf("Supportformat:\r\n");
- while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
- {
- printf("\t%d.%s\r\n",fmtdesc.index+1,fmtdesc.description);
- fmtdesc.index++;
- }
复制代码
4-显示当前帧的相关信息
- struct v4l2_format fmt;
- fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = 640;
- fmt.fmt.pix.height = 480;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- fmt.fmt.pix.field = V4L2_FIELD_NONE;
- ioctl(fd,VIDIOC_S_FMT,&fmt);
- ioctl(fd,VIDIOC_G_FMT,&fmt);
- printf("Currentdata format information:\r\n\twidth:%d\r\n\theight:%d\r\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
复制代码
5-申请一个拥有四个缓冲帧的缓冲区
- struct v4l2_requestbuffers req;
- req.count=n_buffers;
- req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory=V4L2_MEMORY_MMAP;
- ioctl(fd,VIDIOC_REQBUFS,&req);
- buffers =(buffer*)calloc (req.count, sizeof (*buffers));
- if (!buffers) {
- fprintf (stderr,"Out of memory\n");
- exit(EXIT_FAILURE);
- }
复制代码
6-映射内存
- for (unsigned int n_buffers = 0; n_buffers < req.count; ++n_buffers) {
- struct v4l2_buffer buf;
- memset(&buf,0,sizeof(buf));
- buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory =V4L2_MEMORY_MMAP;
- buf.index =n_buffers;
- // 查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小
- if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
- exit(-1);
- buffers[n_buffers].length= buf.length;
- // 映射内存
- buffers[n_buffers].start=
- mmap (
- NULL,
- buf.length,
- PROT_READ | PROT_WRITE ,
- MAP_SHARED,
- fd,
- buf.m.offset);
- if (MAP_FAILED== buffers[n_buffers].start)
- exit(-1);
- }
复制代码
7-把四个缓冲帧放入队列,并启动数据流
- unsigned int i;
- enum v4l2_buf_type type;
- // 将缓冲帧放入队列
- for (i = 0; i< n_buffers; ++i)
- {
- struct v4l2_buffer buf;
- buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory =V4L2_MEMORY_MMAP;
- buf.index = i;
- ioctl (fd,VIDIOC_QBUF, &buf);
- }
- type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ioctl (fd,VIDIOC_STREAMON, &type);
复制代码
8-把图像从缓冲区取出来
- while(cvWaitKey(30)!='q'){
- struct v4l2_buffer buf;
- // clear (buf);
- buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory =V4L2_MEMORY_MMAP;
- // 从缓冲区取出一个缓冲帧
- ioctl (fd,VIDIOC_DQBUF, &buf);
- // 将取出的缓冲帧放回缓冲区
- ioctl (fd, VIDIOC_QBUF,&buf);
- }
复制代码
(二)加入识别 效果
识别速度:
实际跑上视频流之后,速度更快一些。PC上的速度不到3帧秒,这里基本是有7、8帧秒。
|
|