前言
在开始这个功能之前,我们需要一些知识需要知道——对Captrue各个模式的一个理解。
Capture
相机的所有操作和参数配置最终服务于捕获,在Camera2里面所有的相机操作和参数配置都被抽象成Captrue(捕获),切勿理解为拍照,因为使用Captrue也可能是开发者仅仅想对预览进行一个对焦。
Captrue分为三种模式,分别是单次模式,多次模式,重复模式。这几个模式也很好理解,如果要举例来说的话单次模式最经典的运用就是拍照操作,而多次模式最经典的例子就是连拍操作,而对于重复模式,预览操作就能显示出其重复的特征,不断地去捕获画面。
而在这里着重说一下重复模式,这也是本次实现录像过程拍照的关键知识点。重复模式指的是不断重复执行指定的Captrue操作,当有其他模式的Captrue提交时会暂停该模式,转而执行其他模式的captrue,当其他模式的Captrue执行完之后,会自动启动刚刚暂停的重复模式的Captrue,该模式的Captrue是全局唯一的,新提交的重复模式Captrue会覆盖旧的重复模式Captrue。
重复模式会保留我们提交的CaptrueRequest对象用于不断重复执行Captrue操作,所以大多数情况下重复模式的CaptrueRequest和其他模式的CaptrueRequest是独立的。
知道这些知识之后,我们便可以尝试录像过程进行拍照操作。其实本质上跟预览之后进行拍照的原理是一样的,都是从重复模式暂停执行单次模式的Captrue,执行完单次模式之后,系统会自动重启原先暂停的重复模式。
问题描述
我先说一下我一开始的错误思路吧。我原本是想着当我录像点击拍照按钮的时候,执行一个方法,将执行录像的session会话停止关闭后,再打开一个用于拍照的session会话,在拍照结束后再打开一个录像的session会话。很明显这种方式从字面意思上就看得出,就算整个过程没有什么逻辑问题,最后也会产生两段录像,毕竟中间停止了一次嘛,后来那次相当于开了一个新的重复模式的Captrue。果不其然最后确实有问题,而且还不是我预想的问题,拍照完之后,录像结果跟预览从那帧开始一直卡帧。
解决方式
其实解决方法可以参考预览拍照功能进行一个解决。以下我们将通过代码直观的看看这个解决方法。简单来说就是在录像这个重复模式进行中的时候,提交一个捕获图像的单次模式,切勿将录像的session给关闭了,但捕获图像的单次模式执行完之后,session会自动重启之前录像的重复模式接着进行录制。
//首先对于一开始的录像session,需要发生一些改变
//可以看到surface列表需要加多一个mImageReader.getSurface()作为拍照的surface
mCameraDevice.createCaptureSession(Arrays.asList(previewsurface,mediaRcordSurface,
mImageReader.getSurface()),recordingStateCallback,mHandle);
//调用视频拍照方法
private void CaptureOneDuringRecording() {
//准备开始设置录像截屏的captureRequestBuilder
captureRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,CaptureRequest.CONTROL_AF_TRIGGER_START);
if (isRecording){
//正在录制,这是正确的
try {
mCaptureSession.capture(captureRequest.build(),newCameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
startStillCaptureRequest();
}
}, mHandle);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
else
{
//这是错误的,因为不拍的时候,不应该出现这个按钮
try {
throw new Exception("未拍照时,该方法不应该被调用");
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void startStillCaptureRequest() {
try {
captureRequest=mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
captureRequest.addTarget(mImageReader.getSurface());
//先不设置照片方向
captureRequest.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(myOrientoinListener.angle));
mCaptureSession.capture(captureRequest.build(), new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
},mHandle);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}