[英]Camera2 API access synchronization
Camera2 API 允许我们指定线程(传递Handler
实例),我们在该线程上接收包含CameraDevice
、 CameraCaptureSession
、 CaptureResult
等的回调。我们使用来自这些回调的信息来配置捕获 session,创建捕获请求并获取捕获结果。 但是,当用户通过 UI 控制相机配置(例如对焦、测光)时,他是从主线程进行的。 在这里,我们开发人员有两种选择:
main thread
)“直接”使用 Camera2 API 调用(例如CameraCaptureSession.capture
)。 这里我们需要管理session state和同步访问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 控制进行处理。 第二种方法使我们能够避免这种情况下的同步成本,我认为这可能会略微提高性能并降低能耗。
据我从消息来源获得的信息, CameraDeviceImpl
和CameraCaptureSessionImpl
是线程安全的,因此这两种方法都是可以接受的。
但是,我想知道第二种方法是否可行,哪种方法更好?
他们都是可行的。 “更好”取决于一系列因素,例如代码库的大小,以及代码中有多少不同的地方想要使用 session 和设备。
将回调发送到相机处理程序线程会产生一些小的开销,而且要编写更多的样板文件,因此对于较小的应用程序,只需从您所在的任何线程进行调用并适当地进行同步就可以了。
然而,随着应用程序的复杂性增加,将与相机 API 的所有交互保持在单个线程中开始变得有吸引力; 不仅因为您不必显式同步,而且因为如果与相机 object 的每次交互都发生在同一线程上,则更容易推断所有权、系统的 state 等等。 此外,由于某些相机 API 方法可能会阻塞很长时间,因此您真的不想让 UI 冻结那么久。 因此将调用发送到另一个线程是有价值的。
因此,这是一些额外的样板文件 + 少量开销与无法将相机代码集中在一个地方以实现简单性和流畅性之间的权衡。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.