在SurfaceView上重叠GLSurfaceView,反之亦然 [英] Overlapping GLSurfaceView on SurfaceView and vice versa

查看:523
本文介绍了在SurfaceView上重叠GLSurfaceView,反之亦然的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ExoPlayer-SurfaceView

Camera2 + MediaCodec-GLSurfaceView

我正在使用上述视图组来播放视频和摄像机记录.

UI-1 : Exo-Surf 位于中心, Cam-GLS 位于右上角.

UI-2 : Cam-GLS 位于中心, Exo-Surf 位于右上角.

为此,我正在使用 setZOrderOnTop 设置z-index,因为两者都位于RelativeLayout中.

(exoPlayerView.videoSurfaceView as? SurfaceView)?.setZOrderOnTop(true/false)

在具有API 29-Android 10的Samsung S9 +以及API 28上似乎运行良好.

但是对于API 21-27,它的行为带有一些随机性问题.

  • Dash-A SurfaceView/GLSurfaceView的顶部不可见
  • Dash-B SurfaceView/GLSurfaceView的底部不可见
  • 整个SurfaceView/GLSurfaceView在右上角变得完全透明

还尝试使用 setZOrderMediaOverlay ,但没有运气.

我确定两个表面视图可以一起使用,因为Whatsapp和google duo应用程序正在视频通话中使用它们.但是我想知道GLSurfaceView是否引起问题有关锁定GL线程的问题",如下面此答案中所述./p>

希望找到适用于API 21+或任何参考链接的有效解决方案,建议将受到高度赞赏.

解决方案

而不是使用内置的GLSurfaceView,您必须创建多个SurfaceView,并管理OpenGL如何在一个(或多个)上绘制).

Grafika代码(我在对您链接的答案的评论中提到)在这里:
https://github.com/google/grafika/blob/master/app/src/main/java/com/android/grafika/MultiSurfaceActivity.java

在该代码中,onCreate创建了曲面:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_multi_surface_test);

    // #1 is at the bottom; mark it as secure just for fun.  By default, this will use
    // the RGB565 color format.
    mSurfaceView1 = (SurfaceView) findViewById(R.id.multiSurfaceView1);
    mSurfaceView1.getHolder().addCallback(this);
    mSurfaceView1.setSecure(true);

    // #2 is above it, in the "media overlay"; must be translucent or we will totally
    // obscure #1 and it will be ignored by the compositor.  The addition of the alpha
    // plane should switch us to RGBA8888.
    mSurfaceView2 = (SurfaceView) findViewById(R.id.multiSurfaceView2);
    mSurfaceView2.getHolder().addCallback(this);
    mSurfaceView2.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    mSurfaceView2.setZOrderMediaOverlay(true);

    // #3 is above everything, including the UI.  Also translucent.
    mSurfaceView3 = (SurfaceView) findViewById(R.id.multiSurfaceView3);
    mSurfaceView3.getHolder().addCallback(this);
    mSurfaceView3.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    mSurfaceView3.setZOrderOnTop(true);
}

初始绘图代码位于:

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)

会根据某些本地标志调用不同的本地方法.例如,它在此处调用GL绘图的示例:

private void drawRectSurface(Surface surface, int left, int top, int width, int height) {
    EglCore eglCore = new EglCore();
    WindowSurface win = new WindowSurface(eglCore, surface, false);
    win.makeCurrent();
    GLES20.glClearColor(0, 0, 0, 0);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
    for (int i = 0; i < 4; i++) {
        int x, y, w, h;
        if (width < height) {
            // vertical
            w = width / 4;
            h = height;
            x = left + w * i;
            y = top;
        } else {
            // horizontal
            w = width;
            h = height / 4;
            x = left;
            y = top + h * i;
        }
        GLES20.glScissor(x, y, w, h);
        switch (i) {
            case 0:     // 50% blue at 25% alpha, pre-multiplied
                GLES20.glClearColor(0.0f, 0.0f, 0.125f, 0.25f);
                break;
            case 1:     // 100% blue at 25% alpha, pre-multiplied
                GLES20.glClearColor(0.0f, 0.0f, 0.25f, 0.25f);
                break;
            case 2:     // 200% blue at 25% alpha, pre-multiplied (should get clipped)
                GLES20.glClearColor(0.0f, 0.0f, 0.5f, 0.25f);
                break;
            case 3:     // 100% white at 25% alpha, pre-multiplied
                GLES20.glClearColor(0.25f, 0.25f, 0.25f, 0.25f);
                break;
        }
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }
    GLES20.glDisable(GLES20.GL_SCISSOR_TEST);

    win.swapBuffers();
    win.release();
    eglCore.release();
}

我没有使用此代码,所以我只能建议您搜索有关在该代码中看到的各种呼叫的其他详细信息.

首先,尝试获得一个简单的示例工作,该工作具有两个重叠的SurfaceView,而没有任何OpenGL调用.例如.重叠的纯色背景色视图.我重申要点:不要将它们中的任何一个都设为GLSurfaceView

尝试更改其中一个视图以初始化和使用OpenGL. (使用类似于我上面描述的代码的逻辑;仍然不是GLSurfaceView.)

ExoPlayer - SurfaceView

Camera2 + MediaCodec - GLSurfaceView

I am using the above view groups for playing video and camera recording.

UI-1: Exo-Surf at the center and Cam-GLS in the top right corner.

UI-2: Cam-GLS at the center and Exo-Surf in the top right corner.

To achieve this I am using setZOrderOnTop to set z-index, as both are inside RelativeLayout.

(exoPlayerView.videoSurfaceView as? SurfaceView)?.setZOrderOnTop(true/false)

It seems working fine on Samsung S9+ with API 29 - Android 10, and also for API 28.

But for API 21-27, it behaves with some random issues.

  • Dash-A top part of SurfaceView/GLSurfaceView is not visible
  • Dash-B bottom part of SurfaceView/GLSurfaceView is not visible
  • Entire SurfaceView / GLSurfaceView becomes completely transparent in the top right corner

Also tried using setZOrderMediaOverlay but no luck.

I am sure two surface view works together as Whatsapp and google duo apps are using them in video calls. But I am wondering if GLSurfaceView is causing an issue "something about locking the GL thread" as commented below in this answer.

Hoping for a working solution for API 21+ or any reference link, suggestions would be highly appreciated.

解决方案

Instead of using the built-in GLSurfaceView, you'll have to create multiple SurfaceViews, and manage how OpenGL draws on one (or more) of those.

The Grafika code (that I mentioned in my comment to the answer you link) is here:
https://github.com/google/grafika/blob/master/app/src/main/java/com/android/grafika/MultiSurfaceActivity.java

In that code, onCreate creates the surfaces:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_multi_surface_test);

    // #1 is at the bottom; mark it as secure just for fun.  By default, this will use
    // the RGB565 color format.
    mSurfaceView1 = (SurfaceView) findViewById(R.id.multiSurfaceView1);
    mSurfaceView1.getHolder().addCallback(this);
    mSurfaceView1.setSecure(true);

    // #2 is above it, in the "media overlay"; must be translucent or we will totally
    // obscure #1 and it will be ignored by the compositor.  The addition of the alpha
    // plane should switch us to RGBA8888.
    mSurfaceView2 = (SurfaceView) findViewById(R.id.multiSurfaceView2);
    mSurfaceView2.getHolder().addCallback(this);
    mSurfaceView2.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    mSurfaceView2.setZOrderMediaOverlay(true);

    // #3 is above everything, including the UI.  Also translucent.
    mSurfaceView3 = (SurfaceView) findViewById(R.id.multiSurfaceView3);
    mSurfaceView3.getHolder().addCallback(this);
    mSurfaceView3.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    mSurfaceView3.setZOrderOnTop(true);
}

The initial draw code is in:

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)

which calls different local methods depending on some local flags. For example, it calls an example of GL drawing here:

private void drawRectSurface(Surface surface, int left, int top, int width, int height) {
    EglCore eglCore = new EglCore();
    WindowSurface win = new WindowSurface(eglCore, surface, false);
    win.makeCurrent();
    GLES20.glClearColor(0, 0, 0, 0);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
    for (int i = 0; i < 4; i++) {
        int x, y, w, h;
        if (width < height) {
            // vertical
            w = width / 4;
            h = height;
            x = left + w * i;
            y = top;
        } else {
            // horizontal
            w = width;
            h = height / 4;
            x = left;
            y = top + h * i;
        }
        GLES20.glScissor(x, y, w, h);
        switch (i) {
            case 0:     // 50% blue at 25% alpha, pre-multiplied
                GLES20.glClearColor(0.0f, 0.0f, 0.125f, 0.25f);
                break;
            case 1:     // 100% blue at 25% alpha, pre-multiplied
                GLES20.glClearColor(0.0f, 0.0f, 0.25f, 0.25f);
                break;
            case 2:     // 200% blue at 25% alpha, pre-multiplied (should get clipped)
                GLES20.glClearColor(0.0f, 0.0f, 0.5f, 0.25f);
                break;
            case 3:     // 100% white at 25% alpha, pre-multiplied
                GLES20.glClearColor(0.25f, 0.25f, 0.25f, 0.25f);
                break;
        }
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }
    GLES20.glDisable(GLES20.GL_SCISSOR_TEST);

    win.swapBuffers();
    win.release();
    eglCore.release();
}

I haven't used this code, so I can only suggest you search for additional details about the various calls you see in that code.

FIRST, try to get a simple example working that has two overlapping SurfaceViews, WITHOUT any OpenGL calls. E.g. solid background color views that overlap. And I reiterate the key point: Do Not make either of them a GLSurfaceView!

THEN attempt to change one of the views to initialize and use OpenGL. (Using logic similar to the code I describe above; still NOT a GLSurfaceView.)

这篇关于在SurfaceView上重叠GLSurfaceView,反之亦然的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆