1、上一节测试的摄像头驱动程序的缺陷
(1)依次装载驱动程序,出现错误如下
(2)用dmesg命令查看详细输出(某些函数没有识别),可见我们的vivi.ko还依赖于其他驱动程序,上一节直接使用这些命令没有问题,是因为在做虚拟摄像头vivi之前。我们先接上USB摄像头,ubuntu里面自动给我们安装了其他驱动程序。所以在使用vivi的时候,没有出现问题。
(3)sudo modprobe vivi
这是安装ubuntu里面自带的vivi驱动程序,把它依赖的其他驱动程序也一起安装进来
(4)把内核自带的vivi去掉,安装上我们编译出来的vivi.ko,用自己的编译程序是因为
我们以后做实验的时候要用到自己编译的代码
2、根据虚拟驱动vivi的使用过程彻底分析摄像头驱动
(1)分析使用过程,通过应用程序源码xawtv分析,建立sourceinsight工程
(2)快捷了解xawtv所涉及的调用,用strace工具获得所涉及的调用。把xawtv所涉及的系统调用记录在xawtv.log文件里面。
接下来分析xawtv.log
(3)打开xawtv.log文件,搜索关键词“/dev/video0”,结合内核版本的vivi.c来分析
// 1~7都是在v4l2_open里调用
1. open //驱动句柄“4”
2. ioctl(4, VIDIOC_QUERYCAP
// 3~7 都是在get_device_capabilities(获得相关属性)里调用
3. for()
ioctl(4, VIDIOC_ENUMINPUT // 列举输入源,VIDIOC_ENUMINPUT/VIDIOC_G_INPUT/VIDIOC_S_INPUT不是必需的
4. for()
ioctl(4, VIDIOC_ENUMSTD // 列举标准(制式), 不是必需的
5. for()
ioctl(4, VIDIOC_ENUM_FMT // 列举格式
6. ioctl(4, VIDIOC_G_PARM
7. for()
ioctl(4, VIDIOC_QUERYCTRL // 查询属性(比如说亮度值最小值、最大值、默认值)
// 8~10都是通过v4l2_read_attr来调用的
8. ioctl(4, VIDIOC_G_STD // 获得当前使用的标准(制式), 不是必需的
9. ioctl(4, VIDIOC_G_INPUT //获得输入
10. ioctl(4, VIDIOC_G_CTRL // 获得当前属性, 比如亮度是多少
11. ioctl(4, VIDIOC_TRY_FMT // 试试能否支持某种格式
12. ioctl(4, VIDIOC_S_FMT // 设置摄像头使用某种格式
// 13~16在v4l2_start_streaming
13. ioctl(4, VIDIOC_REQBUFS // 请求系统分配缓冲区
14. for()
ioctl(4, VIDIOC_QUERYBUF // 查询所分配的缓冲区
mmap //对于每一个缓冲区都得到地址、大小等信息,利用mmap来映射地址,让应用程序知道以后去哪个地址访问缓冲区
15. for ()
ioctl(4, VIDIOC_QBUF // 把缓冲区放入驱动程序的队列
16. ioctl(4, VIDIOC_STREAMON // 启动摄像头
// 17里都是通过v4l2_write_attr来调用的
17. for ()
ioctl(4, VIDIOC_S_CTRL // 设置属性
ioctl(4, VIDIOC_S_INPUT // 设置输入源
ioctl(4, VIDIOC_S_STD // 设置标准(制式), 不是必需的
// v4l2_nextframe > v4l2_waiton
18. v4l2_queue_all
v4l2_waiton
for ()
{
select(5, [4], NULL, NULL, {5, 0}) = 1 (in [4], left {4, 985979}) //查询到有没有数据,驱动程序有数据后,把应用程序唤醒,唤醒后应用程序调用DQBUF获得buffer信息,然后处理它,处理完后再次放入队列里面
ioctl(4, VIDIOC_DQBUF // de-queue, 把缓冲区从队列中取出
// 处理, 之以已经通过mmap获得了缓冲区的地址, 就可以直接访问数据
ioctl(4, VIDIOC_QBUF // 把缓冲区放入队列
}
2. v4l2_read_attr/v4l2_write_attr //读写属性
3. v4l2_start_streaming //启动流
4. v4l2_nextframe/v4l2_waiton //
3、一边修改vivi.c一边测试
(1)执行xawtv
出现以下画面
(2)点击画面右键出现属性菜单