Linux系统下USB摄像头驱动开发
发布时间:2008/6/3 0:00:00 访问次数:508
摘要:介绍了在iinux系统下开发符合video for linux标准的usb摄像头驱动的方法,并对该标准提出“不间断采集”的改进思路,配合双urb、双帧缓冲等方法,提高采集速度。
关键词:linux设备驱动 usb摄像头 video for linux 不间断采集
usb摄像头以其良好的性能和低廉的价格得到广泛应用。同时因其灵活、方便的特性,易于集成到嵌入式系统中。但是如果使用现有的符合video for linux标准的驱动程序配合通用应用程序,难以充分利用usb带宽,帧速不高,不易满足实时监控等要求。本文首先介绍在linux系统下usb摄像头驱动编制的一般方法,然后说明在此基础上如何提高帧速。
1 linux系统中的usb摄像头驱动程序
usb设备驱动程序完全符合通用设备驱动的准则,不同的是内核提供了一些特别的api函数,方便驱动注册、销毁自己,例如usb_resister()和usb_deresister();2.4版的内核还提供了对于hotplug的支持。
1.1 usb摄像头驱动的一般编写方法
摄像头属于视频类设备。在目前的linux核心中,视频部分的标准是video for linux(简称v4l)。这个标准其实定义了一套接口,内核、驱动、应用程序以这个接口为标准进行交流。目前的v4l涵盖了视、音频流捕捉及处理等内容,usb摄像头也属于它支持的范畴。
因此,usb摄像头的驱动应当与内核提供的视频驱动挂钩。即首先在驱动中声明一个video_device结构,并为其指定文件操作函数指针数组.fops,向系统注册。在应用程序发出文件操作的相关命令时,核心根据这些指针调用相应函数,并将该结构作为参数传递给它们。这样,就完成了驱动和核心之间的通信。例如:
static struct video_device vdev_template={……};
//声明video_device,指出挂接驱动
static struct file_operations ov511_fops={……};
//声明本驱动的文件操作函数指针
struct video_device*vdev=video_devdata(file);
//从文件指针中提取出video_device结构
在video_device结构中,有一个私有指针priv,可以将它指向一块保留内存。在这块内存中,保存着本驱动、本设备的相关初始化信息。这块内存的申请、初始化、指针指向等工作都是在usb驱动的枚举函数.probe中完成。这样,在枚举函数将控制权返还给系统后,因为内核不销毁保留内存,所以驱动仍然保留着自己的信息。这点与windows系统中wdm驱动有异曲同工之处。当然,在驱动卸载函数中,应当将申请的各块内存全部释放。
1.2 使用双urb轮流通信
众所周知,usbl.1总线标准定义了控制、中断、批量、等时等四种管道。对于时间性极强但是准确度要求不高的视频捕捉应用来说,摄像头应当使用等时传输方式。为了尽可能快地得到图像数据,应当在urb中指定usb_iso_asap标志。
urb->transfer_flags=usb_iso_asap;//尽可能快地发出本urb
linux系统中任何usb传输都通过urb实现。为提高速度,可以考虑扩大urb的缓冲,这样可以降低每个usb事务中握手信息所占比例,提高有效数据的传输速度。但是受限于总线带宽和具体的usb设备芯片,单纯扩大urb的缓冲不能无限制地解决问题。具体分析一下usb传输在操作系统中的实现:每次传输都要包括urb的建立、发出、回收、数据整理等阶段,这些时间不产生有效数据。因此可以建立两个urb,在等待一个urb被回收时,也就是图像正在被传感器采集时,处理、初始化另一个urb,并在回收后立刻将其发出。两个urb交替使用,大大减少了额外时间。工作流程如图1所示。
这个过程是在urb的完成例程中实现的,有两点需要注意:首先处理再次初始化的代码时间不能长,否则会造成完成例程的重人,如果确实来不及,可以在完成例程中设定标志,例如“数据采集好”旗语,由应用程序使用阻塞ioctl()来查询该旗语并做处理;其次由于cpu可能会在完成例
摘要:介绍了在iinux系统下开发符合video for linux标准的usb摄像头驱动的方法,并对该标准提出“不间断采集”的改进思路,配合双urb、双帧缓冲等方法,提高采集速度。
关键词:linux设备驱动 usb摄像头 video for linux 不间断采集
usb摄像头以其良好的性能和低廉的价格得到广泛应用。同时因其灵活、方便的特性,易于集成到嵌入式系统中。但是如果使用现有的符合video for linux标准的驱动程序配合通用应用程序,难以充分利用usb带宽,帧速不高,不易满足实时监控等要求。本文首先介绍在linux系统下usb摄像头驱动编制的一般方法,然后说明在此基础上如何提高帧速。
1 linux系统中的usb摄像头驱动程序
usb设备驱动程序完全符合通用设备驱动的准则,不同的是内核提供了一些特别的api函数,方便驱动注册、销毁自己,例如usb_resister()和usb_deresister();2.4版的内核还提供了对于hotplug的支持。
1.1 usb摄像头驱动的一般编写方法
摄像头属于视频类设备。在目前的linux核心中,视频部分的标准是video for linux(简称v4l)。这个标准其实定义了一套接口,内核、驱动、应用程序以这个接口为标准进行交流。目前的v4l涵盖了视、音频流捕捉及处理等内容,usb摄像头也属于它支持的范畴。
因此,usb摄像头的驱动应当与内核提供的视频驱动挂钩。即首先在驱动中声明一个video_device结构,并为其指定文件操作函数指针数组.fops,向系统注册。在应用程序发出文件操作的相关命令时,核心根据这些指针调用相应函数,并将该结构作为参数传递给它们。这样,就完成了驱动和核心之间的通信。例如:
static struct video_device vdev_template={……};
//声明video_device,指出挂接驱动
static struct file_operations ov511_fops={……};
//声明本驱动的文件操作函数指针
struct video_device*vdev=video_devdata(file);
//从文件指针中提取出video_device结构
在video_device结构中,有一个私有指针priv,可以将它指向一块保留内存。在这块内存中,保存着本驱动、本设备的相关初始化信息。这块内存的申请、初始化、指针指向等工作都是在usb驱动的枚举函数.probe中完成。这样,在枚举函数将控制权返还给系统后,因为内核不销毁保留内存,所以驱动仍然保留着自己的信息。这点与windows系统中wdm驱动有异曲同工之处。当然,在驱动卸载函数中,应当将申请的各块内存全部释放。
1.2 使用双urb轮流通信
众所周知,usbl.1总线标准定义了控制、中断、批量、等时等四种管道。对于时间性极强但是准确度要求不高的视频捕捉应用来说,摄像头应当使用等时传输方式。为了尽可能快地得到图像数据,应当在urb中指定usb_iso_asap标志。
urb->transfer_flags=usb_iso_asap;//尽可能快地发出本urb
linux系统中任何usb传输都通过urb实现。为提高速度,可以考虑扩大urb的缓冲,这样可以降低每个usb事务中握手信息所占比例,提高有效数据的传输速度。但是受限于总线带宽和具体的usb设备芯片,单纯扩大urb的缓冲不能无限制地解决问题。具体分析一下usb传输在操作系统中的实现:每次传输都要包括urb的建立、发出、回收、数据整理等阶段,这些时间不产生有效数据。因此可以建立两个urb,在等待一个urb被回收时,也就是图像正在被传感器采集时,处理、初始化另一个urb,并在回收后立刻将其发出。两个urb交替使用,大大减少了额外时间。工作流程如图1所示。
这个过程是在urb的完成例程中实现的,有两点需要注意:首先处理再次初始化的代码时间不能长,否则会造成完成例程的重人,如果确实来不及,可以在完成例程中设定标志,例如“数据采集好”旗语,由应用程序使用阻塞ioctl()来查询该旗语并做处理;其次由于cpu可能会在完成例