与SurfaceView,Camera和OpenGL战斗

时间:2011-04-13 11:12:50

标签: android opengl-es surfaceview glsurfaceview

我们一直在与SurfaceViews相关的一些问题进行斗争一个多星期,并找不到合适的解决方案。我们在论坛中阅读了有关类似问题的其他问题(甚至是Mixare源代码),但找不到答案,所以我们希望你能以某种方式帮助我们。

方案: 我们有

  • 适用于相机的SurfaceView
  • 用于OpenGL图层的SurfaceView,它位于相机顶部。
  • 另一个视图,显示有关我们在屏幕上可以看到的内容的一些信息。这个是在两个SurfaceViews之上。

问题:

无论我们尝试多么努力,两个SurfaceViews显然都不能相处得很好。如果我们尝试:

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

(这似乎合乎逻辑),一切都按预期进行,直到我们锁定/解锁手机。之后,GLSurfaceView就会消失(不是InfoView,仍会显示)。

相反,如果我们尝试:

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

然后问题是GLSurfaceView仅在锁定/解锁后出现,在此之前屏幕显示相机和InfoView。

我们发现,如果我们在显示视图的活动中执行onStart()之后将主线程休眠4.6秒(或更多),则行为与预期相同(即使在显示相机,glsurface和info视图之后锁定/解锁)。

问题是,我们正在寻找更优雅的解决方案。

在我们看来,问题是相机在Camera.open()中花费的时间比预期的多,因此添加了相机视图,添加了GLSurfaceView,当相机实际打开时,它会打开GLSurfaceView。关于这一点,我们在GLSurfaceView上使用bringToFront(),并将其放在信息视图的顶部,但在锁定/解锁后,相机仍在其上方打开,只留下一个带有相机预览的屏幕。 / p>

有什么想法吗?我们如何在它们之上显示SurfaceViews和信息视图?

4 个答案:

答案 0 :(得分:5)

试试这个:

mLayout.addView(mRenderView);
mLayout.addView(mCustomSurfaceView);

// without this line, the camera preview cannot be displayed 
// when running activity at first time.
mCustomSurfaceView.setZOrderMediaOverlay(true);

这对我有用:)

答案 1 :(得分:3)

我遇到了同样的问题。当你暗示自己:多个SurfaceView s彼此不相处,因为它们的Z顺序是未定义的。

在我的三星Galaxy S2上,订购与您描述的相同(不知道它在其他手机上是怎样的)。 我解决这个问题的方法是检查第一次在Activity中创建onCreate()

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

    //...

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

    //...
}

使用:

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
}

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

不是最优雅的解决方案,但它比让线程休眠4.6秒更好。

也可能只是将屏幕锁定在一个方向上,但是你需要做很多丑陋的黑客攻击才能使叠加层以正确的方式旋转。

或者,如果您仅定位到Android 3.0或更高版本(API级别8),则只需在OpenGL SurfaceTexture中显示相机即可。 http://developer.android.com/reference/android/hardware/Camera.html#setPreviewTexture(android.graphics.SurfaceTexture

答案 2 :(得分:1)

我遇到了同样的问题:我想在GLSurfaceView下使用SurfaceView,第一个播放视频,第二个播放游戏。

无论我做了什么,这两个表面视图之间的z顺序似乎是随机的。

但是我找到了解决方案,感谢这篇文章:https://stackoverflow.com/a/6028907/1557915

诀窍是删除布局的使用,而是使用setContentView / addContentView。

答案 3 :(得分:1)

每个SurfaceView的表面都有Z深度。有三种可能的深度:默认(底部),"媒体覆盖" (在它之上)," top" (高于一切,包括基于视图的UI)。如果在相同深度处有两个重叠的表面,则会赢一个,但您无法可靠地定义哪一个。您可能会在一台设备上获得一致的行为,但却发现它在另一台设备上以其他方式工作。

尽可能使用硬件覆盖完成合成。许多目前流行的设备有4个覆盖平面。一旦超过这个,组合就完成了GPU,这将更加昂贵。如果你有一个状态栏,导航栏和View UI,那就是三个,所以你只能获得一个便宜的SurfaceView。

对于问题中的示例,最好将尽可能多的东西组合到使用GLES渲染的曲面上。这可以包括API 11+上的摄像头输出。请参阅"相机纹理"例如Grafika中的活动。 (Grafika还有一个带有三个重叠SurfaceView的演示应用程序;请参阅"多表面测试"活动。)

如果您想了解有关SurfaceView行为方式的更多信息,请参阅Android System-Level Graphics doc。

相关问题