Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java

Issue 1257043004: AppRTCDemo: Render each video in a separate SurfaceView (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: addressing alex's comments Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2014 Google Inc. 3 * Copyright 2014 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 // Create an OpenGL ES 2.0 context. 95 // Create an OpenGL ES 2.0 context.
96 surface.setPreserveEGLContextOnPause(true); 96 surface.setPreserveEGLContextOnPause(true);
97 surface.setEGLContextClientVersion(2); 97 surface.setEGLContextClientVersion(2);
98 surface.setRenderer(this); 98 surface.setRenderer(this);
99 surface.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 99 surface.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
100 100
101 yuvImageRenderers = new ArrayList<YuvImageRenderer>(); 101 yuvImageRenderers = new ArrayList<YuvImageRenderer>();
102 } 102 }
103 103
104 /** 104 /**
105 * Each scaling type has a one-to-one correspondence to a numeric minimum frac tion of the video
106 * that must remain visible.
107 */
108 public static float convertScalingTypeToVisibleFraction(ScalingType scalingTyp e) {
AlexG 2015/08/05 00:47:11 I think these helpers need to me moved to a separa
magjed_webrtc 2015/08/07 17:14:50 Done.
109 switch (scalingType) {
110 case SCALE_ASPECT_FIT:
111 return 1.0f;
112 case SCALE_ASPECT_FILL:
113 return 0.0f;
114 case SCALE_ASPECT_BALANCED:
115 return BALANCED_VISIBLE_FRACTION;
116 default:
117 throw new IllegalArgumentException();
118 }
119 }
120
121 /**
122 * Calculates display size based on minimum fraction of the video that must re main visible,
123 * video aspect ratio, and maximum display size.
124 */
125 public static Point getDisplaySize(float minVisibleFraction, float videoAspect Ratio,
126 int maxDisplayWidth, int maxDisplayHeight) {
127 // If there is no constraint on the amount of cropping, fill the allowed dis play area.
128 if (minVisibleFraction == 0 || videoAspectRatio == 0) {
129 return new Point(maxDisplayWidth, maxDisplayHeight);
130 }
131 // Each dimension is constrained on max display size and how much we are all owed to crop.
132 final int width = Math.min(maxDisplayWidth,
133 (int) (maxDisplayHeight / minVisibleFraction * videoAspectRatio));
134 final int height = Math.min(maxDisplayHeight,
135 (int) (maxDisplayWidth / minVisibleFraction / videoAspectRatio));
136 return new Point(width, height);
137 }
138
139 /**
140 * Calculates a texture transformation matrix based on rotation, mirror, and v ideo vs display
141 * aspect ratio.
142 */
143 public static void getTextureMatrix(float[] outputTextureMatrix, float rotatio nDegree,
144 boolean mirror, float videoAspectRatio, float displayAspectRatio) {
145 // The matrix stack is using post-multiplication, which means that matrix op erations:
146 // A; B; C; will end up as A * B * C. When you apply this to a vertex, it wi ll result in:
147 // v' = A * B * C * v, i.e. the last matrix operation is the first thing tha t affects the
148 // vertex. This is the opposite of what you might expect.
149 Matrix.setIdentityM(outputTextureMatrix, 0);
150 // Move coordinates back to [0,1]x[0,1].
151 Matrix.translateM(outputTextureMatrix, 0, 0.5f, 0.5f, 0.0f);
152 // Rotate frame clockwise in the XY-plane (around the Z-axis).
153 Matrix.rotateM(outputTextureMatrix, 0, -rotationDegree, 0, 0, 1);
154 // Scale one dimension until video and display size have same aspect ratio.
155 if (displayAspectRatio > videoAspectRatio) {
156 Matrix.scaleM(outputTextureMatrix, 0, 1, videoAspectRatio / displayAspectR atio, 1);
157 } else {
158 Matrix.scaleM(outputTextureMatrix, 0, displayAspectRatio / videoAspectRati o, 1, 1);
159 }
160 // TODO(magjed): We currently ignore the texture transform matrix from the S urfaceTexture.
161 // It contains a vertical flip that is hardcoded here instead.
162 Matrix.scaleM(outputTextureMatrix, 0, 1, -1, 1);
163 // Apply optional horizontal flip.
164 if (mirror) {
165 Matrix.scaleM(outputTextureMatrix, 0, -1, 1, 1);
166 }
167 // Center coordinates around origin.
168 Matrix.translateM(outputTextureMatrix, 0, -0.5f, -0.5f, 0.0f);
169 }
170
171 /**
105 * Class used to display stream of YUV420 frames at particular location 172 * Class used to display stream of YUV420 frames at particular location
106 * on a screen. New video frames are sent to display using renderFrame() 173 * on a screen. New video frames are sent to display using renderFrame()
107 * call. 174 * call.
108 */ 175 */
109 private static class YuvImageRenderer implements VideoRenderer.Callbacks { 176 private static class YuvImageRenderer implements VideoRenderer.Callbacks {
110 private GLSurfaceView surface; 177 private GLSurfaceView surface;
111 private int id; 178 private int id;
112 private int[] yuvTextures = { -1, -1, -1 }; 179 private int[] yuvTextures = { -1, -1, -1 };
113 private int oesTexture = -1; 180 private int oesTexture = -1;
114 181
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, 259 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
193 GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 260 GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
194 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, 261 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
195 GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 262 GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
196 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, 263 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
197 GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 264 GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
198 } 265 }
199 GlUtil.checkNoGLES2Error("y/u/v glGenTextures"); 266 GlUtil.checkNoGLES2Error("y/u/v glGenTextures");
200 } 267 }
201 268
202 private static float convertScalingTypeToVisibleFraction(ScalingType scaling Type) {
203 switch (scalingType) {
204 case SCALE_ASPECT_FIT:
205 return 1.0f;
206 case SCALE_ASPECT_FILL:
207 return 0.0f;
208 case SCALE_ASPECT_BALANCED:
209 return BALANCED_VISIBLE_FRACTION;
210 default:
211 throw new IllegalArgumentException();
212 }
213 }
214
215 private static Point getDisplaySize(float minVisibleFraction, float videoAsp ectRatio,
216 int maxDisplayWidth, int maxDisplayHeight) {
217 // If there is no constraint on the amount of cropping, fill the allowed d isplay area.
218 if (minVisibleFraction == 0) {
219 return new Point(maxDisplayWidth, maxDisplayHeight);
220 }
221 // Each dimension is constrained on max display size and how much we are a llowed to crop.
222 final int width = Math.min(maxDisplayWidth,
223 (int) (maxDisplayHeight / minVisibleFraction * videoAspectRatio));
224 final int height = Math.min(maxDisplayHeight,
225 (int) (maxDisplayWidth / minVisibleFraction / videoAspectRatio));
226 return new Point(width, height);
227 }
228
229 private void checkAdjustTextureCoords() { 269 private void checkAdjustTextureCoords() {
230 synchronized(updateTextureLock) { 270 synchronized(updateTextureLock) {
231 if (!updateTextureProperties) { 271 if (!updateTextureProperties) {
232 return; 272 return;
233 } 273 }
234 // Initialize to maximum allowed area. Round to integer coordinates inwa rds the layout 274 // Initialize to maximum allowed area. Round to integer coordinates inwa rds the layout
235 // bounding box (ceil left/top and floor right/bottom) to not break cons traints. 275 // bounding box (ceil left/top and floor right/bottom) to not break cons traints.
236 displayLayout.set( 276 displayLayout.set(
237 (screenWidth * layoutInPercentage.left + 99) / 100, 277 (screenWidth * layoutInPercentage.left + 99) / 100,
238 (screenHeight * layoutInPercentage.top + 99) / 100, 278 (screenHeight * layoutInPercentage.top + 99) / 100,
239 (screenWidth * layoutInPercentage.right) / 100, 279 (screenWidth * layoutInPercentage.right) / 100,
240 (screenHeight * layoutInPercentage.bottom) / 100); 280 (screenHeight * layoutInPercentage.bottom) / 100);
241 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size: " 281 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size: "
242 + displayLayout.width() + " x " + displayLayout.height() + ". Video: " + videoWidth 282 + displayLayout.width() + " x " + displayLayout.height() + ". Video: " + videoWidth
243 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror: " + mirror); 283 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror: " + mirror);
244 final float videoAspectRatio = (rotationDegree % 180 == 0) 284 final float videoAspectRatio = (rotationDegree % 180 == 0)
245 ? (float) videoWidth / videoHeight 285 ? (float) videoWidth / videoHeight
246 : (float) videoHeight / videoWidth; 286 : (float) videoHeight / videoWidth;
247 // Adjust display size based on |scalingType|. 287 // Adjust display size based on |scalingType|.
248 final float minVisibleFraction = convertScalingTypeToVisibleFraction(sca lingType); 288 final float minVisibleFraction = convertScalingTypeToVisibleFraction(sca lingType);
249 final Point displaySize = getDisplaySize(minVisibleFraction, videoAspect Ratio, 289 final Point displaySize = getDisplaySize(minVisibleFraction, videoAspect Ratio,
250 displayLayout.width(), displayLayout.height()); 290 displayLayout.width(), displayLayout.height());
251 displayLayout.inset((displayLayout.width() - displaySize.x) / 2, 291 displayLayout.inset((displayLayout.width() - displaySize.x) / 2,
252 (displayLayout.height() - displaySize.y) / 2); 292 (displayLayout.height() - displaySize.y) / 2);
253 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x " 293 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x "
254 + displayLayout.height()); 294 + displayLayout.height());
255 // The matrix stack is using post-multiplication, which means that matri x operations: 295 getTextureMatrix(texMatrix, rotationDegree, mirror, videoAspectRatio,
256 // A; B; C; will end up as A * B * C. When you apply this to a vertex, i t will result in: 296 (float) displayLayout.width() / displayLayout.height());
257 // v' = A * B * C * v, i.e. the last matrix operation is the first thing that affects the
258 // vertex. This is the opposite of what you might expect.
259 Matrix.setIdentityM(texMatrix, 0);
260 // Move coordinates back to [0,1]x[0,1].
261 Matrix.translateM(texMatrix, 0, 0.5f, 0.5f, 0.0f);
262 // Rotate frame clockwise in the XY-plane (around the Z-axis).
263 Matrix.rotateM(texMatrix, 0, -rotationDegree, 0, 0, 1);
264 // Scale one dimension until video and display size have same aspect rat io.
265 final float displayAspectRatio = (float) displayLayout.width() / display Layout.height();
266 if (displayAspectRatio > videoAspectRatio) {
267 Matrix.scaleM(texMatrix, 0, 1, videoAspectRatio / displayAspectRatio , 1);
268 } else {
269 Matrix.scaleM(texMatrix, 0, displayAspectRatio / videoAspectRatio, 1 , 1);
270 }
271 // TODO(magjed): We currently ignore the texture transform matrix from t he SurfaceTexture.
272 // It contains a vertical flip that is hardcoded here instead.
273 Matrix.scaleM(texMatrix, 0, 1, -1, 1);
274 // Apply optional horizontal flip.
275 if (mirror) {
276 Matrix.scaleM(texMatrix, 0, -1, 1, 1);
277 }
278 // Center coordinates around origin.
279 Matrix.translateM(texMatrix, 0, -0.5f, -0.5f, 0.0f);
280 updateTextureProperties = false; 297 updateTextureProperties = false;
281 Log.d(TAG, " AdjustTextureCoords done"); 298 Log.d(TAG, " AdjustTextureCoords done");
282 } 299 }
283 } 300 }
284 301
285 private void draw(GlRectDrawer drawer) { 302 private void draw(GlRectDrawer drawer) {
286 if (!seenFrame) { 303 if (!seenFrame) {
287 // No frame received yet - nothing to render. 304 // No frame received yet - nothing to render.
288 return; 305 return;
289 } 306 }
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 425
409 this.videoWidth = videoWidth; 426 this.videoWidth = videoWidth;
410 this.videoHeight = videoHeight; 427 this.videoHeight = videoHeight;
411 rotationDegree = rotation; 428 rotationDegree = rotation;
412 int[] strides = { videoWidth, videoWidth / 2, videoWidth / 2 }; 429 int[] strides = { videoWidth, videoWidth / 2, videoWidth / 2 };
413 430
414 // Clear rendering queue. 431 // Clear rendering queue.
415 frameToRenderQueue.poll(); 432 frameToRenderQueue.poll();
416 // Re-allocate / allocate the frame. 433 // Re-allocate / allocate the frame.
417 yuvFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDegree , 434 yuvFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDegree ,
418 strides, null); 435 strides, null, 0);
419 textureFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDe gree, 436 textureFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDe gree,
420 null, -1); 437 null, -1, 0);
421 updateTextureProperties = true; 438 updateTextureProperties = true;
422 Log.d(TAG, " YuvImageRenderer.setSize done."); 439 Log.d(TAG, " YuvImageRenderer.setSize done.");
423 } 440 }
424 } 441 }
425 442
426 @Override 443 @Override
427 public synchronized void renderFrame(I420Frame frame) { 444 public synchronized void renderFrame(I420Frame frame) {
428 setSize(frame.width, frame.height, frame.rotationDegree); 445 setSize(frame.width, frame.height, frame.rotationDegree);
429 long now = System.nanoTime(); 446 long now = System.nanoTime();
430 framesReceived++; 447 framesReceived++;
431 // Skip rendering of this frame if setSize() was not called. 448 // Skip rendering of this frame if setSize() was not called.
432 if (yuvFrameToRender == null || textureFrameToRender == null) { 449 if (yuvFrameToRender == null || textureFrameToRender == null) {
433 framesDropped++; 450 framesDropped++;
451 VideoRenderer.renderFrameDone(frame);
434 return; 452 return;
435 } 453 }
436 // Check input frame parameters. 454 // Check input frame parameters.
437 if (frame.yuvFrame) { 455 if (frame.yuvFrame) {
438 if (frame.yuvStrides[0] < frame.width || 456 if (frame.yuvStrides[0] < frame.width ||
439 frame.yuvStrides[1] < frame.width / 2 || 457 frame.yuvStrides[1] < frame.width / 2 ||
440 frame.yuvStrides[2] < frame.width / 2) { 458 frame.yuvStrides[2] < frame.width / 2) {
441 Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " + 459 Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " +
442 frame.yuvStrides[1] + ", " + frame.yuvStrides[2]); 460 frame.yuvStrides[1] + ", " + frame.yuvStrides[2]);
461 VideoRenderer.renderFrameDone(frame);
443 return; 462 return;
444 } 463 }
445 // Check incoming frame dimensions. 464 // Check incoming frame dimensions.
446 if (frame.width != yuvFrameToRender.width || 465 if (frame.width != yuvFrameToRender.width ||
447 frame.height != yuvFrameToRender.height) { 466 frame.height != yuvFrameToRender.height) {
448 throw new RuntimeException("Wrong frame size " + 467 throw new RuntimeException("Wrong frame size " +
449 frame.width + " x " + frame.height); 468 frame.width + " x " + frame.height);
450 } 469 }
451 } 470 }
452 471
453 if (frameToRenderQueue.size() > 0) { 472 if (frameToRenderQueue.size() > 0) {
454 // Skip rendering of this frame if previous frame was not rendered yet. 473 // Skip rendering of this frame if previous frame was not rendered yet.
455 framesDropped++; 474 framesDropped++;
475 VideoRenderer.renderFrameDone(frame);
456 return; 476 return;
457 } 477 }
458 478
459 // Create a local copy of the frame. 479 // Create a local copy of the frame.
460 if (frame.yuvFrame) { 480 if (frame.yuvFrame) {
461 yuvFrameToRender.copyFrom(frame); 481 yuvFrameToRender.copyFrom(frame);
462 rendererType = RendererType.RENDERER_YUV; 482 rendererType = RendererType.RENDERER_YUV;
463 frameToRenderQueue.offer(yuvFrameToRender); 483 frameToRenderQueue.offer(yuvFrameToRender);
464 } else { 484 } else {
465 textureFrameToRender.copyFrom(frame); 485 textureFrameToRender.copyFrom(frame);
466 rendererType = RendererType.RENDERER_TEXTURE; 486 rendererType = RendererType.RENDERER_TEXTURE;
467 frameToRenderQueue.offer(textureFrameToRender); 487 frameToRenderQueue.offer(textureFrameToRender);
468 } 488 }
469 copyTimeNs += (System.nanoTime() - now); 489 copyTimeNs += (System.nanoTime() - now);
470 seenFrame = true; 490 seenFrame = true;
491 VideoRenderer.renderFrameDone(frame);
471 492
472 // Request rendering. 493 // Request rendering.
473 surface.requestRender(); 494 surface.requestRender();
474 } 495 }
475 496
476 // TODO(guoweis): Remove this once chrome code base is updated. 497 // TODO(guoweis): Remove this once chrome code base is updated.
477 @Override 498 @Override
478 public boolean canApplyRotation() { 499 public boolean canApplyRotation() {
479 return true; 500 return true;
480 } 501 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 GLES20.glViewport(0, 0, screenWidth, screenHeight); 655 GLES20.glViewport(0, 0, screenWidth, screenHeight);
635 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 656 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
636 synchronized (yuvImageRenderers) { 657 synchronized (yuvImageRenderers) {
637 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { 658 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) {
638 yuvImageRenderer.draw(drawer); 659 yuvImageRenderer.draw(drawer);
639 } 660 }
640 } 661 }
641 } 662 }
642 663
643 } 664 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698