【问题标题】:Camera2 API access synchronizationCamera2 API 访问同步
【发布时间】:2020-09-22 14:59:33
【问题描述】:

Camera2 API 允许我们指定线程(传递Handler 实例),我们在该线程上接收包含CameraDeviceCameraCaptureSessionCaptureResult 等的回调。我们使用来自这些回调的信息来配置捕获会话,创建捕获请求并获取捕获结果。但是,当用户通过 UI 控制相机配置(例如对焦、测光)时,他是从主线程中进行的。在这里,我们开发人员有两种选择:

  1. 从任何线程(包括main thread)“直接”使用 Camera2 API 调用(例如 CameraCaptureSession.capture)。在这里,我们需要管理会话状态并同步对 Camera2 API 的访问。
  2. 将所有 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 得到的,CameraDeviceImplCameraCaptureSessionImpl 是线程安全的,所以这两种方法都是可以接受的。

但是,我想知道第二种方法是否可行,哪种方法更好?

【问题讨论】:

    标签: android camera android-camera android-camera2


    【解决方案1】:

    它们都是可行的。 “更好”取决于一系列因素,例如代码库的大小,以及代码中有多少不同的地方需要使用会话和设备。

    将回调发送到相机处理程序线程有一些小开销,加上要编写更多样板,因此对于较小的应用程序,只需从您所在的任何线程进行调用并适当地同步就可以正常工作。

    但是,随着应用程序复杂性的增加,将与相机 API 的所有交互保持在单个线程中变得越来越有吸引力;不仅因为您不必显式同步,还因为如果与相机对象的每次交互都发生在同一个线程上,则更容易推断所有权、系统状态等。此外,由于某些相机 API 方法可能会长时间阻塞,因此您真的不想让 UI 冻结那么久。所以将调用发送到另一个线程是很有价值的。

    因此,这是一些额外的样板文件 + 少量开销与无法将相机代码集中在一个地方以实现简单性和流畅性的权衡。

    【讨论】:

    • 非常感谢您的快速响应。这是我在最短的时间内第二次收到您的答复,干得好!
    猜你喜欢
    • 1970-01-01
    • 2020-01-10
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多