ALVideoDevice 实现细节:
体系结构概述:
该框架是专门为NAO摄像头设计的。其他视频源例如流模式的驱动及其循环缓冲区的管理也通过模拟而采用该架构。
一个视觉模块(V.M.)需要特定格式的图像来完成处理工作,而ALVideoDevice能够对视频流进行转化从而得到所需的格式(分辨率,色彩空间等)。如果请求的图像格式是视频源的原始格式,那个就可以进行直接的原始访问(作为一种高级特性,当然也收到一定的限制)。
如何改变视频源:
ALVideoDevice所使用的视频源是在VideoInput.xml首选项文件中定义。 目前,有3种不同的视频源可供选择:
§ NaoCam:NAO的摄像头(只适用于NAO)
§ SimulatorCam:NAO在模拟器中使用(仅适用于台式机)
§ FileCam(测试版):从任何视频设备抓取的录像(适用于NAO和台式机)
注:可以利用ALVideoDeviceProxy::SetParam()进行摄像头的切换,使用参数为KCameraSelectID (或者是高级参数KCameraFastSwitchID ,如果可用的话)
ALVideoDevice完成哪些工作:
ALVideoDevice的主要工作是管理视频源,以NAO的摄像头为例:
§ 打开摄像头设备,通过I2C总线进行通信。
§ 在流模式启动V4L2驱动程序(V4L2驱动程序将创建一个具有n个单元的循环缓冲区来获取视频流)。
§ 接受视觉模块的订阅,为VM提供一个ALImage用来封装从V4L2驱动得到的原始数据缓存,一个ALImage用来存储转化后的数据
§ 当一个VM请求图像时,决定提供哪一个图像。这取决于是否存在另外的VM已经请求了同样格式的图像
§ 管理所有对视频设备的改变(例如新的增益设置),或者是VM自身参数的改变(例如颜色空间)。管理这些改变对视频设备或驱动造成的影响,(例如从QVGA到VGA的改变)
§ 当一个VM退订时,回收相应未被使用的ALImage,同时为剩下的模块检测 视频设备及驱动的新的最优设置
§ 当没有VM订阅时,停止驱动,关闭视频设备
注:
由于模拟Camera及camera视频文件并没有I2C通信机V4L2驱动程序,两者均运行于一种类似的途径,而不像NAO camera 拥有ALVideoDevice,(一种循环缓冲区已经实现了对V4L2驱动的模拟,同时,模拟camera 视频流被转化为YUV422格式,从而对视频设备保持一个抽象层)
ALVideoDevice如何处理视觉模块需求:
1.VM订阅ALVideoDevice
VM通过代理(broker)使用以下参数订阅ALVideoDevice
名称(ID):如果没有其他模块使用该ID来订阅,那么这个ID将作为标识。否则,该名称将利用一些额外的字符进行扩展(例如“_3”给第三个实例)
注:最多只允许用户订阅8个实例从而避免编程错误,你可以通过调用ALVideoDevice::unsubscribe()
退订所有实例
分辨率(大小):
4VGA(1280 * 960)
VGA(640 * 480)
QVGA(320 * 240)
QQVGA(160 * 120)
色彩空间
YUV422(摄像机的原始格式)
YUV(24位)
Y(8位)
RGB BGR HSY(24位)
帧频(fps)
OV7670 VGA摄像头只支持30fps,MT9M114 HD摄像头将来在某些特定的模式下能够运行的更快
在这个阶段,ALVideoDevice可以在数据库中确定向每个提出请求的VM提供什么
下图显示,三个不同的VM订阅了ALVideoDevice(蓝色部分)。为了对ALVideoDevice的内部工作原理进行解释,首先假设前两个VM请求同样格式的图像,进一步假设第三个VM请求图像格式与视频源原始格式相同。
在ALVideoDevice部分(黄色部分),已经创建了ALVision image 容器来管理未来可能从VM发送来的请求。其中左侧部分接收访问驱动缓存的指针。仅仅是封装了请求的的图像格式,为缓存中的原始数据设置不同的属性(宽,高,分辨率,颜色空间,锁类型等)而并没有分配内存。右侧部分拥有自己的分配内存,将用来接收转换格式(根据VM要求的分辨率,颜色空间进行转换)后的图像。
注:
实际上初始时右侧分配了分辨率及颜色空间所能允许的最大数目的内存空间,因而,在格式转换中分辨率还有颜色空间的变化并不需要内存的重新分配(这是相当耗时的),仅仅是参数的修改
2.设置并请求参数
setResolution,setColorSpace,setFrameRate:在任何时刻,每个VM都能够设定新的分辨率及颜色空间来替代注册时的值,ALVideoDevice会自动检查是否对视频源有新的设定,如果有必要的话讲应用新的设定
setParam:同样新的设置可以对视频源设备进行请求,例如启用/禁用自动增益和白平衡等
getGVMResolution,getGVMColorSpace,getGVMFrameRate:返回当前VM相应的参数(以前被称作通用视觉模块(Generic Vision Module),因而这里使用了GVM...)
getVIMResolution,getVIMColorSpace,getVIMFrameRate:用来了解当前视频源设备的运行模式(运行在最合适的模式去响应每个VM的需求)。以前ALVideoDevice又被叫做视频输入模块(video Imput Module),因为这里的名称为VIM..
getParam:返回特定视频源的参数
3.请求图像
一个VM能够通过两种途径得到图像
1,标准图像访问,允许图像格式转化
2,直接原始访问,通过直接访问驱动程序的图像缓存区实现
两种方式均可以用在远程module,及本地module中
标准访问:
建议使用该模式进行访问,当调用getImageLocal()函数时,ALVideoDevice将以VM请求的格式提供图像
1,在下图中,VM以本地方式向ALVideoDevice发出图像请求
2,假设该请求是第一个,或者最近没有相同格式的图像请求。ALvideoDevice将向驱动程序请求视频源中最新的缓存块
3,与V4L2的“读”模式不同,“流”模式不要求从内核空间中拷贝一份数据到用户空间中,仅仅进行了重映射(作用于指针,而非数据)。因此正如下图左侧所示,驱动程序通过将最新的原始数据从环形缓冲区中出列,来给ALVideoDevice线程提供数据。此时,驱动程序将继续工作于4块缓冲区下,而不再是最初的5块缓冲区
4,ALVideoDevice将转化原始图像缓存块为VM请求的格式。该图像将被存储在具有相同格式,过期且可用(未锁定)的第一块缓冲块内。在下图的右侧部分显示,一旦转化完成,原始图像缓存块将重新入列到环形缓冲区内
5,由于VM发出的是本地请求,VM将通过指针访问格式转化后的ALVisionImage 缓存,只要当前VM(还有其他同样访问它的VM)没有将其释放,该缓存块将被锁定。
现在假设另外一个VM线程向ALVideoDevice请求相同的图像。
1,现假定该请求是远程模块通过getImageRemote()方法请求的,用来说明远程调用有何不同。前半段与本地模块相同,只是在最后阶段获取缓存内容的方法有所不同
2,在这里ALVideoDevice会再次向驱动程序请求最新的缓冲块,同时也会比较与之相同格式的ALVisionImage的时间戳
注:当我们在驱动程序层得到新的一帧时对缓存加盖时间戳,因而精度是毫秒级别的
3,如果没有更新的原始图像缓存,ALVideoDevice将会提供第一个VM使用的相同的缓冲块,这样就避免了多余的转换过程
4,由于该请求是在远程模块下完成的,当前的ALImage缓存块将转化为ALValue,并通过“SOAP”发送到远程VM。由于远程VM通过“SOAP”得到一个缓存的副本,因而不在需要访问ALImage。因此远程VM能够释放对该ALImage缓存连接。释放过程由getImageRemote()函数自动完成。而本地VM组不再使用该ALImage缓存时则需要显式释放ALImage缓存。因此每一个getImageLocal()将同一个releaseImage()函数成对出现,在本地VM任务完成时(并不是进行时,从而阻止VM获取新的图像)
注:远程VM调用releaseImage()并不是强制要求的,但却是一个好的习惯,用来轻松的转化远程模块为本地模块。当在远程模块中调用时,该函数不做任何处理,同时也不会占用处理时间
一旦ALImage缓存块释放,将可以再次允许写操作,但在需要的时候仍然可读。
警告:
很显然,VM不应该改变输入图像,为了让其他VM也能够获得正确的数据。因此,如果你的VM的处理结果是图像的话,强烈建议使用一个输出图像。
直接进行原始访问:
在该模式下,用户可以直接访问驱动程序中的原始图像缓存,这就意味着,VM必须处理与原始视频源相同格式图像。在该模式下,不再是将一个未映射的驱动图像缓存以正确的格式拷贝到ALImage缓存(箭头4),再提供一个指针(箭头5)。而是直接通过指针对驱动程序中最新缓存进行直接访问。该过程更快,同时也消耗更少的资源。
但是该模式有一定的限制:
1,在该模式下,VM将持有该未映射的驱动程序原始缓存,因而,驱动程序环形缓冲区将工作在更少的缓存块下。如果有足够多(和环形缓存快的数目相同)的VM请求驱动程序原始缓存,同时持有缓存时长超多摄像头写图像的时间,那么在某些时间点,将没有缓存供给给视频源去写下一帧。该驱动程序只能等到有缓存释放的时候才能继续写图像
2,这也就是我们为什么建议比缓存块总数少的VMs直接调用原始缓存并超过25ms没有释放缓存。实际上驱动程序在nao上共设定了4个缓存块,同时nao的摄像头每33ms提供一帧数据,但是你需要保证一个安全的间隔时间进行ALVideoDevice管理及其他线程处理
3,另外一点你需要警惕的是,在该模式下,当摄像头正在运行的过程中对其进行改变(例如,分辨率,摄像头之间的切换),如果此时有任何驱动程序的缓存没有被释放将会导致错误
注:类似于远程标准访问,远程直接原始访问模块也将会自动释放原始内存只要ALValue转换完成
正如你所看到的,标准访问模式在内部调用了原始直接访问。
/*简单总结一下:远程模块将得到ALImage的副本(以ALValue的形式)并传递给远程模块;本地模块则 得到指向ALImage的指针。
AL::ALValue img = camProxy.getImageRemote(clientName);//远程调用
AL::ALImage* image = (AL::ALImage* )camProxy.getImageLocal(clientName);//本地调用
标准访问将驱动缓存内容拷贝到ALImage中(含格式转化),而直接原始访问则是得到直接指向驱动缓存内容的指针。
*/