Question

Following the BigFlake example there is a comment that states :

// 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.

I use EGL14.getCurrentContext() to query the current context and pass it into the EGL14.eglCreateContext() share_context parameter, but How do you "switch EGL contexts"?

The GLSurfaceView and MediaCodec.inputSurface have two different surfaces and two different contexts, so I assume you just call eglMakeCurrent() on each set individually, is that correct? Do you need to eglDestroyContext() or eglDestroySurface()?

Added update

Thanks Fadden, I think I figured out this error, instead of drawFrame I was calling drawImage, but you shouldn't have to update the image a second time, right?

Now I am getting an out of memory error glError 1285 when dequeueBuffer is called after EOS has been set??? Maybe I am calling it after the recording has stopped. Thanks for your help.

create EGLSurface in MyEGLWrapper.java

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");
}

In 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();
}

In SurfaceTextureManager.java

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

error in SurfaceTextureManager.java on mSurfaceTexture.updateTexImage();

Was it helpful?

Solution

Yes, use eglMakeCurrent to switch between the two contexts.

You do not need to destroy the contexts or surfaces you're not currently using (until you're shutting things down, anyway).

For an example of rendering twice with a shared context, see the bigflake Breakout game recorder patch.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top