这里介绍的是 CameraManager 、 CameraDevice 、 CaptureRequestSession 、CaptureRequest,先来看一下他们的关系:
CameraManager主要用于管理系统摄像头。
getCameraIdList
获取所有可用和Camera设备的cameraId(唯一标识)getCameraCharacteristics
得到Camera设备的详细数据,由 CameraCharacteristics类 存储openCamera
。CameraManager manager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
public String[] getCameraIdList()
public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
CameraDevice直接与系统摄像头相联系,相当一个抽象摄像头。
// 创建 CaptureRequestSession 对象
// 因为是异步操作,通过 CameraDevice.StateCallback 的 onOpened 方法返回。
public abstract void createCaptureSession(@NonNull List outputs,
@NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler)
public abstract CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType)
当相机被成功开启的时候会通过 CameraStateCallback.onOpened() 方法回调一个 CameraDevice 实例给你,否则的话会通过 CameraStateCallback.onError() 方法回调一个 CameraDevice 实例和一个错误码给你。onOpened() 和 onError() 其实都意味着相机已经被开启了,唯一的区别是 onError() 表示开启过程中出了问题,你必须把传递给你的 CameraDevice 关闭,而不是继续使用它
这个类用于提交创建好的CaptureRequest,要初始化CaptureRequestSession,必须提供初始化好的Surface。
createCaptureSession
这个方法要传入surface参数。CaptureRequestSession 发送 CaptureRequest 可以使用以下api:
// 发送一次性拍照的指令
public abstract int capture(@NonNull CaptureRequest request,
@Nullable CaptureCallback listener, @Nullable Handler handler)
// 发送重复预览的请求
public abstract int setRepeatingRequest(@NonNull CaptureRequest request,
@Nullable CaptureCallback listener, @Nullable Handler handler)
throws CameraAccessException;
CaptureRequestSession 里面有两个Callback:
capture(@NonNull CaptureRequest request,
@Nullable CaptureCallback listener, @Nullable Handler handler)
capture 方法用于发送一次性拍照的指令,其中 request 参数定义了捕获打个图像的所有参数,每个请求对应返回一个CaptureResult,然后通过CaptureRequest.builder的addTarget(Surface)方法附着对应的Surface上显示,其中的Surface就是创建会话时必须传入的参数,完成Surface的注入之后,通过CaptureCallback返回状态。
CaptureRequest可以理解为一个数据包,我们从camera获取单张图像后,通过CaptureRequest对其设置和输出。这里应用了Builder模式,CaptureReques.Builder是从CameraDevice中的createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)方法来创建的。
然后,我们使用构建器来设置变其他属性,比如addTarget(Surface)来设置CaptureRequest的接收者,还可以设置对焦模式、曝光模式,处理流水线,控制算法和输出缓冲区等。
CameraRequest.Builder 同时也负责生成 CameraRequest 对象。
上面 CaptureRequestSession
的预览方法setRepeatingRequest
和拍照方法 capture
都要传入一个 CaptureRequest 对象,来设置拍摄参数。
Surface 是一块用于填充图像数据的内存空间,例如你可以使用 SurfaceView 的 Surface 接收每一帧预览数据用于显示预览画面,也可以使用 ImageReader 的 Surface 接收 JPEG 或 YUV 数据。每一个 Surface 都可以有自己的尺寸和数据格式,你可以从 CameraCharacteristics 获取某一个数据格式支持的尺寸列表。
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
// 是否支持闪光灯
Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available == null ? false : available;
// 是否是前置摄像头
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
StreamConfigurationMap configurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (configurationMap == null) continue;
//获取图片输出的尺寸
configurationMap.getOutputSizes(ImageFormat.JPEG);
//获取预览画面输出的尺寸,因为我使用TextureView作为预览
configurationMap.getOutputSizes(SurfaceTexture.class)
}
我们可以通过 CameraCharacteristics 的属性来选取符合我们需要的Camera,得到其Id
CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
try {
manager.openCamera(mCameraId, mStateCallback, mMainHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
在StateCallback中,我们要实现三个方法,分别为CameraDevice被打开时触发的方法,失去连接时触发的方法,发生异常时触发的方法。在第一个方法中我们可以成功获取到CameraDevice对象,从而进行接下来的相关操作。
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
//打开成功,可以获取CameraDevice对象
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
//断开连接
}
@Override
public void onError(@NonNull CameraDevice camera, final int error) {
//发生异常
}
};
我们需要创建一个CameraCaptureSession的会话对象,通过CameraCaptureSession对象发送预览请求。
createCaptureSession 需要三个参数,第一个是相机预览数据输出的Surface的集合,第二个是回调,在这个回调中我们可以获取CameraCaptureSession对象,第三个参数是Handler,回调触发的线程。
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
mCallback, mCameraHandler)
StateCallback 需要实现onConfigured方法和onConfigFailed方法,会话开始处理捕获请求时触发onConfigured(CameraCaptureSession session)方法,反之配置失败时候触发onConfigureFailed(CameraCaptureSession session)方法。
mCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
mCaptureSession = session;
//发送预览请求
sendRepeatPreviewRequest();
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
}
sendRepeatPreviewRequest 函数通过builder模式给CaptureRequest设置好请求参数,再调用 CameraCaptureSession 的 setRepeatingRequest 方法预览。
private boolean sendRepeatPreviewRequest() {
try {
CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(mPreviewSurface);
builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
builder.setTag(RequestTag.Preview);
addBaselineCaptureKeysToRequest(builder);
mCaptureSession.setRepeatingRequest(builder.build(),
mFocusStateListener,
mCameraHandler);
return true;
} catch (CameraAccessException e) {
e.printStackTrace();
return false;
}
}
同样地获取 CameraCaptureSession,在 onConfigured 方法中调用 sendShootRequest 方法。
private boolean sendRepeatPreviewRequest() {
CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
builder.setTag(RequestTag.Capture);
addBaselineCaptureKeysToRequest(builder);
builder.set(CaptureRequest.JPEG_ORIENTATION,
CameraUtil.getJPEGOrientation(parameters.getOrientation(), mCameraCharacteristics));
builder.addTarget(mPreviewSurface);
builder.addTarget(mImageReader.getSurface());
mCaptureSession.capture(builder.build(),
mFocusStateListener,
mCameraHandler);
}