1、上一节测试的摄像头驱动程序的缺陷(我把缺陷给避免了,在上一篇)
(1)依次装载驱动程序,出现错误如下
(2)用dmesg命令查看详细输出(某些函数没有识别),可见我们的vivi.ko还依赖于其他驱动程序,上一节直接使用这些命令没有问题,是因为在做虚拟摄像头vivi之前。我们先接上USB摄像头,ubuntu里面自动给我们安装了其他驱动程序。所以在使用vivi的时候,没有出现问题。
(3)sudo modprobe vivi
这是安装ubuntu里面自带的vivi驱动程序,把它依赖的其他驱动程序也一起安装进来
(4)使用ls /dev/v* 命令进行查找 如果出现两个/dev/video0 /dev/video1 两个,第一个是usb 的。可以使用
命令 sudo rmmod uvcvideo 去掉usb,可以去掉内核自带的虚拟设备驱动程序,sudo rmmod vivi,
(5)把内核自带的vivi去掉,安装上我们编译出来的vivi.ko,使用命令sudo insmod vivi.ko ,使用命令ls /dev/v* 进行查看
/dev/video0 我们以后做实验的时候要用到自己编译的代码,
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 // 把缓冲区放入队列
}
(4)xawtv的几大函数:
1. v4l2_open
2. v4l2_read_attr/v4l2_write_attr //读写属性
3. v4l2_start_streaming //启动流
4. v4l2_nextframe/v4l2_waiton //
3、一边修改vivi.c一边测试
4经过修改和测试得出必要的个11个ioctl
//表示它是一个摄像头设备
.vidioc_querycap = vidioc_querycap,
/*用于列举,获得,测试,设置摄像头的数据格式这是必须的*/
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
/*缓冲区操作:申请/查询/放入队列/取出队列这些也是必须的*/
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
/*摄像头的启动和关闭*/
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,