Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 package org.webrtc; | 11 package org.webrtc; |
| 12 | 12 |
| 13 import android.graphics.Bitmap; | |
| 13 import android.graphics.SurfaceTexture; | 14 import android.graphics.SurfaceTexture; |
| 14 import android.opengl.GLES20; | 15 import android.opengl.GLES20; |
| 15 import android.os.Handler; | 16 import android.os.Handler; |
| 16 import android.os.HandlerThread; | 17 import android.os.HandlerThread; |
| 17 import android.os.Looper; | 18 import android.os.Looper; |
| 18 import android.view.Surface; | 19 import android.view.Surface; |
| 20 import java.nio.IntBuffer; | |
| 21 import java.util.ArrayList; | |
| 22 import java.util.Iterator; | |
| 19 import java.util.concurrent.CountDownLatch; | 23 import java.util.concurrent.CountDownLatch; |
| 20 import java.util.concurrent.TimeUnit; | 24 import java.util.concurrent.TimeUnit; |
| 21 | 25 |
| 22 /** | 26 /** |
| 23 * Implements org.webrtc.VideoRenderer.Callbacks by displaying the video stream on an EGL Surface. | 27 * Implements org.webrtc.VideoRenderer.Callbacks by displaying the video stream on an EGL Surface. |
| 24 * This class is intended to be used as a helper class for rendering on SurfaceV iews and | 28 * This class is intended to be used as a helper class for rendering on SurfaceV iews and |
| 25 * TextureViews. | 29 * TextureViews. |
| 26 */ | 30 */ |
| 27 public class EglRenderer implements VideoRenderer.Callbacks { | 31 public class EglRenderer implements VideoRenderer.Callbacks { |
| 28 private static final String TAG = "EglRenderer"; | 32 private static final String TAG = "EglRenderer"; |
| 29 private static final long LOG_INTERVAL_SEC = 4; | 33 private static final long LOG_INTERVAL_SEC = 4; |
| 30 private static final int MAX_SURFACE_CLEAR_COUNT = 3; | 34 private static final int MAX_SURFACE_CLEAR_COUNT = 3; |
| 31 | 35 |
| 36 public interface FrameListener { void onFrame(Bitmap frame); } | |
| 37 | |
| 38 private static class ScaleAndFrameListener { | |
| 39 public final float scale; | |
| 40 public final FrameListener listener; | |
| 41 | |
| 42 public ScaleAndFrameListener(float scale, FrameListener listener) { | |
| 43 this.scale = scale; | |
| 44 this.listener = listener; | |
| 45 } | |
| 46 } | |
| 47 | |
| 32 private class EglSurfaceCreation implements Runnable { | 48 private class EglSurfaceCreation implements Runnable { |
| 33 private Object surface; | 49 private Object surface; |
| 34 | 50 |
| 35 public synchronized void setSurface(Object surface) { | 51 public synchronized void setSurface(Object surface) { |
| 36 this.surface = surface; | 52 this.surface = surface; |
| 37 } | 53 } |
| 38 | 54 |
| 39 @Override | 55 @Override |
| 40 public synchronized void run() { | 56 public synchronized void run() { |
| 41 if (surface != null && eglBase != null && !eglBase.hasSurface()) { | 57 if (surface != null && eglBase != null && !eglBase.hasSurface()) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 53 } | 69 } |
| 54 } | 70 } |
| 55 | 71 |
| 56 private final String name; | 72 private final String name; |
| 57 | 73 |
| 58 // |renderThreadHandler| is a handler for communicating with |renderThread|, a nd is synchronized | 74 // |renderThreadHandler| is a handler for communicating with |renderThread|, a nd is synchronized |
| 59 // on |handlerLock|. | 75 // on |handlerLock|. |
| 60 private final Object handlerLock = new Object(); | 76 private final Object handlerLock = new Object(); |
| 61 private Handler renderThreadHandler; | 77 private Handler renderThreadHandler; |
| 62 | 78 |
| 79 private final Object frameListenerLock = new Object(); | |
| 80 private final ArrayList<ScaleAndFrameListener> frameListeners = new ArrayList< >(); | |
| 81 | |
| 63 // Variables for fps reduction. | 82 // Variables for fps reduction. |
| 64 private final Object fpsReductionLock = new Object(); | 83 private final Object fpsReductionLock = new Object(); |
| 65 // Time for when next frame should be rendered. | 84 // Time for when next frame should be rendered. |
| 66 private long nextFrameTimeNs; | 85 private long nextFrameTimeNs; |
| 67 // Minimum duration between frames when fps reduction is active, or -1 if vide o is completely | 86 // Minimum duration between frames when fps reduction is active, or -1 if vide o is completely |
| 68 // paused. | 87 // paused. |
| 69 private long minRenderPeriodNs; | 88 private long minRenderPeriodNs; |
| 70 | 89 |
| 71 // EGL and GL resources for drawing YUV/OES textures. After initilization, the se are only accessed | 90 // EGL and GL resources for drawing YUV/OES textures. After initilization, the se are only accessed |
| 72 // from the render thread. | 91 // from the render thread. |
| 73 private EglBase eglBase; | 92 private EglBase eglBase; |
| 74 private final RendererCommon.YuvUploader yuvUploader = new RendererCommon.YuvU ploader(); | 93 private final RendererCommon.YuvUploader yuvUploader = new RendererCommon.YuvU ploader(); |
| 94 private YuvConverter yuvConverter; | |
|
magjed_webrtc
2016/11/01 18:06:46
Remove this now since you didn't end up using it.
sakal
2016/11/02 08:34:29
Done.
| |
| 75 private RendererCommon.GlDrawer drawer; | 95 private RendererCommon.GlDrawer drawer; |
| 76 // Texture ids for YUV frames. Allocated on first arrival of a YUV frame. | 96 // Texture ids for YUV frames. Allocated on first arrival of a YUV frame. |
| 77 private int[] yuvTextures = null; | 97 private int[] yuvTextures = null; |
| 78 | 98 |
| 79 // Pending frame to render. Serves as a queue with size 1. Synchronized on |fr ameLock|. | 99 // Pending frame to render. Serves as a queue with size 1. Synchronized on |fr ameLock|. |
| 80 private final Object frameLock = new Object(); | 100 private final Object frameLock = new Object(); |
| 81 private VideoRenderer.I420Frame pendingFrame; | 101 private VideoRenderer.I420Frame pendingFrame; |
| 82 | 102 |
| 83 // These variables are synchronized on |layoutLock|. | 103 // These variables are synchronized on |layoutLock|. |
| 84 private final Object layoutLock = new Object(); | 104 private final Object layoutLock = new Object(); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 97 private int framesDropped; | 117 private int framesDropped; |
| 98 // Number of rendered video frames. | 118 // Number of rendered video frames. |
| 99 private int framesRendered; | 119 private int framesRendered; |
| 100 // Start time for counting these statistics, or 0 if we haven't started measur ing yet. | 120 // Start time for counting these statistics, or 0 if we haven't started measur ing yet. |
| 101 private long statisticsStartTimeNs; | 121 private long statisticsStartTimeNs; |
| 102 // Time in ns spent in renderFrameOnRenderThread() function. | 122 // Time in ns spent in renderFrameOnRenderThread() function. |
| 103 private long renderTimeNs; | 123 private long renderTimeNs; |
| 104 // Time in ns spent by the render thread in the swapBuffers() function. | 124 // Time in ns spent by the render thread in the swapBuffers() function. |
| 105 private long renderSwapBufferTimeNs; | 125 private long renderSwapBufferTimeNs; |
| 106 | 126 |
| 127 // Used for bitmap capturing. | |
| 128 private final int[] bitmapTexture = new int[1]; | |
|
magjed_webrtc
2016/11/01 18:06:46
Keep this as an int instead of int[1]. Same for bi
sakal
2016/11/02 08:34:29
Done.
| |
| 129 private final int[] bitmapFramebuffer = new int[1]; | |
| 130 private int bitmapTextureWidth; | |
| 131 private int bitmapTextureHeight; | |
| 132 | |
| 107 // Runnable for posting frames to render thread. | 133 // Runnable for posting frames to render thread. |
| 108 private final Runnable renderFrameRunnable = new Runnable() { | 134 private final Runnable renderFrameRunnable = new Runnable() { |
| 109 @Override | 135 @Override |
| 110 public void run() { | 136 public void run() { |
| 111 renderFrameOnRenderThread(); | 137 renderFrameOnRenderThread(); |
| 112 } | 138 } |
| 113 }; | 139 }; |
| 114 | 140 |
| 115 private final Runnable logStatisticsRunnable = new Runnable() { | 141 private final Runnable logStatisticsRunnable = new Runnable() { |
| 116 @Override | 142 @Override |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 } | 235 } |
| 210 renderThreadHandler.removeCallbacks(logStatisticsRunnable); | 236 renderThreadHandler.removeCallbacks(logStatisticsRunnable); |
| 211 // Release EGL and GL resources on render thread. | 237 // Release EGL and GL resources on render thread. |
| 212 renderThreadHandler.postAtFrontOfQueue(new Runnable() { | 238 renderThreadHandler.postAtFrontOfQueue(new Runnable() { |
| 213 @Override | 239 @Override |
| 214 public void run() { | 240 public void run() { |
| 215 if (drawer != null) { | 241 if (drawer != null) { |
| 216 drawer.release(); | 242 drawer.release(); |
| 217 drawer = null; | 243 drawer = null; |
| 218 } | 244 } |
| 245 if (yuvConverter != null) { | |
| 246 yuvConverter.release(); | |
| 247 yuvConverter = null; | |
| 248 } | |
| 219 if (yuvTextures != null) { | 249 if (yuvTextures != null) { |
| 220 GLES20.glDeleteTextures(3, yuvTextures, 0); | 250 GLES20.glDeleteTextures(3, yuvTextures, 0); |
| 221 yuvTextures = null; | 251 yuvTextures = null; |
| 222 } | 252 } |
| 253 GLES20.glDeleteFramebuffers(1, bitmapFramebuffer, 0); | |
|
magjed_webrtc
2016/11/01 18:06:46
Add 'if (bitmapFramebuffer[0] != 0)' check here. S
sakal
2016/11/02 08:34:29
"glDeleteFramebuffers silently ignores 0's and nam
| |
| 254 bitmapFramebuffer[0] = 0; | |
| 255 GLES20.glDeleteTextures(1, bitmapTexture, 0); | |
| 256 bitmapTexture[0] = 0; | |
| 223 if (eglBase != null) { | 257 if (eglBase != null) { |
| 224 logD("eglBase detach and release."); | 258 logD("eglBase detach and release."); |
| 225 eglBase.detachCurrent(); | 259 eglBase.detachCurrent(); |
| 226 eglBase.release(); | 260 eglBase.release(); |
| 227 eglBase = null; | 261 eglBase = null; |
| 228 } | 262 } |
| 229 eglCleanupBarrier.countDown(); | 263 eglCleanupBarrier.countDown(); |
| 230 } | 264 } |
| 231 }); | 265 }); |
| 232 final Looper renderLooper = renderThreadHandler.getLooper(); | 266 final Looper renderLooper = renderThreadHandler.getLooper(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 } | 360 } |
| 327 | 361 |
| 328 public void disableFpsReduction() { | 362 public void disableFpsReduction() { |
| 329 setFpsReduction(Float.POSITIVE_INFINITY /* fps */); | 363 setFpsReduction(Float.POSITIVE_INFINITY /* fps */); |
| 330 } | 364 } |
| 331 | 365 |
| 332 public void pauseVideo() { | 366 public void pauseVideo() { |
| 333 setFpsReduction(0 /* fps */); | 367 setFpsReduction(0 /* fps */); |
| 334 } | 368 } |
| 335 | 369 |
| 370 /** | |
| 371 * Register a callback to be invoked when a new video frame has been received. | |
| 372 * | |
| 373 * @param listener The callback to be invoked. | |
| 374 * @param scale The scale of the Bitmap passed to the callback, or 0 if no Bitmap is | |
| 375 * required. | |
| 376 */ | |
| 377 public void addFrameListener(FrameListener listener, float scale) { | |
| 378 synchronized (frameListenerLock) { | |
| 379 frameListeners.add(new ScaleAndFrameListener(scale, listener)); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 /** | |
| 384 * Remove any pending callback that was added with addFrameListener. If the ca llback is not in | |
| 385 * the queue, nothing happens. | |
| 386 * | |
| 387 * @param runnable The callback to remove. | |
| 388 */ | |
| 389 public void removeFrameListener(FrameListener listener) { | |
| 390 synchronized (frameListenerLock) { | |
| 391 final Iterator<ScaleAndFrameListener> iter = frameListeners.iterator(); | |
| 392 while (iter.hasNext()) { | |
| 393 if (iter.next().listener == listener) { | |
| 394 iter.remove(); | |
| 395 } | |
| 396 } | |
| 397 } | |
| 398 } | |
| 399 | |
| 336 // VideoRenderer.Callbacks interface. | 400 // VideoRenderer.Callbacks interface. |
| 337 @Override | 401 @Override |
| 338 public void renderFrame(VideoRenderer.I420Frame frame) { | 402 public void renderFrame(VideoRenderer.I420Frame frame) { |
| 339 synchronized (statisticsLock) { | 403 synchronized (statisticsLock) { |
| 340 ++framesReceived; | 404 ++framesReceived; |
| 341 } | 405 } |
| 342 final boolean dropOldFrame; | 406 final boolean dropOldFrame; |
| 343 synchronized (handlerLock) { | 407 synchronized (handlerLock) { |
| 344 if (renderThreadHandler == null) { | 408 if (renderThreadHandler == null) { |
| 345 logD("Dropping frame - Not initialized or already released."); | 409 logD("Dropping frame - Not initialized or already released."); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 465 frame = pendingFrame; | 529 frame = pendingFrame; |
| 466 pendingFrame = null; | 530 pendingFrame = null; |
| 467 } | 531 } |
| 468 if (eglBase == null || !eglBase.hasSurface()) { | 532 if (eglBase == null || !eglBase.hasSurface()) { |
| 469 logD("Dropping frame - No surface"); | 533 logD("Dropping frame - No surface"); |
| 470 VideoRenderer.renderFrameDone(frame); | 534 VideoRenderer.renderFrameDone(frame); |
| 471 return; | 535 return; |
| 472 } | 536 } |
| 473 | 537 |
| 474 final long startTimeNs = System.nanoTime(); | 538 final long startTimeNs = System.nanoTime(); |
| 475 float[] texMatrix = | 539 final float[] texMatrix = |
| 476 RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationD egree); | 540 RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationD egree); |
| 541 final float[] drawMatrix; | |
| 477 | 542 |
| 478 // After a surface size change, the EGLSurface might still have a buffer of the old size in the | 543 // After a surface size change, the EGLSurface might still have a buffer of the old size in the |
| 479 // pipeline. Querying the EGLSurface will show if the underlying buffer dime nsions haven't yet | 544 // pipeline. Querying the EGLSurface will show if the underlying buffer dime nsions haven't yet |
| 480 // changed. Such a buffer will be rendered incorrectly, so flush it with a b lack frame. | 545 // changed. Such a buffer will be rendered incorrectly, so flush it with a b lack frame. |
| 481 synchronized (layoutLock) { | 546 synchronized (layoutLock) { |
| 482 int surfaceClearCount = 0; | 547 int surfaceClearCount = 0; |
| 483 while (eglBase.surfaceWidth() != surfaceWidth || eglBase.surfaceHeight() ! = surfaceHeight) { | 548 while (eglBase.surfaceWidth() != surfaceWidth || eglBase.surfaceHeight() ! = surfaceHeight) { |
| 484 ++surfaceClearCount; | 549 ++surfaceClearCount; |
| 485 if (surfaceClearCount > MAX_SURFACE_CLEAR_COUNT) { | 550 if (surfaceClearCount > MAX_SURFACE_CLEAR_COUNT) { |
| 486 logD("Failed to get surface of expected size - dropping frame."); | 551 logD("Failed to get surface of expected size - dropping frame."); |
| 487 VideoRenderer.renderFrameDone(frame); | 552 VideoRenderer.renderFrameDone(frame); |
| 488 return; | 553 return; |
| 489 } | 554 } |
| 490 logD("Surface size mismatch - clearing surface."); | 555 logD("Surface size mismatch - clearing surface. Size: " + eglBase.surfac eWidth() + "x" |
| 556 + eglBase.surfaceHeight() + " Expected: " + surfaceWidth + "x" + sur faceHeight); | |
| 491 clearSurfaceOnRenderThread(); | 557 clearSurfaceOnRenderThread(); |
| 492 } | 558 } |
| 493 final float[] layoutMatrix; | 559 final float[] layoutMatrix; |
| 494 if (layoutAspectRatio > 0) { | 560 if (layoutAspectRatio > 0) { |
| 495 layoutMatrix = RendererCommon.getLayoutMatrix( | 561 layoutMatrix = RendererCommon.getLayoutMatrix( |
| 496 mirror, frame.rotatedWidth() / (float) frame.rotatedHeight(), layout AspectRatio); | 562 mirror, frame.rotatedWidth() / (float) frame.rotatedHeight(), layout AspectRatio); |
| 497 } else { | 563 } else { |
| 498 layoutMatrix = | 564 layoutMatrix = |
| 499 mirror ? RendererCommon.horizontalFlipMatrix() : RendererCommon.iden tityMatrix(); | 565 mirror ? RendererCommon.horizontalFlipMatrix() : RendererCommon.iden tityMatrix(); |
| 500 } | 566 } |
| 501 texMatrix = RendererCommon.multiplyMatrices(texMatrix, layoutMatrix); | 567 drawMatrix = RendererCommon.multiplyMatrices(texMatrix, layoutMatrix); |
| 502 } | 568 } |
| 503 | 569 |
| 504 GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */) ; | 570 GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */) ; |
| 505 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | 571 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
| 506 if (frame.yuvFrame) { | 572 if (frame.yuvFrame) { |
| 507 // Make sure YUV textures are allocated. | 573 // Make sure YUV textures are allocated. |
| 508 if (yuvTextures == null) { | 574 if (yuvTextures == null) { |
| 509 yuvTextures = new int[3]; | 575 yuvTextures = new int[3]; |
| 510 for (int i = 0; i < 3; i++) { | 576 for (int i = 0; i < 3; i++) { |
| 511 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); | 577 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); |
| 512 } | 578 } |
| 513 } | 579 } |
| 514 yuvUploader.uploadYuvData( | 580 yuvUploader.uploadYuvData( |
| 515 yuvTextures, frame.width, frame.height, frame.yuvStrides, frame.yuvPla nes); | 581 yuvTextures, frame.width, frame.height, frame.yuvStrides, frame.yuvPla nes); |
| 516 drawer.drawYuv(yuvTextures, texMatrix, frame.rotatedWidth(), frame.rotated Height(), 0, 0, | 582 drawer.drawYuv(yuvTextures, drawMatrix, frame.rotatedWidth(), frame.rotate dHeight(), 0, 0, |
| 517 surfaceWidth, surfaceHeight); | 583 surfaceWidth, surfaceHeight); |
| 518 } else { | 584 } else { |
| 519 drawer.drawOes(frame.textureId, texMatrix, frame.rotatedWidth(), frame.rot atedHeight(), 0, 0, | 585 drawer.drawOes(frame.textureId, drawMatrix, frame.rotatedWidth(), frame.ro tatedHeight(), 0, 0, |
| 520 surfaceWidth, surfaceHeight); | 586 surfaceWidth, surfaceHeight); |
| 521 } | 587 } |
| 522 | 588 |
| 589 // Notify callbacks. Make temporary copy of callback list to avoid | |
|
magjed_webrtc
2016/11/01 18:06:46
Move this block of code into a helper function. Al
sakal
2016/11/02 08:34:29
Done.
| |
| 590 // ConcurrentModificationException, in case callbacks call addFramelistener or | |
| 591 // removeFrameListener. | |
| 592 final ArrayList<ScaleAndFrameListener> tmpList = new ArrayList<>(frameListen ers); | |
| 593 frameListeners.clear(); | |
| 594 for (ScaleAndFrameListener scaleAndListener : tmpList) { | |
| 595 final int scaledWidth = (int) (scaleAndListener.scale * frame.rotatedWidth ()); | |
| 596 final int scaledHeight = (int) (scaleAndListener.scale * frame.rotatedHeig ht()); | |
| 597 final float[] bitmapMatrix = RendererCommon.multiplyMatrices( | |
|
magjed_webrtc
2016/11/01 18:06:46
Move this outside the loop.
sakal
2016/11/02 08:34:29
Done.
| |
| 598 RendererCommon.multiplyMatrices(texMatrix, | |
| 599 mirror ? RendererCommon.horizontalFlipMatrix() : RendererCommon.id entityMatrix()), | |
| 600 RendererCommon.verticalFlipMatrix()); | |
| 601 | |
| 602 if (scaledWidth == 0 || scaledHeight == 0) { | |
| 603 scaleAndListener.listener.onFrame(null); | |
| 604 continue; | |
| 605 } | |
| 606 if (bitmapTexture[0] == 0) { | |
| 607 bitmapTexture[0] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D); | |
| 608 bitmapTextureWidth = bitmapTextureHeight = 0; | |
| 609 } | |
| 610 if (bitmapFramebuffer[0] == 0) { | |
| 611 GLES20.glGenFramebuffers(1, bitmapFramebuffer, 0); | |
| 612 } | |
| 613 | |
| 614 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bitmapTexture[0]); | |
| 615 if (scaledWidth != bitmapTextureWidth || scaledHeight != bitmapTextureHeig ht) { | |
|
magjed_webrtc
2016/11/01 18:06:46
Wait a minute... Maybe you can use the helper clas
sakal
2016/11/02 08:34:29
Done.
| |
| 616 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, scaledWidth , scaledHeight, 0, | |
| 617 GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); | |
| 618 bitmapTextureWidth = scaledWidth; | |
| 619 bitmapTextureHeight = scaledHeight; | |
| 620 } | |
| 621 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, bitmapFramebuffer[0]); | |
| 622 GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTAC HMENT0, | |
| 623 GLES20.GL_TEXTURE_2D, bitmapTexture[0], 0); | |
| 624 | |
| 625 if (frame.yuvFrame) { | |
| 626 drawer.drawYuv(yuvTextures, bitmapMatrix, frame.rotatedWidth(), frame.ro tatedHeight(), 0, 0, | |
| 627 scaledWidth, scaledHeight); | |
| 628 } else { | |
| 629 drawer.drawOes(frame.textureId, bitmapMatrix, frame.rotatedWidth(), fram e.rotatedHeight(), | |
| 630 0, 0, scaledWidth, scaledHeight); | |
| 631 } | |
| 632 | |
| 633 final IntBuffer bitmapBuffer = IntBuffer.allocate(scaledWidth * scaledHeig ht); | |
| 634 GLES20.glViewport(0, 0, scaledWidth, scaledHeight); | |
| 635 GLES20.glReadPixels( | |
| 636 0, 0, scaledWidth, scaledHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BY TE, bitmapBuffer); | |
| 637 | |
| 638 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); | |
| 639 GlUtil.checkNoGLES2Error("EglRenderer.renderFrameOnRenderThread - bitmap c apture"); | |
| 640 | |
| 641 // RGBA to ARGB conversion. | |
| 642 final int[] bitmapArray = bitmapBuffer.array(); | |
| 643 nativeABGRToARGB(bitmapArray, scaledWidth, scaledHeight); | |
| 644 | |
| 645 final Bitmap bitmap = Bitmap.createBitmap( | |
| 646 bitmapBuffer.array(), scaledWidth, scaledHeight, Bitmap.Config.ARGB_88 88); | |
| 647 scaleAndListener.listener.onFrame(bitmap); | |
| 648 } | |
| 649 | |
| 523 final long swapBuffersStartTimeNs = System.nanoTime(); | 650 final long swapBuffersStartTimeNs = System.nanoTime(); |
| 524 eglBase.swapBuffers(); | 651 eglBase.swapBuffers(); |
| 525 VideoRenderer.renderFrameDone(frame); | 652 VideoRenderer.renderFrameDone(frame); |
| 526 | 653 |
| 527 final long currentTimeNs = System.nanoTime(); | 654 final long currentTimeNs = System.nanoTime(); |
| 528 synchronized (statisticsLock) { | 655 synchronized (statisticsLock) { |
| 529 ++framesRendered; | 656 ++framesRendered; |
| 530 renderTimeNs += (currentTimeNs - startTimeNs); | 657 renderTimeNs += (currentTimeNs - startTimeNs); |
| 531 renderSwapBufferTimeNs += (currentTimeNs - swapBuffersStartTimeNs); | 658 renderSwapBufferTimeNs += (currentTimeNs - swapBuffersStartTimeNs); |
| 532 } | 659 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 552 + " Average render time: " + averageTimeAsString(renderTimeNs, framesR endered) + "." | 679 + " Average render time: " + averageTimeAsString(renderTimeNs, framesR endered) + "." |
| 553 + " Average swapBuffer time: " | 680 + " Average swapBuffer time: " |
| 554 + averageTimeAsString(renderSwapBufferTimeNs, framesRendered) + "."); | 681 + averageTimeAsString(renderSwapBufferTimeNs, framesRendered) + "."); |
| 555 resetStatistics(currentTimeNs); | 682 resetStatistics(currentTimeNs); |
| 556 } | 683 } |
| 557 } | 684 } |
| 558 | 685 |
| 559 private void logD(String string) { | 686 private void logD(String string) { |
| 560 Logging.d(TAG, name + string); | 687 Logging.d(TAG, name + string); |
| 561 } | 688 } |
| 689 | |
| 690 private static native void nativeABGRToARGB(int[] array, int width, int height ); | |
| 562 } | 691 } |
| OLD | NEW |