I got an issue using Camera2 API and Google MLKit. What I try to do, for now, is just to log a message if a face is detected. But I have this issue:

It is spamming on console:

W/ImageReader_JNI: Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers

And then crash my application with:

java.lang.IllegalStateException: maxImages (2) has already been acquired, call #close before acquiring more.

But as suggested by google for CameraX (I use Camera2 but I must do the same thing I think), I close the image I got with image.close() in the addOnCompleteListener.

Here is my code from the image reader:

val imageReader = ImageReader.newInstance(rotatedPreviewWidth, rotatedPreviewHeight,
    ImageFormat.YUV_420_888, 2)

    imageReader.setOnImageAvailableListener({
        it.acquireLatestImage()?.let { image ->

            val mlImage = InputImage.fromMediaImage(image, getRotationCompensation(cameraDevice.id, getInstance(), true))


            val result = detector.process(mlImage)
                 .addOnSuccessListener {faces ->
                     if (faces.size > 0)
                         Log.d("photo", "Face found!")
                     else
                         Log.d("photo", "No face have been found")
                     }
                     .addOnFailureListener { e ->
                         Log.d("photo", "Error: $e")
                     }
                     .addOnCompleteListener {
                         image.close()
                     }
                 }
             }, Handler { true })

What I think is happening is this:

Since the processing of google might be slow, the addOnCompleteListener is not called before the acquireLatestImage() is called to get a new image.

But I have no idea on how to prevent that :(, does anyone has an idea? Or maybe my asumptions about the problem are wrong?

And also to prevent the crash, I have increased the maxImages to 4, now it is just spamming "W/ImageReader_JNI: Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers" for some time (and then stop) but no crash.

But I think this solution is a way to hide the problem instead of solving it.

EDIT: Increasing the maxImages amount just delay the crash which still happens later.

2

There are 2 answers

1
Chenxi Song On BEST ANSWER

according to the best practice in MLKit developer guide: "If you use the Camera or camera2 API, throttle calls to the detector. If a new video frame becomes available while the detector is running, drop the frame. See the VisionProcessorBase class in the quickstart sample app for an example."

https://developers.google.com/ml-kit/vision/object-detection/android

0
Eddy Talvala On

Are the image.close method actually getting called? It's very likely that you'll need a few buffers acquired at the same time, but if 4 is not enough, it's possible you're not releasing them when the scanning is done. But maybe the processing is very slow, and you'll need more buffers to be available in parallel.

Note that if the processing cannot keep up with frame rate, you may need to drop frames manually to ensure you don't block the frame flow.