Piglet Piglet - 2 months ago 13
Android Question

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() {
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?


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