Piglet
Piglet

Reputation: 29

How to thread camera callbacks in Android?

I'm writing an Android app that obtains continuous updates from the camera and processes them whenever onPreviewFrame(byte[] data, Camera camera) is called.

The problem is that onPreviewFrame is only getting called around 8-10 times per second, as opposed to 30 times (which I expected for a 30 FPS camera). I think it's because my UI is receiving all of the camera callbacks as opposed to a separate thread.

Here is my SurfaceView that holds the camera and receives camera callbacks:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback, Callback {
private Camera mCamera;
...
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    //Frame received (about 8 per second)

And here is the code where I open the camera (in my main activity):

final Camera camera = getCameraInstance();    //calls camera.open()

mPreview = new CameraPreview(this, camera);

How should I go about using a thread, Asynctask, or Handler to make the camera callbacks happen on the side? And how would I receive these updates in the UI thread?

Upvotes: 0

Views: 3014

Answers (2)

QZHua
QZHua

Reputation: 374

Here is my answer, this problem blocks me for weeks.

In my case, my camera is started from a thread created in low level C code.

But as @Pavitra Kansara answered , the thread needs an event loop, if it does not, the onPreviewFrame might nerver be called. So you need to put the camera open funcalls back to the main(UI) thread which is something like this:

((SomeActivity)context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            try {
                open camera funcalls ...
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

Upvotes: 0

Pavitra Kansara
Pavitra Kansara

Reputation: 828

Yes, the callback will be invoked on the main (UI) thread. As per Documentation all Camera Callbacks from other methods are delivered to the event loop of the thread which called open().
This means if there isn't any event loop for a thread, then callbacks are delivered to the Main application event loop. And if there is no main application event loop, callbacks are not delivered at all.

In that case, since the onPreviewFrame gets called on Main thread, and so the task of dealing with the huge pixel matrices may get stuck when the UI operations are performed such as displaying animations, opening menus or even if message in printed on the screen.

A solution would be to create a new HandlerThread. HandlerThread comes in handy for starting a new thread that has a looper mechanism inbuilt.

Also, try using setPreviewCallbackWithBuffer(), rather than setPreviewCallback() because it reuses one buffer and does not have to allocate new buffer on every frame. It improves preview efficiency and frame rate by allowing preview frame memory reuse.

See here for a good tutorial for understanding Looper, AsyncTask and HandlerThread

Upvotes: 4

Related Questions