【问题标题】:How to use MediaMuxer / MediaCodec InputSurface with GLSurfaceView?如何将 MediaMuxer / MediaCodec InputSurface 与 GLSurfaceView 一起使用?
【发布时间】:2013-11-08 09:21:40
【问题描述】:

BigFlake 示例之后,有一条评论指出:

// Acquire a new frame of input, and render it to the Surface.  If we had a
// GLSurfaceView we could switch EGL contexts and call drawImage() a second
// time to render it on screen.  The texture can be shared between contexts by
// passing the GLSurfaceView's EGLContext as eglCreateContext()'s share_context
// argument.

我使用EGL14.getCurrentContext() 查询当前上下文并将其传递给EGL14.eglCreateContext() share_context 参数,但是您如何“切换EGL 上下文”?

GLSurfaceView 和 MediaCodec.inputSurface 有两个不同的表面和两个不同的上下文,所以我假设您只是在每个集合上单独调用 eglMakeCurrent(),对吗?您需要eglDestroyContext() 还是eglDestroySurface()

添加更新

感谢 Fadden,我想我发现了这个错误,而不是我调用 drawImage 的 drawFrame,但您不应该再次更新图像,对吧?

现在我在设置 EOS 后调用 dequeueBuffer 时收到内存不足错误 glError 1285?也许我在录音停止后打电话给它。感谢您的帮助。

在 MyEGLWrapper.java 中创建 EGLSurface

saveToScreenRenderState();
mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], mScreenEglContext, 
        contextAttribs, 0);
checkEglError("eglCreateContext");

// Create a window surface, and attach it to the Surface we received.
mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface,
        surfaceAttribs, 0);
checkEglError("eglCreateWindowSurface");

...

private void saveToScreenRenderState() {
    //System.arraycopy(mProjectionMatrix, 0, mSavedMatrix, 0, mProjectionMatrix.length);
    mScreenEglDisplay = EGL14.eglGetCurrentDisplay();
    mScreenEglDrawSurface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
    mScreenEglReadSurface = EGL14.eglGetCurrentSurface(EGL14.EGL_READ);
    mScreenEglContext = EGL14.eglGetCurrentContext();
}

public void makeCurrent(boolean toScreen, Surface surface) {
    if (toScreen) { //as opposed to toEncoder
        makeScreenSurfaceCurrent();
        return;
    } 
    EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
    checkEglError("eglMakeCurrent");
}

private void makeScreenSurfaceCurrent() {
    EGL14.eglMakeCurrent(mScreenEglDisplay, mScreenEglDrawSurface, 
            mScreenEglReadSurface, mScreenEglContext);
    checkEglError("eglMakeCurrent");
}

在 CaptureManager.java 中

private void drawFrameOnInputSurface() {
    //draw a second time for inputSurface 
    mEGLWrapper.makeCurrent(false, videoCodec.videoCodecInputSurface);
    drawFrame(false);
    //ByteBuffer frame = mStManager.drawImage();
    videoCodec.runQue(false); // clear que before posting should this be on this thread???
    mEGLWrapper.setPresentationTime(mSt.getTimestamp(),!recordingStopped);
    mEGLWrapper.swapBuffers(!recordingStopped);
    videoHandler.post(new Runnable(){
        @Override
        public void run(){
            videoCodec.updateFrame(!isRecording);
        }
    });
}

private void drawFrame(boolean updateImage){
    mStManager.drawImage(updateImage);
    mGLView.mRenderer.drawFrame();
}

在 SurfaceTextureManager.java 中

public ByteBuffer drawImage(boolean updateImage) {
    // Latch the data.
    if (updateImage){
        mTextureRender.checkGlError("before updateTexImage");
        mSurfaceTexture.updateTexImage();
    }
    return mTextureRender.drawFrame(mSurfaceTexture);
}

SurfaceTextureManager.java 中的错误mSurfaceTexture.updateTexImage();

【问题讨论】:

  • FWIW,我在漂亮的simple, straightforward project 中得到了这个工作。一个活动托管 GLSurfaceView,一个类管理所有 MediaCodec 调用。很高兴谈论它。
  • 谢谢,我搞定了。需要一点帮助来为较长的剪辑排列音频,但可以为较短的剪辑录制可播放的 mp4。几周前我构建了你的代码。很好的例子。

标签: java android opengl-es egl android-mediacodec


【解决方案1】:

是的,使用eglMakeCurrent 在两个上下文之间切换。

您无需销毁当前未使用的上下文或表面(无论如何,直到您将其关闭)。

有关使用共享上下文进行两次渲染的示例,请参阅 bigflake Breakout game recorder patch

【讨论】:

  • 非常感谢,我应该看到那个例子。我阅读了您的前两个示例,并在过去一个月的实施中迷失了方向,但它开始融合在一起。现在实际上并不是很复杂,我建议任何从事这些工作的人先阅读EGL。当一切都有意义时,它将节省大量时间。
  • 它没有用,与此答案相反,您对dbro's question 的回答表明您需要销毁并重新创建表面???我应该澄清我希望在屏幕上显示相机预览。最简单或成本最低的方法是什么?有没有办法将textureSurface 复制到另一个上下文拥有的纹理?
  • dbro 的问题是关于 MediaCodec 输入表面的。您不能“重新启动”编码器,并且输入 Surface 绑定到编码器,因此您必须为每个视频片段创建一个新的 MediaCodec + 输入 Surface 对。注意SurfaceEGLSurface不是一回事——前者是Android的概念,后者是OpenGL的概念,在你调用eglCreateWindowSurface()之前,两者是完全不相关的。
  • 我不确定您所说的 textureSurface 是什么意思。使用SurfaceTexture 捕捉相机预览,该帧可用作可用作图像源的“外部纹理”。您需要两个 EGL 上下文,一个用于视频输出,一个用于GLSurfaceView;您想在后者为当前状态时创建前者,并将 eglGetCurrentContext() 传递给 eglCreateContext(),如 Breakout 示例中所示。然后你只需渲染两次,改变上下文,如GameSurfaceRenderer#onDrawFrame() 所示。在同一个线程上执行所有这些操作。观察 logcat 是否有错误。
  • 对不起,我换个说法,我得到了同样的错误,checkAndUpdateEglState: invalid current EGLContext in mSurfaceTexture.updateTexImage(); 代码是 here,但它有点像意大利面。让我用相关代码更新问题。
猜你喜欢
  • 2014-02-13
  • 2015-09-07
  • 1970-01-01
  • 2021-04-26
  • 2014-01-03
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多