| Index: talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
|
| diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
|
| index e15b49fab31f1d9f82cb1cafe7ebd2e3ca425b97..75143578e2587e21dcbfa1b2aaed1cda4b6da06d 100644
|
| --- a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
|
| +++ b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
|
| @@ -99,9 +99,12 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
|
| // |surface| is synchronized on |this|.
|
| private GLSurfaceView surface;
|
| private int id;
|
| - // TODO(magjed): Delete |yuvTextures| in release(). Must be synchronized with draw().
|
| + // TODO(magjed): Delete GL resources in release(). Must be synchronized with draw(). We are
|
| + // currently leaking resources to avoid a rare crash in release() where the EGLContext has
|
| + // become invalid beforehand.
|
| private int[] yuvTextures = { 0, 0, 0 };
|
| - private int oesTexture = 0;
|
| + // Resources for making a deep copy of incoming OES texture frame.
|
| + private GlTextureFrameBuffer textureCopy;
|
|
|
| // Pending frame to render. Serves as a queue with size 1. |pendingFrame| is accessed by two
|
| // threads - frames are received in renderFrame() and consumed in draw(). Frames are dropped in
|
| @@ -187,6 +190,8 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
|
| for (int i = 0; i < 3; i++) {
|
| yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
|
| }
|
| + // Generate texture and framebuffer for offscreen texture copy.
|
| + textureCopy = new GlTextureFrameBuffer(GLES20.GL_RGB);
|
| }
|
|
|
| private void updateLayoutMatrix() {
|
| @@ -228,10 +233,6 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
|
| }
|
| long now = System.nanoTime();
|
|
|
| - // OpenGL defaults to lower left origin.
|
| - GLES20.glViewport(displayLayout.left, screenHeight - displayLayout.bottom,
|
| - displayLayout.width(), displayLayout.height());
|
| -
|
| final boolean isNewFrame;
|
| synchronized (pendingFrameLock) {
|
| isNewFrame = (pendingFrame != null);
|
| @@ -240,42 +241,47 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
|
| }
|
|
|
| if (isNewFrame) {
|
| - final float[] samplingMatrix;
|
| + rotatedSamplingMatrix = RendererCommon.rotateTextureMatrix(
|
| + pendingFrame.samplingMatrix, pendingFrame.rotationDegree);
|
| if (pendingFrame.yuvFrame) {
|
| rendererType = RendererType.RENDERER_YUV;
|
| drawer.uploadYuvData(yuvTextures, pendingFrame.width, pendingFrame.height,
|
| pendingFrame.yuvStrides, pendingFrame.yuvPlanes);
|
| - // The convention in WebRTC is that the first element in a ByteBuffer corresponds to the
|
| - // top-left corner of the image, but in glTexImage2D() the first element corresponds to
|
| - // the bottom-left corner. We correct this discrepancy by setting a vertical flip as
|
| - // sampling matrix.
|
| - samplingMatrix = RendererCommon.verticalFlipMatrix();
|
| } else {
|
| rendererType = RendererType.RENDERER_TEXTURE;
|
| - // External texture rendering. Copy texture id and update texture image to latest.
|
| - // TODO(magjed): We should not make an unmanaged copy of texture id. Also, this is not
|
| - // the best place to call updateTexImage.
|
| - oesTexture = pendingFrame.textureId;
|
| - final SurfaceTexture surfaceTexture = (SurfaceTexture) pendingFrame.textureObject;
|
| - surfaceTexture.updateTexImage();
|
| - samplingMatrix = new float[16];
|
| - surfaceTexture.getTransformMatrix(samplingMatrix);
|
| + // Make a deep copy of the external texture.
|
| + // Reallocate offscreen texture if necessary.
|
| + textureCopy.setSize(pendingFrame.rotatedWidth(), pendingFrame.rotatedHeight());
|
| +
|
| + // Bind our offscreen framebuffer.
|
| + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, textureCopy.getFrameBufferId());
|
| + GlUtil.checkNoGLES2Error("glBindFramebuffer");
|
| +
|
| + // Copy the OES texture content. This will also normalize the sampling matrix.
|
| + GLES20.glViewport(0, 0, textureCopy.getWidth(), textureCopy.getHeight());
|
| + drawer.drawOes(pendingFrame.textureId, rotatedSamplingMatrix);
|
| + rotatedSamplingMatrix = RendererCommon.identityMatrix();
|
| +
|
| + // Restore normal framebuffer.
|
| + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
| }
|
| - rotatedSamplingMatrix = RendererCommon.rotateTextureMatrix(
|
| - samplingMatrix, pendingFrame.rotationDegree);
|
| copyTimeNs += (System.nanoTime() - now);
|
| VideoRenderer.renderFrameDone(pendingFrame);
|
| pendingFrame = null;
|
| }
|
| }
|
|
|
| + // OpenGL defaults to lower left origin - flip vertically.
|
| + GLES20.glViewport(displayLayout.left, screenHeight - displayLayout.bottom,
|
| + displayLayout.width(), displayLayout.height());
|
| +
|
| updateLayoutMatrix();
|
| final float[] texMatrix =
|
| RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix);
|
| if (rendererType == RendererType.RENDERER_YUV) {
|
| drawer.drawYuv(yuvTextures, texMatrix);
|
| } else {
|
| - drawer.drawOes(oesTexture, texMatrix);
|
| + drawer.drawRgb(textureCopy.getTextureId(), texMatrix);
|
| }
|
|
|
| if (isNewFrame) {
|
|
|