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

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

Issue 1343163003: Partial revert of r9936. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@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 2015 Google Inc. 3 * Copyright 2015 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,
11 * this list of conditions and the following disclaimer in the documentation 11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution. 12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products 13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 package org.webrtc; 28 package org.webrtc;
29 29
30 import java.nio.ByteBuffer;
31
32 import android.content.Context; 30 import android.content.Context;
33 import android.graphics.Point; 31 import android.graphics.Point;
34 import android.graphics.SurfaceTexture; 32 import android.graphics.SurfaceTexture;
35 import android.opengl.EGLContext; 33 import android.opengl.EGLContext;
36 import android.opengl.GLES20; 34 import android.opengl.GLES20;
37 import android.opengl.Matrix; 35 import android.opengl.Matrix;
38 import android.os.Handler; 36 import android.os.Handler;
39 import android.os.HandlerThread; 37 import android.os.HandlerThread;
40 import android.util.AttributeSet; 38 import android.util.AttributeSet;
39 import android.util.Log;
41 import android.view.SurfaceHolder; 40 import android.view.SurfaceHolder;
42 import android.view.SurfaceView; 41 import android.view.SurfaceView;
43 42
44 import org.webrtc.Logging;
45
46 /** 43 /**
47 * Implements org.webrtc.VideoRenderer.Callbacks by displaying the video stream on a SurfaceView. 44 * Implements org.webrtc.VideoRenderer.Callbacks by displaying the video stream on a SurfaceView.
48 * renderFrame() is asynchronous to avoid blocking the calling thread. 45 * renderFrame() is asynchronous to avoid blocking the calling thread.
49 * This class is thread safe and handles access from potentially four different threads: 46 * This class is thread safe and handles access from potentially four different threads:
50 * Interaction from the main app in init, release, setMirror, and setScalingtype . 47 * Interaction from the main app in init, release, setMirror, and setScalingtype .
51 * Interaction from C++ webrtc::VideoRendererInterface in renderFrame and canApp lyRotation. 48 * Interaction from C++ webrtc::VideoRendererInterface in renderFrame and canApp lyRotation.
52 * Interaction from the Activity lifecycle in surfaceCreated, surfaceChanged, an d surfaceDestroyed. 49 * Interaction from the Activity lifecycle in surfaceCreated, surfaceChanged, an d surfaceDestroyed.
53 * Interaction with the layout framework in onMeasure and onSizeChanged. 50 * Interaction with the layout framework in onMeasure and onSizeChanged.
54 */ 51 */
55 public class SurfaceViewRenderer extends SurfaceView 52 public class SurfaceViewRenderer extends SurfaceView
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 } 137 }
141 138
142 /** 139 /**
143 * Initialize this class, sharing resources with |sharedContext|. 140 * Initialize this class, sharing resources with |sharedContext|.
144 */ 141 */
145 public void init( 142 public void init(
146 EGLContext sharedContext, RendererCommon.RendererEvents rendererEvents) { 143 EGLContext sharedContext, RendererCommon.RendererEvents rendererEvents) {
147 if (renderThreadHandler != null) { 144 if (renderThreadHandler != null) {
148 throw new IllegalStateException("Already initialized"); 145 throw new IllegalStateException("Already initialized");
149 } 146 }
150 Logging.d(TAG, "Initializing"); 147 Log.d(TAG, "Initializing");
151 this.rendererEvents = rendererEvents; 148 this.rendererEvents = rendererEvents;
152 renderThread = new HandlerThread(TAG); 149 renderThread = new HandlerThread(TAG);
153 renderThread.start(); 150 renderThread.start();
154 renderThreadHandler = new Handler(renderThread.getLooper()); 151 renderThreadHandler = new Handler(renderThread.getLooper());
155 eglBase = new EglBase(sharedContext, EglBase.ConfigType.PLAIN); 152 eglBase = new EglBase(sharedContext, EglBase.ConfigType.PLAIN);
156 drawer = new GlRectDrawer(); 153 drawer = new GlRectDrawer();
157 getHolder().addCallback(this); 154 getHolder().addCallback(this);
158 } 155 }
159 156
160 /** 157 /**
161 * Release all resources. This needs to be done manually, otherwise the resour ces are leaked. You 158 * Release all resources. This needs to be done manually, otherwise the resour ces are leaked. You
162 * should call this before the Activity is destroyed, while the EGLContext is still valid. 159 * should call this before the Activity is destroyed, while the EGLContext is still valid.
163 */ 160 */
164 public void release() { 161 public void release() {
165 synchronized (threadLock) { 162 synchronized (threadLock) {
166 if (renderThreadHandler == null) { 163 if (renderThreadHandler == null) {
167 Logging.d(TAG, "Already released"); 164 Log.d(TAG, "Already released");
168 return; 165 return;
169 } 166 }
170 // Release EGL and GL resources on render thread. 167 // Release EGL and GL resources on render thread.
171 // TODO(magjed): This might not be necessary - all OpenGL resources are au tomatically deleted 168 // TODO(magjed): This might not be necessary - all OpenGL resources are au tomatically deleted
172 // when the EGL context is lost. It might be dangerous to delete them manu ally in 169 // when the EGL context is lost. It might be dangerous to delete them manu ally in
173 // Activity.onDestroy(). 170 // Activity.onDestroy().
174 renderThreadHandler.post(new Runnable() { 171 renderThreadHandler.post(new Runnable() {
175 @Override public void run() { 172 @Override public void run() {
176 drawer.release(); 173 drawer.release();
177 drawer = null; 174 drawer = null;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 } 214 }
218 215
219 // VideoRenderer.Callbacks interface. 216 // VideoRenderer.Callbacks interface.
220 @Override 217 @Override
221 public void renderFrame(VideoRenderer.I420Frame frame) { 218 public void renderFrame(VideoRenderer.I420Frame frame) {
222 synchronized (statisticsLock) { 219 synchronized (statisticsLock) {
223 ++framesReceived; 220 ++framesReceived;
224 } 221 }
225 synchronized (threadLock) { 222 synchronized (threadLock) {
226 if (renderThreadHandler == null) { 223 if (renderThreadHandler == null) {
227 Logging.d(TAG, "Dropping frame - SurfaceViewRenderer not initialized or already released."); 224 Log.d(TAG, "Dropping frame - SurfaceViewRenderer not initialized or alre ady released.");
228 } else { 225 } else {
229 synchronized (frameLock) { 226 synchronized (frameLock) {
230 if (pendingFrame == null) { 227 if (pendingFrame == null) {
231 updateFrameDimensionsAndReportEvents(frame); 228 updateFrameDimensionsAndReportEvents(frame);
232 pendingFrame = frame; 229 pendingFrame = frame;
233 renderThreadHandler.post(renderFrameRunnable); 230 renderThreadHandler.post(renderFrameRunnable);
234 return; 231 return;
235 } 232 }
236 } 233 }
237 } 234 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 layoutWidth = right - left; 274 layoutWidth = right - left;
278 layoutHeight = bottom - top; 275 layoutHeight = bottom - top;
279 } 276 }
280 // Might have a pending frame waiting for a layout of correct size. 277 // Might have a pending frame waiting for a layout of correct size.
281 runOnRenderThread(renderFrameRunnable); 278 runOnRenderThread(renderFrameRunnable);
282 } 279 }
283 280
284 // SurfaceHolder.Callback interface. 281 // SurfaceHolder.Callback interface.
285 @Override 282 @Override
286 public void surfaceCreated(final SurfaceHolder holder) { 283 public void surfaceCreated(final SurfaceHolder holder) {
287 Logging.d(TAG, "Surface created"); 284 Log.d(TAG, "Surface created");
288 runOnRenderThread(new Runnable() { 285 runOnRenderThread(new Runnable() {
289 @Override public void run() { 286 @Override public void run() {
290 eglBase.createSurface(holder.getSurface()); 287 eglBase.createSurface(holder.getSurface());
291 eglBase.makeCurrent(); 288 eglBase.makeCurrent();
292 // Necessary for YUV frames with odd width. 289 // Necessary for YUV frames with odd width.
293 GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); 290 GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
294 } 291 }
295 }); 292 });
296 } 293 }
297 294
298 @Override 295 @Override
299 public void surfaceDestroyed(SurfaceHolder holder) { 296 public void surfaceDestroyed(SurfaceHolder holder) {
300 Logging.d(TAG, "Surface destroyed"); 297 Log.d(TAG, "Surface destroyed");
301 synchronized (layoutLock) { 298 synchronized (layoutLock) {
302 surfaceWidth = 0; 299 surfaceWidth = 0;
303 surfaceHeight = 0; 300 surfaceHeight = 0;
304 } 301 }
305 runOnRenderThread(new Runnable() { 302 runOnRenderThread(new Runnable() {
306 @Override public void run() { 303 @Override public void run() {
307 eglBase.releaseSurface(); 304 eglBase.releaseSurface();
308 } 305 }
309 }); 306 });
310 } 307 }
311 308
312 @Override 309 @Override
313 public void surfaceChanged(SurfaceHolder holder, int format, int width, int he ight) { 310 public void surfaceChanged(SurfaceHolder holder, int format, int width, int he ight) {
314 Logging.d(TAG, "Surface changed: " + width + "x" + height); 311 Log.d(TAG, "Surface changed: " + width + "x" + height);
315 synchronized (layoutLock) { 312 synchronized (layoutLock) {
316 surfaceWidth = width; 313 surfaceWidth = width;
317 surfaceHeight = height; 314 surfaceHeight = height;
318 } 315 }
319 // Might have a pending frame waiting for a surface of correct size. 316 // Might have a pending frame waiting for a surface of correct size.
320 runOnRenderThread(renderFrameRunnable); 317 runOnRenderThread(renderFrameRunnable);
321 } 318 }
322 319
323 /** 320 /**
324 * Private helper function to post tasks safely. 321 * Private helper function to post tasks safely.
325 */ 322 */
326 private void runOnRenderThread(Runnable runnable) { 323 private void runOnRenderThread(Runnable runnable) {
327 synchronized (threadLock) { 324 synchronized (threadLock) {
328 if (renderThreadHandler != null) { 325 if (renderThreadHandler != null) {
329 renderThreadHandler.post(runnable); 326 renderThreadHandler.post(runnable);
330 } 327 }
331 } 328 }
332 } 329 }
333 330
334 /** 331 /**
335 * Requests new layout if necessary. Returns true if layout and surface size a re consistent. 332 * Requests new layout if necessary. Returns true if layout and surface size a re consistent.
336 */ 333 */
337 private boolean checkConsistentLayout() { 334 private boolean checkConsistentLayout() {
338 synchronized (layoutLock) { 335 synchronized (layoutLock) {
339 final Point desiredLayoutSize = getDesiredLayoutSize(); 336 final Point desiredLayoutSize = getDesiredLayoutSize();
340 if (desiredLayoutSize.x != layoutWidth || desiredLayoutSize.y != layoutHei ght) { 337 if (desiredLayoutSize.x != layoutWidth || desiredLayoutSize.y != layoutHei ght) {
341 Logging.d(TAG, "Requesting new layout with size: " 338 Log.d(TAG, "Requesting new layout with size: "
342 + desiredLayoutSize.x + "x" + desiredLayoutSize.y); 339 + desiredLayoutSize.x + "x" + desiredLayoutSize.y);
343 // Request layout update on UI thread. 340 // Request layout update on UI thread.
344 post(new Runnable() { 341 post(new Runnable() {
345 @Override public void run() { 342 @Override public void run() {
346 requestLayout(); 343 requestLayout();
347 } 344 }
348 }); 345 });
349 return false; 346 return false;
350 } 347 }
351 // Wait for requestLayout() to propagate through this sequence before retu rning true: 348 // Wait for requestLayout() to propagate through this sequence before retu rning true:
352 // requestLayout() -> onMeasure() -> onLayout() -> surfaceChanged(). 349 // requestLayout() -> onMeasure() -> onLayout() -> surfaceChanged().
353 return surfaceWidth == layoutWidth && surfaceHeight == layoutHeight; 350 return surfaceWidth == layoutWidth && surfaceHeight == layoutHeight;
354 } 351 }
355 } 352 }
356 353
357 /** 354 /**
358 * Renders and releases |pendingFrame|. 355 * Renders and releases |pendingFrame|.
359 */ 356 */
360 private void renderFrameOnRenderThread() { 357 private void renderFrameOnRenderThread() {
361 if (eglBase == null || !eglBase.hasSurface()) { 358 if (eglBase == null || !eglBase.hasSurface()) {
362 Logging.d(TAG, "No surface to draw on"); 359 Log.d(TAG, "No surface to draw on");
363 return; 360 return;
364 } 361 }
365 if (!checkConsistentLayout()) { 362 if (!checkConsistentLayout()) {
366 // Output intermediate black frames while the layout is updated. 363 // Output intermediate black frames while the layout is updated.
367 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 364 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
368 eglBase.swapBuffers(); 365 eglBase.swapBuffers();
369 return; 366 return;
370 } 367 }
371 // After a surface size change, the EGLSurface might still have a buffer of the old size in the 368 // After a surface size change, the EGLSurface might still have a buffer of the old size in the
372 // pipeline. Querying the EGLSurface will show if the underlying buffer dime nsions haven't yet 369 // pipeline. Querying the EGLSurface will show if the underlying buffer dime nsions haven't yet
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 } 442 }
446 443
447 // Update frame dimensions and report any changes to |rendererEvents|. 444 // Update frame dimensions and report any changes to |rendererEvents|.
448 private void updateFrameDimensionsAndReportEvents(VideoRenderer.I420Frame fram e) { 445 private void updateFrameDimensionsAndReportEvents(VideoRenderer.I420Frame fram e) {
449 synchronized (layoutLock) { 446 synchronized (layoutLock) {
450 if (frameWidth != frame.width || frameHeight != frame.height 447 if (frameWidth != frame.width || frameHeight != frame.height
451 || frameRotation != frame.rotationDegree) { 448 || frameRotation != frame.rotationDegree) {
452 if (rendererEvents != null) { 449 if (rendererEvents != null) {
453 final String id = getResources().getResourceEntryName(getId()); 450 final String id = getResources().getResourceEntryName(getId());
454 if (frameWidth == 0 || frameHeight == 0) { 451 if (frameWidth == 0 || frameHeight == 0) {
455 Logging.d(TAG, "ID: " + id + ". Reporting first rendered frame."); 452 Log.d(TAG, "ID: " + id + ". Reporting first rendered frame.");
456 rendererEvents.onFirstFrameRendered(); 453 rendererEvents.onFirstFrameRendered();
457 } 454 }
458 Logging.d(TAG, "ID: " + id + ". Reporting frame resolution changed to " 455 Log.d(TAG, "ID: " + id + ". Reporting frame resolution changed to "
459 + frame.width + "x" + frame.height + " with rotation " + frame.rot ationDegree); 456 + frame.width + "x" + frame.height + " with rotation " + frame.rot ationDegree);
460 rendererEvents.onFrameResolutionChanged(frame.width, frame.height, fra me.rotationDegree); 457 rendererEvents.onFrameResolutionChanged(frame.width, frame.height, fra me.rotationDegree);
461 } 458 }
462 frameWidth = frame.width; 459 frameWidth = frame.width;
463 frameHeight = frame.height; 460 frameHeight = frame.height;
464 frameRotation = frame.rotationDegree; 461 frameRotation = frame.rotationDegree;
465 } 462 }
466 } 463 }
467 } 464 }
468 465
469 private void logStatistics() { 466 private void logStatistics() {
470 synchronized (statisticsLock) { 467 synchronized (statisticsLock) {
471 Logging.d(TAG, "ID: " + getResources().getResourceEntryName(getId()) + ". Frames received: " 468 Log.d(TAG, "ID: " + getResources().getResourceEntryName(getId()) + ". Fram es received: "
472 + framesReceived + ". Dropped: " + framesDropped + ". Rendered: " + fr amesRendered); 469 + framesReceived + ". Dropped: " + framesDropped + ". Rendered: " + fr amesRendered);
473 if (framesReceived > 0 && framesRendered > 0) { 470 if (framesReceived > 0 && framesRendered > 0) {
474 final long timeSinceFirstFrameNs = System.nanoTime() - firstFrameTimeNs; 471 final long timeSinceFirstFrameNs = System.nanoTime() - firstFrameTimeNs;
475 Logging.d(TAG, "Duration: " + (int) (timeSinceFirstFrameNs / 1e6) + 472 Log.d(TAG, "Duration: " + (int) (timeSinceFirstFrameNs / 1e6) +
476 " ms. FPS: " + (float) framesRendered * 1e9 / timeSinceFirstFrameNs) ; 473 " ms. FPS: " + (float) framesRendered * 1e9 / timeSinceFirstFrameNs) ;
477 Logging.d(TAG, "Average render time: " 474 Log.d(TAG, "Average render time: "
478 + (int) (renderTimeNs / (1000 * framesRendered)) + " us."); 475 + (int) (renderTimeNs / (1000 * framesRendered)) + " us.");
479 } 476 }
480 } 477 }
481 } 478 }
482 } 479 }
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/android/org/webrtc/GlUtil.java ('k') | talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698