Android设备对新Camera2 API的支持问题:以华为M2为例
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.PreviewCallback
的onPreviewFrame()
方法获得预览帧,一般来说格式是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支持的意思。
参考
- android.hardware.camera2 | Android Developers
- StreamConfigurationMap | Android Developers
- CameraCharacteristics | Android Developers
- ImageFormat | Android Developers
- CameraDevice | Android Developers
- CameraMetadata | Android Developers
- googlesamples/android-Camera2Basic
- pinguo-yuyidong/Camera2: Android L Camera2 Demo
- Android Camera2 Output sizes - Stack Overflow
您好,看了您的这篇文章,对我非常有帮助,非常感谢您!想问下,我这边使用摄像头录制视频,是推荐使用Camera,还是Camera2呢?用户群体会很多,能给个建议么?谢谢!
肯定是camera2啦,camera已经被弃用了
作者,我想问下,Camera不是不支持曝光吗,只有Camera2才支持曝光,你是怎么实现的
楼主的华为手机可以运行Google的Camera2Basic吗?
我这边 华为 mate 9 点击拍照按钮就会有 CameraAccessException,无法使用
之前试了小米和三星的手机都没问题
非常感谢!都2018年了,翻到了这篇文章,看了下小米6还是legacy,还是老老实实用老API吧_(:з」∠)_
你好
你給的兩個範例連結是使用Camera2
googlesamples/android-Camera2Basic
和
pinguo-yuyidong/Camera2
他在AndroidManifest.xml有設定
<uses-feature android:name="android.hardware.camera" />
但為何在AndroidManifest.xml裡卻都不用設置android.hardware.camera2呢?
请问您知道,现在哪些手机相机有full权限,支持camera2 API 的曝光控制吗?
你好,抱歉这些天太忙了。现在手上没有新设备供测试了,所以不知道有哪些新手机达到full支持了。
抱歉没太听懂你的意思,AndroidManifest.xml对相机的声明只需要声明使用相机,即<uses-permission android:name="android.permission.CAMERA"/>。
android.hardware.camera2作为一个“普通”的Android API,是可以直接在代码中使用的,和Camera API一样,你可以看到相关源代码中,java文件头部有import android.hardware.camera2.*
你好
好比我在代碼中用了`import android.hardware.camera2.*
需要在AndroidManifest.xml內声明下面這行嗎?
<uses-feature android:name="android.hardware.camera2.legacy"/>
我發現宣告這行敘述,發布到Google Play上,所支援的手機是0。為何會如此?
怎么权限申请那句发不出来...在AndroidManifest.xml中声明camera权限就好了,详细请参考官方文档https://developer.android.com/reference/android/hardware/Camera.html。
另外手机能否支持Camera2是由API level确定的,Camera2的API要求为level 21。
更正~
你好
好比我在代碼中用了`import android.hardware.camera2.*
你剛剛的官方文档在AndroidManifest.xml声明的是
uses-permission android:name="android.permission.CAMERA"
uses-feature android:name="android.hardware.camera"
uses-feature android:name="android.hardware.camera.autofocus"
感覺沒有針對Camera2声明
需要在AndroidManifest.xml內声明下面這行嗎?
uses-feature android:name="android.hardware.camera2"
我發現宣告這行敘述,發布到Google Play上,所支援的手機是0。為何會如此?
不需要加入
uses-feature android:name="android.hardware.camera2"
事实上,也不能加入这行。
我猜你实际想表达的问题是,“我的代码用到了Camera2 API,那如何声明我的APP只适用于支持Camera2 API的设备呢?”。
如果是这个问题的话,AndroidManifest.xml中声明android.permission.CAMERA是表达“我需要用到相机这个硬件,没有相机的手机我的APP不支持”。
而在gradle中想必你设置的min-sdk-level是21或以上,就是“APP仅支持Level 21及以上,Android低于这个版本的不支持”。而level 21潜在就包含了“支持Camera2 API”(Camera2 在API 21引入,同时deprecated掉了Camera),其实这里就是声明了只有支持Camera2 API的手机才支持。
我也是这个问题的受害者, 就是加了
uses-feature android:name="android.hardware.camera2"
以後,哈哈 發現 發布到Google Play上,所支援的手機數是 0
这里可能是一个bug,但官方文档也没有解释太详细(其实主要原因是我没看到官方有示例代码这么写过),理论上你加上这一句是没问题的,不过鉴于API level 21和这个句是一个意思,所以尽量不加咯。
你說中我的心坎了~哈
我的意思就是我要說的。
感謝你的解說,已經差不多豁然開朗了
我懂你的意思。
其實在gradle設定level 21已經潜在就包含了“支持Camera2 API。
但是你說不能加入這行?
uses-feature android:name="android.hardware.camera2"
又到底是什麼原因呢?
即使是多此一舉也不行嗎?
你好
好比我在代碼中用了`import android.hardware.camera2.*
需要在AndroidManifest.xml內声明下面這行嗎?
<uses-feature android:name="android.hardware.camera2"/>
我發現宣告這行敘述,發布到Google Play上,所支援的手機是0。為何會如此?
在Android版本没有大面积的兼容升级的时候,不敢随便换API,本来也准备把项目的Camera换成Camera2的,看完各种issues就放弃了。。。。
就怕Google出到哪个API的时候把Camera直接remove掉了...不过这几年应该不用担心咯
真到5.0以下都被弃用的时候,估计7.0都已经算老版本了。
非常感谢,最近做相机遇到了各种兼容性的问题,您的文章对我很有帮助,谢谢。
^_^
非常感谢您的文案,最近正好在做相关的毕业设计,之前用Camera类实现相机的文案,我借鉴了很多,希望您不会介意。我的毕业设计主要是做一个很简单的适应于特定实验的照相App。因为通过您的文章得到了很多帮助,还是想给您打声招呼吧。
非常感谢您的文章,谢谢!~
很高兴对你有帮助 ^_^
PS.我还以为根本没人看呢...