CameraCaptureSession
是一个事务,用来向相机设备发送获取图像的请求。
主要有 setRepeatingRequest()
和 capture()
方法。setRepeatingRequest()
是重复请求获取图像数据,常用于预览或连拍,capture()
是获取一次,常用于单张拍照。
CameraCaptureSession
类是一个抽象类,其直接的实现类为 CameraConstrainedHighSpeedCaptureSession
。
官方文档链接:https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession
通过 CameraDevice 类的 createCaptureSession()
方法创建,并在回调的 onConfigured(CameraCaptureSession session)
方法中获取实例。
示例:
try {
mCameraDevice.createCaptureSession(Arrays.asList(mPreviewSurface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
mCaptureSession = session;
// ...(省略)
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.e(TAG, "ConfigureFailed. session: mCaptureSession");
}
}, mBackgroundHandler); // handle 传入 null 表示使用当前线程的 Looper
} catch (CameraAccessException e) {
e.printStackTrace();
}
函数原型:
createCaptureSession(List outputs, CameraCaptureSession.StateCallback callback, Handler handler)
参数说明:
mPreviewSurface
用于预览的输出,一个 mImageReader.getSurface()
用于拍照的输出。onConfigured(CameraCaptureSession session)
方法。当相机捕捉事务的状态发生变化时,会回调这个类中的相应方法。其中只有 onConfigured
和 onConfigureFailed
两个方法是抽象的(必须重写),其余均有空实现。
方法名 | 描述 |
---|---|
onConfigureFailed(CameraCaptureSession session) | 该会话无法按照相应的配置发起请求时回调 |
onConfigured(CameraCaptureSession session) | 相机设备完成配置,并开始处理捕捉请求时回调 |
onActive(CameraCaptureSession session) | 在 onConfigured 后执行,即开始真的处理捕捉请求了 |
onCaptureQueueEmpty(CameraCaptureSession session) | 当相机设备的输入捕捉队列为空时回调 |
onClosed(CameraCaptureSession session) | 当事务关闭时回调 |
onReady(CameraCaptureSession session) | 每当没有捕捉请求处理时都会回调该方法,即该方法会回调多次 |
示例: 见上面创建 CameraCaptureSession
的代码即可。
当一个捕捉请求发送给相机设备时,可以使用这个类来跟踪各进度。
所有方法均有默认的空实现,根据需求重写相应的方法即可。
方法名 | 描述 |
---|---|
onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) | 当相机设备开始为请求捕捉输出图时 |
onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) | 当图像捕获部分进行时就会回调该方法,此时一些(但不是全部)结果是可用的 |
onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) | 当图像捕捉完全完成时,并且结果已经可用时回调该方法 |
onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) | 对应 onCaptureCompleted 方法,当相机设备产生 TotalCaptureResult 失败时就回调该方法 |
onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) | 当一个捕捉段完成时并且所有 CaptureResult 或者 captureFailure 都通过该监听器返回时被回调,这个方法独立于 CaptureCallback 的其他方法 |
onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) | 当 CaptureResult 或者 captureFailure 没有通过该监听器被返回而被中断时被回调,这个方法同样独立于 CaptureCallback 的其他方法 |
onCaptureBufferLost(CameraCaptureSession session, CaptureRequest request, Surface target, long frameNumber) | 当捕捉的缓冲没有被送到目标 surface 时被回调 |
示例: 见最下面。
不断的重复请求捕捉画面,常用于预览或者连拍场景。
参数解释:
CaptureCallback#onCaptureSequenceCompleted
。提交一个获取单张图片的捕捉请求,常用于拍照场景。参数解释同上。
停止任何一个正常进行的重复请求。
尽可能快的取消当前队列中或正在处理中的所有捕捉请求。
异步关闭这个 CameraCaptureSession
。应当在相机释放的步骤中对 session 也进行关闭操作。
获取该 CameraCaptureSession
创建对应的 CameraDevice
对象。
/**
* Creates a new {@link CameraCaptureSession} for camera preview.
*/
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Flash is automatically enabled when necessary.
setAutoFlash(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback captureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.abortCaptures();
mCaptureSession.capture(captureBuilder.build(), captureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
我们在 onCaptureCompleted()
回调中执行 unlockFocus()
重新开启预览。而保存图片的逻辑实际是在 mImageReader
的回调中。
https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java