Перекрытие GLSurfaceView на SurfaceView и наоборот

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)

Кажется, он отлично работает на Samsung S9+ с API 29 — Android 10, а также для API 28.

Но для API 21-27 он ведет себя с некоторыми случайными проблемами.

  • Dash-A верхняя часть SurfaceView/GLSurfaceView не видна
  • Dash-B нижняя часть SurfaceView/GLSurfaceView не видна
  • Весь SurfaceView/GLSurfaceView становится полностью прозрачным в правом верхнем углу

Также пробовал использовать setZOrderMediaOverlay, но безуспешно.

Я уверен, что два поверхностных вида работают вместе, поскольку приложения Whatsapp и Google Duo используют их в видеозвонках. Но мне интересно, вызывает ли GLSurfaceView проблему «что-то с блокировкой потока GL», как прокомментировано ниже в этом ответе.

Надеемся на рабочее решение для API 21+ или любую справочную ссылку, предложения будут высоко оценены.


person Chitrang    schedule 23.05.2020    source источник


Ответы (1)


Вместо использования встроенного 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.)

person ToolmakerSteve    schedule 26.05.2020
comment
На самом деле, я использую эту библиотеку github.com/natario1/CameraView, и в ней я установил GLSurfaceView для запись видео. Так что у меня не так много свободы, чтобы изменить это. - person Chitrang; 29.05.2020