![](/img/trans.png)
[英]How to get each frame data using camera2 API in Android5.0 in realtime
[英]How to properly implement camera2 realtime frame processing using RxJava?
我正在使用camera2进行反应性包装,我的目标是获取每一帧,然后传递到面部识别。
因此,我在setOnImageAvailableListener上创建了一个包装方法
fun createOnImageAvailableFlowable(imageReader: ImageReader, handler: Handler): Flowable<ImageReader> {
return Flowable.create({ subscriber ->
imageReader.setOnImageAvailableListener({
if (!subscriber.isCancelled)
subscriber.onNext(it)
}, handler)
subscriber.setCancellable {
imageReader.setOnImageAvailableListener(null, null)
}
}, BackpressureStrategy.LATEST)
}
反应链如下所示:
createOnImageAvailableFlowable(imageReader!!, null)
.concatMap {
it.acquireLatestImage()?.use { image ->
val rotation = ReactiveCamera.getRotationCompensation(cameraId!!, this, applicationContext)
val visionImage = FirebaseVisionImage.fromMediaImage(image, rotation)
firebaseFaceDetector
.detectInImage(visionImage)
.toFlowable(BackpressureStrategy.LATEST)
.map { list ->Optional(list)}
} ?: Flowable.just(Optional(null))
}
...
该代码有效,但由于所有工作均在主线程中执行,因此在预览表面上会造成一些延迟。 这需要在单独的线程中执行。 我天真的解决方案是在concatMap之前添加observeOn运算符:
createOnImageAvailableFlowable(imageReader!!, null)
.observeOn(Schedulers.io()) // doesn't switch thread
.concatMap {
// still main thread
}
...
但这并不影响,所有工作仍在主线程中。 如果我指定concatMapEager而不是concatMap,则所有操作都将在单独的线程中按预期工作,但是帧会带来很大的延迟。
我做错了什么? 在这种情况下,如何指示反应流在单独的线程中执行? 在实时帧处理的情况下如何处理背压?
更新
我按照Kiskae的建议提供了自己的线程,但是现在,只有第一个发射发生在调度程序的线程中,而其余的发射仍保留在主线程中:
createOnImageAvailableFlowable(imageReader!!, null)
.subscribeOn(AndroidSchedulers.from(nonMainThread.looper))
.concatMap {
val t = Thread.currentThread()
val name = t.name
Log.d(TAG, "current thread {$name}")
...
}
输出:
D/MainActivity: current thread {Camera2}
D/MainActivity: current thread {main}
D/MainActivity: current thread {main}
D/MainActivity: current thread {main}
D/MainActivity: current thread {main}
查看ImageReader.setOnImageAvailableListener
的文档:
处理程序:应在其上调用侦听器的处理程序;如果应在调用线程的循环程序上调用侦听器,则为null。
由于您正在订阅主循环程序,因此最终使用主concatMap
程序设置了回调,这将导致concatMap
之前的所有处理始终在应用程序线程上发生。
您可以通过提供处理程序,而不是解决这个null
或致电subscribeOn
和提供基于处理器的调度样RxAndroid的HandlerScheduler
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.