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

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: Change to updateLayoutMatrix() 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
« no previous file with comments | « talk/app/webrtc/java/android/org/webrtc/RendererCommon.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
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 // Layout properties update lock. Guards |updateLayoutProperties|, |screenWi dth|,
141 private final Object updateTextureLock = new Object(); 142 // |screenHeight|, |videoWidth|, |videoHeight|, |rotationDegree|, |scalingTy pe|, and |mirror|.
143 private final Object updateLayoutLock = new Object();
144 // Texture sampling matrix.
145 private float[] samplingMatrix;
142 // Viewport dimensions. 146 // Viewport dimensions.
143 private int screenWidth; 147 private int screenWidth;
144 private int screenHeight; 148 private int screenHeight;
145 // Video dimension. 149 // Video dimension.
146 private int videoWidth; 150 private int videoWidth;
147 private int videoHeight; 151 private int videoHeight;
148 152
149 // This is the degree that the frame should be rotated clockwisely to have 153 // This is the degree that the frame should be rotated clockwisely to have
150 // it rendered up right. 154 // it rendered up right.
151 private int rotationDegree; 155 private int rotationDegree;
152 156
153 private YuvImageRenderer( 157 private YuvImageRenderer(
154 GLSurfaceView surface, int id, 158 GLSurfaceView surface, int id,
155 int x, int y, int width, int height, 159 int x, int y, int width, int height,
156 RendererCommon.ScalingType scalingType, boolean mirror) { 160 RendererCommon.ScalingType scalingType, boolean mirror) {
157 Log.d(TAG, "YuvImageRenderer.Create id: " + id); 161 Log.d(TAG, "YuvImageRenderer.Create id: " + id);
158 this.surface = surface; 162 this.surface = surface;
159 this.id = id; 163 this.id = id;
160 this.scalingType = scalingType; 164 this.scalingType = scalingType;
161 this.mirror = mirror; 165 this.mirror = mirror;
162 layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100 , y + height)); 166 layoutInPercentage = new Rect(x, y, Math.min(100, x + width), Math.min(100 , y + height));
163 updateTextureProperties = false; 167 updateLayoutProperties = false;
164 rotationDegree = 0; 168 rotationDegree = 0;
165 } 169 }
166 170
167 private synchronized void release() { 171 private synchronized void release() {
168 surface = null; 172 surface = null;
169 synchronized (pendingFrameLock) { 173 synchronized (pendingFrameLock) {
170 if (pendingFrame != null) { 174 if (pendingFrame != null) {
171 VideoRenderer.renderFrameDone(pendingFrame); 175 VideoRenderer.renderFrameDone(pendingFrame);
172 pendingFrame = null; 176 pendingFrame = null;
173 } 177 }
174 } 178 }
175 } 179 }
176 180
177 private void createTextures() { 181 private void createTextures() {
178 Log.d(TAG, " YuvImageRenderer.createTextures " + id + " on GL thread:" + 182 Log.d(TAG, " YuvImageRenderer.createTextures " + id + " on GL thread:" +
179 Thread.currentThread().getId()); 183 Thread.currentThread().getId());
180 184
181 // Generate 3 texture ids for Y/U/V and place them into |yuvTextures|. 185 // Generate 3 texture ids for Y/U/V and place them into |yuvTextures|.
182 for (int i = 0; i < 3; i++) { 186 for (int i = 0; i < 3; i++) {
183 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); 187 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
184 } 188 }
185 } 189 }
186 190
187 private void checkAdjustTextureCoords() { 191 private void updateLayoutMatrix() {
188 synchronized(updateTextureLock) { 192 synchronized(updateLayoutLock) {
189 if (!updateTextureProperties) { 193 if (!updateLayoutProperties) {
190 return; 194 return;
191 } 195 }
192 // Initialize to maximum allowed area. Round to integer coordinates inwa rds the layout 196 // 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. 197 // bounding box (ceil left/top and floor right/bottom) to not break cons traints.
194 displayLayout.set( 198 displayLayout.set(
195 (screenWidth * layoutInPercentage.left + 99) / 100, 199 (screenWidth * layoutInPercentage.left + 99) / 100,
196 (screenHeight * layoutInPercentage.top + 99) / 100, 200 (screenHeight * layoutInPercentage.top + 99) / 100,
197 (screenWidth * layoutInPercentage.right) / 100, 201 (screenWidth * layoutInPercentage.right) / 100,
198 (screenHeight * layoutInPercentage.bottom) / 100); 202 (screenHeight * layoutInPercentage.bottom) / 100);
199 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size: " 203 Log.d(TAG, "ID: " + id + ". AdjustTextureCoords. Allowed display size: "
200 + displayLayout.width() + " x " + displayLayout.height() + ". Video: " + videoWidth 204 + displayLayout.width() + " x " + displayLayout.height() + ". Video: " + videoWidth
201 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror: " + mirror); 205 + " x " + videoHeight + ". Rotation: " + rotationDegree + ". Mirror: " + mirror);
202 final float videoAspectRatio = (rotationDegree % 180 == 0) 206 final float videoAspectRatio = (rotationDegree % 180 == 0)
203 ? (float) videoWidth / videoHeight 207 ? (float) videoWidth / videoHeight
204 : (float) videoHeight / videoWidth; 208 : (float) videoHeight / videoWidth;
205 // Adjust display size based on |scalingType|. 209 // Adjust display size based on |scalingType|.
206 final Point displaySize = RendererCommon.getDisplaySize(scalingType, 210 final Point displaySize = RendererCommon.getDisplaySize(scalingType,
207 videoAspectRatio, displayLayout.width(), displayLayout.height()); 211 videoAspectRatio, displayLayout.width(), displayLayout.height());
208 displayLayout.inset((displayLayout.width() - displaySize.x) / 2, 212 displayLayout.inset((displayLayout.width() - displaySize.x) / 2,
209 (displayLayout.height() - displaySize.y) / 2); 213 (displayLayout.height() - displaySize.y) / 2);
210 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x " 214 Log.d(TAG, " Adjusted display size: " + displayLayout.width() + " x "
211 + displayLayout.height()); 215 + displayLayout.height());
212 RendererCommon.getTextureMatrix(texMatrix, rotationDegree, mirror, video AspectRatio, 216 layoutMatrix = RendererCommon.getLayoutMatrix(
213 (float) displayLayout.width() / displayLayout.height()); 217 mirror, videoAspectRatio, (float) displayLayout.width() / displayLay out.height());
214 updateTextureProperties = false; 218 updateLayoutProperties = false;
215 Log.d(TAG, " AdjustTextureCoords done"); 219 Log.d(TAG, " AdjustTextureCoords done");
216 } 220 }
217 } 221 }
218 222
219 private void draw(GlRectDrawer drawer) { 223 private void draw(GlRectDrawer drawer) {
220 if (!seenFrame) { 224 if (!seenFrame) {
221 // No frame received yet - nothing to render. 225 // No frame received yet - nothing to render.
222 return; 226 return;
223 } 227 }
224 long now = System.nanoTime(); 228 long now = System.nanoTime();
225 229
226 // OpenGL defaults to lower left origin. 230 // OpenGL defaults to lower left origin.
227 GLES20.glViewport(displayLayout.left, screenHeight - displayLayout.bottom, 231 GLES20.glViewport(displayLayout.left, screenHeight - displayLayout.bottom,
228 displayLayout.width(), displayLayout.height()); 232 displayLayout.width(), displayLayout.height());
229 233
230 final boolean isNewFrame; 234 final boolean isNewFrame;
231 synchronized (pendingFrameLock) { 235 synchronized (pendingFrameLock) {
232 // Check if texture vertices/coordinates adjustment is required when
233 // screen orientation changes or video frame size changes.
234 checkAdjustTextureCoords();
235
236 isNewFrame = (pendingFrame != null); 236 isNewFrame = (pendingFrame != null);
237 if (isNewFrame && startTimeNs == -1) { 237 if (isNewFrame && startTimeNs == -1) {
238 startTimeNs = now; 238 startTimeNs = now;
239 } 239 }
240 240
241 if (isNewFrame) { 241 if (isNewFrame) {
242 if (pendingFrame.yuvFrame) { 242 if (pendingFrame.yuvFrame) {
243 rendererType = RendererType.RENDERER_YUV; 243 rendererType = RendererType.RENDERER_YUV;
244 drawer.uploadYuvData(yuvTextures, pendingFrame.width, pendingFrame.h eight, 244 drawer.uploadYuvData(yuvTextures, pendingFrame.width, pendingFrame.h eight,
245 pendingFrame.yuvStrides, pendingFrame.yuvPlanes); 245 pendingFrame.yuvStrides, pendingFrame.yuvPlanes);
246 } else { 246 } else {
247 rendererType = RendererType.RENDERER_TEXTURE; 247 rendererType = RendererType.RENDERER_TEXTURE;
248 // External texture rendering. Copy texture id and update texture im age to latest. 248 // External texture rendering. Copy texture id and update texture im age to latest.
249 // TODO(magjed): We should not make an unmanaged copy of texture id. Also, this is not 249 // TODO(magjed): We should not make an unmanaged copy of texture id. Also, this is not
250 // the best place to call updateTexImage. 250 // the best place to call updateTexImage.
251 oesTexture = pendingFrame.textureId; 251 oesTexture = pendingFrame.textureId;
252 if (pendingFrame.textureObject instanceof SurfaceTexture) { 252 if (pendingFrame.textureObject instanceof SurfaceTexture) {
253 SurfaceTexture surfaceTexture = 253 SurfaceTexture surfaceTexture =
254 (SurfaceTexture) pendingFrame.textureObject; 254 (SurfaceTexture) pendingFrame.textureObject;
255 surfaceTexture.updateTexImage(); 255 surfaceTexture.updateTexImage();
256 } 256 }
257 } 257 }
258 samplingMatrix = RendererCommon.getSamplingMatrix(
259 (SurfaceTexture) pendingFrame.textureObject, pendingFrame.rotation Degree);
258 copyTimeNs += (System.nanoTime() - now); 260 copyTimeNs += (System.nanoTime() - now);
259 VideoRenderer.renderFrameDone(pendingFrame); 261 VideoRenderer.renderFrameDone(pendingFrame);
260 pendingFrame = null; 262 pendingFrame = null;
261 } 263 }
262 } 264 }
263 265
266 updateLayoutMatrix();
267 final float[] texMatrix = new float[16];
268 Matrix.multiplyMM(texMatrix, 0, samplingMatrix, 0, layoutMatrix, 0);
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 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 GLES20.glViewport(0, 0, screenWidth, screenHeight); 586 GLES20.glViewport(0, 0, screenWidth, screenHeight);
582 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 587 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
583 synchronized (yuvImageRenderers) { 588 synchronized (yuvImageRenderers) {
584 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { 589 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) {
585 yuvImageRenderer.draw(drawer); 590 yuvImageRenderer.draw(drawer);
586 } 591 }
587 } 592 }
588 } 593 }
589 594
590 } 595 }
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/android/org/webrtc/RendererCommon.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698