上篇在做相机桌面的时候用的是5.0之前的Camera,但Camera在5.0之后已经被淘汰了,官方也是推荐使用Camera2,这两天也分别尝试了下Camera和Camera2的使用。
因为新的API换了加购,让开发者用起来更麻烦了。虽然按照官网的说法可能逻辑更加清晰,理解起来也更容易懂了,但是个人使用后的感觉还是觉得太麻烦了。如果仅仅只是拍个照预览下什么的还是乖乖使用Camera吧,用Camera2实在太麻烦。
android6.0之后要动态请求权限,相机使用需要相机权限,拍照保存图片需要文件读写权限。Android6.0之后权限请求工具类
Camera使用
1、打开相机
可传入cameraId来打开前置或后置摄像头
Camera.open()
2、设置预览并取景
用SurfaceView显示预览,由于相机方向是横屏的,需要旋转90度
try {
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
3、拍照
takePicture第三个参数回调方法是拍照传回来的二进制数据,可以进行图片保存,拍完照之后需要再次打开预览,不然就定格在拍照的画面
camera.takePicture(new Camera.ShutterCallback() {
@Override
public void onShutter() {
//按下快门
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
}, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
savePicture(data);
startPreview(camera, surfaceHolder);
}
});
4、切换摄像头
遍历所有摄像头,前置后置切换,切换前停止预览,再打开相应摄像头
/**
* 切换摄像头
*/
private void switchCamera() {
int count = Camera.getNumberOfCameras();
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
//后置变前置
stopPreview();
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
openCamera();
break;
} else if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
//前置变后置
stopPreview();
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
openCamera();
break;
}
}
}
Camera2使用
Camera2用管道的概念将安卓设备和摄像头之间连通,应用向设备发送请求,设备返回结果,再由应用处理结果。
1、CameraManager
CameraManager是所有CameraDevice的管理者。
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
2、打开摄像头
//第一个参数指定哪个摄像头,第二个参数打开摄像头的状态回调,第三个参数是运行在哪个线程(null是当前线程)
cameraManager.openCamera(String.valueOf(currentCameraId), stateCallback, handler);
打开相机的回调
//打开相机回调
private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
Log.i(TAG, "onOpened");
//相机开启,打开预览
cameraDevice = camera;
startPreview();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
Log.i(TAG, "onDisconnected");
//相机关闭
camera.close();
cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
Log.i(TAG, "onError");
//相机报错
camera.close();
cameraDevice = null;
finish();
}
};
3、预览
相机打开后创建CameraBuilder,再创建CameraCaptireSession,最后调用CameraCaptureSession#setRepeatingRequest预览
/**
* 开始预览
*/
private void startPreview() {
try {
previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//设置预览数据输出界面
previewBuilder.addTarget(surfaceHolder.getSurface());
//创建相机捕获会话,
//第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession状态回调接口,第三个参数是在哪个线程(null是当前线程)
cameraDevice.createCaptureSession(Arrays.asList(surfaceHolder.getSurface(), imageReader.getSurface()), sessionStateCallback, handler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
CameraCaptureSession会话
//创建session回调
private CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
cameraCaptureSession = session;
//自动对焦
previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
cameraCaptureSession.setRepeatingRequest(previewBuilder.build(), null, handler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
session.close();
cameraCaptureSession = null;
cameraDevice.close();
cameraDevice = null;
}
};
4、拍照
/**
* 拍照
*/
private void takePhoto() {
try {
captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(imageReader.getSurface());
//自动对焦
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
cameraCaptureSession.stopRepeating();
//拍照
cameraCaptureSession.capture(captureBuilder.build(), captureCallback, handler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
拍完照后回调,重新打开预览
//拍完照回调
private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
super.onCaptureProgressed(session, request, partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
try {
//自动对焦
captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
//重新打开预览
session.setRepeatingRequest(previewBuilder.build(), null, handler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
cameraCaptureSession.close();
cameraCaptureSession = null;
cameraDevice.close();
cameraDevice = null;
}
};
拍照处理器
/**
* 初始化拍照处理器
*/
private void initImageReader() {
imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), ImageFormat.JPEG, 1);
//监听ImageReader时间,有图像数据可用时回调,参数就是帧数据
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
//将帧数据转换成字节数组
ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
byte[] data = new byte[byteBuffer.remaining()];
byteBuffer.get(data);
//保存照片
savePicture(data);
image.close();
}
}, handler);
}
5、切换摄像头
遍历所有cameraId,前置后置互相切换,切换前先关闭CameraDevice,再打开对应摄像头
/**
* 切换摄像头
*/
private void switchCamera() {
try {
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size maxSize = getMaxSize(map.getOutputSizes(SurfaceHolder.class));
if (currentCameraId == CameraCharacteristics.LENS_FACING_BACK && characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
//前置转后置
previewSize = maxSize;
currentCameraId = CameraCharacteristics.LENS_FACING_FRONT;
cameraDevice.close();
openCamera();
break;
} else if (currentCameraId == CameraCharacteristics.LENS_FACING_FRONT && characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {
//后置转前置
previewSize = maxSize;
currentCameraId = CameraCharacteristics.LENS_FACING_BACK;
cameraDevice.close();
openCamera();
break;
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />