Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/209.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用MediaCodec中的曲面时,EGLSWAPBuffer与EGL_BAD_曲面一起失败_Android_Opengl Es_Android Mediacodec_Video Encoding_Egl - Fatal编程技术网

Android 使用MediaCodec中的曲面时,EGLSWAPBuffer与EGL_BAD_曲面一起失败

Android 使用MediaCodec中的曲面时,EGLSWAPBuffer与EGL_BAD_曲面一起失败,android,opengl-es,android-mediacodec,video-encoding,egl,Android,Opengl Es,Android Mediacodec,Video Encoding,Egl,我正在尝试使用MediaCodec和Surfaces对电影进行编码(像素缓冲模式可以工作,但性能不够好)。但是,每次我尝试调用eglSwapBuffers(),它都会因EGL\u BAD\u SURFACE而失败,因此,dequeueOutputBuffer()总是返回-1(INFO\u请稍后重试) 我已经看过Bigflake和Grafika上的例子,我还有一个工作项目,一切正常,但我需要在另一个稍微不同的设置中工作 我目前有一个GLSURFACHEVIEW,它可以进行屏幕渲染,并提供了一个自定

我正在尝试使用MediaCodec和Surfaces对电影进行编码(像素缓冲模式可以工作,但性能不够好)。但是,每次我尝试调用
eglSwapBuffers()
,它都会因
EGL\u BAD\u SURFACE
而失败,因此,
dequeueOutputBuffer()
总是返回-1(
INFO\u请稍后重试

我已经看过Bigflake和Grafika上的例子,我还有一个工作项目,一切正常,但我需要在另一个稍微不同的设置中工作

我目前有一个GLSURFACHEVIEW,它可以进行屏幕渲染,并提供了一个自定义的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];
    }
现在,我尝试简化场景,因此当开始录制时,我初始化MediaCodec的一个实例作为编码器,并在GLSurfaceView的线程上调用
createInputSurface()
。创建曲面后,我将其转换为EGLSurface(EGL14),如下所示:

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;
    }
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");
    }
当一个新的帧从相机到达时,我将它发送到屏幕和另一个处理录制的类。该类只是将其渲染到从MediaCodec的输入表面构建的
EGLSurface
,如下所示:

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;
    }
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\u BAD\u曲面
,我还没有找到进一步调试的方法

更新 我尝试在调用后查询当前曲面,使其成为当前曲面,它总是返回一个格式错误的曲面(从内部看,我可以看到句柄是
0
,查询时总是失败)。看起来,
eglMakeCurrent()
默认设置将曲面绑定到上下文失败


此外,我已经确定这个问题出现在高通芯片(Adreno)上,而不是麒麟芯片上,因此它肯定与本机OpenGL实现有关(这很有趣,因为我一直注意到Adreno在涉及“糟糕”的OpenGL配置时更为宽容)

修复!事实证明,EGL10和EGL14似乎配合得很好,但在某些情况下会以非常微妙的方式失败,比如我遇到的那个

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

解决方案是将EGLContextFactory切换为从使用EGL14创建的上下文开始,然后继续使用EGL14创建共享上下文。对于仍然需要EGL10的GLSURFACHEVIEW,我不得不使用黑客

    @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上下文(在我的例子中,它被放入一个堆栈中,稍后再重用)

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