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

Unified Diff: webrtc/sdk/android/api/org/webrtc/EglRenderer.java

Issue 3002563002: Add VideoSink interface to SurfaceViewRenderer. (Closed)
Patch Set: Address comments. Created 3 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | webrtc/sdk/android/api/org/webrtc/RendererCommon.java » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/sdk/android/api/org/webrtc/EglRenderer.java
diff --git a/webrtc/sdk/android/api/org/webrtc/EglRenderer.java b/webrtc/sdk/android/api/org/webrtc/EglRenderer.java
index e5863d3d716a144be9ca65a7cde93e1735faf73d..38d79951d34372db4cf640301170f3c3241a68ae 100644
--- a/webrtc/sdk/android/api/org/webrtc/EglRenderer.java
+++ b/webrtc/sdk/android/api/org/webrtc/EglRenderer.java
@@ -11,6 +11,7 @@
package org.webrtc;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.os.Handler;
@@ -29,7 +30,7 @@ import java.util.concurrent.TimeUnit;
* This class is intended to be used as a helper class for rendering on SurfaceViews and
* TextureViews.
*/
-public class EglRenderer implements VideoRenderer.Callbacks {
+public class EglRenderer implements VideoRenderer.Callbacks, VideoSink {
private static final String TAG = "EglRenderer";
private static final long LOG_INTERVAL_SEC = 4;
private static final int MAX_SURFACE_CLEAR_COUNT = 3;
@@ -100,7 +101,7 @@ public class EglRenderer implements VideoRenderer.Callbacks {
// Pending frame to render. Serves as a queue with size 1. Synchronized on |frameLock|.
private final Object frameLock = new Object();
- private VideoRenderer.I420Frame pendingFrame;
+ private VideoFrame pendingFrame;
// These variables are synchronized on |layoutLock|.
private final Object layoutLock = new Object();
@@ -252,7 +253,7 @@ public class EglRenderer implements VideoRenderer.Callbacks {
ThreadUtils.awaitUninterruptibly(eglCleanupBarrier);
synchronized (frameLock) {
if (pendingFrame != null) {
- VideoRenderer.renderFrameDone(pendingFrame);
+ pendingFrame.release();
pendingFrame = null;
}
}
@@ -414,6 +415,14 @@ public class EglRenderer implements VideoRenderer.Callbacks {
// VideoRenderer.Callbacks interface.
@Override
public void renderFrame(VideoRenderer.I420Frame frame) {
+ VideoFrame videoFrame = frame.toVideoFrame();
+ onFrame(videoFrame);
+ videoFrame.release();
+ }
+
+ // VideoSink interface.
+ @Override
+ public void onFrame(VideoFrame frame) {
synchronized (statisticsLock) {
++framesReceived;
}
@@ -421,15 +430,16 @@ public class EglRenderer implements VideoRenderer.Callbacks {
synchronized (handlerLock) {
if (renderThreadHandler == null) {
logD("Dropping frame - Not initialized or already released.");
- VideoRenderer.renderFrameDone(frame);
+ frame.release();
return;
}
synchronized (frameLock) {
dropOldFrame = (pendingFrame != null);
if (dropOldFrame) {
- VideoRenderer.renderFrameDone(pendingFrame);
+ pendingFrame.release();
}
pendingFrame = frame;
+ pendingFrame.retain();
renderThreadHandler.post(this ::renderFrameOnRenderThread);
}
}
@@ -507,7 +517,7 @@ public class EglRenderer implements VideoRenderer.Callbacks {
*/
private void renderFrameOnRenderThread() {
// Fetch and render |pendingFrame|.
- final VideoRenderer.I420Frame frame;
+ final VideoFrame frame;
synchronized (frameLock) {
if (pendingFrame == null) {
return;
@@ -517,7 +527,7 @@ public class EglRenderer implements VideoRenderer.Callbacks {
}
if (eglBase == null || !eglBase.hasSurface()) {
logD("Dropping frame - No surface");
- VideoRenderer.renderFrameDone(frame);
+ frame.release();
return;
}
// Check if fps reduction is active.
@@ -544,38 +554,25 @@ public class EglRenderer implements VideoRenderer.Callbacks {
}
final long startTimeNs = System.nanoTime();
- final float[] texMatrix =
- RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationDegree);
- final float[] drawMatrix;
-
- // After a surface size change, the EGLSurface might still have a buffer of the old size in the
- // pipeline. Querying the EGLSurface will show if the underlying buffer dimensions haven't yet
- // changed. Such a buffer will be rendered incorrectly, so flush it with a black frame.
- final int drawnFrameWidth;
- final int drawnFrameHeight;
+
+ final float frameAspectRatio = frame.getRotatedWidth() / (float) frame.getRotatedHeight();
+ final float drawnAspectRatio;
synchronized (layoutLock) {
- final float[] layoutMatrix;
- if (layoutAspectRatio > 0) {
- final float frameAspectRatio = frame.rotatedWidth() / (float) frame.rotatedHeight();
- layoutMatrix = RendererCommon.getLayoutMatrix(mirror, frameAspectRatio, layoutAspectRatio);
- if (frameAspectRatio > layoutAspectRatio) {
- drawnFrameWidth = (int) (frame.rotatedHeight() * layoutAspectRatio);
- drawnFrameHeight = frame.rotatedHeight();
- } else {
- drawnFrameWidth = frame.rotatedWidth();
- drawnFrameHeight = (int) (frame.rotatedWidth() / layoutAspectRatio);
- }
- } else {
- layoutMatrix =
- mirror ? RendererCommon.horizontalFlipMatrix() : RendererCommon.identityMatrix();
- drawnFrameWidth = frame.rotatedWidth();
- drawnFrameHeight = frame.rotatedHeight();
- }
- drawMatrix = RendererCommon.multiplyMatrices(texMatrix, layoutMatrix);
+ drawnAspectRatio = layoutAspectRatio != 0f ? layoutAspectRatio : frameAspectRatio;
}
+ VideoFrame.Buffer buffer = frame.getBuffer();
+ final boolean isYuvBuffer;
+ if (buffer instanceof VideoFrame.TextureBuffer) {
+ isYuvBuffer = false;
+ } else {
+ isYuvBuffer = true;
+ VideoFrame.Buffer oldBuffer = buffer;
+ buffer = buffer.toI420();
+ oldBuffer.release();
+ }
boolean shouldUploadYuvTextures = false;
- if (frame.yuvFrame) {
+ if (isYuvBuffer) {
shouldUploadYuvTextures = shouldRenderFrame;
// Check if there are frame listeners that we want to render a bitmap for regardless of if the
// frame was rendered. This is the case when there are frameListeners with scale != 0f.
@@ -590,17 +587,43 @@ public class EglRenderer implements VideoRenderer.Callbacks {
}
}
final int[] yuvTextures = shouldUploadYuvTextures
- ? yuvUploader.uploadYuvData(frame.width, frame.height, frame.yuvStrides, frame.yuvPlanes)
+ ? yuvUploader.uploadFromBuffer((VideoFrame.I420Buffer) buffer)
: null;
+ final float scaleX;
+ final float scaleY;
+
+ if (frameAspectRatio > drawnAspectRatio) {
+ scaleX = drawnAspectRatio / frameAspectRatio;
+ scaleY = 1f;
+ } else {
+ scaleX = 1f;
+ scaleY = frameAspectRatio / drawnAspectRatio;
+ }
+
+ final int drawnFrameWidth = (int) (scaleX * frame.getRotatedWidth());
+ final int drawnFrameHeight = (int) (scaleY * frame.getRotatedHeight());
+
+ final Matrix drawMatrix = new Matrix();
+ drawMatrix.preTranslate(0.5f, 0.5f);
+ if (isYuvBuffer)
+ drawMatrix.preScale(1f, -1f); // I420-frames are upside down
+ drawMatrix.preRotate(frame.getRotation());
+ if (mirror)
+ drawMatrix.preScale(-1f, 1f);
+ drawMatrix.preScale(scaleX, scaleY);
+ drawMatrix.preTranslate(-0.5f, -0.5f);
+
if (shouldRenderFrame) {
GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- if (frame.yuvFrame) {
- drawer.drawYuv(yuvTextures, drawMatrix, drawnFrameWidth, drawnFrameHeight, 0, 0,
- eglBase.surfaceWidth(), eglBase.surfaceHeight());
+ if (isYuvBuffer) {
+ drawer.drawYuv(yuvTextures,
+ RendererCommon.convertMatrixFromAndroidGraphicsMatrix(drawMatrix), drawnFrameWidth,
+ drawnFrameHeight, 0, 0, eglBase.surfaceWidth(), eglBase.surfaceHeight());
} else {
- drawer.drawOes(frame.textureId, drawMatrix, drawnFrameWidth, drawnFrameHeight, 0, 0,
+ VideoFrame.TextureBuffer textureBuffer = (VideoFrame.TextureBuffer) buffer;
+ drawer.drawTexture(textureBuffer, drawMatrix, drawnFrameWidth, drawnFrameHeight, 0, 0,
eglBase.surfaceWidth(), eglBase.surfaceHeight());
}
@@ -615,19 +638,24 @@ public class EglRenderer implements VideoRenderer.Callbacks {
}
}
- notifyCallbacks(frame, yuvTextures, texMatrix, shouldRenderFrame);
- VideoRenderer.renderFrameDone(frame);
+ notifyCallbacks(frame, isYuvBuffer, yuvTextures, shouldRenderFrame);
+ frame.release();
}
private void notifyCallbacks(
- VideoRenderer.I420Frame frame, int[] yuvTextures, float[] texMatrix, boolean wasRendered) {
+ VideoFrame frame, boolean isYuvBuffer, int[] yuvTextures, boolean wasRendered) {
if (frameListeners.isEmpty())
return;
- final float[] bitmapMatrix = RendererCommon.multiplyMatrices(
- RendererCommon.multiplyMatrices(texMatrix,
- mirror ? RendererCommon.horizontalFlipMatrix() : RendererCommon.identityMatrix()),
- RendererCommon.verticalFlipMatrix());
+ final Matrix drawMatrix = new Matrix();
+ drawMatrix.preTranslate(0.5f, 0.5f);
+ if (isYuvBuffer)
+ drawMatrix.preScale(1f, -1f); // I420-frames are upside down
+ drawMatrix.preRotate(frame.getRotation());
+ if (mirror)
+ drawMatrix.preScale(-1f, 1f);
+ drawMatrix.preScale(1f, -1f); // We want the output to be upside down for Bitmap.
+ drawMatrix.preTranslate(-0.5f, -0.5f);
Iterator<FrameListenerAndParams> it = frameListeners.iterator();
while (it.hasNext()) {
@@ -637,8 +665,8 @@ public class EglRenderer implements VideoRenderer.Callbacks {
}
it.remove();
- final int scaledWidth = (int) (listenerAndParams.scale * frame.rotatedWidth());
- final int scaledHeight = (int) (listenerAndParams.scale * frame.rotatedHeight());
+ final int scaledWidth = (int) (listenerAndParams.scale * frame.getRotatedWidth());
+ final int scaledHeight = (int) (listenerAndParams.scale * frame.getRotatedHeight());
if (scaledWidth == 0 || scaledHeight == 0) {
listenerAndParams.listener.onFrame(null);
@@ -656,12 +684,14 @@ public class EglRenderer implements VideoRenderer.Callbacks {
GLES20.glClearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- if (frame.yuvFrame) {
- listenerAndParams.drawer.drawYuv(yuvTextures, bitmapMatrix, frame.rotatedWidth(),
- frame.rotatedHeight(), 0 /* viewportX */, 0 /* viewportY */, scaledWidth, scaledHeight);
+ if (isYuvBuffer) {
+ drawer.drawYuv(yuvTextures,
+ RendererCommon.convertMatrixFromAndroidGraphicsMatrix(drawMatrix),
+ frame.getRotatedWidth(), frame.getRotatedHeight(), 0, 0, scaledWidth, scaledHeight);
} else {
- listenerAndParams.drawer.drawOes(frame.textureId, bitmapMatrix, frame.rotatedWidth(),
- frame.rotatedHeight(), 0 /* viewportX */, 0 /* viewportY */, scaledWidth, scaledHeight);
+ VideoFrame.TextureBuffer textureBuffer = (VideoFrame.TextureBuffer) frame.getBuffer();
+ drawer.drawTexture(textureBuffer, drawMatrix, frame.getRotatedWidth(),
+ frame.getRotatedHeight(), 0, 0, scaledWidth, scaledHeight);
}
final ByteBuffer bitmapBuffer = ByteBuffer.allocateDirect(scaledWidth * scaledHeight * 4);
« no previous file with comments | « no previous file | webrtc/sdk/android/api/org/webrtc/RendererCommon.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698