当前位置: 首页 > 知识库问答 >
问题:

当使用来自MediaCodec的表面时,eglSwapBuffers与EGL_BAD_SURFACE一起失败

董阳平
2023-03-14

我正在尝试使用MediaCodec和Surfaces对一部电影进行编码(像素缓冲区模式工作,但性能不够好)。但是,每次尝试调用EGLSwapBuffers()时,它都会失败,因为EGL_BAD_Surface并且因此,DequeueOutputBuffer()总是返回-1(INFO_TRY_AGAIN_LATER)

我看过Bigflake和Grafika的例子,我有另一个工作项目,在那里一切都是好的,但我需要在另一个稍微不同的设置下工作。

我目前有一个GLSurfaceView,它执行屏幕呈现,并随自定义EGLContextFactory/EGLConfigChooser一起提供。这允许我创建共享上下文,用于在本机库中进行单独的OpenGL呈现。这些是使用EGL10创建的,但这不应该是一个问题,因为根据我所知,底层上下文只关心客户机版本。

我已经使用以下配置确保上下文是可记录的:

private android.opengl.EGLConfig chooseConfig14(android.opengl.EGLDisplay display) {
        // Configure EGL for recording and OpenGL ES 3.x
        int[] attribList = {
                EGL14.EGL_RED_SIZE, 8,
                EGL14.EGL_GREEN_SIZE, 8,
                EGL14.EGL_BLUE_SIZE, 8,
                EGL14.EGL_ALPHA_SIZE, 8,
                EGL14.EGL_RENDERABLE_TYPE, EGLExt.EGL_OPENGL_ES3_BIT_KHR,
                EGLExt.EGL_RECORDABLE_ANDROID, 1,
                EGL14.EGL_NONE
        };

        android.opengl.EGLConfig[] configs = new android.opengl.EGLConfig[1];
        int[] numConfigs = new int[1];
        if (!EGL14.eglChooseConfig(display, attribList, 0, configs, 0,
                configs.length, numConfigs, 0)) {
            return null;
        }

        return configs[0];
    }
EGLSurface createEGLSurface(Surface surface) {
        if (surface == null) return null;

        int[] surfaceAttribs = { EGL14.EGL_NONE };

        android.opengl.EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);

        android.opengl.EGLConfig config = chooseConfig14(display);

        EGLSurface eglSurface = EGL14.eglCreateWindowSurface(display, config, surface, surfaceAttribs, 0);

        return eglSurface;
    }

当一个新帧从相机到达时,我将它发送到屏幕和另一个处理记录的类。该类只是将其呈现给从MediaCodec的输入表面构建的EGLSurface,如下所示:

public void drawToSurface(EGLSurface targetSurface, int width, int height, long timestampNano, boolean ignoreOrientation) {
        if (mTextures[0] == null) {
            Log.w(TAG, "Attempting to draw without a source texture");
            return;
        }

        EGLContext currentContext = EGL14.eglGetCurrentContext();
        EGLDisplay currentDisplay = EGL14.eglGetCurrentDisplay();

        EGL14.eglMakeCurrent(currentDisplay, targetSurface, targetSurface, currentContext);
        int error = EGL14.eglGetError();

        ShaderProgram program = getProgramForTextureType(mTextures[0].getTextureType());

        program.draw(width, height, TextureRendererView.LayoutType.LINEAR_HORIZONTAL, 0, 1, mTextures[0]);
        error = EGL14.eglGetError();

        EGLExt.eglPresentationTimeANDROID(currentDisplay, targetSurface, timestampNano);
        error = EGL14.eglGetError();

        EGL14.eglSwapBuffers(currentDisplay, targetSurface);
        error = EGL14.eglGetError();

        Log.d(TAG, "drawToSurface");
    }

由于某种原因,EGLSwapBuffers()失败并报告EGL_BAD_Surface并且我还没有找到进一步调试的方法。

更新我试过在调用当前曲面后查询它,但它总是返回一个格式错误的曲面(往里看,我可以看到句柄是0,当查询时它总是失败)。看起来EGLMakeCurrent()无法将表面设置为上下文的绑定。

而且,我已经确定这个问题出现在高通芯片(Adreno)上,而不是麒麟上,所以它肯定与本机OpenGL实现有关(这有点搞笑,因为我一直注意到Adreno在涉及“坏的”OpenGL配置时比较宽容)

共有1个答案

柯建业
2023-03-14

修好了!结果是EGL10和EGL14看起来在一起很好,但在某些情况下以非常微妙的方式失败,比如我遇到的。

在我的例子中,我编写的EGLContextFactory使用EGL10创建一个基本的OpenGL ES上下文,然后根据需要创建更多的共享上下文,同样使用EGL10。虽然我可以使用EGL14(无论是Java还是C)检索它们,并且上下文句柄总是正确的(在上下文之间共享纹理就像一种魅力一样工作),但当尝试使用从上下文或EGL10起源创建的EGLSurface时,它却神秘地失败了...用肾上腺素芯片。

解决方案是切换EGLContextFactory以从使用EGL14创建的上下文开始,并继续使用EGL14创建共享上下文。对于仍然需要EGL10的GLSurfaceView,我不得不使用hack

    @Override
    public javax.microedition.khronos.egl.EGLContext createContext(EGL10 egl10, javax.microedition.khronos.egl.EGLDisplay eglDisplay, javax.microedition.khronos.egl.EGLConfig eglConfig) {
        EGLContext context = createContext();
        boolean success = EGL14.eglMakeCurrent(mBaseEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, context);

        if (!success) {
            int error = EGL14.eglGetError();
            Log.w(TAG, "Failed to create a context. Error: " + error);
        }

        javax.microedition.khronos.egl.EGLContext egl14Context = egl10.eglGetCurrentContext(); //get an EGL10 context representation of our EGL14 context
        javax.microedition.khronos.egl.EGLContext trueEGL10Context = egl10.eglCreateContext(eglDisplay, eglConfig, egl14Context, glAttributeList);

        destroyContext(context);
        return trueEGL10Context;
    }

这样做的目的是用EGL14创建一个新的共享上下文,使其成为当前上下文,然后检索它的EGL10版本。这个版本不能直接使用(原因我不能完全理解),但是它的另一个共享上下文可以很好地工作。然后可以销毁开始的EGL14上下文(在我的例子中,它被放入一个堆栈中,稍后再被重用)。

我真的很想理解为什么需要这个黑客,但我很高兴有一个工作的解决方案仍然。

 类似资料:
  • 当试图将EnumTypeAdapter与Proguard一起使用时,它会在gson.getAdapter()中导致AssertionError。此错误似乎是由于类型信息丢失...以下是所有相关源代码: 例外情况: 正在使用的EnumTypeAdapter: 如何构造GSON对象: 我的ProGuard配置: 如前所述,我怀疑由于丢失了类型信息而出现了故障--在深入研究了GSON源代码后,这是用来解

  • 我有一个带有Spring(5.7.2)Web/Security的REST API项目。 我只有一个表,它包含一个id和一个名称。 当我删除光盘时,我的DiscsService会 当我需要插入或更新时,我会: 我了解到,当您希望在同一事务中使用值(提交之前)时,将使用,并且将同步并清空SQL缓存。 在我的例子中,我看到我在数据库中插入/更新或删除了值。 我应该使用flush()(我认为不应该),但可

  • 问题内容: 介绍 让我为这个长期的问题表示歉意。它要尽我所能,但是很不幸,它不是很短。 设定 我定义了两个接口A和B: 然后,我有一个共享库“ testc”,它构造类C的对象,实现A和B,然后传递指向其A接口的指针: 最后,我有一个第二共享库“TESTD”,需要一个作为输入,并尝试将其转换为一个,使用 最后,我有一个主要应用程序,在库之间传递: 题 如果我构建主应用程序,并链接到“ testc”和

  • 问题内容: 当同时使用Logstash和Elasticsearch时,带有的字段会附加到已分析的字段中,因此,当使用诸如Kibana之类的工具查询Elasticsearch时,可以按原样使用字段的值,而无需按词拆分。 我用最新的所有版本构建了ELK堆栈的新安装,并注意到不再像在较早版本的堆栈中那样创建我的字段。有很多人在Elasticsearch上发布了创建模板的解决方案,但是我无法找到很多有关

  • 我试图将Hibernate与我的spring应用程序上下文联系起来。我正在成功地连接SessionFactory,但当我尝试调用getCurrentSession时,我看到以下错误: 我正在配置数据源会话工厂和事务管理器。我还指定了事务处理将是注释驱动的 下面是我的上下文XML: null 下面是我发现错误的类: 当这被称为sessionFactory时不是null,而是带有上述错误的错误。如果我

  • 问题内容: 我正在创建一个基于测验的系统,该系统的一部分包括2个表: Answer_bank表: 和Question_bank表: 目的是允许某人创建一个问题和一个答案,答案将以等于的形式存储在答案库表中。我不想在同一张表中使用它,因为这会使我变得更加复杂。 我尝试使用以下PDO / SQL插入两个表中。 不过这个问题我已经是在表总是插入,而不是相同的ID 。这是这样做的不正确方法吗?答案表包括?