最近因为工作需求,又要重新接触Android Camera1的API,详细整理了下相关知识点,这次没有记录到的知识点,后面会陆续补充,欢迎在公众号留言交流或者加我微信好友交流
Camera API简介
Camera API1: Android 4.4 以及更低版本设备上的应用级相机框架,通过 android.hardware.Camera 类提供功能接口;
Camera API2: Android 5.0 以及更高版本设备上的应用级相机框架,通过 android.hardware.camera2 包提供;
虽然Android5.0开始弃用Camera API1,但是各个手机厂商对Camera API2的支持是一个渐进式的过程,所以淘汰周期是比较长的,在很多高版本中使用Camera API1的情况也是很常见的
相对于Camera2的API,Camera1使用流程上没有那么多的状态回调和更多精细控制的接口,导致整体使用起来是非常简单的
基本使用流程
一、注册权限
最基础的是需要注册Camera的权限,如果APP中有录像,保存照片和视频等需求,还需要加上录音,存储读写等权限。Android6.0以后除了在Manifest清单中注册,还需要动态申请它
<uses-permission android:name="android.permission.CAMERA"/>
如果不希望设备没有相机相关硬件的用户在Google play等应用商店看到你的APP,可以添加
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
二、获取摄像头信息
现在市场上的手机摄像头是越来越多,在使用前我们首先需要获取设备支持多少摄像头,每个Camera id是前置还是后置,或者是广角,微距镜头等。当然摄像头虽然多,但是如果手机厂商不向第三方开放的话,第三方开发者获取到的也就是基本的摄像头信息,比如只有前后置,或者只有后置摄像头等,获取Android设备中摄像头个数,通过调用接口:
/**
* @return total number of accessible camera devices, or 0 if there are no
* cameras or an error was encountered enumerating them.
* If returns N, the valid id is 0 to N-1.
*/
public native static int getNumberOfCameras();
通过摄像头id,可以查询到该摄像头的3个属性:
public static class CameraInfo {
// 判断前后置
public int facing;
// 拍照后的图像需要顺时针旋转多少度才是自然方向,通常后置90,前置270
public int orientation;
// 是否可以在拍照时禁止拍照声音,
// 这个是因为一些国家的法律要求拍照必须带声音
public boolean canDisableShutterSound;
};
比如我们需要使用后置摄像头
int cameraNum = Camera.getNumberOfCameras();
int cameraId = -1;
Camera.CameraInfo info = new Camera.CameraInfo();
for (int i = 0; i < cameraNum; i++) {
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
cameraId = i;
break;
}
}
三、打开相机
直接调用open接口即可:
camera = Camera.open(cameraId);
四、启动预览
通过调用startPreview接口即可启动预览,不过在这个接口之前,我们需要额外配置一些东西,比如预览size,拍照size,显示方向,预览数据输出口等。
如果需要预览数据在屏幕中显示,我们可以利用SurfaceView,TextureView或者GLSurfaceView等控件,Camera类提供了相应接口来配置
// SurfaceView
camera.setPreviewDisplay(surfaceHolder);
// TextureView & GLSurfaceView
camera.setPreviewTexture(surfaceTexture);
考虑到Sensor出的预览数据并不一定就是自然方向(人头向上)和横竖屏的影响,要想正确的显示预览,还需要设置预览在自然方向进行显示所需要的顺时针旋转角度:
displayOrientation = CameraUtils.getCameraDisplayOrientation(this, cameraId);
camera.setDisplayOrientation(displayOrientation);
获取这个旋转角度的模板代码为:
注:
1. 这个角度只是会影响预览的显示方向,不影响在onPreviewFrame接口中的byte array,Jpeg图像和录制的视频数据的方向
2. 该接口不能在启动预览后进行调用
配置预览,拍照size等都需要通过Parameter来设置,根据自己的业务需求,从支持列表中选择合适的尺寸并设置即可
parameters = camera.getParameters();
parameters.getSupportedPreviewSizes();
parameters.getSupportedPictureSizes();
parameters.setPreviewSize(previewW, previewH);
parameters.setPictureSize(pictureW, pictureH);
camera.setParameters(parameters);
启动预览:
camera.startPreview();
五、停止预览并关闭Camera
不再使用相机的时候一定要及时释放相机资源,否则将可能会导致其它APP无法使用Camera
camera.stopPreview();
camera.release();
拍照
拍照直接调用takePicture接口即可:
camera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
Log.d(TAG, "onShutter: ");
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// raw data
Log.d(TAG, "onPictureTaken: raw");
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 有些机型上非zsl拍照会停预览,所以拍完后需要重新启动预览
camera.startPreview();
// 保存或者直接显示
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
pictureImageView.setImageBitmap(bitmap);
pictureImageView.setVisibility(View.VISIBLE);
}
});
如果想要在PictureCallback回调中拿到正确方向的jpeg数据,还需要考虑sensor出图的方向和手机屏幕旋转方向
最后
关于Camera1中对焦和测光的知识,下周再水
,也可以看提供的Demo,手动对焦,CAF切换等逻辑已经实现
Demo地址:
https://github.com/sifutang/Camera1Demo.git
加我好友在公众号内发送“技术交流”就可以啦,加好友的时候也请备注下“技术交流”