summaryrefslogtreecommitdiff
path: root/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
diff options
context:
space:
mode:
authorPrimiano Tucci <primiano@google.com>2014-09-30 14:46:33 +0100
committerPrimiano Tucci <primiano@google.com>2014-09-30 14:46:33 +0100
commitda0509e3087cc5ee9adc0fe1abb85112ea6529a5 (patch)
tree532416c2f3025131e902ab655f3d404945485a6b /app/webrtc/java/android/org/webrtc/VideoRendererGui.java
parent67bbc8e3efef31646fec91b0b422a78708a3f4aa (diff)
parent6fd722a3e5cdf933ad206ec7cd697ce95a5630cd (diff)
downloadtalk-da0509e3087cc5ee9adc0fe1abb85112ea6529a5.tar.gz
This commit was generated by merge_to_master.py. Change-Id: I3cccc8f04ad0036aecdb7eefe316a059ebcefaf9
Diffstat (limited to 'app/webrtc/java/android/org/webrtc/VideoRendererGui.java')
-rw-r--r--app/webrtc/java/android/org/webrtc/VideoRendererGui.java420
1 files changed, 323 insertions, 97 deletions
diff --git a/app/webrtc/java/android/org/webrtc/VideoRendererGui.java b/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
index 439f942..af625c0 100644
--- a/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
+++ b/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
@@ -37,6 +37,10 @@ import java.util.concurrent.LinkedBlockingQueue;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import android.graphics.SurfaceTexture;
+import android.opengl.EGL14;
+import android.opengl.EGLContext;
+import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.Log;
@@ -54,14 +58,28 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
private static VideoRendererGui instance = null;
private static final String TAG = "VideoRendererGui";
private GLSurfaceView surface;
+ private static EGLContext eglContext = null;
// Indicates if SurfaceView.Renderer.onSurfaceCreated was called.
// If true then for every newly created yuv image renderer createTexture()
// should be called. The variable is accessed on multiple threads and
// all accesses are synchronized on yuvImageRenderers' object lock.
private boolean onSurfaceCreatedCalled;
+ private int screenWidth;
+ private int screenHeight;
// List of yuv renderers.
private ArrayList<YuvImageRenderer> yuvImageRenderers;
- private int program;
+ private int yuvProgram;
+ private int oesProgram;
+ // Types of video scaling:
+ // SCALE_ASPECT_FIT - video frame is scaled to fit the size of the view by
+ // maintaining the aspect ratio (black borders may be displayed).
+ // SCALE_ASPECT_FILL - video frame is scaled to fill the size of the view by
+ // maintaining the aspect ratio. Some portion of the video frame may be
+ // clipped.
+ // SCALE_FILL - video frame is scaled to to fill the size of the view. Video
+ // aspect ratio is changed if necessary.
+ private static enum ScalingType
+ { SCALE_ASPECT_FIT, SCALE_ASPECT_FILL, SCALE_FILL };
private final String VERTEX_SHADER_STRING =
"varying vec2 interp_tc;\n" +
@@ -73,7 +91,7 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
" interp_tc = in_tc;\n" +
"}\n";
- private final String FRAGMENT_SHADER_STRING =
+ private final String YUV_FRAGMENT_SHADER_STRING =
"precision mediump float;\n" +
"varying vec2 interp_tc;\n" +
"\n" +
@@ -91,6 +109,19 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
" y + 1.77 * u, 1);\n" +
"}\n";
+
+ private static final String OES_FRAGMENT_SHADER_STRING =
+ "#extension GL_OES_EGL_image_external : require\n" +
+ "precision mediump float;\n" +
+ "varying vec2 interp_tc;\n" +
+ "\n" +
+ "uniform samplerExternalOES oes_tex;\n" +
+ "\n" +
+ "void main() {\n" +
+ " gl_FragColor = texture2D(oes_tex, interp_tc);\n" +
+ "}\n";
+
+
private VideoRendererGui(GLSurfaceView surface) {
this.surface = surface;
// Create an OpenGL ES 2.0 context.
@@ -124,23 +155,46 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
return buffer;
}
- // Compile & attach a |type| shader specified by |source| to |program|.
- private static void addShaderTo(
- int type, String source, int program) {
+ private int loadShader(int shaderType, String source) {
int[] result = new int[] {
GLES20.GL_FALSE
};
- int shader = GLES20.glCreateShader(type);
+ int shader = GLES20.glCreateShader(shaderType);
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, result, 0);
- abortUnless(result[0] == GLES20.GL_TRUE,
- GLES20.glGetShaderInfoLog(shader) + ", source: " + source);
- GLES20.glAttachShader(program, shader);
- GLES20.glDeleteShader(shader);
+ if (result[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not compile shader " + shaderType + ":" +
+ GLES20.glGetShaderInfoLog(shader));
+ throw new RuntimeException(GLES20.glGetShaderInfoLog(shader));
+ }
+ checkNoGLES2Error();
+ return shader;
+}
+
+ private int createProgram(String vertexSource, String fragmentSource) {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+ int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+ int program = GLES20.glCreateProgram();
+ if (program == 0) {
+ throw new RuntimeException("Could not create program");
+ }
+ GLES20.glAttachShader(program, vertexShader);
+ GLES20.glAttachShader(program, fragmentShader);
+ GLES20.glLinkProgram(program);
+ int[] linkStatus = new int[] {
+ GLES20.GL_FALSE
+ };
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: " +
+ GLES20.glGetProgramInfoLog(program));
+ throw new RuntimeException(GLES20.glGetProgramInfoLog(program));
+ }
checkNoGLES2Error();
- }
+ return program;
+}
/**
* Class used to display stream of YUV420 frames at particular location
@@ -149,9 +203,12 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
*/
private static class YuvImageRenderer implements VideoRenderer.Callbacks {
private GLSurfaceView surface;
- private int program;
- private FloatBuffer textureVertices;
+ private int id;
+ private int yuvProgram;
+ private int oesProgram;
private int[] yuvTextures = { -1, -1, -1 };
+ private int oesTexture = -1;
+ private float[] stMatrix = new float[16];
// Render frame queue - accessed by two threads. renderFrame() call does
// an offer (writing I420Frame to render) and early-returns (recording
@@ -159,8 +216,13 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
// copies frame to texture and then removes it from a queue using poll().
LinkedBlockingQueue<I420Frame> frameToRenderQueue;
// Local copy of incoming video frame.
- private I420Frame frameToRender;
- // Flag if renderFrame() was ever called
+ private I420Frame yuvFrameToRender;
+ private I420Frame textureFrameToRender;
+ // Type of video frame used for recent frame rendering.
+ private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE };
+ private RendererType rendererType;
+ private ScalingType scalingType;
+ // Flag if renderFrame() was ever called.
boolean seenFrame;
// Total number of video frames received in renderFrame() call.
private int framesReceived;
@@ -174,40 +236,68 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
// Time in ns spent in draw() function.
private long drawTimeNs;
// Time in ns spent in renderFrame() function - including copying frame
- // data to rendering planes
+ // data to rendering planes.
private long copyTimeNs;
-
- // Texture Coordinates mapping the entire texture.
- private final FloatBuffer textureCoords = directNativeFloatBuffer(
- new float[] {
- 0, 0, 0, 1, 1, 0, 1, 1
- });
+ // Texture vertices.
+ private float texLeft;
+ private float texRight;
+ private float texTop;
+ private float texBottom;
+ private FloatBuffer textureVertices;
+ // Texture UV coordinates offsets.
+ private float texOffsetU;
+ private float texOffsetV;
+ private FloatBuffer textureCoords;
+ // Flag if texture vertices or coordinates update is needed.
+ private boolean updateTextureProperties;
+ // Viewport dimensions.
+ private int screenWidth;
+ private int screenHeight;
+ // Video dimension.
+ private int videoWidth;
+ private int videoHeight;
private YuvImageRenderer(
- GLSurfaceView surface,
- int x, int y, int width, int height) {
- Log.v(TAG, "YuvImageRenderer.Create");
+ GLSurfaceView surface, int id,
+ int x, int y, int width, int height,
+ ScalingType scalingType) {
+ Log.d(TAG, "YuvImageRenderer.Create id: " + id);
this.surface = surface;
+ this.id = id;
+ this.scalingType = scalingType;
frameToRenderQueue = new LinkedBlockingQueue<I420Frame>(1);
// Create texture vertices.
- float xLeft = (x - 50) / 50.0f;
- float yTop = (50 - y) / 50.0f;
- float xRight = Math.min(1.0f, (x + width - 50) / 50.0f);
- float yBottom = Math.max(-1.0f, (50 - y - height) / 50.0f);
+ texLeft = (x - 50) / 50.0f;
+ texTop = (50 - y) / 50.0f;
+ texRight = Math.min(1.0f, (x + width - 50) / 50.0f);
+ texBottom = Math.max(-1.0f, (50 - y - height) / 50.0f);
float textureVeticesFloat[] = new float[] {
- xLeft, yTop,
- xLeft, yBottom,
- xRight, yTop,
- xRight, yBottom
+ texLeft, texTop,
+ texLeft, texBottom,
+ texRight, texTop,
+ texRight, texBottom
};
textureVertices = directNativeFloatBuffer(textureVeticesFloat);
+ // Create texture UV coordinates.
+ texOffsetU = 0;
+ texOffsetV = 0;
+ float textureCoordinatesFloat[] = new float[] {
+ texOffsetU, texOffsetV, // left top
+ texOffsetU, 1.0f - texOffsetV, // left bottom
+ 1.0f - texOffsetU, texOffsetV, // right top
+ 1.0f - texOffsetU, 1.0f - texOffsetV // right bottom
+ };
+ textureCoords = directNativeFloatBuffer(textureCoordinatesFloat);
+ updateTextureProperties = false;
}
- private void createTextures(int program) {
- Log.v(TAG, " YuvImageRenderer.createTextures");
- this.program = program;
+ private void createTextures(int yuvProgram, int oesProgram) {
+ Log.d(TAG, " YuvImageRenderer.createTextures " + id + " on GL thread:" +
+ Thread.currentThread().getId());
+ this.yuvProgram = yuvProgram;
+ this.oesProgram = oesProgram;
- // Generate 3 texture ids for Y/U/V and place them into |textures|.
+ // Generate 3 texture ids for Y/U/V and place them into |yuvTextures|.
GLES20.glGenTextures(3, yuvTextures, 0);
for (int i = 0; i < 3; i++) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
@@ -226,39 +316,139 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
checkNoGLES2Error();
}
+ private void checkAdjustTextureCoords() {
+ if (!updateTextureProperties ||
+ scalingType == ScalingType.SCALE_FILL) {
+ return;
+ }
+ // Re - calculate texture vertices to preserve video aspect ratio.
+ float texRight = this.texRight;
+ float texLeft = this.texLeft;
+ float texTop = this.texTop;
+ float texBottom = this.texBottom;
+ float displayWidth = (texRight - texLeft) * screenWidth / 2;
+ float displayHeight = (texTop - texBottom) * screenHeight / 2;
+ if (displayWidth > 1 && displayHeight > 1 &&
+ videoWidth > 1 && videoHeight > 1) {
+ float displayAspectRatio = displayWidth / displayHeight;
+ float videoAspectRatio = (float)videoWidth / videoHeight;
+ if (scalingType == ScalingType.SCALE_ASPECT_FIT) {
+ // Need to re-adjust vertices width or height to match video AR.
+ if (displayAspectRatio > videoAspectRatio) {
+ float deltaX = (displayWidth - videoAspectRatio * displayHeight) /
+ instance.screenWidth;
+ texRight -= deltaX;
+ texLeft += deltaX;
+ } else {
+ float deltaY = (displayHeight - displayWidth / videoAspectRatio) /
+ instance.screenHeight;
+ texTop -= deltaY;
+ texBottom += deltaY;
+ }
+ // Re-allocate vertices buffer to adjust to video aspect ratio.
+ float textureVeticesFloat[] = new float[] {
+ texLeft, texTop,
+ texLeft, texBottom,
+ texRight, texTop,
+ texRight, texBottom
+ };
+ textureVertices = directNativeFloatBuffer(textureVeticesFloat);
+ }
+ if (scalingType == ScalingType.SCALE_ASPECT_FILL) {
+ // Need to re-adjust UV coordinates to match display AR.
+ if (displayAspectRatio > videoAspectRatio) {
+ texOffsetV = (1.0f - videoAspectRatio / displayAspectRatio) / 2.0f;
+ } else {
+ texOffsetU = (1.0f - displayAspectRatio / videoAspectRatio) / 2.0f;
+ }
+ // Re-allocate coordinates buffer to adjust to display aspect ratio.
+ float textureCoordinatesFloat[] = new float[] {
+ texOffsetU, texOffsetV, // left top
+ texOffsetU, 1.0f - texOffsetV, // left bottom
+ 1.0f - texOffsetU, texOffsetV, // right top
+ 1.0f - texOffsetU, 1.0f - texOffsetV // right bottom
+ };
+ textureCoords = directNativeFloatBuffer(textureCoordinatesFloat);
+ }
+ }
+ updateTextureProperties = false;
+ }
+
private void draw() {
- long now = System.nanoTime();
if (!seenFrame) {
// No frame received yet - nothing to render.
return;
}
+ // Check if texture vertices/coordinates adjustment is required when
+ // screen orientation changes or video frame size changes.
+ checkAdjustTextureCoords();
+
+ long now = System.nanoTime();
+
I420Frame frameFromQueue;
synchronized (frameToRenderQueue) {
frameFromQueue = frameToRenderQueue.peek();
if (frameFromQueue != null && startTimeNs == -1) {
startTimeNs = now;
}
- for (int i = 0; i < 3; ++i) {
- int w = (i == 0) ? frameToRender.width : frameToRender.width / 2;
- int h = (i == 0) ? frameToRender.height : frameToRender.height / 2;
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]);
+
+ if (rendererType == RendererType.RENDERER_YUV) {
+ // YUV textures rendering.
+ GLES20.glUseProgram(yuvProgram);
+
+ for (int i = 0; i < 3; ++i) {
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]);
+ if (frameFromQueue != null) {
+ int w = (i == 0) ?
+ frameFromQueue.width : frameFromQueue.width / 2;
+ int h = (i == 0) ?
+ frameFromQueue.height : frameFromQueue.height / 2;
+ GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
+ w, h, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
+ frameFromQueue.yuvPlanes[i]);
+ }
+ }
+ } else {
+ // External texture rendering.
+ GLES20.glUseProgram(oesProgram);
+
if (frameFromQueue != null) {
- GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
- w, h, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
- frameFromQueue.yuvPlanes[i]);
+ oesTexture = frameFromQueue.textureId;
+ if (frameFromQueue.textureObject instanceof SurfaceTexture) {
+ SurfaceTexture surfaceTexture =
+ (SurfaceTexture) frameFromQueue.textureObject;
+ surfaceTexture.updateTexImage();
+ surfaceTexture.getTransformMatrix(stMatrix);
+ }
}
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, oesTexture);
}
+
if (frameFromQueue != null) {
frameToRenderQueue.poll();
}
}
- int posLocation = GLES20.glGetAttribLocation(program, "in_pos");
+
+ if (rendererType == RendererType.RENDERER_YUV) {
+ GLES20.glUniform1i(GLES20.glGetUniformLocation(yuvProgram, "y_tex"), 0);
+ GLES20.glUniform1i(GLES20.glGetUniformLocation(yuvProgram, "u_tex"), 1);
+ GLES20.glUniform1i(GLES20.glGetUniformLocation(yuvProgram, "v_tex"), 2);
+ }
+
+ int posLocation = GLES20.glGetAttribLocation(yuvProgram, "in_pos");
+ if (posLocation == -1) {
+ throw new RuntimeException("Could not get attrib location for in_pos");
+ }
GLES20.glEnableVertexAttribArray(posLocation);
GLES20.glVertexAttribPointer(
posLocation, 2, GLES20.GL_FLOAT, false, 0, textureVertices);
- int texLocation = GLES20.glGetAttribLocation(program, "in_tc");
+ int texLocation = GLES20.glGetAttribLocation(yuvProgram, "in_tc");
+ if (texLocation == -1) {
+ throw new RuntimeException("Could not get attrib location for in_tc");
+ }
GLES20.glEnableVertexAttribArray(texLocation);
GLES20.glVertexAttribPointer(
texLocation, 2, GLES20.GL_FLOAT, false, 0, textureCoords);
@@ -281,29 +471,41 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
private void logStatistics() {
long timeSinceFirstFrameNs = System.nanoTime() - startTimeNs;
- Log.v(TAG, "Frames received: " + framesReceived + ". Dropped: " +
- framesDropped + ". Rendered: " + framesRendered);
+ Log.d(TAG, "ID: " + id + ". Type: " + rendererType +
+ ". Frames received: " + framesReceived +
+ ". Dropped: " + framesDropped + ". Rendered: " + framesRendered);
if (framesReceived > 0 && framesRendered > 0) {
- Log.v(TAG, "Duration: " + (int)(timeSinceFirstFrameNs / 1e6) +
+ Log.d(TAG, "Duration: " + (int)(timeSinceFirstFrameNs / 1e6) +
" ms. FPS: " + (float)framesRendered * 1e9 / timeSinceFirstFrameNs);
- Log.v(TAG, "Draw time: " +
+ Log.d(TAG, "Draw time: " +
(int) (drawTimeNs / (1000 * framesRendered)) + " us. Copy time: " +
(int) (copyTimeNs / (1000 * framesReceived)) + " us");
}
}
+ public void setScreenSize(final int screenWidth, final int screenHeight) {
+ this.screenWidth = screenWidth;
+ this.screenHeight = screenHeight;
+ updateTextureProperties = true;
+ }
+
@Override
public void setSize(final int width, final int height) {
- Log.v(TAG, "YuvImageRenderer.setSize: " + width + " x " + height);
+ Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " +
+ width + " x " + height);
+ videoWidth = width;
+ videoHeight = height;
int[] strides = { width, width / 2, width / 2 };
// Frame re-allocation need to be synchronized with copying
// frame to textures in draw() function to avoid re-allocating
// the frame while it is being copied.
synchronized (frameToRenderQueue) {
- // Clear rendering queue
+ // Clear rendering queue.
frameToRenderQueue.poll();
- // Re-allocate / allocate the frame
- frameToRender = new I420Frame(width, height, strides, null);
+ // Re-allocate / allocate the frame.
+ yuvFrameToRender = new I420Frame(width, height, strides, null);
+ textureFrameToRender = new I420Frame(width, height, null, -1);
+ updateTextureProperties = true;
}
}
@@ -311,24 +513,26 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
public synchronized void renderFrame(I420Frame frame) {
long now = System.nanoTime();
framesReceived++;
- // Check input frame parameters.
- if (!(frame.yuvStrides[0] == frame.width &&
- frame.yuvStrides[1] == frame.width / 2 &&
- frame.yuvStrides[2] == frame.width / 2)) {
- Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " +
- frame.yuvStrides[1] + ", " + frame.yuvStrides[2]);
- return;
- }
// Skip rendering of this frame if setSize() was not called.
- if (frameToRender == null) {
+ if (yuvFrameToRender == null || textureFrameToRender == null) {
framesDropped++;
return;
}
- // Check incoming frame dimensions
- if (frame.width != frameToRender.width ||
- frame.height != frameToRender.height) {
- throw new RuntimeException("Wrong frame size " +
- frame.width + " x " + frame.height);
+ // Check input frame parameters.
+ if (frame.yuvFrame) {
+ if (!(frame.yuvStrides[0] == frame.width &&
+ frame.yuvStrides[1] == frame.width / 2 &&
+ frame.yuvStrides[2] == frame.width / 2)) {
+ Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " +
+ frame.yuvStrides[1] + ", " + frame.yuvStrides[2]);
+ return;
+ }
+ // Check incoming frame dimensions.
+ if (frame.width != yuvFrameToRender.width ||
+ frame.height != yuvFrameToRender.height) {
+ throw new RuntimeException("Wrong frame size " +
+ frame.width + " x " + frame.height);
+ }
}
if (frameToRenderQueue.size() > 0) {
@@ -336,20 +540,36 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
framesDropped++;
return;
}
- frameToRender.copyFrom(frame);
+
+ // Create a local copy of the frame.
+ if (frame.yuvFrame) {
+ yuvFrameToRender.copyFrom(frame);
+ rendererType = RendererType.RENDERER_YUV;
+ frameToRenderQueue.offer(yuvFrameToRender);
+ } else {
+ textureFrameToRender.copyFrom(frame);
+ rendererType = RendererType.RENDERER_TEXTURE;
+ frameToRenderQueue.offer(textureFrameToRender);
+ }
copyTimeNs += (System.nanoTime() - now);
- frameToRenderQueue.offer(frameToRender);
seenFrame = true;
+
+ // Request rendering.
surface.requestRender();
}
+
}
/** Passes GLSurfaceView to video renderer. */
public static void setView(GLSurfaceView surface) {
- Log.v(TAG, "VideoRendererGui.setView");
+ Log.d(TAG, "VideoRendererGui.setView");
instance = new VideoRendererGui(surface);
}
+ public static EGLContext getEGLContext() {
+ return eglContext;
+ }
+
/**
* Creates VideoRenderer with top left corner at (x, y) and resolution
* (width, height). All parameters are in percentage of screen resolution.
@@ -360,6 +580,11 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
return new VideoRenderer(javaGuiRenderer);
}
+ public static VideoRenderer.Callbacks createGuiRenderer(
+ int x, int y, int width, int height) {
+ return create(x, y, width, height);
+ }
+
/**
* Creates VideoRenderer.Callbacks with top left corner at (x, y) and
* resolution (width, height). All parameters are in percentage of
@@ -379,7 +604,8 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
"Attempt to create yuv renderer before setting GLSurfaceView");
}
final YuvImageRenderer yuvImageRenderer = new YuvImageRenderer(
- instance.surface, x, y, width, height);
+ instance.surface, instance.yuvImageRenderers.size(),
+ x, y, width, height, ScalingType.SCALE_ASPECT_FIT);
synchronized (instance.yuvImageRenderers) {
if (instance.onSurfaceCreatedCalled) {
// onSurfaceCreated has already been called for VideoRendererGui -
@@ -388,7 +614,10 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
final CountDownLatch countDownLatch = new CountDownLatch(1);
instance.surface.queueEvent(new Runnable() {
public void run() {
- yuvImageRenderer.createTextures(instance.program);
+ yuvImageRenderer.createTextures(
+ instance.yuvProgram, instance.oesProgram);
+ yuvImageRenderer.setScreenSize(
+ instance.screenWidth, instance.screenHeight);
countDownLatch.countDown();
}
});
@@ -407,43 +636,40 @@ public class VideoRendererGui implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
- Log.v(TAG, "VideoRendererGui.onSurfaceCreated");
-
- // Create program.
- program = GLES20.glCreateProgram();
- addShaderTo(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_STRING, program);
- addShaderTo(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_STRING, program);
+ Log.d(TAG, "VideoRendererGui.onSurfaceCreated");
+ // Store render EGL context
+ eglContext = EGL14.eglGetCurrentContext();
+ Log.d(TAG, "VideoRendererGui EGL Context: " + eglContext);
- GLES20.glLinkProgram(program);
- int[] result = new int[] {
- GLES20.GL_FALSE
- };
- result[0] = GLES20.GL_FALSE;
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, result, 0);
- abortUnless(result[0] == GLES20.GL_TRUE,
- GLES20.glGetProgramInfoLog(program));
- GLES20.glUseProgram(program);
-
- GLES20.glUniform1i(GLES20.glGetUniformLocation(program, "y_tex"), 0);
- GLES20.glUniform1i(GLES20.glGetUniformLocation(program, "u_tex"), 1);
- GLES20.glUniform1i(GLES20.glGetUniformLocation(program, "v_tex"), 2);
+ // Create YUV and OES programs.
+ yuvProgram = createProgram(VERTEX_SHADER_STRING,
+ YUV_FRAGMENT_SHADER_STRING);
+ oesProgram = createProgram(VERTEX_SHADER_STRING,
+ OES_FRAGMENT_SHADER_STRING);
synchronized (yuvImageRenderers) {
// Create textures for all images.
for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) {
- yuvImageRenderer.createTextures(program);
+ yuvImageRenderer.createTextures(yuvProgram, oesProgram);
}
onSurfaceCreatedCalled = true;
}
checkNoGLES2Error();
- GLES20.glClearColor(0.0f, 0.0f, 0.3f, 1.0f);
+ GLES20.glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
- Log.v(TAG, "VideoRendererGui.onSurfaceChanged: " +
+ Log.d(TAG, "VideoRendererGui.onSurfaceChanged: " +
width + " x " + height + " ");
+ screenWidth = width;
+ screenHeight = height;
GLES20.glViewport(0, 0, width, height);
+ synchronized (yuvImageRenderers) {
+ for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) {
+ yuvImageRenderer.setScreenSize(screenWidth, screenHeight);
+ }
+ }
}
@Override