最近公司开发的一款型号客户要求相机拍照分辨率最大支持到3600万像素,相机模组硬件支持的最大分辨率为400万,驱动工程师通过插值算法实现支持最大3600万像素。APP是采用高通SDM450 9.0平台的SnapdragonCamera应用实现,前期实现正常没问题。
后来因为要实现视频水印和分段录像功能更换camera应用框架后,新框架采用Mediacodec+OpenGL方式实现,获取的camera对象方式如下:
import android.hardware.Camera;mCamera = Camera.open(mCameraId);
final Camera.Parameters params = mCamera.getParameters();
List<Size> supported = params.getSupportedPictureSizes();
通过此种方式获取系统支持的照片尺寸发现最高只能支持到400万,插值的方式支持的方式这里获取不到了。原来SnapdragonCamera获取camera对象是通过CameraProxy接口封装后获取,这是他们的差异。
谷歌从Android4.4版本之后的camera开始引入了CameraProxy和4.0版本的设计差距还是很大的,4.0版本以前的camera在是camera 主activity中直接调用camera hal层的的接口(如android.hardware.camera.open(), android.hardware.camera.setPreviewDisplay(),android.hardware.camera..startPreview()等)与camera device通信。Android4.4版本camera app对camera device的访问又封装了一次,对camera device的访问必须经过camera manager接口,camera manager接口定义了camera基本操作,这样便于控制和管理camera device。此次修改APP架构没有采用CameraProxy类,直接通过Android 4.0版本以前的方式来直接调用 camera hal层的接口。
这样的话需要分析引入新的封装机制后与直接调用hal层打开camera的区别之处。首先来了解下camera相关的接口。
1.CameraManager接口:提供的访问camera设备基本的操作,实现类必须调用CameraManager.cameraOpen获取CameraManager.CameraProxy接口对象来控制camera,实现CameraManager接口的类必须拥有一个独立于主线程的线程来实现对camera的操作,CameraManager接口也包装回调函数
2.CameraProxy接口,封装在CameraManager接口之内,接收对camera操作请求,发送消息到camer handle。所有对camera的操作都经由改接口,进行异步处理
3. AndroidCameraManagerImpl类,该类实现了CameraManager接口,与camera framework层接口直接通信,起到camera app 与camera framework对话中介的作用。
4.AndroidCameraProxyImpl类,AndroidCameraManagerImpl内部类,实现CameraManager.CameraProxy接口,CameraProxy已经介绍过了就是控制对camera的访问,AndroidCameraProxyImpl类实现了具体的操作。
5. CameraManagerFactory类,这个类的实现很简单,看到Factory,会想到软件设计中的工厂模式,这里就是封装了创建CameraManager对象的细节
6. CameraHolder类,看名字就可以看出这个类的基本功能了,就用来保存camera实力对象的,用在不同的module之间快速切换。
以上是Android 4.4之后camera app对camera framework层接口封装的介绍。下面我们来看camera初始化过程。时序图如下;
通过跟踪代码发现封装CameraProxy代理最终打开camera获取camera对象的方式与上面代码实现方式的区别之处:
最终打开camera是通过cameraholder类调用AndroidCameraManagerImpl.java中的 public CameraManager.CameraProxy cameraOpen(
Handler handler, int cameraId, CameraOpenErrorCallback callback)方式打开camera:
case OPEN_CAMERA:
try {
Method openMethod = Class.forName("android.hardware.Camera").getMethod( "openLegacy", int.class, int.class);
mCamera = (android.hardware.Camera) openMethod.invoke( null, msg.arg1, CAMERA_HAL_API_VERSION_1_0); }
catch (Exception e) {
/* Retry with open if openLegacy doesn't exist/fails */ Log.v(TAG, "openLegacy failed due to " + e.getMessage() + ", using open instead");
mCamera = android.hardware.Camera.open(msg.arg1); }
尝试采用此种方式获取camera对象后,重新通过以下代码打印log,发现底层插值算法支持的高分辨率最大到3600万像素都可以打印出来。
List<Size> supported = params.getSupportedPictureSizes();
for(Size size:supported){
Log.i(TAG, "Camera support size.width="+size.width+",size.height="+size.height);
}
至此就解决了新框架无法获取插值算法支持的分辨率的问题。