简体   繁体   English

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

[英]How to properly implement camera2 realtime frame processing using RxJava?

I'm making reactive wrapper over camera2, my goal is to get each frame and then pass to face recognition. 我正在使用camera2进行反应性包装,我的目标是获取每一帧,然后传递到面部识别。

So, I created a wrapper method over setOnImageAvailableListener 因此,我在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)
    }

Reactive chain looks as follows: 反应链如下所示:

 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))
 }
 ...

This code works, but cause some lags on preview surface because all work performed in the main thread. 该代码有效,但由于所有工作均在主线程中执行,因此在预览表面上会造成一些延迟。 This needs to be performed in separate thread. 这需要在单独的线程中执行。 My naive solution is to add observeOn operator before concatMap: 我天真的解决方案是在concatMap之前添加observeOn运算符:

createOnImageAvailableFlowable(imageReader!!, null)
.observeOn(Schedulers.io()) // doesn't switch thread
.concatMap {
 // still main thread
}
...

But it doesn't affect, all work still in the main thread. 但这并不影响,所有工作仍在主线程中。 If I specify concatMapEager instead of concatMap, all works as expected in separate thread, but the frames comes with a significant delay. 如果我指定concatMapEager而不是concatMap,则所有操作都将在单独的线程中按预期工作,但是帧会带来很大的延迟。

What I'm doing wrong? 我做错了什么? How can I instruct the reactive stream to be performed in a separate thread in this case? 在这种情况下,如何指示反应流在单独的线程中执行? How can backpressure be handled in case of realtime frame processing? 在实时帧处理的情况下如何处理背压?

Upd 更新

I provided my own thread as Kiskae suggested, but now, only first emission happens in scheduler's thread, but the rest emissions remain in the main thread: 我按照Kiskae的建议提供了自己的线程,但是现在,只有第一个发射发生在调度程序的线程中,而其余的发射仍保留在主线程中:

createOnImageAvailableFlowable(imageReader!!, null)
.subscribeOn(AndroidSchedulers.from(nonMainThread.looper))
.concatMap {
   val t = Thread.currentThread()
   val name = t.name
   Log.d(TAG, "current thread {$name}")
 ...
}

Output: 输出:

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}

Looking at the documentation of ImageReader.setOnImageAvailableListener : 查看ImageReader.setOnImageAvailableListener的文档:

Handler: The handler on which the listener should be invoked, or null if the listener should be invoked on the calling thread's looper. 处理程序:应在其上调用侦听器的处理程序;如果应在调用线程的循环程序上调用侦听器,则为null。

Since you're subscribing on the main looper it ends up setting up the callback using the main looper, this causes all the processing before the concatMap to always occur on the application thread. 由于您正在订阅主循环程序,因此最终使用主concatMap程序设置了回调,这将导致concatMap之前的所有处理始终在应用程序线程上发生。

You can solve this by either providing a handler instead of null or calling subscribeOn and providing a handler-based scheduler like RxAndroid's HandlerScheduler . 您可以通过提供处理程序,而不是解决这个null或致电subscribeOn和提供基于处理器的调度样RxAndroid的HandlerScheduler

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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