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) { |