基于Linux V4L2子系统的ISP及Camera驱动接口标准化方法及应用
2021-08-16陈二微
陈二微
随着行业互联网的持续发展,各行业对Camera数据的采集、应用提出了不同的需求。以Linux操作系统为基础的V4L2子系统是一种较为通用的驱动架构。本文描述基于电子的硬件ISP在V4L2接口下的实现方法、Camera连接的拓扑结构、提出了一种3A独立进程的图像调试方式,及其灵活的、可拓展的应用形式。
Linux V412及ISP硬件
Video For Linux 2(V412),是Linux Kernel中专用于处理视频、图像的子系统框架,向Linux操作系统应用层提供了ISP及Camera硬件的标准接口,被广泛应用于各芯片厂商的设备驱动。通过对数据流的详细定义,使得应用程序的开发有统一的接口,LinuxTV组织即是这个子系统的维护者。
ISP在本文中指集成于SoC中的图像处理核心,它能够将Camera感光元件获取的Raw Bayer原始数据进行去马赛克(Demosaicing)处理,从而转成一张YUV或RGB图像;同时对图像进行3A (Auto Focus,Auto Exposure,Auto White Balance)信息统计并调试校正出一张曝光及白平衡准确的图像。ISP的硬件接口灵活,能够接收不同分辨率、不同格式、MIPI或DVP协议传输的原始图像数据,也可接收已经调试好的YUV或RGB图像输入;能够对原图进行裁剪、缩放,并可同时输出两路不同格式(YUV或RGB)、不同大小的图像。
驱动的实现方法
一个完整的ISP传输Camera数据链路如图1所示,它分为了Camera感光Sensor(可以包含一个或多个),MIPI DPHY 数据传输通路,ISP转发数据,统计图像信息,调试参数配置,双路图像输出6个大模块。各个模块分别表示为一个Entity 节点,使用Link将两个Entity连接起来,从而形成一条或2条的链路。
其中Camera摄像头Entity可以支持1个或多个,在建立Link链接时,可以指定当前有效的摄像头。2个的图像输出接口从上一级Entity处得到图像后,可以分别自由地裁剪、缩放并输出。3A的调试过程从统计输出数据Entity获取3A信息,调整后将修改数据由调试参数Entity传入,直到统计值收敛。
各个Entity需要按功能实现回调函数。如摄像头、ISP转发数据、图像输出接口,都需要实现set_fmt、get_fmt用于设置图像的大小与格式;s_power用于给模块上下电;s_stream用于使能数据流的输出。图像输出接口另外还需要实现与应用层的buffer轮转,即QBUF、DQBUF、QBUF...这样的循环操作,以及裁剪与缩放接口,即s_selection,g_selection。这里采用v412框架中集成的vb2(video buffer 2)管理buffer,同时实现ISP内嵌的iommu模块,将不连续的物理内存映射成ISP可以访问的虚拟的连接内存。
摄像头模块并不集成在SoC芯片中,与MIPI DPHY或ISP是物理上独立的,驱动上它也是最大限度地独立,并且通过异步加载的形式注册成为子设备(Sub-Device)。
应用开发与3A独立成一个进程
基于V4L2的驱动接口,应用程序开发获取图像帧数据,主要包括设置链路选择摄像头输入、打开/dev/video设备、设置各个Entity的输入与输出大小格式、分配存储Buffer、通过QBUF将Buffer配置到kernel、使能整个链路、等待一帧数据完成并DQBUF到应用层、Buffer处理(或显示或保存等等)完毕后再通过QBUF配置到kernel,并循环DQBUF与QBUF的操作直到退出。
得益于驱动的标准化,例如v4l-utils、gstreamer、vlc等通用程序能直接获取数据流并显示出图像、视频。然而因公司的策略,3A调试部分是闭源且不在驱动中实现。在没有3A调试时,应用程序获取的图像或偏亮或偏暗,或颜色与实际相差太大。虽然有提供动态链接库供调用并使能3A,以完成图像的调试,但需要修改v4l-utils、gstreamer、vlc等的源代码,加入3A的初始化、使能與关闭。
本文提出了将3A与数据流分割开,独立成一个进程。令3A进程通过v4l2-event 监听isp驱动中start_stream与stop_ stream操作,在start_stream时在用户空间完成3A的初始化,反之在stop_stream时关闭3A的操作。从而使得v4l-utils等工具能够无缝地直接使用,也简化了应用程序的开发。
Camera驱动开发
除了应用的开发,另一个大块是Camera(Sensor)摄像头的驱动如何移植。
基于该ISP的驱动结构,Camera作为一个sub-device,驱动的移植有简洁统一的步骤。概括为6个部分:
照datasheet 编写上电时序,主要包括vdd,reset,powerdown,clk等;
配置sensor的寄存器以输出所需的分辨率、格式;
编写struct v4l2_subdev_ops所需要的回调函数,一般包括set_fmt,get_fmt,s_power,s_stream,用于描述Camera所支持的格式与分辨率,上下电及输出的开关;
增加v412controller用来设置女口fps,exposure,gain,test pattern,用于调整帧率,设置曝光及增益,输出内嵌的测试图片编写.probe()函数,并添加media control 及v4l2sub device 初始化代码,使得该设备可以作为一个sub-device添加到ISP的完整链路中;
Dts(Device Tree Source)中通过remote-endpoint建立与ISP的具体链接信息。
相对于旧的驱动,新的驱动主要的提升包含6个内容,
①是使接口标准化;
②是使得3A进程独立运行,极简了应用的开发;
③是双路的图像输出可以同时独立地进行;
④是采用了vb2的buffer管理,有效地复用了代码;
⑤是使得Camera,MipiDphy,ISP驱动相互独立,Camera异步注册,从而解耦合了整体结构;
⑥是能复用ISP模块支持多个Camera接入到同一个ISP。
该isp驱动已经形成了一套完整的Camera驱动、应用程序开发方法,于项目实践中应用。