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

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

Issue 1318153007: Android video rendering: Apply SurfaceTexture.getTransformationMatrix() (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 3 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 23 matching lines...) Expand all
34 import javax.microedition.khronos.opengles.GL10; 34 import javax.microedition.khronos.opengles.GL10;
35 35
36 import android.annotation.SuppressLint; 36 import android.annotation.SuppressLint;
37 import android.graphics.Point; 37 import android.graphics.Point;
38 import android.graphics.Rect; 38 import android.graphics.Rect;
39 import android.graphics.SurfaceTexture; 39 import android.graphics.SurfaceTexture;
40 import android.opengl.EGL14; 40 import android.opengl.EGL14;
41 import android.opengl.EGLContext; 41 import android.opengl.EGLContext;
42 import android.opengl.GLES20; 42 import android.opengl.GLES20;
43 import android.opengl.GLSurfaceView; 43 import android.opengl.GLSurfaceView;
44 import android.opengl.Matrix;
44 import android.util.Log; 45 import android.util.Log;
45 46
46 import org.webrtc.VideoRenderer.I420Frame; 47 import org.webrtc.VideoRenderer.I420Frame;
47 48
48 /** 49 /**
49 * Efficiently renders YUV frames using the GPU for CSC. 50 * Efficiently renders YUV frames using the GPU for CSC.
50 * Clients will want first to call setView() to pass GLSurfaceView 51 * Clients will want first to call setView() to pass GLSurfaceView
51 * and then for each video stream either create instance of VideoRenderer using 52 * and then for each video stream either create instance of VideoRenderer using
52 * createGui() call or VideoRenderer.Callbacks interface using create() call. 53 * createGui() call or VideoRenderer.Callbacks interface using create() call.
53 * Only one instance of the class can be created. 54 * Only one instance of the class can be created.
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 // Time in ns spent in draw() function. 127 // Time in ns spent in draw() function.
127 private long drawTimeNs; 128 private long drawTimeNs;
128 // Time in ns spent in draw() copying resources from |pendingFrame| - includ ing uploading frame 129 // Time in ns spent in draw() copying resources from |pendingFrame| - includ ing uploading frame
129 // data to rendering planes. 130 // data to rendering planes.
130 private long copyTimeNs; 131 private long copyTimeNs;
131 // The allowed view area in percentage of screen size. 132 // The allowed view area in percentage of screen size.
132 private final Rect layoutInPercentage; 133 private final Rect layoutInPercentage;
133 // The actual view area in pixels. It is a centered subrectangle of the rect angle defined by 134 // The actual view area in pixels. It is a centered subrectangle of the rect angle defined by
134 // |layoutInPercentage|. 135 // |layoutInPercentage|.
135 private final Rect displayLayout = new Rect(); 136 private final Rect displayLayout = new Rect();
136 // Cached texture transformation matrix, calculated from current layout para meters. 137 // Cached layout transformation matrix, calculated from current layout param eters.
137 private final float[] texMatrix = new float[16]; 138 private float[] layoutMatrix = new float[16];
hbos 2015/09/08 14:08:47 This probably shouldn't be used at all until it ha
magjed_webrtc 2015/09/08 15:24:28 True, I will default to null instead.
hbos 2015/09/09 08:27:54 Acknowledged.
138 // Flag if texture vertices or coordinates update is needed. 139 // Flag if layout transformation matrix update is needed.
139 private boolean updateTextureProperties; 140 private boolean updateLayoutProperties;
140 // Texture properties update lock. 141 // Texture properties update lock.
141 private final Object updateTextureLock = new Object(); 142 private final Object updateLayoutLock = new Object();
hbos 2015/09/08 14:08:47 What variables are guarded by this lock? Can you l
magjed_webrtc 2015/09/08 15:24:28 Done.
143 // Texture sampling matrix.
144 private float[] samplingMatrix;
142 // Viewport dimensions. 145 // Viewport dimensions.
143 private int screenWidth; 146 private int screenWidth;
144 private int screenHeight; 147 private int screenHeight;
145 // Video dimension. 148 // Video dimension.
146 private int videoWidth; 149 private int videoWidth;
147 private int videoHeight; 150 private int videoHeight;
148 151
149 // This is the degree that the frame should be rotated clockwisely to have 152 // This is the degree that the frame should be rotated clockwisely to have
150 // it rendered up right. 153 // it rendered up right.
151 private int rotationDegree; 154 private int rotationDegree;
152 155
153 private YuvImageRenderer( 156 private YuvImageRenderer(
154 GLSurfaceView surface, int id, 157 GLSurfaceView surface, int id,
155 int x, int y, int width, int height, 158 int x, int y, int width, int height,
156 RendererCommon.ScalingType scalingType, boolean mirror) { 159 RendererCommon.ScalingType scalingType, boolean mirror) {
157 Log.d(TAG, "YuvImageRenderer.Create id: " + id); 160 Log.d(TAG, "YuvImageRenderer.Create id: " + id);
158 this.surface = surface; 161 this.surface = surface;
159 this.id = id; 162 this.id = id;
160 this.scalingType = scalingType; 163 this.scalingType = scalingType;
161 this.mirror = mirror; 164 this.mirror = mirror;
162 layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100 , y + height)); 165 layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100 , y + height));
163 updateTextureProperties = false; 166 updateLayoutProperties = false;
164 rotationDegree = 0; 167 rotationDegree = 0;
165 } 168 }
166 169
167 private synchronized void release() { 170 private synchronized void release() {
168 surface = null; 171 surface = null;
169 synchronized (pendingFrameLock) { 172 synchronized (pendingFrameLock) {
170 if (pendingFrame != null) { 173 if (pendingFrame != null) {
171 VideoRenderer.renderFrameDone(pendingFrame); 174 VideoRenderer.renderFrameDone(pendingFrame);
172 pendingFrame = null; 175 pendingFrame = null;
173 } 176 }
174 } 177 }
175 } 178 }
176 179
177 private void createTextures() { 180 private void createTextures() {
178 Log.d(TAG, " YuvImageRenderer.createTextures " + id + " on GL thread:" + 181 Log.d(TAG, " YuvImageRenderer.createTextures " + id + " on GL thread:" +
179 Thread.currentThread().getId()); 182 Thread.currentThread().getId());
180 183
181 // Generate 3 texture ids for Y/U/V and place them into |yuvTextures|. 184 // Generate 3 texture ids for Y/U/V and place them into |yuvTextures|.
182 for (int i = 0; i < 3; i++) { 185 for (int i = 0; i < 3; i++) {
183 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); 186 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
184 } 187 }
185 } 188 }
186 189
187 private void checkAdjustTextureCoords() { 190 private void checkAdjustTextureCoords() {
hbos 2015/09/08 14:08:47 Rename to checkAdjustLayoutMatrix?
magjed_webrtc 2015/09/08 15:24:28 Renamed to getLayoutMatrix() and changed it a bit.
188 synchronized(updateTextureLock) { 191 synchronized(updateLayoutLock) {
189 if (!updateTextureProperties) { 192 if (!updateLayoutProperties) {
190 return; 193 return;
191 } 194 }
192 // Initialize to maximum allowed area. Round to integer coordinates inwa rds the layout 195 // Initialize to maximum allowed area. Round to integer coordinates inwa rds the layout
193 // bounding box (ceil left/top and floor right/bottom) to not break cons traints. 196 // bounding box (ceil left/top and floor right/bottom) to not break cons traints.
194 displayLayout.set( 197 displayLayout.set(
195 (screenWidth * layoutInPercentage.left + 99) / 100, 198 (screenWidth * layoutInPercentage.left + 99) / 100,
196 (screenHeight * layoutInPercentage.top + 99) / 100, 199 (screenHeight * layoutInPercentage.top + 99) / 100,
197 (screenWidth * layoutInPercentage.right) / 100, 200 (screenWidth * layoutInPercentage.right) / 100,
198 (screenHeight * layoutInPercentage.bottom) / 100); 201 (screenHeight * layoutInPercentage.bottom) / 100);
199 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size: " 202 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size: "
200 + displayLayout.width() + " x " + displayLayout.height() + ". Video: " + videoWidth 203 + displayLayout.width() + " x " + displayLayout.height() + ". Video: " + videoWidth
201 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror: " + mirror); 204 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror: " + mirror);
202 final float videoAspectRatio = (rotationDegree % 180 == 0) 205 final float videoAspectRatio = (rotationDegree % 180 == 0)
203 ? (float) videoWidth / videoHeight 206 ? (float) videoWidth / videoHeight
204 : (float) videoHeight / videoWidth; 207 : (float) videoHeight / videoWidth;
205 // Adjust display size based on |scalingType|. 208 // Adjust display size based on |scalingType|.
206 final Point displaySize = RendererCommon.getDisplaySize(scalingType, 209 final Point displaySize = RendererCommon.getDisplaySize(scalingType,
207 videoAspectRatio, displayLayout.width(), displayLayout.height()); 210 videoAspectRatio, displayLayout.width(), displayLayout.height());
208 displayLayout.inset((displayLayout.width() - displaySize.x) / 2, 211 displayLayout.inset((displayLayout.width() - displaySize.x) / 2,
209 (displayLayout.height() - displaySize.y) / 2); 212 (displayLayout.height() - displaySize.y) / 2);
210 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x " 213 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x "
211 + displayLayout.height()); 214 + displayLayout.height());
212 RendererCommon.getTextureMatrix(texMatrix, rotationDegree, mirror, video AspectRatio, 215 layoutMatrix = RendererCommon.getLayoutMatrix(
213 (float) displayLayout.width() / displayLayout.height()); 216 mirror, videoAspectRatio, (float) displayLayout.width() / displayLay out.height());
hbos 2015/09/08 14:08:47 What are the implications of mirroring? I'm thinki
magjed_webrtc 2015/09/08 15:24:28 We need to take care when we multiply matrices tog
hbos 2015/09/09 08:27:54 Acknowledged.
214 updateTextureProperties = false; 217 updateLayoutProperties = false;
215 Log.d(TAG, " AdjustTextureCoords done"); 218 Log.d(TAG, " AdjustTextureCoords done");
216 } 219 }
217 } 220 }
218 221
219 private void draw(GlRectDrawer drawer) { 222 private void draw(GlRectDrawer drawer) {
220 if (!seenFrame) { 223 if (!seenFrame) {
221 // No frame received yet - nothing to render. 224 // No frame received yet - nothing to render.
222 return; 225 return;
223 } 226 }
224 long now = System.nanoTime(); 227 long now = System.nanoTime();
(...skipping 29 matching lines...) Expand all
254 (SurfaceTexture) pendingFrame.textureObject; 257 (SurfaceTexture) pendingFrame.textureObject;
255 surfaceTexture.updateTexImage(); 258 surfaceTexture.updateTexImage();
256 } 259 }
257 } 260 }
258 copyTimeNs += (System.nanoTime() - now); 261 copyTimeNs += (System.nanoTime() - now);
259 VideoRenderer.renderFrameDone(pendingFrame); 262 VideoRenderer.renderFrameDone(pendingFrame);
260 pendingFrame = null; 263 pendingFrame = null;
261 } 264 }
262 } 265 }
263 266
267 final float[] texMatrix = new float[16];
268 Matrix.multiplyMM(texMatrix, 0, samplingMatrix, 0, layoutMatrix, 0);
hbos 2015/09/08 14:08:47 Is reading from samplingMatrix thread-safe without
magjed_webrtc 2015/09/08 15:24:28 Thanks, this is a bug. I moved all usage of |sampl
hbos 2015/09/09 08:27:54 You're still updating and returning a reference to
264 if (rendererType == RendererType.RENDERER_YUV) { 269 if (rendererType == RendererType.RENDERER_YUV) {
265 drawer.drawYuv(yuvTextures, texMatrix); 270 drawer.drawYuv(yuvTextures, texMatrix);
266 } else { 271 } else {
267 drawer.drawOes(oesTexture, texMatrix); 272 drawer.drawOes(oesTexture, texMatrix);
268 } 273 }
269 274
270 if (isNewFrame) { 275 if (isNewFrame) {
271 framesRendered++; 276 framesRendered++;
272 drawTimeNs += (System.nanoTime() - now); 277 drawTimeNs += (System.nanoTime() - now);
273 if ((framesRendered % 300) == 0) { 278 if ((framesRendered % 300) == 0) {
(...skipping 10 matching lines...) Expand all
284 if (framesReceived > 0 && framesRendered > 0) { 289 if (framesReceived > 0 && framesRendered > 0) {
285 Log.d(TAG, "Duration: " + (int)(timeSinceFirstFrameNs / 1e6) + 290 Log.d(TAG, "Duration: " + (int)(timeSinceFirstFrameNs / 1e6) +
286 " ms. FPS: " + (float)framesRendered * 1e9 / timeSinceFirstFrameNs); 291 " ms. FPS: " + (float)framesRendered * 1e9 / timeSinceFirstFrameNs);
287 Log.d(TAG, "Draw time: " + 292 Log.d(TAG, "Draw time: " +
288 (int) (drawTimeNs / (1000 * framesRendered)) + " us. Copy time: " + 293 (int) (drawTimeNs / (1000 * framesRendered)) + " us. Copy time: " +
289 (int) (copyTimeNs / (1000 * framesReceived)) + " us"); 294 (int) (copyTimeNs / (1000 * framesReceived)) + " us");
290 } 295 }
291 } 296 }
292 297
293 public void setScreenSize(final int screenWidth, final int screenHeight) { 298 public void setScreenSize(final int screenWidth, final int screenHeight) {
294 synchronized(updateTextureLock) { 299 synchronized(updateLayoutLock) {
295 if (screenWidth == this.screenWidth && screenHeight == this.screenHeight ) { 300 if (screenWidth == this.screenWidth && screenHeight == this.screenHeight ) {
296 return; 301 return;
297 } 302 }
298 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setScreenSize: " + 303 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setScreenSize: " +
299 screenWidth + " x " + screenHeight); 304 screenWidth + " x " + screenHeight);
300 this.screenWidth = screenWidth; 305 this.screenWidth = screenWidth;
301 this.screenHeight = screenHeight; 306 this.screenHeight = screenHeight;
302 updateTextureProperties = true; 307 updateLayoutProperties = true;
303 } 308 }
304 } 309 }
305 310
306 public void setPosition(int x, int y, int width, int height, 311 public void setPosition(int x, int y, int width, int height,
307 RendererCommon.ScalingType scalingType, boolean mirror) { 312 RendererCommon.ScalingType scalingType, boolean mirror) {
308 final Rect layoutInPercentage = 313 final Rect layoutInPercentage =
309 new Rect(x, y, Math.min(100, x + width), Math.min(100, y + height)); 314 new Rect(x, y, Math.min(100, x + width), Math.min(100, y + height));
310 synchronized(updateTextureLock) { 315 synchronized(updateLayoutLock) {
311 if (layoutInPercentage.equals(this.layoutInPercentage) && scalingType == this.scalingType 316 if (layoutInPercentage.equals(this.layoutInPercentage) && scalingType == this.scalingType
312 && mirror == this.mirror) { 317 && mirror == this.mirror) {
313 return; 318 return;
314 } 319 }
315 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setPosition: (" + x + ", " + y + 320 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setPosition: (" + x + ", " + y +
316 ") " + width + " x " + height + ". Scaling: " + scalingType + 321 ") " + width + " x " + height + ". Scaling: " + scalingType +
317 ". Mirror: " + mirror); 322 ". Mirror: " + mirror);
318 this.layoutInPercentage.set(layoutInPercentage); 323 this.layoutInPercentage.set(layoutInPercentage);
319 this.scalingType = scalingType; 324 this.scalingType = scalingType;
320 this.mirror = mirror; 325 this.mirror = mirror;
321 updateTextureProperties = true; 326 updateLayoutProperties = true;
322 } 327 }
323 } 328 }
324 329
325 private void setSize(final int videoWidth, final int videoHeight, final int rotation) { 330 private void setSize(final int videoWidth, final int videoHeight, final int rotation) {
326 if (videoWidth == this.videoWidth && videoHeight == this.videoHeight 331 if (videoWidth == this.videoWidth && videoHeight == this.videoHeight
327 && rotation == rotationDegree) { 332 && rotation == rotationDegree) {
328 return; 333 return;
329 } 334 }
330 if (rendererEvents != null) { 335 if (rendererEvents != null) {
331 Log.d(TAG, "ID: " + id + 336 Log.d(TAG, "ID: " + id +
332 ". Reporting frame resolution changed to " + videoWidth + " x " + vi deoHeight); 337 ". Reporting frame resolution changed to " + videoWidth + " x " + vi deoHeight);
333 rendererEvents.onFrameResolutionChanged(videoWidth, videoHeight, rotatio n); 338 rendererEvents.onFrameResolutionChanged(videoWidth, videoHeight, rotatio n);
334 } 339 }
335 340
336 synchronized (updateTextureLock) { 341 synchronized (updateLayoutLock) {
337 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " + 342 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " +
338 videoWidth + " x " + videoHeight + " rotation " + rotation); 343 videoWidth + " x " + videoHeight + " rotation " + rotation);
339 344
340 this.videoWidth = videoWidth; 345 this.videoWidth = videoWidth;
341 this.videoHeight = videoHeight; 346 this.videoHeight = videoHeight;
342 rotationDegree = rotation; 347 rotationDegree = rotation;
343 updateTextureProperties = true; 348 updateLayoutProperties = true;
344 Log.d(TAG, " YuvImageRenderer.setSize done."); 349 Log.d(TAG, " YuvImageRenderer.setSize done.");
345 } 350 }
346 } 351 }
347 352
348 @Override 353 @Override
349 public synchronized void renderFrame(I420Frame frame) { 354 public synchronized void renderFrame(I420Frame frame) {
350 if (surface == null) { 355 if (surface == null) {
351 // This object has been released. 356 // This object has been released.
352 VideoRenderer.renderFrameDone(frame); 357 VideoRenderer.renderFrameDone(frame);
353 return; 358 return;
(...skipping 17 matching lines...) Expand all
371 } 376 }
372 377
373 if (pendingFrame != null) { 378 if (pendingFrame != null) {
374 // Skip rendering of this frame if previous frame was not rendered yet . 379 // Skip rendering of this frame if previous frame was not rendered yet .
375 framesDropped++; 380 framesDropped++;
376 VideoRenderer.renderFrameDone(frame); 381 VideoRenderer.renderFrameDone(frame);
377 return; 382 return;
378 } 383 }
379 pendingFrame = frame; 384 pendingFrame = frame;
380 } 385 }
386 samplingMatrix = RendererCommon.getSamplingMatrix(
387 (SurfaceTexture) frame.textureObject, frame.rotationDegree);
381 setSize(frame.width, frame.height, frame.rotationDegree); 388 setSize(frame.width, frame.height, frame.rotationDegree);
382 seenFrame = true; 389 seenFrame = true;
383 390
384 // Request rendering. 391 // Request rendering.
385 surface.requestRender(); 392 surface.requestRender();
386 } 393 }
387 } 394 }
388 395
389 /** Passes GLSurfaceView to video renderer. */ 396 /** Passes GLSurfaceView to video renderer. */
390 public static synchronized void setView(GLSurfaceView surface, 397 public static synchronized void setView(GLSurfaceView surface,
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 GLES20.glViewport(0, 0, screenWidth, screenHeight); 588 GLES20.glViewport(0, 0, screenWidth, screenHeight);
582 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 589 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
583 synchronized (yuvImageRenderers) { 590 synchronized (yuvImageRenderers) {
584 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { 591 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) {
585 yuvImageRenderer.draw(drawer); 592 yuvImageRenderer.draw(drawer);
586 } 593 }
587 } 594 }
588 } 595 }
589 596
590 } 597 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698