繁体   English   中英

如何使用RxJava正确实现camera2实时帧处理?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM