Android Camera启动流程和配置介绍
1. Android Camera Architecture¶
2. Android Camera HAL3与上层的交互过程¶
get_number_of_cameras: 获取camera个数,取值范围从0-N的整数,注意这里只统计built-in camera个数,不包含external camera个数。
get_camera_info: 获取camera信息,主要包括镜头旋转角度、前置还是后置、sensor相关的静态参数(static metadata)
get_vendor_tag_ops: 获取一些函数指针,用于查询厂商的扩展属性
set_callbacks: 设置两个回调函数到HAL,主要用于通知上层摄像头状态改变以及闪光灯状态改变
open: 通过index打开一个camera,返回hw_device_t结构体,上层通过这个结构体可以获取到如下这些HAL提供的API
initialize: 初始化函数,在这里我们会起一个线程,用于分发处理framework层传下来的消息
configure_streams: 新创建一路pipeline或者重置原来已经存在的pipeline。在这个API里面会告知HAL当前Pipeline的宽、高、以及格式信息。这个API必须至少包含一路输出流。同时HAL需要通过对这个API带来的一些参数赋值,比如max_buffers以及usage
construct_default_request_settings: 配置一个标准的捕获配置模板,这里的捕获case包含Preview、Record、Capture等。app层会基于这个settings来做修改,构造最终的捕获设置
process_capture_request: 调用这个API开始获取图片数据。
notify: HAL用于告知framework shutter/metadata/buffer
flush: 调用这个API主要是为了通知HAL尽快把指定设备还在处理的captures尽快返回,以便framework可以通过configure_streams来重新配置Pipeline。
close: 彻底销毁HAL创建的Camera实例
3. Android Camera HAL软件框架¶
4. 预览、拍照、录像介绍¶
4.1. 预览¶
Preview是Android Camera最基本的功能之一。预览最重要的四个步骤如下:
1)Framework调用 construct_default_request_settings来获取预览这个usecase的默认请求的settings,HAL会返回一个模板Camera Metadata,后续的取数据的设定就是基于这个模板来构造
2)Framework调用configure_streams配置一路预览流,带有operation_mode/stream_type/width/height/format/priv等参数。HAL根据这里面的width/height/format配置MI输出一路流
3)Framework开始不断调用process_capture_request来获取预览流,每个process_capture_request里面都带有camera_metadata,HAL解析camera_metadata并根据camera_metadata做一些参数调整,然后捕获数据
4)HAL通过notify 通知Framework SHUTTER事件,接着调用process_capture_result回调函数将当前帧对应一些设置放在camera_metadata返回给Framework,最后再通过process_capture_result把buffer返回给Framework。
整体流程图如下:
4.2. 拍照¶
拍照是Android Camera最基本的功能之一。流程如下:
1)Framework调用 construct_default_request_settings来获取拍照这个usecase的默认请求的settings,HAL会返回一个Camera Metadata,后续的捕获settings就是基于这个模板来构造
2)Framework调用configure_streams配置一路预览流,带有operation_mode/stream_type/width/height/format/priv/等参数。HAL根据这里面的width/height/format配置MI输出一路流。一般配置预览时,会同时配置拍照
3)Framework开始不断调用process_capture_request来获取预览流,每个process_capture_request里面都带有camera_metadata,HAL解析camera_metadata并根据camera_metadata做一些参数调整,然后捕获数据
4)HAL通过notify 通知Framework SHUTTER事件,接着调用process_capture_result回调函数将当前帧对应一些设置放在camera_metadata返回给Framework,最后再通过process_capture_result把buffer返回给Framework。
整体数据流处理流程基本和预览一致,唯一需要注意的有:
1) 拍照有两个实现方式,软编码和硬编码。默认aosp Camera2.apk是走的软编码,由APP决定的
2)如果是走软编码,预览的数据一般是从MI_SCL取NV12数据。如果是硬件编码,需要从MI_VENC获取编码后的es数据,然后按照规则组装成JPEG EXIF
3)对于软编码,上层传下来的format是HAL_PIXEL_FORMAT_YCbCr_420_888,对应的就是NV12的数据。对于走硬件编码,上层传下来的format是HAL_PIXEL_FORMAT_BLOB,拍照的buffer则是width = max.jpeg.size,height=1的buffer类型
JPEG EXIF介绍
我们打开一张JPEG,通过选项可以查看图片的详细信息,如下图:
这部分信息就是EXIF信息,是在HAL进行填充的,另外,我们拍完照会有一个缩略图,这个也是在HAL中产生的。所有的EXIF信息、缩略图信息、原JPEG图,组成最终一张完整的带有EXIF的JPEG图上传给APP。APP通过android提供的API可读写到这些信息,如图就是一张完整的带有EXIF的JPEG图:
下图为JPEG Encoder编码出来的es流数据内容,可以看出是没有EXIF信息的,是JFIF格式(JPEG FILE Interchange Format):
完整的一张JPEG数据,是由一些标记码,EXIF,图片信息组成。图片信息包含原图JPEG信息,Thumbnail是嵌入在其中的缩略图,也是jpeg格式。所有的标记都由0xFF开头,表示一个标记码开始。标记码解释:
1)0xFFD8 :start of image,图像的开始,2字节
2)0xFFE0:Application 0,JFIF应用程序保留标记0,标记码之后包含九个具体字段:
3)0xFFE1 — 0xFFEF:Application n,其他应用程序保留标记n(n=1---15),包含两个字段:
4)0xFFDB:DQT,Define Quantization Table,定义量化表;包含具体九个字段:
5)0xFFC0:Start Of Frame,帧图像的开始,包含具体九个字段:
6)0xFFC4:Define Huffman Table,定义Huffman表,包含两个字段:
7)0xFFDD:Define Restart Interval,定义差分编码累计复位的间隔
8)0xFFDA:start of scan,扫描开始,包含具体2个字段,图像数据就是在这里面:
9)0xFFD9:end of image,图像结束
ref: https://www.cnblogs.com/sddai/p/5666924.html
我们JPEG编码器编码出来的是JFIF格式,而android需求的是EXIF格式,两种结构基本样式:
可以看出我们JPEG 编码器的结构JFIF和安卓要求的EXIF差别主要是在APP1和JFIF-APP0这部分,所以假设编码一张图片,流程如下:
1)根据Thumbnail size,编码出一张JFIF缩略图jpg0
2)编码原图,编码出一张JFIF结构的jpg1
3)把jpg1重新组装成带有缩略图的EXIF格式,如上图的EXIF APP1,即SOI-APP1-jpg0-jpg1
对于APP1的内容,主要填充如下tag:
对应HAL实现如下:
1)Framework调用process_capture_request请求一张JPEG数据
2)从MI_SCL获取一张yuv buffer
3)将原图送进SCL,并crop成metadata中要求的thumbnail size
4)编码thumbnail
5)编码原图
6)将EXIF信息、缩略图、原图整合成一张EXIF结构的JPEG图片,并写到buffer_handle_t
7)通过process_capture_result返回给Framework
4.3. 录像¶
录像是Android Camera最基本的功能之一。对于HAL来说,行为和preview一样,HAL只要负责把YUV数据返回即可。录制的视频编码和保存是在上层完成的。
上层行为:
1)APP通过setPreviewDisplay将预览surface设置给CamerService。
2)APP通过setVideoSource(CAMER)告知创建CameraSource,将camera作为producer。内部将自动创建BufferQueue,连接CameraService作为producer,CameraSource作为consumer。
3)CamerService产生2路stream,1路preview,另1路为recording。
4)media codec从BufferQueue获取数据进行编码
5. camera_configuration.xml 配置文件介绍¶
camera_configuration.xml是Camera HAL的配置文件,可以在里面添加删减支持的Camera信息,Camera HAL在初始化时会来读取这个配置文件,然后根据配置的Camera信息来配置对应的Pipeline。不同Camera对应的属性值会有不同,需要根据实际进行配置。
camera_configuration.xml配置文件在设备端路径为:/vendor/etc/camera/camera_configuration.xml
如Figure 10所示,整个配置文件主要由几个几点组成。根节点是CameraSettings,CameraInfo节点是配置当前设备上要使用的Camera信息。Common节点配置一些功能项,目前只有IQServer一项。Settings节点可以由很多个,表示支持的Camera列表。接下来一一介绍。
5.1. CameraInfo节点¶
CameraInfo节点表示当前设备接入的Camera信息。实际接入几个Camera,这里就填写几个Sensor节点。字段解释:
name:Camera名称,注意需要跟下面Settings节点的name匹配,否则将会找不到Metadata信息
cameraId:即index,从0开始依次加1递增。当前默认支持两个sensor,0表示Back Camera,1表示Front Camera
chmap:根据实际接在哪个sensor pad填写,计算方法为 chmap = 2^(sensor pad),比如接在sensor pad0,那么chmap就是2的0次方1,接在sensor pad1,那么chmap就是2的1次方2,一次类推
sensorType:camera 类型,分为SENSOR_TYPE_SOC/SENSOR_TYPE_RAW/SENSOR_TYPE_USB三种,根据实际填写即可
frame.initialSkip:由于AE收敛过程导致的颜色异常,可以通过这个值来Skip掉前面未收敛前的帧数
cus3a.enable: 是否使用cus3a
5.2. Common节点¶
目前只有一项配置,IQServer.open,表示是否打开IQServer
5.3. Settings节点¶
Settings节点是个很重要的节点,里面包含了name和CameraStaticMetadata。
CameraStaticMetadata是描述Camera的静态能力属性,hal初始化时,上层会通过get_camera_info来获取这些能力属性值。
5.3.1. CameraStaticMetadata介绍¶
更详细的字段定义请查看官网:https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics
或者AOSP:system/media/camera/docs/docs.html
以下为部分重要节点介绍:
Settings | Values | Descriptions |
---|---|---|
Control.aeAvailableAntibandingModes | [AUTO,50HZ,60HZ,OFF] | SOC:AUTO RAW:50HZ,60HZ //以排在首位作为初始化配置 |
Control.aeAvailableModes | [OFF,ON,ON_AUTO_FLASH,ON_ALWAYS_FLASH] | OFF:不支持FLASH时设置为OFF ON/ON_AUTO_FLASH/ON_ALWAYS_FLASH:支持flash时的选项 |
Control.aeAvailableTargetFpsRanges | int32 x 2 x n | 这个设置项有多个限制需要注意: 1)录像必需要有一组恒定帧率,加入帧率为x,那就要包含(x,x) 2)录像帧率必须至少一组大于24帧 3)第一组必须Min<=15.所以第一组一般为(15,x) 4)各组帧率需要按升序排列 升序的具体意义为,假设有定义有两组帧率:(min1,max1),(min2,max2),则max2>=max1,max2==max1时,还需要满足min1 <= min2. 注:min fps可用于控制拍照预览时的最小帧率,也就是控制最大曝光时间,可以根据需要进行调整,但是设置多小会影响拍照速度,但在较暗的情况下能获得更好的预览效果。在设置template时,rk是选择最大的一组,也就是最后一组,从配置来看,都是固定分辨率,比如[30,30],[60,60] |
Control.afAvailableModes | [AUTO,CONTINUOUS_VIDEO,CONTINUOUTS_PICTURE,OFF] | OFF:Camera不支持AF AUTO/CONTINUOUS_VIDEO/CONTINUOUTS_PICTURE/OFF: Camera具有支持AF功能 注:在构造template时,rk的做法是对于STILL_CAPTURE/ZERO_SHUTTER_LAG/PREVIEW,如果支持CONTINUOUTS_PICTURE,则为CONTINUOUS_PICTURE。对于VIDEO_RECORD/VIDEO_SNAPSHOT,如果支持CONTINUOUS_VIDEO,则为CONTINUOUS_VIDEO。对于INTENT_MANUAL,如果支持MODE_OFF,则为MODE_OFF。其他情况下为AUTO。CONTINUOUS_VIDEO表示慢对焦,CONTINUOUS_PICTURE表示快对焦 |
Control.awbAvailableModes | [AUTO,INCANDESCENT(白炽灯),FLUORESCENT(荧光灯),DAYLIGHT(白天),CLOUDY_DAYLIGHT] | SOC: AUTO RAW:AUTO,INCANDESCENT(白炽灯),FLUORESCENT(荧光灯),DAYLIGHT(白天),CLOUDY_DAYLIGHT |
Jpeg.maxSize | int | 计算公式如下: 最大分辨率为:scaler.availableStreamConfigurations中BLOB项最大的分辨 Jpeg.maxSize >= max_blob_w * max_blob_h * 3 / 2 |
Lens.info.availableApertures | todo | 可选光圈 |
lens.info.availableFocalLengths | todo | 可选焦长 |
lens.info.miniumFocusDistance | 0和非0 | 0:不支持AF 非0:支持AF时,需要根据模组规格数来设置 |
scaler.availableMaxDigitalZoom | 4 | 最大缩放倍数,按照以往经验,设置为4倍是比较稳妥的。如果影响帧率,可适当降低缩放倍数 |
scaler.availableStreamConfigurations | format,res,output/input | HAL层支持的分辨率列表,有如下限制: 1)需要按照分辨率依次降序排列 2)为了满足CTS要求,需要包含352x288,320x240,176x144配置项 3) 列表中需要支持BLOB,YCbCr_420_888,IMPLEMENTATION_DEFINED三种格式输出配置,三种格式中支持的分辨率要相同,例如 BLOB,1920x1080,OUTPUT, BLOB,640x480,OUTPUT, BLOB,352x288,OUTPUT, BLOB,320x240,OUTPUT, BLOB,176x144,OUTPUT, YCbCr_420_888,1920x1080,OUTPUT, YCbCr_420_888,640x480,OUTPUT, YCbCr_420_888,352x288,OUTPUT, YCbCr_420_888,320x240,OUTPUT, YCbCr_420_888,176x144,OUTPUT, IMPLEMENTATION_DEFINED,1920x1080,OUTPUT, IMPLEMENTATION_DEFINED,640x480,OUTPUT, IMPLEMENTATION_DEFINED,352x288,OUTPUT, IMPLEMENTATION_DEFINED,320x240,OUTPUT,/br> IMPLEMENTATION_DEFINED,176x144,OUTPUT |
scaler.availableMinFrameDurations | format,res,duration | 配置scaler.availableStreamConfigurations中各个分辨率下最小帧间隔(即最大帧率),需要满足以下条件: 需要包含scaler.availableStreamConfigurations中定义的所有格式,分辨率,如: BLOB,1920x1080,33333333, BLOB,640x480,33333333, BLOB,352x288,33333333, BLOB,320x240,33333333, BLOB,176x144,33333333, YCbCr_420_888,1920x1080,33333333, YCbCr_420_888,640x480,33333333, YCbCr_420_888,352x288,33333333, YCbCr_420_888,320x240,33333333, YCbCr_420_888,176x144,33333333, IMPLEMENTATION_DEFINED,1920x1080,33333333, IMPLEMENTATION_DEFINED,640x480,33333333, IMPLEMENTATION_DEFINED,352x288,33333333, IMPLEMENTATION_DEFINED,320x240,33333333, IMPLEMENTATION_DEFINED,176x144,33333333" |
scaler.availableStallDurations | format,res,duration | 配置scaler.availableStreamConfigurations中BLOB格式各个分辨率的允许的最大间隔时长,可直接复制scaler.availableMinFrameDuraitions中BLOB选项,也可以设置大于scaler.availableMinFrameDurations中的值,只需要满足小于sensor.info.maxFrameDuration中配置的最大间隔即可。设置大一点有利于CTS拍照相关测试项的稳定性。如: BLOB,1920x1080,33333333, BLOB,640x480,33333333, BLOB,352x288,33333333, BLOB,320x240,33333333, BLOB,176x144,33333333" |
sensor.info.activeArraySize | 0,0,1920,1080 | 设置成sensor驱动输出的最大分辨率 |
sensor.info.physicalSize | todo | sensor的物理尺寸,可从模组规格书中获取,与FOV计算相关 |
sensor.info.pixelArraySize | 1920x1080 | 设置成sensor驱动输出的最大分辨率 |
sensor.orientation | 0,90,180,270 | 模组安装方向,可设置0,90,180,270。客户根据摄像头安装方向进行调整,需要通过CTS verifier相关项的测试 |
flash.info.available | TRUE,FALSE | FALSE:不支持闪光灯 TRUE: 支持闪光灯 |
sensorType | SENSOR_TYPE_YUV SENSOR_TYPE_RAW SENSOR_TYPE_USB |
SENSOR_TYPE_SOC:自带ISP的模组,可输出YUV格式,不需要经过主芯片的ISP。走MI流程。 SENSOR_TYPE_RAW:输出raw数据,需要经过主芯片的ISP。走MI流程。 SENSOR_TYPE_USB:usbcam,不需要经过主芯片的ISP,会走V4L2,不走MI流程,所以跟SENSOR_TYPE_SOC区分开来 |
frame.initialSkip | int | 打开camera应用时,预览前几帧3A未收敛,可能在不同场景下存在前几帧颜色不对,可以设置过滤前面几帧来避免这个现象。此外,由于CTS很多帧率相关项是以发送固定的request数量,然后得到相应的帧结果时间来统计的,前面几个request结果返回可能会比较慢,也可以通过设置合适的过滤帧数来避免这个问题。 |
info.supportedHardwareLevel | byte | 支持的硬件等级,分为FULL 和LIMITED mode,FULL mode需要做到per-frame-control,而我们ISP目前最快也要下一帧才能生效,且3A至少要3帧才能生效。所以我们只能选择LIMITED mode |
6. 如何适配一个新的Camera¶
-
配置对应sensor的驱动
1)sensor driver源码路径在vendor/sigmastar/alkaid/sdk/driver/SensorDriver/drv/src下面,编译完成之后,需要将对应的ko拷贝到aosp/device/sigmastar/pioneer5/kernel下面
2)sensor driver编译方式:
source build/envsetup.sh lunch xxxx cd vendor/sigmastar/alkaid/sdk/driver/SensorDriver make
生成的ko在vendor/sigmastar/alkaid/sdk/driver/SensorDriver/drv/src下
-
配置dts
dts配置请参考Linux上的sensor配置
修改dts之后需要重新编译kernel
./sstar_make.sh -k
-
配置camera_configuration.xml
1)在CameraInfo节点中添加对应新的sensor的
节点 2)配置一个新的Settings节点。
3)camera_configuration.xml在源码树的位置在/device/sigmastar/pioneer5/product/camera_configuration.xml
-
修改/device/sigmastar/pioneer5/modpram.json里面的E_MI_MODULE_ID_SNR节点,如下:
Figure 11: modparam节点配置 每一个配置项都是一个数组,数组同一个index对应的是同一个camera配置。比如上图IMX307_HDR对应的chmap是1,mclk是36M,lane_num是4,hdr_lane_num是4,IMX415_HDR对应的chmap是4,mclk用default值,lane_num是4。sensor_name可以从sensor driver里面SENSOR_DRV_ENTRY_IMPL_BEGIN_EX这个宏定义的参数获得
-
./sstar_make.sh -a -r
重新打包升级
7. IQ调试¶
由于Android不允许Camera HAL联网,所以iqserver无法在Camera HAL中打开。目前的实现方式是把iqserver放在单独一个可执行文件来单独执行。
代码路径:vendor/sigmastar/hardware/camera/sstar_iqserver
可执行文件在板端的位置: /vendor/bin/sstar_iqserver
使用方式:
-
板子联网,确认和iqtool所在电脑互通
-
打开iqserver
cd /vendor/bin ./sstar_iqserver & 或者在camera_configuration.xml中把IQServer.open设置为TRUE,打开camera即可自动打开iqserver
-
iq tool连接
8. CUS3A 使用¶
cus3a的代码在vendor/sigmastar/hardware/camera/cus3a ,主要是参考alkaid下isp_cus3a_if.c写的。实现方式如下:
9. DEBUG相关¶
-
判断进程是否都正常启动
Figure 13: camera相关进程 -
dumpsys media.camera
Figure 14: dumpsys -
logcat中搜索带有“CAM_" 的log
10. Misc¶
主要介绍Camera相关的路径及配置在AOSP的对应位置
-
device配置:device/sigmastar/pioneer5/pioneer5_sdp/device.mk
Figure 15: Device配置 -
camera_configuration.xml在aosp位置: device/sigmastar/pioneer5/product/camera_configuration.xml
-
default iqfile以及iqbin在aosp位置: device/sigmastar/pioneer5/sdk下
-
HAL代码: vendor/sigmastar/hardware/camera