第1章:Camera2预览流程——从零到一看到画面
各位同学,今天我们来聊聊Camera2预览流程。说实话,我刚接触Camera2时也被它那套复杂的回调机制搞得头大。但别怕,咱们一步步拆解,你会发现其实就那么回事。
Camera2的预览流程,说白了就是五个步骤:
- 创建CameraManager
- 打开CameraDevice
- 创建CaptureSession
- 设置预览Request
- 处理预览回调
嗯,这五步走完,你就能在手机屏幕上看到摄像头画面了。我当年第一次跑通这个流程时,盯着屏幕上的自己愣了好几秒——那种成就感,真的爽。
1.1 创建CameraManager
第一步,拿到CameraManager。这玩意儿是系统服务,专门管摄像头设备的。怎么拿?代码很简单:
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
就这一行。但有个坑——别忘了检查权限。我刚开始做项目时,忘了加CAMERA权限,结果getCameraIdList()直接抛异常,排查了半天才发现。嗯,血的教训。
1.2 打开CameraDevice
拿到CameraManager后,下一步就是打开摄像头。这里要用到openCamera()方法,它是个异步操作。什么意思?就是你不能指望它立刻返回,得等回调。
cameraManager.openCamera(cameraId, stateCallback, backgroundHandler);
三个参数:摄像头ID、状态回调、后台Handler。我个人习惯用CameraCharacteristics先查一下摄像头方向,再决定用前置还是后置。
回调里最关键的是onOpened()——摄像头打开成功后会触发这里。你想想看,如果摄像头被别的App占着,就会触发onError()。所以一定要做好异常处理。
1.3 创建CaptureSession
摄像头打开了,但还不能直接预览。你得先创建一个CaptureSession,说白了就是告诉系统:「我要开始拍照/录像了,给我分配资源吧」。
创建Session需要两个东西:
- 一个输出Surface列表——比如TextureView的Surface
- 一个Session状态回调——监听Session是否创建成功
cameraDevice.createCaptureSession(
Arrays.asList(surface),
sessionCallback,
backgroundHandler
);
这里有个细节:Surface可以不止一个。比如你要同时预览和拍照,那就传两个Surface进去。我在做双摄项目时,就传了三个Surface——预览、拍照、人脸检测,系统会帮你协调好。
1.4 设置预览Request
Session创建成功后,就可以设置预览请求了。这里用到了CaptureRequest.Builder。说白了,就是告诉摄像头:「我要什么样的画面」。
CaptureRequest.Builder previewBuilder =
cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewBuilder.addTarget(surface);
// 可以设置一些参数,比如自动对焦模式
previewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
CaptureRequest previewRequest = previewBuilder.build();
然后通过Session发送这个Request:
captureSession.setRepeatingRequest(previewRequest, previewCallback, backgroundHandler);
注意这里用的是setRepeatingRequest——它会持续不断地发送请求,形成连续的画面流。如果你只想拍一张照片,那就用capture()。
为什么会用setRepeatingRequest而不是capture?你想想看,预览需要的是实时画面流,不是单张照片。所以要用重复请求模式。
1.5 处理预览回调
最后一步,处理回调。Camera2的回调接口是CameraCaptureSession.CaptureCallback。里面有几个关键方法:
| 方法 | 触发时机 | 常用场景 |
|---|---|---|
| onCaptureStarted | 开始捕获时 | 显示快门动画 |
| onCaptureProgressed | 捕获进行中 | 更新进度条 |
| onCaptureCompleted | 捕获完成 | 获取帧数据 |
预览时,我们最常用的是onCaptureCompleted。每次帧数据返回后,系统会回调这个方法。你可以在这里获取曝光时间、ISO等元数据。
private CameraCaptureSession.CaptureCallback previewCallback =
new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
// 帧数据已就绪,可以更新UI或做其他处理
long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
// 我一般在这里做帧率统计
}
};
避坑指南
最后,分享几个我踩过的坑:
- SurfaceView vs TextureView:预览用TextureView更灵活,但性能上SurfaceView更好。我一般用TextureView,因为可以加动画效果。
- 关闭摄像头:记得在onPause()里关闭Session和Device。不关的话,下次打开会报错。
- 摄像头ID:别硬编码0或1。用CameraManager.getCameraIdList()动态获取,不同手机摄像头编号不一样。
好了,Camera2预览流程就讲到这里。这五步是Camera2开发的基础,后面的拍照、录像、HDR都是在这个框架上扩展的。你把这五步吃透了,后面就轻松了。
公众号:蓝海资料掘金营,微信deep3321