QNX下低成本视频监控方案及实现
2015-01-13蒋俊铭
蒋俊铭
(上海交通大学自动化系,上海 200240)
控制系统中,在进行实时控制的同时,常常还希望能够得到被控对象的视频监控图像,这时就必须使用到摄像头。USB摄像头作为市场上广泛使用的设备,具有价格低廉、运用广泛及技术成熟等特点[1]。使用USB摄像头可以加速系统开发,同时还能保证系统的稳定性和可靠性。然而QNX操作系统却没有提供对于UVC(USB Video Class)摄像头的支持,为了在QNX控制系统中引入视频监控,笔者介绍了在resource manager框架[2]下UVC标准摄像头驱动程序的编写。
与传统的操作系统不同,QNX操作系统是一个完全的微内核实时操作系统[3],在其内核中,只提供了线程服务、信号服务、消息传输服务、同步服务、时间服务、调度服务和进程管理服务[3]。而常见的网络协议栈、文件系统、设备驱动及UI接口等都是作为独立的进程存在于操作系统中的。QNX充分发挥了虚拟内存技术的优势,保证了系统中各个模块的独立,同时也保证了系统各个进程的安全。QNX系统的内核架构如图1所示。
图1 QNX系统内核架构
2 驱动程序框架
为了便于实现QNX操作系统下驱动程序的编写和多进程程序的模块化,系统提供了resource manager框架。该框架使用了POSIX接口来实现服务进程和客户端进程的通信,还提供了类似于LINUX文件系统模型的设备访问接口。这在提高系统灵活性的同时也降低了开发难度。resource manager的结构框架如图2所示。
图2 resource manager结构框架
在该框架下,可以方便地使用open()、read()及write()[2]等函数对QNX下的设备进行简单而快捷的操作。具体的操作流程为:客户端向驱动程序发送IPC信息(调用open()等函数时产生),驱动程序端的消息等待函数从阻塞等待状态醒来,然后再到resource manager层搜索相关的函数来处理该信息;待处理过程结束后,消息等待函数重新回到消息等待状态。为了实现完整的resource manager功能,在编写驱动程序时,需要提供相应的消息处理函数。本驱动程序在io_open()函数(处理由客户端open()函数向resource manager发送的io_open消息)中实现了UVC摄像头描述符解析、配置及启动等功能,在io_read()函数中实现了同步查询式的图像帧数据传输等功能,而io_close()函数则用于取消数据传输及关闭设备等。
3 UVC标准与USB摄像头操作
USB设备支持热插拔,标准统一,同时还有很好的通用性,越来越多的厂商愿意在自己的设备中加入对USB标准的支持。然而随着越来越多厂商实现了各自的USB摄像头,USB摄像头的控制协议也变得越来越纷乱,为了实现对USB摄像头的标准化,USB标准化组织制定了UVC标准协议。
UVC标准的基本思想为:将USB摄像头的基本信息(设备描述符)按一定的格式写在设备自身内部,当USB摄像头接入系统时,标准的USB协议栈能够正确地识别该设备所属的子类,然后将设备注册到相应的驱动程序,设备对应的驱动程序解读存储于设备内部的设备描述符,并根据描述符提供的信息,按UVC协议完成对设备的控制和图像的获取。设备描述符如图3所示。
图3 设备描述符结构
在获取了以上描述符并成功注册设备之后,驱动程序便可以根据UVC操作流程对摄像头进行操作了。
UVC对于摄像头的控制主要有视频控制请求和视频流请求两种。这两种请求都是通过设置请求(set request)和获取请求(get request)两种操作来实现的。设置请求和获取请求的操作参数分别见表1、2。
表1 设置请求操作参数
表2 获取请求操作参数
由表1和表2的比较可知设置请求操作和获取请求操作的区别是bmRequestType和bRequest两个参数不同,bmRequestType指明了具体的操作类型,bRequest指明了要获取或者设置的参数项,这些参数项所对应的实体和实体内的对象分别由wIndex和wValue指定。需注意的是在同种操作中,针对实体(接口通常被视为虚拟实体)和端点的请求类型码是不同的。在以上两个操作的基础上,UVC标准协议定义了具体的视频控制请求和视频流请求。当摄像头能够自动调节参数时,处理好视频流请求操作便可以控制摄像头了。
视频流请求最重要的操作是参数探测、参数确认和接口切换,这些操作是启动视频流传输必须的步骤,图4为具体的视频启动流程。在启动视频的过程中,需要进行3次设置操作和一次获取操作。在探测过程中,需要设置的参数主要有格式编号、帧索引编号及帧间隔等,其中帧格式编号指明了所使用图像的格式,如MJPG,帧索引编号用于设定分辨率,而帧间隔用于设定帧率。当获取的默认设置不能满足要求时需要设置以上参数。
图4 视频启动流程
4 QNX下程序的实现
UVC驱动程序的主要工作包括两个部分:与QNX系统USB协议栈进行数据交互和建立resource manager处理来自用户的信息。与QNX系统USB协议栈进行数据交互的过程如图5所示。该图详细描述了UVC驱动程序与其他程序的交互顺序。USB协议栈随操作系统启动后处于服务状态,然后UVC驱动进程启动并向USB栈注册该驱动所处理设备的类型(UVC设备子类型在USB标准中为0x0e)和相应的回调函数。
图5 与QNX系统USB协议栈进行 数据交互的过程
完成注册后,当有UVC标准的摄像头接入系统时,QNX下USB协议栈会主动通知UVC驱动程序。具体为图5中“设备接入通知”所示。要启动视频流传输,还需要客户端启动相应的程序,如图5中“打开设备”所示。因为resource manager支持POSIX标准,所以可以很方便地使用open()、read()及close()等POSIX标准函数实现设备的操作。
图像数据的传输是通过同步查询的方式实现的。USB下数据的传输需要建立URB(Usb Request Block)[4],然后用如下函数向USB协议栈提交URB和数据传输请求:
int usbd_setup_isochronous(
struct usbd_urb * urb, //URB指针
uint32_t flags,//请求传输类型
int32_t frame,//特定帧编号
void * addr,//缓冲区地址
uint32_tlen );//缓冲区长度
视频传输启动后,数据帧随URB返回到驱动程序。当获取数据帧之后,需要将图像数据从数据帧中提取出来。本程序中使用了MJPEG格式作为图像帧格式,相应的数据帧格式如图6所示。当URB收到数据并返回后,会同时返回数据帧的总长度,将帧头长度减去之后,得到有效数据的长度,将有效图像数据从数据帧中取出,并重新组装成图像帧,便可以成功获取MJPEG图像帧了。
5 结束语
选用了罗技C270型号的摄像头作为图像获取设备,并在QNX平台下成功实现了UVC标准下摄像头驱动程序的编写。该驱动程序能够稳定获取320×240、30Hz的图像,并能够满足对分辨率要求不高的环境下的监控。因为该摄像头驱动程序满足UVC标准,所以该驱动程序同时还具有很好的移植性,可以很方便地进行移植。
图6 数据帧格式
[1] 李涵.USB接口驱动的研究与设计[D].青岛:山东科技大学,2005.
[2] 徐竟青,黄俊峰,李一平.QNX设备驱动程序的编制[J].计算机工程,2003,29(12): 176~178.
[3] 任宁宁.多核平台下强实时操作系统QNX调度机制的应用研究[D].成都:西南交通大学,2013.
[4] 杨伟,刘强,顾新.Linux下USB设备驱动研究与开发[J].计算机工程,2006,32(19):283~285.