在上两节视频里面分析了v4l2的框架,然后安装了一个测试程序来测试虚拟驱动的程序vivi.c,但对这个框架的分析并没有深入里面的结构。比如说它有很多ioctl,并没有分析哪些ioctl是必须的,也没有分析这个测试程序怎样去获得里面的摄像头数据。本节就结合摄像头的测试程序xawtv的源码及根据虚拟驱动vivi的使用过程彻底分析摄像头驱动。然后在第4节里面来从头写一个虚拟摄像头驱动程序。这样就可以彻底的掌握摄像头驱动程序。
1.更改虚拟摄像头vivi测试软件安装方法
在上一节里面测试了一下摄像头虚拟测试程序,这种方法是有一些小缺陷的,现在来实验一下:
安装到这一步会报错,输入“dmesg”查看系统报错原因:
提示这些函数未识别,那显然vivi.ko还依赖其他驱动程序,为什么在上一节视频里面直接使用这些命令没有问题呢?
是因为在做这个虚拟摄像头vivi的实验之前我们先接上了usb摄像头,ubuntu里面自动给我们安装了其他驱动程序,所以我们去使用vivi的时候,安装这个测试程序xawtv没有问题。
现在怎么修改?
modprobe是linux的一个命令,可载入指定的个别模块,或是载入一组相依的模块。modprobe会根据depmod所产生的相依关系,决定要载入哪些模块。若在载入过程中发生错误,在modprobe会卸载整组的模块
为什么用我们自己编译出来的vivi.ko,而不用ubuntu自带的vivi驱动程序?
因为以后做实验的时候要用到自己编译的代码。
上一节视频中,vivi对应的是 /dev/video1,因为/dev/video0对应的是usb摄像头。在本节视频中vivi对应的是 /dev/video0。
2.结合xawtv(虚拟摄像头vivi测试软件)分析USB摄像头驱动
要想去分析虚拟驱动vivi的使用过程,必须要得到测试程序xawtv的源码。源码xawtv-3.95.tar.gz在:
http://www.kraxel.org/releases/xawtv/ 。这个源码跟我们使用“sudo apt-get install xawtv”命令安装的xawtv稍有不同,但不影响我们分析的过程。
下载到源码后(第三期文件夹中有这个源码),建立sourceinsight工程。我们可以从xawtv.c的main函数一路分析进去,看看它涉及对vivi驱动程序哪一些系统调用,但这个过程会非常复杂。因为xawtv除了调用vivi驱动程序之外,还有其他很多的工作,那我们怎样才能快捷的了解到xawtv涉及哪些调用呢?
有一个办法,用“strace”这个工具,可以获得xawtv所涉及的系统调用:
strace是个功能强大的Linux调试分析诊断工具,可用于跟踪程序执行时进程系统调用(system call)和所接收的信号,尤其是针对源码不可读或源码无法再编译的程序。
执行“strace -o xawtv.log xawtv”后xawtv所涉及的所有open、read、write、ioctl这些调用都会记录在这个xawtv.log文件里面。
现在就要去分析这个xawtv.log文件(F:\004_韦东山嵌入式笔记\第三期\源码文档图片\第2课第1.1.3节文档和图片\xawtv.log)。
在这个log文件中搜索“/dev/video0”:
发现vivi对应的这个设备节点打开了两次,我们不关心它为什么打开了两次,从后面这一次开始分析:
open成功之后得到一个文件句柄4,之后就有一大堆的ioctl,我们搜索“(4,”,就可以知道它涉及哪些调用:
搜索到一大堆结果,把它们复制下来保存在“F:\004_韦东山嵌入式笔记\第三期\源码文档图片\第2课第1.1.3节文档和图片\xawtv涉及的vivi驱动的系统调用.txt”
我们现在要根据这个文本文件把里面涉及的ioctl等等全部都分析一遍:
作者使用的虚拟机版本是2.6.31.14,那么我们就应该结合这个版本的内核里的vivi.c来分析:
(1)根据虚拟驱动vivi的使用过程彻底分析摄像头驱动
经过上面的分析,我们也大概了解到虚拟摄像头里面的数据是怎样获得的。首先应用程序调用13.VIDIOC_REQBUFS来请求系统分配缓冲区14.VIDIOC_QUERYBUF来查询所分配的缓冲区,用14.mmp来让应用程序知道去哪个地址来访问这个缓冲区,然后调用15.VIDIOC_QBUF把缓冲区放入队列里面。然后使用16.VIDIOC_STREAMON来启动摄像头。然后调用select函数来查询有没有数据,如果驱动程序有了数据之后它就会把应用程序给唤醒,唤醒完之后应用程序就调用18.ioctl(4, VIDIOC_DQBUF 获得这些buffer的信息然后来处理它,处理完之后把缓冲区放入队列里面。
(2)xawtv的几大函数
(3)摄像头驱动程序必需的11个ioctl
(4)继续分析数据的获取过程
===> vivi.c缓冲区操作过程:
①VIDIOC_REQBUFS(分配头部信息) -> ②VIDIOC_QUERYBUF(返回属性) / mmap(映射地址(把缓存映射到应用层空间,应用层就可以直接操作这块缓存),分配实际空间) -> ③
VIDIOC_QBUF(把缓冲区放入队列) -> ④VIDIOC_STREAMON(启动摄像头)->
⑤用select查询是否有数据:在队列头一个buf上操作-> ⑥ VIDIOC_DQBUF(返回队列头的buf并从队列中删除) -> ⑦
VIDIOC_DQBUF(重新放回队列-③)
(5)怎么写摄像头驱动程序