Android: Camera2 API support problem

前言

开发相机时看着Camera一直是删除线显示deprecated很不爽,趁着有空把API level从19升到21,准备抛弃Camera迎接Camera2,才发现手上这个出厂就是Android 5.1 API 22的华为M2对Camera2的支持还不够。那你为啥还要硬上API 22呢...

测试发现不仅仅是华为M2,还有一些出厂就是API 21以上的设备对Camera2 API的支持都相当差。

对Camera2的支持

我个人觉得,虽然好多厂商近两年推出的Android设备都是Android 5.0及以上(API 21),但其中也有噱头的成分。API 21要求实现Camera2 API,虽然厂商实现了这些API,但实际上可设置的参数比Camera少,甚至性能都比Camera差。Camera2留给厂商一条退路,可以指明设备对Camera2的支持程度,结果好多不乏主力设备机型,都是最低支持程度。

通过

CameraCharacteristics characteristics
                        = manager.getCameraCharacteristics(cameraId);
characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);

可以得到对Camera2的支持程度,具体描述在INFO_SUPPORTED_HARDWARE_LEVEL中有介绍。得到的int值在CameraMetadata中定义,其中FULL值为1,LEGACY值为2,LIMITED值为0,其支持程度为FULL > LIMITED > LEGACY。

摘抄CameraCharacteristics中的介绍:

A FULL device will support below capabilities:

  • BURST_CAPTURE capability (android.request.availableCapabilities contains BURST_CAPTURE)
  • Per frame control (android.sync.maxLatency == PER_FRAME_CONTROL)
  • Manual sensor control (android.request.availableCapabilities contains MANUAL_SENSOR)
  • Manual post-processing control (android.request.availableCapabilities contains MANUAL_POST_PROCESSING)
  • At least 3 processed (but not stalling) format output streams (android.request.maxNumOutputProc >= 3)
  • The required stream configurations defined in android.scaler.availableStreamConfigurations
  • The required exposure time range defined in android.sensor.info.exposureTimeRange
  • The required maxFrameDuration defined in android.sensor.info.maxFrameDuration

A LIMITED device may have some or none of the above characteristics. To find out more refer to android.request.availableCapabilities.

Some features are not part of any particular hardware level or capability and must be queried separately. These include:

  • Calibrated timestamps (android.sensor.info.timestampSource == REALTIME)
  • Precision lens control (android.lens.info.focusDistanceCalibration == CALIBRATED)
  • Face detection (android.statistics.info.availableFaceDetectModes)
  • Optical or electrical image stabilization (android.lens.info.availableOpticalStabilization, android.control.availableVideoStabilizationModes)

A LEGACY device does not support per-frame control, manual sensor control, manual post-processing, arbitrary cropping regions, and has relaxed performance constraints.

这里不负责任地说,如果你的设备没支持到FULL,还是老老实实用回旧Camera API吧。

HUAWEI M2

华为M2在2015年7月上市,搭载Android 5.1,CPU为麒麟930,内存3G,屏幕分辨率1920x1200,摄像头800万像素。应该算作配置还不错了,可惜Camera2的支持是LEGACY。

相机预览格式

旧Camera

Camera API通过Camera.PreviewCallbackonPreviewFrame()方法获得预览帧,一般来说格式是NV21,也没有太多选择的余地。

新Camera2

通过

StreamConfigurationMap map = characteristics.get(
                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
map.getOutputFormats()

可以得到支持的格式,得到的int值在ImageFormat中定义。

华为M2支持的是JPEG,YV12和YUV_420_888。而比较期待的RAW_SENSOR原始格式没有支持。

预览分辨率

旧Camera

通过

Camera.Parameters mParameters = camera.getParameters();
mParameters.getSupportedPreviewSizes();

得到支持的预览分辨率大小,华为M2支持的是

640x480
1280x720
1280x960
1440x1080
1920x1080
208x144
176x144
352x288
320x240
960x544
960x720
720x720
640x480

虽然最大预览分辨率没有超过屏幕分辨率1920x1200,但达到1080P已经很满足了。

新Camera2

一般来说预览帧格式应当是YUV格式,Camera2的说明中也提到了这一点,格式应当设置为YUV_420_888。

通过

map.getOutputSizes(ImageFormat.YUV_420_888);

得到相机支持的YUV_420_888输出分辨率。对于华为M2来说,其支持的YV12和YUV_420_888支持的分辨率都是

1440x1080
1280x960
1280x720
960x720
960x544
720x720
640x480
352x288
320x240
208x144
176x144

看到最大分辨率支持已经从1920x1080降到1440x1080了。而1440x1080这个神奇的分辨率我也不知道是怎么来的,在Stackoverflow上(见参考)也有人有同样的遭遇,他的Samsung Galaxy Tab S在使用新Camera2时最大分辨率也是1440x1080...不过他更悲剧,用旧Camera支持的分辨率最大是2560x2560。所以我比较怀疑是不是在厂商根本没有用心做Camera2时,所有设备支持的分辨率都是一样的...

获取预览帧

这里指将预览帧输出到屏幕,同时获取预览帧数据。

旧Camera

Camera的方法一般是通过设置camera.setPreviewDisplay()将预览帧输出到SurfaceView,并通过接口Camera.PreviewCallback中的onPreviewFrame()获取预览帧数据。

对于华为M2,在1920x1080分辨率下也能保持相机支持的最高30fps的输出。

新Camera2

Camera2对这部分改动很大。通过CameraCaptureSession.setRepeatingRequest()开始预览,而传入的request则由PreviewRequestBuilder创建

mPreviewRequestBuilder.addTarget(surface);

表示将预览输出到surface,一般来说就是屏幕了。华为M2对这个是支持的,目测也应该是达到了30fps。

获取预览帧则由

mPreviewRequestBuilder.addTarget(mImageReader.getSurface());

得到,就是将预览帧同时发送给屏幕surface和ImageReader,其中发送给ImageReader的预览帧分辨率由ImageReader根据支持的分辨率指定。

然后问题就来了,当设置ImageReader为1440x1080时,运行APP会发现屏幕输出卡顿,且ImageReader获得预览帧速度明显不够30fps;选择不输出屏幕,只输出ImageReader时,获得预览帧速度也明显不够30fps。(测试ImageReader是通过ImageReader.OnImageAvailableListener接口,在另一线程中处理获取到的Image,且获取到后Image后立即释放。)

关于输出Target的个数和分辨率的支持,在createCaptureSession中有详细介绍,而对于我的两次实验,都是满足要求的。

关于支持Camera2的设备

学习怎么用Camera2 API都是通过Google的googlesamples/android-Camera2Basic这里例子学的吧...这个例子比较简单,不太容易出现问题,但在“Issues”里还有有些设备已经出现了兼容性问题。

另外还有个例子pinguo-yuyidong/Camera2,他用了比较多的Camera2 API新特性,在Nexus 5上运行成功,但"Issues"中就有几例设备不支持的情况了。

所以...还是Google亲儿子好。

小结

就像最开始说的那样,如果你的设备没支持到FULL,还是老老实实用回旧Camera API吧。虽然API 21两年前就推出,但各大厂商还是没有太多实现Camera2 FULL支持的意思。

参考