javaandroidandroid-camerasurfaceview

How to show two identical camera previews with the Android camera?


I need to be able to display two identical previews from a running camera instance on screen, is this possible?

So far the only way I could think of was to clone the preview surfaceview. So using the raw video data provided to onPreviewFrame, I am creating a new bitmap for the current frame and then drawing that to the surfaceholder canvas.

This displayed perfectly when run on the ui thread, but obviously it blocked the UI every couple of seconds whilst creating the bitmaps. I have now moved the bitmap creation into a new thread which resolves the app locking up, but now my surfaceview flickers/tears slightly!

Would this ever work? or am I going the wrong way about it? How can I stop the flicker?

Cut down sample code;

public void onPreviewFrame(byte[] data, Camera camera) {

-- new thread
// create bitmap from YUV (videoFrame)


-- UI thread
  Canvas canvas = null;
    try {
        canvas = surfaceHolder.lockCanvas();
        if (canvas != null) {
        canvas.drawBitmap(videoFrame, null, new Rect(0, 0, 200, 200), null);
        }
    } catch (Exception e) {
        mLogger.error(e.getMessage());
    } finally {
        if (canvas != null) {
        surfaceHolder.unlockCanvasAndPost(canvas);
        }
    }
}

I believe this is something to do with the surfaceview double buffer, I have quite a few solutions but cant stop the flicker!


Solution

  • If you don't need to run on Android releases before 3.0 (Honeycomb), you can use the SurfaceTexture output option, and OpenGL ES for rendering multiple previews.

    Setting up a working OpenGL view is a bit involved, so you'll want to find a guide for that. Once you have that working, create a SurfaceTexture object with a OpenGL texture ID you want to use for the preview texture, pass that into the camera with setPreviewTexture instead of using setPreviewDisplay, and then in your OpenGL thread, call updateTexImage to update the texture to show the latest frame from the camera (best to do so in response to a onFrameAvailable callback for best performance).

    Then you need OpenGL code to render two rectangles for your two copies of preview, and a shader to draw the preview texture on both.

    This is a decent bit of setup, but in the end, you'll have a very flexible system - then you can animate the preview in various fun ways, etc.