下面将给出Hi3559AV100外接UVC/MJPEG相机实时采图设计的整体流程,主要实现是通过V4L2接口将UVC/MJPEG相机采集的数据送入至MPP平台,经过VDEC、VPSS、VO最后通过HDMI的输出,给出(二)V4L2接口的实现。

可以先参照前面随笔介绍(一)Linux USB摄像头驱动加载与分析:https://www.cnblogs.com/iFrank/p/14399421.html

板载平台:BOXER-8410AI

芯片型号:Hi3559AV100

相机型号:Logitch c270

开发环境:VM15.5+ubuntu16.04+Hilinux

1、V4L2接口说明

  V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video*下,如果只有一个视频设备,通常为/dev/video0。V4L2是内核提供给应用程序访问音、视频驱动的统一接口。V4L2 的相关定义包含在头文件<linux/videodev2.h> 中。

  V4L2 支持两种方式来采集图像:内存映射(mmap)和直接读取方式(read)。V4L2 在/usr/include/linux/videodev2.h 文件下定义了一些重要的数据结构,在采集图像的过程中,就是通过对这些数据的操作来获得最终的图像数据。Linux 系统 V4L2 使能可在内核编译阶段配置,默认情况下是在 make menuconfig 是打开的。应用程序可以通过 V4L2 进行视频采集。V4L2 支持内存映射(mmap)方式和直接读取方式(read)方式采集数据。前者
一般用于连续的视频数据采集,后者常用静态图片数据采集。v4l2 中不仅定义了通用 API 元素,图像的格式,输入/输出方法,还定义了Linux 内核驱动处理视频信息的一系列接口,这些接口主要有:
  视频采集接口——Video Capture interface;
  视频输出接口——Video Output Interface;
  视频覆盖/预览接口——Video Overlay Interface;
  视频输出覆盖接口——Video Output Overlay Interface;
  编解码接口——Codec Interface

IOCTL的实现V4L2的控制

  打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:
extern int ioctl (int __fd, unsigned long int __request, …) __THROW;
__fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;
__request:具体的命令标志符。
在进行V4L2开发中,一般会用到以下的命令标志符:
 1:分配内存
2 VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
3 VIDIOC_QUERYCAP:查询驱动功能
4 VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
5 VIDIOC_S_FMT:设置当前驱动的频捕获格式
6 VIDIOC_G_FMT:读取当前驱动的频捕获格式
7 VIDIOC_TRY_FMT:验证当前驱动的显示格式
8 VIDIOC_CROPCAP:查询驱动的修剪能力
9 VIDIOC_S_CROP:设置视频信号的边框
10 VIDIOC_G_CROP:读取视频信号的边框
11 VIDIOC_QBUF:把数据放回缓存队列
12 VIDIOC_DQBUF:把数据从缓存中读取出来
13 VIDIOC_STREAMON:开始视频显示函数
14 VIDIOC_STREAMOFF:结束视频显示函数
15 VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。

这些IO调用,有些是必须的,有些是可选择的,其命令标志符在在头文件<linux/videodev2.h> 定义,具体如下:

1 #define VIDIOC_QUERYCAP         _IOR('V',  0, struct v4l2_capability)
2 #define VIDIOC_RESERVED _IO('V', 1)
3 #define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc)
4 #define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format)
5 #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
6 #define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers)

Logitch c270支持的像素格式有两种:

1 YUYV 4:2:2 2 Motion-JPEG

2、V4L2的实现流程

一般来说V4L2 采集视频数据分为五个步骤:
  首先,打开视频设备文件,进行视频采集的参数初始化,通过 V4L2 接口设置视频图像的采集窗口、采集的点阵大小和格式;
  其次,申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用户空间,便于应用程序读取/处理视频数据;
  第三,将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集;
  第四,驱动开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲区,处理完后,将帧缓冲区重新放入视频采集输入队列,循环往复采      集连续的视频数据;
  第五,停止视频采集。在本次设计中,定义了几个函数实现对摄像头的配置和采集。
一帧图片采集流程:

动态视频采集流程:

 

  图解过程已经很详细了,重新总结下。整个过程:
  首先:先启动视频采集,驱动程序开始采集一帧数据,把采集的数据放入视频采集输入队列的第一个帧缓冲区,一帧数据采集完成,也就是第
一个帧缓冲区存满一帧数据后,驱动程序将该帧缓冲区移至视频采集输出队列,等待应用程序从输出队列取出。驱动程序则继续采集下一帧数据放入第二个缓冲区,同样帧缓冲区存满下一帧数据后,被放入视频采集输出队列。
  然后:应用程序从视频采集输出队列中取出含有视频数据的帧缓冲区,处理帧缓冲区中的视频数据,如存储或压缩。
  最后:应用程序将处理完数据的帧缓冲区重新放入视频采集输入队列,这样可以循环采集。我们从摄像头中获取的视频帧数据会放入视频缓存队列中,当其他模块需要处理对应的视频帧的时候,就会占用缓存块,也就是这一块内存被占用,当处理完之后,对应的数据通过 VO/VENC/VDA 显示之后,这一缓存块就没有用了,可以回收利用。现在来看,其实海思的底层处理和 linux 的底层处理是一样的。不过海思本身使用的就是 linux 内核。应该也就是对这一块进行封装了而已吧!
  海思的公共视频缓存池按我的理解应该有两部分,一部分是视频采集输入队列,另一部分是视频采集输出队列,VI 通道是是视频采集输出队列中获取的视频帧,而中间 linux 内核的驱动程序会在视频采集输入队列中填充视频帧,变成视频输出队列。

部分代码实现:

 1     /*打开视频*/
2 if ((fd = open(FILE_VIDEO, O_RDWR)) == -1)
3 {
4 printf("Error opening V4L interface\n");
5 return (FALSE);
6 }
7
8 /*读video_capability中信息。
9 通过调用IOCTL函数和接口命令VIDIOC_QUERYCAP查询
10 摄像头的信息*/
11 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
12 {
13 printf("Error opening device %s: unable to query device.\n",FILE_VIDEO);
14 return (FALSE);
15 }
16 else
17 {
18 printf("driver:\t\t%s\n",cap.driver);
19 printf("card:\t\t%s\n",cap.card);
20 printf("bus_info:\t%s\n",cap.bus_info);
21 printf("version:\t%d\n",cap.version);
22 printf("capabilities:\t%x\n",cap.capabilities);
23
24 /*其中capabilities: 4000001通过与各种宏位与,
25 可以获得物理设备的功能属性*/
26 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
27 {
28 printf("Device %s: supports capture.\n",FILE_VIDEO);
29 }
30
31 if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
32 {
33 printf("Device %s: supports streaming.\n",FILE_VIDEO);
34 }
35 } //VIDIOC_QUERYCAP对应唯一结构体

3、V4L2测试(640×480像素一帧图片输出)

  我板载上装的是Logitch c270摄像头,从摄像头支持的图像像素输出的信息可以看出,在Hi3559板载上可以支持2种像素格式,这里选用的是V4L2_PIX_FMT_YUV422 格式。从生成image的大小可以判断出是正确的(YUV422数据大小 = 长 * 宽 * 1.5 = 640 * 480 * 2 = 614400 bytes = 600k)可以将image文件拷出来,使用pYUV 软件查看YUV图片。这里需要注意,使用pYUV 查看YUV图片的时候,需要正确设置图片格式,按我上面代码采集的数据格式,最后一帧图片输出结果如下:

  之后随笔将推出结合MPP平台实现视频流的输出。

问题:

  在虚拟机上,脚本运行正常,但是会卡在视频采集处,个人认为是虚拟机的缓存问题,而板载缓存比较充足,所以能够很好实现。

Hi3559AV100外接UVC/MJPEG相机实时采图设计(二):V4L2接口的实现(以YUV422为例)的更多相关文章

  1. Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出

    可以首先参考前面两篇文章: Hi3559AV100外接UVC/MJPEG相机实时采图设计(一):Linux USB摄像头驱动分析: https://www.cnblogs.com/iFrank/p/1 ...

  2. Hi3559AV100外接UVC/MJPEG相机实时采图设计(一):Linux USB摄像头驱动分析

    下面将给出Hi3559AV100外接UVC/MJPEG相机实时采图设计的整体流程,主要实现是通过V4L2接口将UVC/MJPEG相机采集的数据送入至MPP平台,经过VDEC.VPSS.VO最后通过HD ...

  3. Hi3559AV100外接UVC/MJPEG相机实时采图设计(四):VDEC_Send_Stream线程分析

    下面随笔将对Hi3559AV100外接UVC/MJPEG相机实现实时采图设计的关键点-VDEC_Send_Stream线程进行分析,一两个星期前我写了有三篇系列随笔,已经实现了项目功能,大家可以参考下 ...

  4. Dalsa 8K彩色相机Camera link C#采图

    一个采图工具,所以界面做的很简单. private SapAcquisition m_Acquisition; private SapBuffer m_Buffers; private SapAcqT ...

  5. 相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了!

    相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了! 先说图片X×dpi=点数dotX是图片实际尺寸,简单点,我们只算图片的高吧,比如说拍了张图片14 ...

  6. FusionCharts制作实时刷新图

    转自:http://yklovejava-163-com.iteye.com/blog/1889949 下面介绍的是用FusionCharts制作实时刷新图的过程(FusionCharts确实太好用了 ...

  7. Android相机实时自动对焦的完美实现

    https://zhidao.baidu.com/question/873328177698804372.html Android相机实时自动对焦的完美实现 http://blog.csdn.net/ ...

  8. 关于nagios系统下使用shell脚本自定义监控插件的编写以及没有实时监控图的问题

    关于nagios系统下shell自定义监控插件的编写.脚本规范以及没有实时监控图的问题的解决办法 在自已编写监控插件之前我们首先需要对nagios监控原理有一定的了解 Nagios的功能是监控服务和主 ...

  9. Hi3559AV100板载开发系列-pthread_create()下V4L2接口MJPEG像素格式的VIDIOC_DQBUF error问题解决-采用阻塞方式下select监听

     最近一直加班加点进行基于Hi3559AV100平台的BOXER-8410AI板载开发,在开发的过程中,遇到了相当多的问题,其一是板载的开发资料没有且功能不完整,厂家不提供太多售后技术支持,厂家对部分 ...

随机推荐

  1. BZOJ1951 古代猪文 【数论全家桶】

    BZOJ1951 古代猪文 题目链接: 题意: 计算\(g^{\sum_{k|n}(^n_k)}\%999911659\) \(n\le 10^9, g\le 10^9\) 题解: 首先,根据扩展欧拉 ...

  2. 单源最短路问题 Dijkstra 算法(朴素+堆)

    选择某一个点开始,每次去找这个点的最短边,然后再从这个开始不断迭代,更新距离. 代码: 朴素(vector存图) #include <iostream> #include <cstd ...

  3. MySQL菜鸟实录(一):MySQL服务安装实战

    CentOS 7 基本信息 系统版本: CentOS 7.3 64bit 系统配置: 4vCPUs | 8GB 磁盘空间: [root@ecs-ce5a-0001 ~]# df -h Filesyst ...

  4. 文件的读写(cpp)

    文件的读写(cpp) c++中要进行文件的读入,首先要包含一个头文件 fstream . 输出到文件 为打开一个可供输出的文件需要定义一个ofstream 对象并将文件名传入: std::ofstre ...

  5. k8s二进制部署 - 总结

    镜像仓库: 安装软件:docker.docker-compose.harbor.nginx 1.下载cfssl.cfssljson.cfssl-certinfo,增加执行权限并放在PATH环境变量路径 ...

  6. Javascript实现"点按钮出随机背景色的"三个DIV

    <!DOCTYPE html> <html> <head> <title>Random_Color-Transformation</title&g ...

  7. TypeScript Errors All In One

    TypeScript Errors All In One 1. Property 'name' has no initializer and is not definitely assigned in ...

  8. CSS Grid Layout In Action

    CSS Grid Layout In Action CSS 异形网格布局实战 refs https://static-nginx-online.fbcontent.cn/tutor/tutor-ybc ...

  9. GitHub & GitHub Package Registry

    GitHub & GitHub Package Registry npm https://github.blog/2019-05-10-introducing-github-package-r ...

  10. taro table component

    taro table component https://juejin.im/post/5d901696f265da5b926bbcaa https://taro-ext.jd.com/search? ...