Alex Rivera | Logout

Fighting with SurfaceView, Camera and OpenGL

Asked 2011-04-13T11:12:49.573
12

We've been fighting with some problems relating to SurfaceViews for more than a week, and find no proper solution to them. We read the other questions in the forum regarding to similar problems (and even Mixare source code) but couldn't find an answer, so we hope you could help us somehow.

Scenario: We've got

  • a SurfaceView for the Camera
  • a SurfaceView for an OpenGL layer, which goes on top of the camera.
  • another View, which shows some information about what we can see on the screen. This one goes on top of both SurfaceViews.

Problem:

No matter how hard we try, both SurfaceViews apparently don't get on well with each other. If we try to:

setContentView(mCameraPreview); 
addContentView(mGLSurfaceView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 
addContentView(mInfoView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

(which seems logical), everything goes as expected until we lock/unlock the phone. After that, the GLSurfaceView just disappears (not the InfoView, that one is still shown).

If, instead, we try to:

setContentView(mGLSurfaceView); 
addContentView(mCameraPreview, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 
addContentView(mInfoView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

Then the problem is that the GLSurfaceView only appears after lock/unlock, and before that the screen is showing the camera and the InfoView.

We discovered that if we sleep the main thread for 4.6 seconds (or more) after executing onStart() in the activity that shows the views, the behaviour is as expected (both camera, glsurface and info views are shown, even after lock/unlock).

The thing is, we're looking for a more... elegant solution.

It seems to us that the problem is the camera taking more time than expe

Edit
Report

1 Answer

3

I had the same problem. As you hint at yourself: multiple SurfaceViews don't get along with each other in that their Z order is undefined.

On my Samsung Galaxy S2 the ordering is the same as you describe (don't know how it is on other phones). The way I solved this, is checking for first time creation of the Activity in onCreate():

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    //...

    if ( savedInstanceState == null )
    {
        initCamView();
        initOpenGL();
    }
    else
    {
        initOpenGL();
        initCamView();
    }

    //...
}

with:

private void initOpenGL()
{
    mGLSurfaceView = new GLSurfaceView(this);
    mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
    mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);

    mOGLRenderer = new OGLRenderer(this);
    mGLSurfaceView.setRenderer(mOGLRenderer);
    mRL.addView(mGLSurfaceView); // mRL is the Relative Layout
}

and:

private void initCamView()
{
    mCamView = new CustomCameraView( this.getApplicationContext(),
                                     this.getWindowManager() );
    mRL.addView(mCamView); // mRL is the Relative Layout
}

Not the most elegant solution, but it's better than letting the thread sleep for 4.6 seconds.

It might also be possible to just lock the screen in a single orientation, but then you need to do a lot of ugly hacking to get the overlays rotated the right way.

Or, if you're only targeting Android 3.0 or above (API level 8), you can just show the camera in an OpenGL SurfaceTexture. http://developer.android.com/reference/android/hardware/Camera.html#setPreviewTexture(android.graphics.S

answered 2011-07-29T08:08:29.417

Your Answer