OLD | NEW |
---|---|
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, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
49 * This class is thread safe and handles access from potentially four different threads: | 49 * 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 . | 50 * Interaction from the main app in init, release, setMirror, and setScalingtype . |
51 * Interaction from C++ webrtc::VideoRendererInterface in renderFrame and canApp lyRotation. | 51 * Interaction from C++ webrtc::VideoRendererInterface in renderFrame and canApp lyRotation. |
52 * Interaction from the Activity lifecycle in surfaceCreated, surfaceChanged, an d surfaceDestroyed. | 52 * Interaction from the Activity lifecycle in surfaceCreated, surfaceChanged, an d surfaceDestroyed. |
53 * Interaction with the layout framework in onMeasure and onSizeChanged. | 53 * Interaction with the layout framework in onMeasure and onSizeChanged. |
54 */ | 54 */ |
55 public class SurfaceViewRenderer extends SurfaceView | 55 public class SurfaceViewRenderer extends SurfaceView |
56 implements SurfaceHolder.Callback, VideoRenderer.Callbacks { | 56 implements SurfaceHolder.Callback, VideoRenderer.Callbacks { |
57 private static final String TAG = "SurfaceViewRenderer"; | 57 private static final String TAG = "SurfaceViewRenderer"; |
58 | 58 |
59 /** | |
60 * Convenience class for layout plus surface size with equals() and toString() functionality. | |
61 */ | |
62 private static class LayoutConfiguration { | |
hbos
2015/11/12 11:35:47
If two objects are considered equal in java they s
| |
63 public int layoutWidth; | |
64 public int layoutHeight; | |
65 public int surfaceWidth; | |
66 public int surfaceHeight; | |
67 | |
68 public LayoutConfiguration() {} | |
69 | |
70 public LayoutConfiguration( | |
71 int layoutWidth, int layoutHeight, int surfaceWidth, int surfaceHeight) { | |
72 this.layoutWidth = layoutWidth; | |
73 this.layoutHeight = layoutHeight; | |
74 this.surfaceWidth = surfaceWidth; | |
75 this.surfaceHeight = surfaceHeight; | |
76 } | |
77 | |
78 @Override | |
79 public boolean equals(Object that) { | |
80 if (!(that instanceof LayoutConfiguration)) { | |
81 return false; | |
82 } | |
83 final LayoutConfiguration lc = (LayoutConfiguration) that; | |
84 return layoutWidth == lc.layoutWidth && layoutHeight == lc.layoutHeight | |
85 && surfaceWidth == lc.surfaceWidth && surfaceHeight == lc.surfaceHeigh t; | |
86 } | |
87 | |
88 @Override | |
89 public String toString() { | |
90 return "Layout: " + layoutWidth + "x" + layoutHeight | |
91 + ", Surface: " + surfaceWidth + "x" + surfaceHeight; | |
92 } | |
93 } | |
94 | |
59 // Dedicated render thread. | 95 // Dedicated render thread. |
60 private HandlerThread renderThread; | 96 private HandlerThread renderThread; |
61 // |renderThreadHandler| is a handler for communicating with |renderThread|, a nd is synchronized | 97 // |renderThreadHandler| is a handler for communicating with |renderThread|, a nd is synchronized |
62 // on |handlerLock|. | 98 // on |handlerLock|. |
63 private final Object handlerLock = new Object(); | 99 private final Object handlerLock = new Object(); |
64 private Handler renderThreadHandler; | 100 private Handler renderThreadHandler; |
65 | 101 |
66 // EGL and GL resources for drawing YUV/OES textures. After initilization, the se are only accessed | 102 // EGL and GL resources for drawing YUV/OES textures. After initilization, the se are only accessed |
67 // from the render thread. | 103 // from the render thread. |
68 private EglBase eglBase; | 104 private EglBase eglBase; |
69 private GlRectDrawer drawer; | 105 private GlRectDrawer drawer; |
70 // Texture ids for YUV frames. Allocated on first arrival of a YUV frame. | 106 // Texture ids for YUV frames. Allocated on first arrival of a YUV frame. |
71 private int[] yuvTextures = null; | 107 private int[] yuvTextures = null; |
72 | 108 |
73 // Pending frame to render. Serves as a queue with size 1. Synchronized on |fr ameLock|. | 109 // Pending frame to render. Serves as a queue with size 1. Synchronized on |fr ameLock|. |
74 private final Object frameLock = new Object(); | 110 private final Object frameLock = new Object(); |
75 private VideoRenderer.I420Frame pendingFrame; | 111 private VideoRenderer.I420Frame pendingFrame; |
76 | 112 |
77 // These variables are synchronized on |layoutLock|. | 113 // These variables are synchronized on |layoutLock|. |
78 private final Object layoutLock = new Object(); | 114 private final Object layoutLock = new Object(); |
79 // These three different dimension values are used to keep track of the state in these functions: | 115 // |widthSpec|/|heightSpec| is the most recent measurement specification from onMeasure(). |
80 // requestLayout() -> onMeasure() -> onLayout() -> surfaceChanged(). | |
81 // requestLayout() is triggered internally by frame size changes, but can also be triggered | |
82 // externally by layout update requests. | |
83 // Most recent measurement specification from onMeasure(). | |
84 private int widthSpec; | 116 private int widthSpec; |
85 private int heightSpec; | 117 private int heightSpec; |
86 // Current size on screen in pixels. Updated in onLayout(), and should be cons istent with | 118 // |isBlack| is true if the current surface is completely black. Changing layo ut aspect ratio or |
87 // |widthSpec|/|heightSpec| after that. | 119 // surface size is only allowed while the surface is black to avoid render art ifacts. |
88 private int layoutWidth; | 120 private boolean isBlack = true; |
89 private int layoutHeight; | 121 // |desiredConfig| is the layout configuration we want and are waiting for. |
90 // Current surface size of the underlying Surface. Updated in surfaceChanged() , and should be | 122 private LayoutConfiguration desiredConfig; |
91 // consistent with |layoutWidth|/|layoutHeight| after that. | 123 // |currentConfig| is the actual current layout configuration. |
92 // TODO(magjed): Enable hardware scaler with SurfaceHolder.setFixedSize(). Thi s will decouple | 124 private final LayoutConfiguration currentConfig = new LayoutConfiguration(); |
93 // layout and surface size. | |
94 private int surfaceWidth; | |
95 private int surfaceHeight; | |
96 // |isSurfaceCreated| keeps track of the current status in surfaceCreated()/su rfaceDestroyed(). | 125 // |isSurfaceCreated| keeps track of the current status in surfaceCreated()/su rfaceDestroyed(). |
97 private boolean isSurfaceCreated; | 126 private boolean isSurfaceCreated; |
98 // Last rendered frame dimensions, or 0 if no frame has been rendered yet. | 127 // Last rendered frame dimensions, or 0 if no frame has been rendered yet. |
99 private int frameWidth; | 128 private int frameWidth; |
100 private int frameHeight; | 129 private int frameHeight; |
101 private int frameRotation; | 130 private int frameRotation; |
102 // |scalingType| determines how the video will fill the allowed layout area in onMeasure(). | 131 // |scalingType| determines how the video will fill the allowed layout area in onMeasure(). |
103 private RendererCommon.ScalingType scalingType = RendererCommon.ScalingType.SC ALE_ASPECT_BALANCED; | 132 private RendererCommon.ScalingType scalingType = RendererCommon.ScalingType.SC ALE_ASPECT_BALANCED; |
104 // If true, mirrors the video stream horizontally. | 133 // If true, mirrors the video stream horizontally. |
105 private boolean mirror; | 134 private boolean mirror; |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
289 VideoRenderer.renderFrameDone(pendingFrame); | 318 VideoRenderer.renderFrameDone(pendingFrame); |
290 } | 319 } |
291 pendingFrame = frame; | 320 pendingFrame = frame; |
292 updateFrameDimensionsAndReportEvents(frame); | 321 updateFrameDimensionsAndReportEvents(frame); |
293 renderThreadHandler.post(renderFrameRunnable); | 322 renderThreadHandler.post(renderFrameRunnable); |
294 } | 323 } |
295 } | 324 } |
296 } | 325 } |
297 | 326 |
298 // Returns desired layout size given current measure specification and video a spect ratio. | 327 // Returns desired layout size given current measure specification and video a spect ratio. |
299 private Point getDesiredLayoutSize() { | 328 private static Point getDesiredLayoutSize( |
300 synchronized (layoutLock) { | 329 int widthSpec, int heightSpec, |
301 final int maxWidth = getDefaultSize(Integer.MAX_VALUE, widthSpec); | 330 RendererCommon.ScalingType scalingType, float frameAspectRatio) { |
302 final int maxHeight = getDefaultSize(Integer.MAX_VALUE, heightSpec); | 331 final int maxWidth = getDefaultSize(Integer.MAX_VALUE, widthSpec); |
303 final Point size = | 332 final int maxHeight = getDefaultSize(Integer.MAX_VALUE, heightSpec); |
304 RendererCommon.getDisplaySize(scalingType, frameAspectRatio(), maxWidt h, maxHeight); | 333 final Point size = |
305 if (MeasureSpec.getMode(widthSpec) == MeasureSpec.EXACTLY) { | 334 RendererCommon.getDisplaySize(scalingType, frameAspectRatio, maxWidth, m axHeight); |
306 size.x = maxWidth; | 335 if (MeasureSpec.getMode(widthSpec) == MeasureSpec.EXACTLY) { |
307 } | 336 size.x = maxWidth; |
308 if (MeasureSpec.getMode(heightSpec) == MeasureSpec.EXACTLY) { | |
309 size.y = maxHeight; | |
310 } | |
311 return size; | |
312 } | 337 } |
338 if (MeasureSpec.getMode(heightSpec) == MeasureSpec.EXACTLY) { | |
339 size.y = maxHeight; | |
340 } | |
hbos
2015/11/12 11:35:47
What about MeasureSpec.AT_MOST? What if X is restr
| |
341 return size; | |
342 } | |
343 | |
344 /** | |
345 * Calculate desired LayoutConfiguration based on measure specification, scali ng type, | |
346 * and frame size. | |
347 */ | |
348 private static LayoutConfiguration getDesiredLayoutConfiguration(int widthSpec , int heightSpec, | |
349 RendererCommon.ScalingType scalingType, int frameWidth, int frameHeight) { | |
350 final Point layoutSize = getDesiredLayoutSize( | |
351 widthSpec, heightSpec, scalingType, (float) frameWidth / frameHeight); | |
352 // Calculate at what scale we are rendering the frame. | |
353 final float displayScale = | |
354 Math.max((float) layoutSize.x / frameWidth, (float) layoutSize.y / frame Height); | |
hbos
2015/11/12 11:35:47
Do we always want the max scale? Thinking about bl
| |
355 final int surfaceWidth; | |
356 final int surfaceHeight; | |
357 if (displayScale > 1) { | |
358 // Upscaling - decrease surface size and let the HW scaler take care of th e upscaling | |
359 // instead of the GPU. | |
360 surfaceWidth = Math.round(layoutSize.x / displayScale); | |
361 surfaceHeight = Math.round(layoutSize.y / displayScale); | |
hbos
2015/11/12 11:35:47
How does the HW scaler know to take care of the up
| |
362 } else { | |
363 // Downscaling - render at layout resolution. | |
364 surfaceWidth = layoutSize.x; | |
365 surfaceHeight = layoutSize.y; | |
366 } | |
367 return new LayoutConfiguration(layoutSize.x, layoutSize.y, surfaceWidth, sur faceHeight); | |
313 } | 368 } |
314 | 369 |
315 // View layout interface. | 370 // View layout interface. |
316 @Override | 371 @Override |
317 protected void onMeasure(int widthSpec, int heightSpec) { | 372 protected void onMeasure(int widthSpec, int heightSpec) { |
318 synchronized (layoutLock) { | 373 synchronized (layoutLock) { |
319 this.widthSpec = widthSpec; | 374 this.widthSpec = widthSpec; |
320 this.heightSpec = heightSpec; | 375 this.heightSpec = heightSpec; |
321 final Point size = getDesiredLayoutSize(); | 376 |
377 final RendererCommon.ScalingType scalingType; | |
378 final float aspectRatio; | |
379 if (isBlack) { | |
380 // Unconstrained layout change - update to latest. | |
381 scalingType = this.scalingType; | |
382 aspectRatio = frameAspectRatio(); | |
383 } else { | |
384 // Lock aspect of currently rendered frame with |SCALE_ASPECT_FIT|. | |
385 scalingType = RendererCommon.ScalingType.SCALE_ASPECT_FIT; | |
386 aspectRatio = (float) currentConfig.surfaceWidth / currentConfig.surface Height; | |
387 } | |
388 final Point size = getDesiredLayoutSize(widthSpec, heightSpec, scalingType , aspectRatio); | |
322 setMeasuredDimension(size.x, size.y); | 389 setMeasuredDimension(size.x, size.y); |
323 } | 390 } |
324 } | 391 } |
325 | 392 |
326 @Override | 393 @Override |
327 protected void onLayout(boolean changed, int left, int top, int right, int bot tom) { | 394 protected void onLayout(boolean changed, int left, int top, int right, int bot tom) { |
328 synchronized (layoutLock) { | 395 synchronized (layoutLock) { |
329 layoutWidth = right - left; | 396 currentConfig.layoutWidth = right - left; |
330 layoutHeight = bottom - top; | 397 currentConfig.layoutHeight = bottom - top; |
331 } | 398 } |
332 // Might have a pending frame waiting for a layout of correct size. | 399 // Might have a pending frame waiting for a layout of correct size. |
333 runOnRenderThread(renderFrameRunnable); | 400 runOnRenderThread(renderFrameRunnable); |
334 } | 401 } |
335 | 402 |
336 // SurfaceHolder.Callback interface. | 403 // SurfaceHolder.Callback interface. |
337 @Override | 404 @Override |
338 public void surfaceCreated(final SurfaceHolder holder) { | 405 public void surfaceCreated(final SurfaceHolder holder) { |
339 Logging.d(TAG, getResourceName() + "Surface created."); | 406 Logging.d(TAG, getResourceName() + "Surface created."); |
340 synchronized (layoutLock) { | 407 synchronized (layoutLock) { |
341 isSurfaceCreated = true; | 408 isSurfaceCreated = true; |
342 } | 409 } |
343 tryCreateEglSurface(); | 410 tryCreateEglSurface(); |
344 } | 411 } |
345 | 412 |
346 @Override | 413 @Override |
347 public void surfaceDestroyed(SurfaceHolder holder) { | 414 public void surfaceDestroyed(SurfaceHolder holder) { |
348 Logging.d(TAG, getResourceName() + "Surface destroyed."); | 415 Logging.d(TAG, getResourceName() + "Surface destroyed."); |
349 synchronized (layoutLock) { | 416 synchronized (layoutLock) { |
350 isSurfaceCreated = false; | 417 isSurfaceCreated = false; |
351 surfaceWidth = 0; | 418 currentConfig.surfaceWidth = 0; |
352 surfaceHeight = 0; | 419 currentConfig.surfaceHeight = 0; |
353 } | 420 } |
354 runOnRenderThread(new Runnable() { | 421 runOnRenderThread(new Runnable() { |
355 @Override public void run() { | 422 @Override public void run() { |
356 eglBase.releaseSurface(); | 423 eglBase.releaseSurface(); |
357 } | 424 } |
358 }); | 425 }); |
359 } | 426 } |
360 | 427 |
361 @Override | 428 @Override |
362 public void surfaceChanged(SurfaceHolder holder, int format, int width, int he ight) { | 429 public void surfaceChanged(SurfaceHolder holder, int format, int width, int he ight) { |
363 Logging.d(TAG, getResourceName() + "Surface changed: " + width + "x" + heigh t); | 430 Logging.d(TAG, getResourceName() + "Surface changed: " + width + "x" + heigh t); |
364 synchronized (layoutLock) { | 431 synchronized (layoutLock) { |
365 surfaceWidth = width; | 432 currentConfig.surfaceWidth = width; |
366 surfaceHeight = height; | 433 currentConfig.surfaceHeight = height; |
367 } | 434 } |
368 // Might have a pending frame waiting for a surface of correct size. | 435 // Might have a pending frame waiting for a surface of correct size. |
369 runOnRenderThread(renderFrameRunnable); | 436 runOnRenderThread(renderFrameRunnable); |
370 } | 437 } |
371 | 438 |
372 /** | 439 /** |
373 * Private helper function to post tasks safely. | 440 * Private helper function to post tasks safely. |
374 */ | 441 */ |
375 private void runOnRenderThread(Runnable runnable) { | 442 private void runOnRenderThread(Runnable runnable) { |
376 synchronized (handlerLock) { | 443 synchronized (handlerLock) { |
(...skipping 11 matching lines...) Expand all Loading... | |
388 } | 455 } |
389 } | 456 } |
390 | 457 |
391 private void makeBlack() { | 458 private void makeBlack() { |
392 if (Thread.currentThread() != renderThread) { | 459 if (Thread.currentThread() != renderThread) { |
393 throw new IllegalStateException(getResourceName() + "Wrong thread."); | 460 throw new IllegalStateException(getResourceName() + "Wrong thread."); |
394 } | 461 } |
395 GLES20.glClearColor(0, 0, 0, 0); | 462 GLES20.glClearColor(0, 0, 0, 0); |
396 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | 463 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
397 eglBase.swapBuffers(); | 464 eglBase.swapBuffers(); |
465 isBlack = true; | |
398 } | 466 } |
399 | 467 |
400 /** | 468 /** |
401 * Requests new layout if necessary. Returns true if layout and surface size a re consistent. | 469 * Requests new layout if necessary. Returns true if layout and surface size a re consistent. |
402 */ | 470 */ |
403 private boolean checkConsistentLayout() { | 471 private boolean checkConsistentLayout() { |
hbos
2015/11/12 11:35:47
if (Thread.currentThread() != renderThread) throw
| |
404 synchronized (layoutLock) { | 472 synchronized (layoutLock) { |
405 final Point desiredLayoutSize = getDesiredLayoutSize(); | 473 final int rotatedFrameWidth = (frameRotation % 180 == 0) ? frameWidth : fr ameHeight; |
406 if (desiredLayoutSize.x != layoutWidth || desiredLayoutSize.y != layoutHei ght) { | 474 final int rotatedFrameHeight = (frameRotation % 180 == 0) ? frameHeight : frameWidth; |
407 Logging.d(TAG, getResourceName() + "Requesting new layout with size: " | 475 final LayoutConfiguration newDesiredConfig = getDesiredLayoutConfiguration ( |
408 + desiredLayoutSize.x + "x" + desiredLayoutSize.y); | 476 widthSpec, heightSpec, scalingType, rotatedFrameWidth, rotatedFrameHei ght); |
477 if (!newDesiredConfig.equals(this.desiredConfig)) { | |
478 Logging.d(TAG, getResourceName() + "Requesting new config: " + newDesire dConfig); | |
479 this.desiredConfig = newDesiredConfig; | |
480 // Output intermediate black frame while the layout is updated. | |
481 makeBlack(); | |
409 // Request layout update on UI thread. | 482 // Request layout update on UI thread. |
410 post(new Runnable() { | 483 post(new Runnable() { |
411 @Override public void run() { | 484 @Override public void run() { |
485 getHolder().setFixedSize(newDesiredConfig.surfaceWidth, newDesiredCo nfig.surfaceHeight); | |
486 // requestLayout() triggers onMeasure() -> onLayout(). | |
412 requestLayout(); | 487 requestLayout(); |
413 } | 488 } |
414 }); | 489 }); |
415 return false; | 490 return false; |
416 } | 491 } |
417 // Wait for requestLayout() to propagate through this sequence before retu rning true: | 492 return desiredConfig.equals(currentConfig); |
418 // requestLayout() -> onMeasure() -> onLayout() -> surfaceChanged(). | |
419 return surfaceWidth == layoutWidth && surfaceHeight == layoutHeight; | |
420 } | 493 } |
421 } | 494 } |
422 | 495 |
423 /** | 496 /** |
424 * Renders and releases |pendingFrame|. | 497 * Renders and releases |pendingFrame|. |
425 */ | 498 */ |
426 private void renderFrameOnRenderThread() { | 499 private void renderFrameOnRenderThread() { |
427 if (Thread.currentThread() != renderThread) { | 500 if (Thread.currentThread() != renderThread) { |
428 throw new IllegalStateException(getResourceName() + "Wrong thread."); | 501 throw new IllegalStateException(getResourceName() + "Wrong thread."); |
429 } | 502 } |
430 if (eglBase == null || !eglBase.hasSurface()) { | 503 if (eglBase == null || !eglBase.hasSurface()) { |
431 Logging.d(TAG, getResourceName() + "No surface to draw on"); | 504 Logging.d(TAG, getResourceName() + "No surface to draw on"); |
432 return; | 505 return; |
433 } | 506 } |
507 synchronized (frameLock) { | |
508 if (pendingFrame == null) { | |
509 return; | |
510 } | |
511 } | |
434 if (!checkConsistentLayout()) { | 512 if (!checkConsistentLayout()) { |
435 // Output intermediate black frames while the layout is updated. | 513 // Wait until layout update is done. |
436 makeBlack(); | |
437 return; | 514 return; |
438 } | 515 } |
439 // After a surface size change, the EGLSurface might still have a buffer of the old size in the | 516 // After a surface size change, the EGLSurface might still have a buffer of the old size in the |
440 // pipeline. Querying the EGLSurface will show if the underlying buffer dime nsions haven't yet | 517 // pipeline. Querying the EGLSurface will show if the underlying buffer dime nsions haven't yet |
441 // changed. Such a buffer will be rendered incorrectly, so flush it with a b lack frame. | 518 // changed. Such a buffer will be rendered incorrectly, so flush it with a b lack frame. |
442 synchronized (layoutLock) { | 519 synchronized (layoutLock) { |
443 if (eglBase.surfaceWidth() != surfaceWidth || eglBase.surfaceHeight() != s urfaceHeight) { | 520 if (eglBase.surfaceWidth() != currentConfig.surfaceWidth |
521 || eglBase.surfaceHeight() != currentConfig.surfaceHeight) { | |
444 makeBlack(); | 522 makeBlack(); |
445 } | 523 } |
446 } | 524 } |
447 // Fetch and render |pendingFrame|. | 525 // Fetch and render |pendingFrame|. |
448 final VideoRenderer.I420Frame frame; | 526 final VideoRenderer.I420Frame frame; |
449 synchronized (frameLock) { | 527 synchronized (frameLock) { |
450 if (pendingFrame == null) { | 528 if (pendingFrame == null) { |
451 return; | 529 return; |
452 } | 530 } |
453 frame = pendingFrame; | 531 frame = pendingFrame; |
454 pendingFrame = null; | 532 pendingFrame = null; |
455 } | 533 } |
456 | 534 |
457 final long startTimeNs = System.nanoTime(); | 535 final long startTimeNs = System.nanoTime(); |
458 final float[] texMatrix; | 536 final float[] texMatrix; |
459 synchronized (layoutLock) { | 537 synchronized (layoutLock) { |
460 final float[] rotatedSamplingMatrix = | 538 final float[] rotatedSamplingMatrix = |
461 RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotatio nDegree); | 539 RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotatio nDegree); |
462 final float[] layoutMatrix = RendererCommon.getLayoutMatrix( | 540 final float[] layoutMatrix = RendererCommon.getLayoutMatrix(mirror, frameA spectRatio(), |
463 mirror, frameAspectRatio(), (float) layoutWidth / layoutHeight); | 541 (float) currentConfig.surfaceWidth / currentConfig.surfaceHeight); |
464 texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutM atrix); | 542 texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutM atrix); |
543 isBlack = false; | |
465 } | 544 } |
466 | 545 |
467 GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight); | 546 GLES20.glViewport(0, 0, currentConfig.surfaceWidth, currentConfig.surfaceHei ght); |
547 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | |
468 if (frame.yuvFrame) { | 548 if (frame.yuvFrame) { |
469 // Make sure YUV textures are allocated. | 549 // Make sure YUV textures are allocated. |
470 if (yuvTextures == null) { | 550 if (yuvTextures == null) { |
471 yuvTextures = new int[3]; | 551 yuvTextures = new int[3]; |
472 for (int i = 0; i < 3; i++) { | 552 for (int i = 0; i < 3; i++) { |
473 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); | 553 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); |
474 } | 554 } |
475 } | 555 } |
476 drawer.uploadYuvData( | 556 drawer.uploadYuvData( |
477 yuvTextures, frame.width, frame.height, frame.yuvStrides, frame.yuvPla nes); | 557 yuvTextures, frame.width, frame.height, frame.yuvStrides, frame.yuvPla nes); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 if (framesReceived > 0 && framesRendered > 0) { | 613 if (framesReceived > 0 && framesRendered > 0) { |
534 final long timeSinceFirstFrameNs = System.nanoTime() - firstFrameTimeNs; | 614 final long timeSinceFirstFrameNs = System.nanoTime() - firstFrameTimeNs; |
535 Logging.d(TAG, getResourceName() + "Duration: " + (int) (timeSinceFirstF rameNs / 1e6) + | 615 Logging.d(TAG, getResourceName() + "Duration: " + (int) (timeSinceFirstF rameNs / 1e6) + |
536 " ms. FPS: " + (float) framesRendered * 1e9 / timeSinceFirstFrameNs) ; | 616 " ms. FPS: " + (float) framesRendered * 1e9 / timeSinceFirstFrameNs) ; |
537 Logging.d(TAG, getResourceName() + "Average render time: " | 617 Logging.d(TAG, getResourceName() + "Average render time: " |
538 + (int) (renderTimeNs / (1000 * framesRendered)) + " us."); | 618 + (int) (renderTimeNs / (1000 * framesRendered)) + " us."); |
539 } | 619 } |
540 } | 620 } |
541 } | 621 } |
542 } | 622 } |
OLD | NEW |