【发布时间】:2020-09-22 14:59:33
【问题描述】:
Camera2 API 允许我们指定线程(传递Handler 实例),我们在该线程上接收包含CameraDevice、CameraCaptureSession、CaptureResult 等的回调。我们使用来自这些回调的信息来配置捕获会话,创建捕获请求并获取捕获结果。但是,当用户通过 UI 控制相机配置(例如对焦、测光)时,他是从主线程中进行的。在这里,我们开发人员有两种选择:
- 从任何线程(包括
main thread)“直接”使用 Camera2 API 调用(例如CameraCaptureSession.capture)。在这里,我们需要管理会话状态并同步对 Camera2 API 的访问。 - 将所有 Camera2 API 调用移至“CameraThread”。每当我们需要访问 Camera2 API 时,使用
Handler将消息发送到“CameraThread”。所以我们实际上只会在单线程(“CameraThread”)中使用它。
请让我澄清一下我的意思。假设我们为 Camera2 API 回调创建了HandlerThread。
mCameraThread = new HandlerThread("CameraThread");
mCameraThread.start();
mHandler = new Handler(mCameraThread.getLooper());
第一种方法:
CameraCaptureSession.StateCallback 在“CameraThread”上运行。
public void onConfigured(@NonNull CameraCaptureSession session) {
synchronized (STATE_MONITOR){
mState = State.Configured;
mSession = session;
}
}
以下方法可能被用户在任何线程上调用,包括“MainThread”,所以我们需要同步对mSession的访问。
public void takePicture() {
synchronized (STATE_MONITOR){
if(mState == State.Configured){
CaptureRequest request = ...;
mSession.capture(request, callback, mHandler)
}
}
}
此方法用于Camera2Basic 示例。到目前为止,我还在使用第一种方法。
第二种方法:
CameraCaptureSession.StateCallback 与前一种情况一样在“CameraThread”上运行。
public void onConfigured(@NonNull CameraCaptureSession session) {
mState = State.Configured;
mSession = session;
}
但是,我们不会“直接”访问mSession,而是将消息发布到“CameraThread”。因此,我们这里不需要同步,因为mSession只能从单线程访问。
public void takePicture() {
assertThatThreadIsRunning();
mHandler.post(() -> {
if(mState == State.Configured){
CaptureRequest request = ...;
mSession.capture(request, callback, mHandler)
}
});
}
第二种方法的好处是我们可以避免任何多线程问题。
例如,我们可以将CameraCaptureSession.CaptureCallback 用于预览捕获请求。此类重复请求的回调非常频繁地触发,应针对 AF 和 AE 控制进行处理。第二种方法可以让我们避免这种情况下的同步成本,我认为这可能会略微提高性能并降低能耗。
据我从sources 得到的,CameraDeviceImpl 和CameraCaptureSessionImpl 是线程安全的,所以这两种方法都是可以接受的。
但是,我想知道第二种方法是否可行,哪种方法更好?
【问题讨论】:
标签: android camera android-camera android-camera2