11

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

场景:我们有

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

问题:

无论我们如何努力,两个 SurfaceView 显然都不能很好地相处。如果我们尝试:

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。

我们发现,如果我们在显示视图的 Activity 中执行 onStart() 后让主线程休眠 4.6 秒(或更长时间),则行为符合预期(即使在锁定/解锁之后,也会显示相机、glsurface 和信息视图)。

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

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

有任何想法吗?我们怎样才能同时显示 SurfaceView 和它们之上的信息视图?

4

4 回答 4

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);

这对我有用:)

于 2011-11-30T03:18:56.320 回答
3

我有同样的问题。正如您向自己暗示的那样:多个SurfaceViews 彼此不相处,因为它们的 Z 顺序是未定义的。

在我的三星 Galaxy S2 上,订购与您描述的相同(不知道在其他手机上如何)。Activity我解决这个问题的方法是检查in的首次创建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 )

于 2011-07-29T08:08:29.417 回答
2

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

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

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

如果您想了解更多有关 SurfaceView 为何如此行事的信息,请参阅Android System-Level Graphics文档。

于 2014-07-29T16:23:10.777 回答
1

我有同样的问题:我想要一个 GLSurfaceView 下的 SurfaceView,第一个播放视频,第二个运行游戏。

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

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

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

于 2013-03-06T22:20:01.207 回答