Access to complex video devices with libcamera
By Jonathan Corbet
July 25, 2019
OSS Japan
Laurent Pinchart在Open Source Summit Japan 2019的演讲开始时,分享了一个观点,在很久之前,camera device都只有很简单的pipeline逻辑,最终生成一系列的video frame,应用陈旭可以试用Video4Linux(V4L) API来操纵文件系统中的一个设备节点从而控制camera。当时虽然有很多控制参数,不过整体来说开发工作还是很简明直接的。现在的情况大不一样了,应用程序开发者的工作不再那么简单了,也需要更多帮助。因此libcamera项目出现了。
其实,在编者看来,哪怕最开始的V4L API对初次进入这个领域的开发者也不够简明直接。首先需要经过一个协商流程然后应用程序才能了解它面对的camera设备能否按它要求的格式给出数据。并且需要调整大量参数。经常看到某些应用程序只能配合特定的camera device上才能工作。V4L确实提供了很多帮助,不过那时哪怕对camera进行最简单的操作也不是那么容易的。
libcamera
现在回到演讲内容上来,目前的硬件设备比起当初要复杂的多。通常一个camera device内部会有很多处理单元(来实现图像缩放,颜色矫正,色彩空间转换,自动聚焦,等等等等),这些处理单元可以按照很多种通路来互相连接起来。之前大家实现了media controller subsystem,来把这些复杂的配置交给user space来做,不过它的帮助也就仅此而已了。举例来说,如果想实现一个特定目的application,在了解设备上的video device之后,还是挺容易开发出来的。但是要想写出一个application能够支持数量众多的video hardware,那就非常难做好了。
Nokia的开发者曾经在多年前计划实现一套基于插件的camera配置机制,不过还没等完成开发,Nokia就停止了智能手机的项目,因此开发也就终止了。10年之后,libcamera出现了,它希望能成为camera stack里面的核心库,就像Mesa在3D处理领域里的地位那样。libcamera致力于让application能更加容易的同camera device交互。设计上来说它希望让camera stack包含4个层级:
libcamera是最底层,直接同kernel进行交互。它完全在user space实现,不打算更改kernel API
libcamera会有多种编程语言的binding接口,这样能支持多种语言下的camera开发。
适配层(adaptation layer),会提供一系列的操作接口来包装libcamera操作,使得对此前的application能轻松适配到libcamera上来。这里包含V4L兼容层,Android HAL接口,GStreamer接口,目的是让libcamera能支持所有Linux设备。
应用程序层(application layer),这个layer早已经存在了,例如使用GStreamer接口的应用程序、V4L应用程序、Android应用程序等等。今后还会有基于libcamera直接开发的应用程序。
Application interface
libcamera application需要在最开始先枚举看一下系统上有哪些camera设备。这里说的"camera"是指用户能看到的camera device,其实一个camera device底层实现上来说包含有很多模块(camera传感器,DMA bridge,各种特定的处理单元,等等)。camera设备都会上报一下它自己的能力,例如能支持同一时刻多少路的video stream(视频流),支持哪些control控制,支持哪些分辨率。把这些能力针对各种应用场景包装在一起,就是“Profile”的概念了,例如针对“point-and-shoot camera”或者“video conferencing视频会议”等应用场景,使用不同profile。
libcamera的一个主要功能就是支持并发多路视频流(concurrent stream)。例如,针对普通拍照设备,可能会想要是要使用一路中等分辨率的视频流来在显示屏上做预览(preview),与此同时还有一个最大分辨率的stream来做image capture(拍照)。
libcamera里面的control可以针对每个frame来做,只要硬件允许的话。这些控制包括曝光时间,对焦设置,白平衡,等等。对video conference视频会议这种场景来说这些设置可能并不重要,但是对人脸识别或者机器视觉场景下,应用程序必须要能知道每一帧的相关参数。
如果application直接使用libcamera库进行开发,那么在枚举到设备之后,需要确保拿到设备的访问权限。libcamera里面对设备都是独占访问的。如果需要多方同时使用的话,就需要在上层通过GStreamer framework调用实现了。还需要经过一个配置阶段,此时camera会根据应用场景来创建一组配置模板,然后application可以修改这些参数,并验证确保camera真能支持新配的参数。也就是说还是需要有一个协商过程的,不过最开始提供的配置模板会让协商过程轻松得多。针对application打开的每路视频流都需要做这个配置工作,在完成配置之后,application就分配数个buffer来准备接收video data。还有一个"create request"操作,会提供一组参数送给camera来发起一个capture操作,抓取video stream里面的一帧送到自己分配好的buffer里。大多数application可能会不断发起多个request,确保视频流不停下来。用到的buffer在处理完其中的video data之后可以再次用在新的request里面,循环利用。
Advanced algorithms
当然还要支持各种图像处理算法,例如自动曝光、白平衡、对焦,甚至高级功能例如噪声消除等等。这里需要思考清楚做出选择,这些算法通常都是由camera厂商提供的,很多都是私有软件。Libcamera会以独立加载的module的形式来支持这些功能。Pinchart也说,我们都希望这些代码能open source,不过现在还是无法做到的,第一优先级仍然是能让系统在一个安全可靠的方式下正常工作起来。
这里设计时有一个比较重要的决策,就是图像处理的module都不能直接跟硬件本身交互,都需要经过一组标准接口。通常来说一个module会需要从硬件获取一些统计信息或者图像数据,计算最优化的图像参数,然后利用libcamera接口来对这个设备进行配置。他保证“不会有秘密的ioctl()调用”。所有的Module都需要按照沙箱标准来做,确保他们不能伤害系统的其他部分。
camera device abstraction底层抽象设计时尽量做得代码与特定设备无关。现在已经有了很多独立的camera底层实现了,例如Andriod和ChromeOS都实现了他们自己的底层方案。因此就需要能让供应商只要在libcamera里面提供了他们设备的支持,就能让任何上层开发者都用同样的接口来操作。
libcamera项目还是在一个比较早期的开发阶段,尚未发布过任何正式版本。目前Pinchart已经能用libcamera来快速进行一次video conference演示了。会议上展示时拨通了欧洲的一位半夜还不睡觉的热心开发者。图像质量还需要改善,不过基本功能都已经能用了。假如libcamera能坚持按照路线图进行开发,很有可能会在不久之后就获得某些系统的采用。
【编辑声明,感谢Linux Foundation支持参会】
全文完
LWN文章遵循CC BY-SA 4.0许可协议。
极度欢迎将文章分享到朋友圈热烈欢迎转载以及基于现有协议修改再创作~
长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~