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

Side by Side Diff: webrtc/sdk/android/api/org/webrtc/EglRenderer.java

Issue 3008423002: Android: Add helper class VideoFrameDrawer that can render VideoFrames (Closed)
Patch Set: similarity=10 Created 3 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 * 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
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 private final Object fpsReductionLock = new Object(); 89 private final Object fpsReductionLock = new Object();
90 // Time for when next frame should be rendered. 90 // Time for when next frame should be rendered.
91 private long nextFrameTimeNs; 91 private long nextFrameTimeNs;
92 // Minimum duration between frames when fps reduction is active, or -1 if vide o is completely 92 // Minimum duration between frames when fps reduction is active, or -1 if vide o is completely
93 // paused. 93 // paused.
94 private long minRenderPeriodNs; 94 private long minRenderPeriodNs;
95 95
96 // EGL and GL resources for drawing YUV/OES textures. After initilization, the se are only accessed 96 // EGL and GL resources for drawing YUV/OES textures. After initilization, the se are only accessed
97 // from the render thread. 97 // from the render thread.
98 private EglBase eglBase; 98 private EglBase eglBase;
99 private final RendererCommon.YuvUploader yuvUploader = new RendererCommon.YuvU ploader(); 99 private final VideoFrameDrawer frameDrawer = new VideoFrameDrawer();
100 private RendererCommon.GlDrawer drawer; 100 private RendererCommon.GlDrawer drawer;
101 private final Matrix drawMatrix = new Matrix();
101 102
102 // Pending frame to render. Serves as a queue with size 1. Synchronized on |fr ameLock|. 103 // Pending frame to render. Serves as a queue with size 1. Synchronized on |fr ameLock|.
103 private final Object frameLock = new Object(); 104 private final Object frameLock = new Object();
104 private VideoFrame pendingFrame; 105 private VideoFrame pendingFrame;
105 106
106 // These variables are synchronized on |layoutLock|. 107 // These variables are synchronized on |layoutLock|.
107 private final Object layoutLock = new Object(); 108 private final Object layoutLock = new Object();
108 private float layoutAspectRatio; 109 private float layoutAspectRatio;
109 // If true, mirrors the video stream horizontally. 110 // If true, mirrors the video stream horizontally.
110 private boolean mirror; 111 private boolean mirror;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 logD("Already released"); 221 logD("Already released");
221 return; 222 return;
222 } 223 }
223 renderThreadHandler.removeCallbacks(logStatisticsRunnable); 224 renderThreadHandler.removeCallbacks(logStatisticsRunnable);
224 // Release EGL and GL resources on render thread. 225 // Release EGL and GL resources on render thread.
225 renderThreadHandler.postAtFrontOfQueue(() -> { 226 renderThreadHandler.postAtFrontOfQueue(() -> {
226 if (drawer != null) { 227 if (drawer != null) {
227 drawer.release(); 228 drawer.release();
228 drawer = null; 229 drawer = null;
229 } 230 }
230 yuvUploader.release(); 231 frameDrawer.release();
231 if (bitmapTextureFramebuffer != null) { 232 if (bitmapTextureFramebuffer != null) {
232 bitmapTextureFramebuffer.release(); 233 bitmapTextureFramebuffer.release();
233 bitmapTextureFramebuffer = null; 234 bitmapTextureFramebuffer = null;
234 } 235 }
235 if (eglBase != null) { 236 if (eglBase != null) {
236 logD("eglBase detach and release."); 237 logD("eglBase detach and release.");
237 eglBase.detachCurrent(); 238 eglBase.detachCurrent();
238 eglBase.release(); 239 eglBase.release();
239 eglBase = null; 240 eglBase = null;
240 } 241 }
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 } 554 }
554 555
555 final long startTimeNs = System.nanoTime(); 556 final long startTimeNs = System.nanoTime();
556 557
557 final float frameAspectRatio = frame.getRotatedWidth() / (float) frame.getRo tatedHeight(); 558 final float frameAspectRatio = frame.getRotatedWidth() / (float) frame.getRo tatedHeight();
558 final float drawnAspectRatio; 559 final float drawnAspectRatio;
559 synchronized (layoutLock) { 560 synchronized (layoutLock) {
560 drawnAspectRatio = layoutAspectRatio != 0f ? layoutAspectRatio : frameAspe ctRatio; 561 drawnAspectRatio = layoutAspectRatio != 0f ? layoutAspectRatio : frameAspe ctRatio;
561 } 562 }
562 563
563 VideoFrame.Buffer buffer = frame.getBuffer();
564 final boolean isYuvBuffer;
565 if (buffer instanceof VideoFrame.TextureBuffer) {
566 isYuvBuffer = false;
567 } else {
568 isYuvBuffer = true;
569 VideoFrame.Buffer oldBuffer = buffer;
570 buffer = buffer.toI420();
571 oldBuffer.release();
572 }
573 boolean shouldUploadYuvTextures = false;
574 if (isYuvBuffer) {
575 shouldUploadYuvTextures = shouldRenderFrame;
576 // Check if there are frame listeners that we want to render a bitmap for regardless of if the
577 // frame was rendered. This is the case when there are frameListeners with scale != 0f.
578 if (!shouldUploadYuvTextures) {
579 for (FrameListenerAndParams listenerAndParams : frameListeners) {
580 if (listenerAndParams.scale != 0f
581 && (shouldRenderFrame || !listenerAndParams.applyFpsReduction)) {
582 shouldUploadYuvTextures = true;
583 break;
584 }
585 }
586 }
587 }
588 final int[] yuvTextures = shouldUploadYuvTextures
589 ? yuvUploader.uploadFromBuffer((VideoFrame.I420Buffer) buffer)
590 : null;
591
592 final float scaleX; 564 final float scaleX;
593 final float scaleY; 565 final float scaleY;
594 566
595 if (frameAspectRatio > drawnAspectRatio) { 567 if (frameAspectRatio > drawnAspectRatio) {
596 scaleX = drawnAspectRatio / frameAspectRatio; 568 scaleX = drawnAspectRatio / frameAspectRatio;
597 scaleY = 1f; 569 scaleY = 1f;
598 } else { 570 } else {
599 scaleX = 1f; 571 scaleX = 1f;
600 scaleY = frameAspectRatio / drawnAspectRatio; 572 scaleY = frameAspectRatio / drawnAspectRatio;
601 } 573 }
602 574
603 final int drawnFrameWidth = (int) (scaleX * frame.getRotatedWidth()); 575 drawMatrix.reset();
604 final int drawnFrameHeight = (int) (scaleY * frame.getRotatedHeight());
605
606 final Matrix drawMatrix = new Matrix();
607 drawMatrix.preTranslate(0.5f, 0.5f); 576 drawMatrix.preTranslate(0.5f, 0.5f);
608 if (isYuvBuffer)
609 drawMatrix.preScale(1f, -1f); // I420-frames are upside down
610 drawMatrix.preRotate(frame.getRotation());
611 if (mirror) 577 if (mirror)
612 drawMatrix.preScale(-1f, 1f); 578 drawMatrix.preScale(-1f, 1f);
613 drawMatrix.preScale(scaleX, scaleY); 579 drawMatrix.preScale(scaleX, scaleY);
614 drawMatrix.preTranslate(-0.5f, -0.5f); 580 drawMatrix.preTranslate(-0.5f, -0.5f);
615 581
616 if (shouldRenderFrame) { 582 if (shouldRenderFrame) {
617 GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha * /); 583 GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha * /);
618 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 584 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
619 if (isYuvBuffer) { 585 frameDrawer.drawFrame(frame, drawer, drawMatrix, 0 /* viewportX */, 0 /* v iewportY */,
620 drawer.drawYuv(yuvTextures, 586 eglBase.surfaceWidth(), eglBase.surfaceHeight());
621 RendererCommon.convertMatrixFromAndroidGraphicsMatrix(drawMatrix), d rawnFrameWidth,
622 drawnFrameHeight, 0, 0, eglBase.surfaceWidth(), eglBase.surfaceHeigh t());
623 } else {
624 VideoFrame.TextureBuffer textureBuffer = (VideoFrame.TextureBuffer) buff er;
625 RendererCommon.drawTexture(drawer, textureBuffer, drawMatrix, drawnFrame Width,
626 drawnFrameHeight, 0, 0, eglBase.surfaceWidth(), eglBase.surfaceHeigh t());
627 }
628 587
629 final long swapBuffersStartTimeNs = System.nanoTime(); 588 final long swapBuffersStartTimeNs = System.nanoTime();
630 eglBase.swapBuffers(); 589 eglBase.swapBuffers();
631 590
632 final long currentTimeNs = System.nanoTime(); 591 final long currentTimeNs = System.nanoTime();
633 synchronized (statisticsLock) { 592 synchronized (statisticsLock) {
634 ++framesRendered; 593 ++framesRendered;
635 renderTimeNs += (currentTimeNs - startTimeNs); 594 renderTimeNs += (currentTimeNs - startTimeNs);
636 renderSwapBufferTimeNs += (currentTimeNs - swapBuffersStartTimeNs); 595 renderSwapBufferTimeNs += (currentTimeNs - swapBuffersStartTimeNs);
637 } 596 }
638 } 597 }
639 598
640 notifyCallbacks(frame, isYuvBuffer, yuvTextures, shouldRenderFrame); 599 notifyCallbacks(frame, shouldRenderFrame);
641 buffer.release(); 600 frame.release();
642 } 601 }
643 602
644 private void notifyCallbacks( 603 private void notifyCallbacks(VideoFrame frame, boolean wasRendered) {
645 VideoFrame frame, boolean isYuvBuffer, int[] yuvTextures, boolean wasRende red) {
646 if (frameListeners.isEmpty()) 604 if (frameListeners.isEmpty())
647 return; 605 return;
648 606
649 final Matrix drawMatrix = new Matrix(); 607 drawMatrix.reset();
650 drawMatrix.preTranslate(0.5f, 0.5f); 608 drawMatrix.preTranslate(0.5f, 0.5f);
651 if (isYuvBuffer)
652 drawMatrix.preScale(1f, -1f); // I420-frames are upside down
653 drawMatrix.preRotate(frame.getRotation());
654 if (mirror) 609 if (mirror)
655 drawMatrix.preScale(-1f, 1f); 610 drawMatrix.preScale(-1f, 1f);
656 drawMatrix.preScale(1f, -1f); // We want the output to be upside down for Bi tmap. 611 drawMatrix.preScale(1f, -1f); // We want the output to be upside down for Bi tmap.
657 drawMatrix.preTranslate(-0.5f, -0.5f); 612 drawMatrix.preTranslate(-0.5f, -0.5f);
658 613
659 Iterator<FrameListenerAndParams> it = frameListeners.iterator(); 614 Iterator<FrameListenerAndParams> it = frameListeners.iterator();
660 while (it.hasNext()) { 615 while (it.hasNext()) {
661 FrameListenerAndParams listenerAndParams = it.next(); 616 FrameListenerAndParams listenerAndParams = it.next();
662 if (!wasRendered && listenerAndParams.applyFpsReduction) { 617 if (!wasRendered && listenerAndParams.applyFpsReduction) {
663 continue; 618 continue;
(...skipping 12 matching lines...) Expand all
676 bitmapTextureFramebuffer = new GlTextureFrameBuffer(GLES20.GL_RGBA); 631 bitmapTextureFramebuffer = new GlTextureFrameBuffer(GLES20.GL_RGBA);
677 } 632 }
678 bitmapTextureFramebuffer.setSize(scaledWidth, scaledHeight); 633 bitmapTextureFramebuffer.setSize(scaledWidth, scaledHeight);
679 634
680 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, bitmapTextureFramebuffer.g etFrameBufferId()); 635 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, bitmapTextureFramebuffer.g etFrameBufferId());
681 GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTAC HMENT0, 636 GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTAC HMENT0,
682 GLES20.GL_TEXTURE_2D, bitmapTextureFramebuffer.getTextureId(), 0); 637 GLES20.GL_TEXTURE_2D, bitmapTextureFramebuffer.getTextureId(), 0);
683 638
684 GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha * /); 639 GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha * /);
685 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 640 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
686 if (isYuvBuffer) { 641 frameDrawer.drawFrame(frame, listenerAndParams.drawer, drawMatrix, 0 /* vi ewportX */,
687 listenerAndParams.drawer.drawYuv(yuvTextures, 642 0 /* viewportY */, scaledWidth, scaledHeight);
688 RendererCommon.convertMatrixFromAndroidGraphicsMatrix(drawMatrix),
689 frame.getRotatedWidth(), frame.getRotatedHeight(), 0, 0, scaledWidth , scaledHeight);
690 } else {
691 VideoFrame.TextureBuffer textureBuffer = (VideoFrame.TextureBuffer) fram e.getBuffer();
692 RendererCommon.drawTexture(listenerAndParams.drawer, textureBuffer, draw Matrix,
693 frame.getRotatedWidth(), frame.getRotatedHeight(), 0, 0, scaledWidth , scaledHeight);
694 }
695 643
696 final ByteBuffer bitmapBuffer = ByteBuffer.allocateDirect(scaledWidth * sc aledHeight * 4); 644 final ByteBuffer bitmapBuffer = ByteBuffer.allocateDirect(scaledWidth * sc aledHeight * 4);
697 GLES20.glViewport(0, 0, scaledWidth, scaledHeight); 645 GLES20.glViewport(0, 0, scaledWidth, scaledHeight);
698 GLES20.glReadPixels( 646 GLES20.glReadPixels(
699 0, 0, scaledWidth, scaledHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BY TE, bitmapBuffer); 647 0, 0, scaledWidth, scaledHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BY TE, bitmapBuffer);
700 648
701 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); 649 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
702 GlUtil.checkNoGLES2Error("EglRenderer.notifyCallbacks"); 650 GlUtil.checkNoGLES2Error("EglRenderer.notifyCallbacks");
703 651
704 final Bitmap bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitma p.Config.ARGB_8888); 652 final Bitmap bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitma p.Config.ARGB_8888);
(...skipping 23 matching lines...) Expand all
728 + " Average swapBuffer time: " 676 + " Average swapBuffer time: "
729 + averageTimeAsString(renderSwapBufferTimeNs, framesRendered) + "."); 677 + averageTimeAsString(renderSwapBufferTimeNs, framesRendered) + ".");
730 resetStatistics(currentTimeNs); 678 resetStatistics(currentTimeNs);
731 } 679 }
732 } 680 }
733 681
734 private void logD(String string) { 682 private void logD(String string) {
735 Logging.d(TAG, name + string); 683 Logging.d(TAG, name + string);
736 } 684 }
737 } 685 }
OLDNEW
« no previous file with comments | « webrtc/sdk/android/BUILD.gn ('k') | webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698