2021-06-27 20:44:35 +00:00
|
|
|
package org.webrtc;
|
|
|
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.Matrix;
|
|
|
|
import android.graphics.SurfaceTexture;
|
|
|
|
import android.opengl.GLES20;
|
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.HandlerThread;
|
|
|
|
import android.os.Looper;
|
|
|
|
import android.os.Message;
|
|
|
|
import android.view.Surface;
|
|
|
|
import androidx.annotation.Nullable;
|
2021-08-09 22:50:01 +00:00
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
2021-10-19 23:48:27 +00:00
|
|
|
import g0.c.e;
|
|
|
|
import g0.c.f;
|
|
|
|
import g0.c.g;
|
|
|
|
import g0.c.h;
|
|
|
|
import g0.c.i;
|
|
|
|
import g0.c.j;
|
|
|
|
import g0.c.k;
|
|
|
|
import g0.c.l;
|
|
|
|
import g0.c.n0;
|
2021-06-27 20:44:35 +00:00
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.text.DecimalFormat;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import org.webrtc.EglBase;
|
|
|
|
import org.webrtc.GlUtil;
|
|
|
|
import org.webrtc.RendererCommon;
|
|
|
|
public class EglRenderer implements VideoSink {
|
|
|
|
private static final long LOG_INTERVAL_SEC = 4;
|
|
|
|
private static final String TAG = "EglRenderer";
|
|
|
|
private final GlTextureFrameBuffer bitmapTextureFramebuffer;
|
|
|
|
private final Matrix drawMatrix;
|
|
|
|
@Nullable
|
|
|
|
private RendererCommon.GlDrawer drawer;
|
|
|
|
@Nullable
|
|
|
|
private EglBase eglBase;
|
|
|
|
private final EglSurfaceCreation eglSurfaceCreationRunnable;
|
|
|
|
private volatile ErrorCallback errorCallback;
|
|
|
|
private final Object fpsReductionLock;
|
|
|
|
private final VideoFrameDrawer frameDrawer;
|
|
|
|
private final ArrayList<FrameListenerAndParams> frameListeners;
|
|
|
|
private final Object frameLock;
|
|
|
|
private int framesDropped;
|
|
|
|
private int framesReceived;
|
|
|
|
private int framesRendered;
|
|
|
|
private final Object handlerLock;
|
|
|
|
private float layoutAspectRatio;
|
|
|
|
private final Object layoutLock;
|
|
|
|
private final Runnable logStatisticsRunnable;
|
|
|
|
private long minRenderPeriodNs;
|
|
|
|
private boolean mirrorHorizontally;
|
|
|
|
private boolean mirrorVertically;
|
|
|
|
public final String name;
|
|
|
|
private long nextFrameTimeNs;
|
|
|
|
@Nullable
|
|
|
|
private VideoFrame pendingFrame;
|
|
|
|
private long renderSwapBufferTimeNs;
|
|
|
|
@Nullable
|
|
|
|
private Handler renderThreadHandler;
|
|
|
|
private long renderTimeNs;
|
|
|
|
private final Object statisticsLock;
|
|
|
|
private long statisticsStartTimeNs;
|
|
|
|
private boolean usePresentationTimeStamp;
|
|
|
|
|
|
|
|
/* renamed from: org.webrtc.EglRenderer$1 reason: invalid class name */
|
|
|
|
public class AnonymousClass1 implements Runnable {
|
|
|
|
public AnonymousClass1() {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // java.lang.Runnable
|
|
|
|
public void run() {
|
|
|
|
EglRenderer.access$100(EglRenderer.this);
|
|
|
|
synchronized (EglRenderer.access$200(EglRenderer.this)) {
|
|
|
|
if (EglRenderer.access$300(EglRenderer.this) != null) {
|
|
|
|
EglRenderer.access$300(EglRenderer.this).removeCallbacks(EglRenderer.access$400(EglRenderer.this));
|
|
|
|
EglRenderer.access$300(EglRenderer.this).postDelayed(EglRenderer.access$400(EglRenderer.this), TimeUnit.SECONDS.toMillis(4));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* renamed from: org.webrtc.EglRenderer$2 reason: invalid class name */
|
|
|
|
public class AnonymousClass2 implements Runnable {
|
|
|
|
public AnonymousClass2() {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // java.lang.Runnable
|
|
|
|
public void run() {
|
|
|
|
synchronized (EglRenderer.access$200(EglRenderer.this)) {
|
|
|
|
EglRenderer.access$302(EglRenderer.this, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class EglSurfaceCreation implements Runnable {
|
|
|
|
private Object surface;
|
|
|
|
|
|
|
|
private EglSurfaceCreation() {
|
|
|
|
}
|
|
|
|
|
|
|
|
public /* synthetic */ EglSurfaceCreation(EglRenderer eglRenderer, AnonymousClass1 r2) {
|
|
|
|
this();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // java.lang.Runnable
|
|
|
|
public synchronized void run() {
|
|
|
|
if (!(this.surface == null || EglRenderer.access$000(EglRenderer.this) == null || EglRenderer.access$000(EglRenderer.this).hasSurface())) {
|
|
|
|
Object obj = this.surface;
|
|
|
|
if (obj instanceof Surface) {
|
|
|
|
EglRenderer.access$000(EglRenderer.this).createSurface((Surface) this.surface);
|
|
|
|
} else if (obj instanceof SurfaceTexture) {
|
|
|
|
EglRenderer.access$000(EglRenderer.this).createSurface((SurfaceTexture) this.surface);
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("Invalid surface: " + this.surface);
|
|
|
|
}
|
|
|
|
EglRenderer.access$000(EglRenderer.this).makeCurrent();
|
|
|
|
GLES20.glPixelStorei(3317, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized void setSurface(Object obj) {
|
|
|
|
this.surface = obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface ErrorCallback {
|
|
|
|
void onGlOutOfMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface FrameListener {
|
|
|
|
void onFrame(Bitmap bitmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class FrameListenerAndParams {
|
|
|
|
public final boolean applyFpsReduction;
|
|
|
|
public final RendererCommon.GlDrawer drawer;
|
|
|
|
public final FrameListener listener;
|
|
|
|
public final float scale;
|
|
|
|
|
|
|
|
public FrameListenerAndParams(FrameListener frameListener, float f, RendererCommon.GlDrawer glDrawer, boolean z2) {
|
|
|
|
this.listener = frameListener;
|
|
|
|
this.scale = f;
|
|
|
|
this.drawer = glDrawer;
|
|
|
|
this.applyFpsReduction = z2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class HandlerWithExceptionCallback extends Handler {
|
|
|
|
private final Runnable exceptionCallback;
|
|
|
|
|
|
|
|
public HandlerWithExceptionCallback(Looper looper, Runnable runnable) {
|
|
|
|
super(looper);
|
|
|
|
this.exceptionCallback = runnable;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // android.os.Handler
|
|
|
|
public void dispatchMessage(Message message) {
|
|
|
|
try {
|
|
|
|
super.dispatchMessage(message);
|
|
|
|
} catch (Exception e) {
|
2021-08-09 22:50:01 +00:00
|
|
|
Logging.e(EglRenderer.TAG, "Exception on EglRenderer thread", e);
|
2021-06-27 20:44:35 +00:00
|
|
|
this.exceptionCallback.run();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public EglRenderer(String str) {
|
|
|
|
this(str, new VideoFrameDrawer());
|
|
|
|
}
|
|
|
|
|
|
|
|
public EglRenderer(String str, VideoFrameDrawer videoFrameDrawer) {
|
|
|
|
this.handlerLock = new Object();
|
|
|
|
this.frameListeners = new ArrayList<>();
|
|
|
|
this.fpsReductionLock = new Object();
|
|
|
|
this.drawMatrix = new Matrix();
|
|
|
|
this.frameLock = new Object();
|
|
|
|
this.layoutLock = new Object();
|
|
|
|
this.statisticsLock = new Object();
|
|
|
|
this.bitmapTextureFramebuffer = new GlTextureFrameBuffer(6408);
|
|
|
|
this.logStatisticsRunnable = new AnonymousClass1();
|
|
|
|
this.eglSurfaceCreationRunnable = new EglSurfaceCreation(this, null);
|
|
|
|
this.name = str;
|
|
|
|
this.frameDrawer = videoFrameDrawer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ EglBase access$000(EglRenderer eglRenderer) {
|
|
|
|
return eglRenderer.eglBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ void access$100(EglRenderer eglRenderer) {
|
|
|
|
eglRenderer.logStatistics();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ Object access$200(EglRenderer eglRenderer) {
|
|
|
|
return eglRenderer.handlerLock;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ Handler access$300(EglRenderer eglRenderer) {
|
|
|
|
return eglRenderer.renderThreadHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ Handler access$302(EglRenderer eglRenderer, Handler handler) {
|
|
|
|
eglRenderer.renderThreadHandler = handler;
|
|
|
|
return handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ Runnable access$400(EglRenderer eglRenderer) {
|
|
|
|
return eglRenderer.logStatisticsRunnable;
|
|
|
|
}
|
|
|
|
|
|
|
|
private String averageTimeAsString(long j, int i) {
|
|
|
|
if (i <= 0) {
|
|
|
|
return "NA";
|
|
|
|
}
|
|
|
|
return TimeUnit.NANOSECONDS.toMicros(j / ((long) i)) + " us";
|
|
|
|
}
|
|
|
|
|
|
|
|
public static /* synthetic */ void c(EglRenderer eglRenderer) {
|
|
|
|
eglRenderer.renderFrameOnRenderThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* access modifiers changed from: private */
|
|
|
|
/* renamed from: clearSurfaceOnRenderThread */
|
|
|
|
public void b(float f, float f2, float f3, float f4) {
|
|
|
|
EglBase eglBase = this.eglBase;
|
|
|
|
if (eglBase != null && eglBase.hasSurface()) {
|
|
|
|
logD("clearSurface");
|
|
|
|
GLES20.glClearColor(f, f2, f3, f4);
|
|
|
|
GLES20.glClear(16384);
|
|
|
|
this.eglBase.swapBuffers();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void createEglSurfaceInternal(Object obj) {
|
|
|
|
this.eglSurfaceCreationRunnable.setSurface(obj);
|
|
|
|
postToRenderThread(this.eglSurfaceCreationRunnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* access modifiers changed from: private */
|
|
|
|
/* renamed from: lambda$init$0 */
|
|
|
|
public void d(EglBase.Context context, int[] iArr) {
|
|
|
|
if (context == null) {
|
|
|
|
logD("EglBase10.create context");
|
|
|
|
Object obj = EglBase.lock;
|
|
|
|
this.eglBase = new EglBase10Impl(null, iArr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
logD("EglBase.create shared context");
|
|
|
|
this.eglBase = n0.b(context, iArr);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void logD(String str) {
|
2021-08-09 22:50:01 +00:00
|
|
|
Logging.d(TAG, this.name + str);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void logE(String str, Throwable th) {
|
2021-08-09 22:50:01 +00:00
|
|
|
Logging.e(TAG, this.name + str, th);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void logStatistics() {
|
|
|
|
DecimalFormat decimalFormat = new DecimalFormat("#.0");
|
|
|
|
long nanoTime = System.nanoTime();
|
|
|
|
synchronized (this.statisticsLock) {
|
|
|
|
long j = nanoTime - this.statisticsStartTimeNs;
|
|
|
|
if (j > 0) {
|
2021-08-09 22:50:01 +00:00
|
|
|
if (this.minRenderPeriodNs != RecyclerView.FOREVER_NS || this.framesReceived != 0) {
|
2021-06-27 20:44:35 +00:00
|
|
|
float nanos = ((float) (((long) this.framesRendered) * TimeUnit.SECONDS.toNanos(1))) / ((float) j);
|
|
|
|
logD("Duration: " + TimeUnit.NANOSECONDS.toMillis(j) + " ms. Frames received: " + this.framesReceived + ". Dropped: " + this.framesDropped + ". Rendered: " + this.framesRendered + ". Render fps: " + decimalFormat.format((double) nanos) + ". Average render time: " + averageTimeAsString(this.renderTimeNs, this.framesRendered) + ". Average swapBuffer time: " + averageTimeAsString(this.renderSwapBufferTimeNs, this.framesRendered) + ".");
|
|
|
|
resetStatistics(nanoTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void logW(String str) {
|
2021-08-09 22:50:01 +00:00
|
|
|
Logging.w(TAG, this.name + str);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void notifyCallbacks(VideoFrame videoFrame, boolean z2) {
|
|
|
|
if (!this.frameListeners.isEmpty()) {
|
|
|
|
this.drawMatrix.reset();
|
|
|
|
this.drawMatrix.preTranslate(0.5f, 0.5f);
|
|
|
|
this.drawMatrix.preScale(this.mirrorHorizontally ? -1.0f : 1.0f, this.mirrorVertically ? -1.0f : 1.0f);
|
|
|
|
this.drawMatrix.preScale(1.0f, -1.0f);
|
|
|
|
this.drawMatrix.preTranslate(-0.5f, -0.5f);
|
|
|
|
Iterator<FrameListenerAndParams> it = this.frameListeners.iterator();
|
|
|
|
while (it.hasNext()) {
|
|
|
|
FrameListenerAndParams next = it.next();
|
|
|
|
if (z2 || !next.applyFpsReduction) {
|
|
|
|
it.remove();
|
|
|
|
int rotatedWidth = (int) (next.scale * ((float) videoFrame.getRotatedWidth()));
|
|
|
|
int rotatedHeight = (int) (next.scale * ((float) videoFrame.getRotatedHeight()));
|
|
|
|
if (rotatedWidth == 0 || rotatedHeight == 0) {
|
|
|
|
next.listener.onFrame(null);
|
|
|
|
} else {
|
|
|
|
this.bitmapTextureFramebuffer.setSize(rotatedWidth, rotatedHeight);
|
|
|
|
GLES20.glBindFramebuffer(36160, this.bitmapTextureFramebuffer.getFrameBufferId());
|
|
|
|
GLES20.glFramebufferTexture2D(36160, 36064, 3553, this.bitmapTextureFramebuffer.getTextureId(), 0);
|
|
|
|
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
GLES20.glClear(16384);
|
|
|
|
this.frameDrawer.drawFrame(videoFrame, next.drawer, this.drawMatrix, 0, 0, rotatedWidth, rotatedHeight);
|
|
|
|
ByteBuffer allocateDirect = ByteBuffer.allocateDirect(rotatedWidth * rotatedHeight * 4);
|
|
|
|
GLES20.glViewport(0, 0, rotatedWidth, rotatedHeight);
|
|
|
|
GLES20.glReadPixels(0, 0, rotatedWidth, rotatedHeight, 6408, 5121, allocateDirect);
|
|
|
|
GLES20.glBindFramebuffer(36160, 0);
|
|
|
|
GlUtil.checkNoGLES2Error("EglRenderer.notifyCallbacks");
|
|
|
|
Bitmap createBitmap = Bitmap.createBitmap(rotatedWidth, rotatedHeight, Bitmap.Config.ARGB_8888);
|
|
|
|
createBitmap.copyPixelsFromBuffer(allocateDirect);
|
|
|
|
next.listener.onFrame(createBitmap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void postToRenderThread(Runnable runnable) {
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
Handler handler = this.renderThreadHandler;
|
|
|
|
if (handler != null) {
|
|
|
|
handler.post(runnable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* JADX WARNING: Removed duplicated region for block: B:82:0x013b */
|
|
|
|
private void renderFrameOnRenderThread() {
|
|
|
|
VideoFrame videoFrame;
|
|
|
|
boolean z2;
|
|
|
|
boolean z3;
|
|
|
|
float f;
|
|
|
|
float f2;
|
|
|
|
float f3;
|
|
|
|
Throwable th;
|
|
|
|
GlUtil.GlOutOfMemoryException e;
|
|
|
|
synchronized (this.frameLock) {
|
|
|
|
videoFrame = this.pendingFrame;
|
|
|
|
if (videoFrame != null) {
|
|
|
|
this.pendingFrame = null;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EglBase eglBase = this.eglBase;
|
|
|
|
if (eglBase == null || !eglBase.hasSurface()) {
|
|
|
|
logD("Dropping frame - No surface");
|
|
|
|
videoFrame.release();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
synchronized (this.fpsReductionLock) {
|
|
|
|
long j = this.minRenderPeriodNs;
|
|
|
|
z2 = true;
|
2021-08-09 22:50:01 +00:00
|
|
|
if (j != RecyclerView.FOREVER_NS) {
|
2021-06-27 20:44:35 +00:00
|
|
|
if (j > 0) {
|
|
|
|
long nanoTime = System.nanoTime();
|
|
|
|
long j2 = this.nextFrameTimeNs;
|
|
|
|
if (nanoTime < j2) {
|
|
|
|
logD("Skipping frame rendering - fps reduction is active.");
|
|
|
|
} else {
|
|
|
|
long j3 = j2 + this.minRenderPeriodNs;
|
|
|
|
this.nextFrameTimeNs = j3;
|
|
|
|
this.nextFrameTimeNs = Math.max(j3, nanoTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
z3 = true;
|
|
|
|
}
|
|
|
|
z3 = false;
|
|
|
|
}
|
|
|
|
long nanoTime2 = System.nanoTime();
|
|
|
|
float rotatedWidth = ((float) videoFrame.getRotatedWidth()) / ((float) videoFrame.getRotatedHeight());
|
|
|
|
synchronized (this.layoutLock) {
|
|
|
|
f = this.layoutAspectRatio;
|
|
|
|
if (f == 0.0f) {
|
|
|
|
f = rotatedWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
float f4 = 1.0f;
|
|
|
|
if (rotatedWidth > f) {
|
|
|
|
f2 = f / rotatedWidth;
|
|
|
|
f3 = 1.0f;
|
|
|
|
} else {
|
|
|
|
f3 = rotatedWidth / f;
|
|
|
|
f2 = 1.0f;
|
|
|
|
}
|
|
|
|
this.drawMatrix.reset();
|
|
|
|
this.drawMatrix.preTranslate(0.5f, 0.5f);
|
|
|
|
Matrix matrix = this.drawMatrix;
|
|
|
|
float f5 = this.mirrorHorizontally ? -1.0f : 1.0f;
|
|
|
|
if (this.mirrorVertically) {
|
|
|
|
f4 = -1.0f;
|
|
|
|
}
|
|
|
|
matrix.preScale(f5, f4);
|
|
|
|
this.drawMatrix.preScale(f2, f3);
|
|
|
|
this.drawMatrix.preTranslate(-0.5f, -0.5f);
|
|
|
|
try {
|
|
|
|
notifyCallbacks(videoFrame, z3);
|
|
|
|
if (z3) {
|
|
|
|
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
GLES20.glClear(16384);
|
|
|
|
this.frameDrawer.drawFrame(videoFrame, this.drawer, this.drawMatrix, 0, 0, this.eglBase.surfaceWidth(), this.eglBase.surfaceHeight());
|
|
|
|
long nanoTime3 = System.nanoTime();
|
|
|
|
if (this.usePresentationTimeStamp) {
|
|
|
|
long timestampNs = videoFrame.getTimestampNs();
|
|
|
|
videoFrame.release();
|
|
|
|
try {
|
|
|
|
this.eglBase.swapBuffers(timestampNs);
|
|
|
|
} catch (GlUtil.GlOutOfMemoryException e2) {
|
|
|
|
e = e2;
|
|
|
|
z2 = false;
|
|
|
|
} catch (Throwable th2) {
|
|
|
|
th = th2;
|
|
|
|
z2 = false;
|
|
|
|
if (z2) {
|
|
|
|
}
|
|
|
|
throw th;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
videoFrame.release();
|
|
|
|
this.eglBase.swapBuffers();
|
|
|
|
}
|
|
|
|
long nanoTime4 = System.nanoTime();
|
|
|
|
synchronized (this.statisticsLock) {
|
|
|
|
this.framesRendered++;
|
|
|
|
this.renderTimeNs = (nanoTime4 - nanoTime2) + this.renderTimeNs;
|
|
|
|
this.renderSwapBufferTimeNs = (nanoTime4 - nanoTime3) + this.renderSwapBufferTimeNs;
|
|
|
|
}
|
|
|
|
z2 = false;
|
|
|
|
}
|
|
|
|
notifyCallbacks(videoFrame, z3);
|
|
|
|
if (!z2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} catch (GlUtil.GlOutOfMemoryException e3) {
|
|
|
|
e = e3;
|
|
|
|
try {
|
|
|
|
logE("Error while drawing frame", e);
|
|
|
|
ErrorCallback errorCallback = this.errorCallback;
|
|
|
|
if (errorCallback != null) {
|
|
|
|
errorCallback.onGlOutOfMemory();
|
|
|
|
}
|
|
|
|
this.drawer.release();
|
|
|
|
this.frameDrawer.release();
|
|
|
|
this.bitmapTextureFramebuffer.release();
|
|
|
|
if (!z2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
videoFrame.release();
|
|
|
|
} catch (Throwable th3) {
|
|
|
|
th = th3;
|
|
|
|
if (z2) {
|
|
|
|
videoFrame.release();
|
|
|
|
}
|
|
|
|
throw th;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
videoFrame.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void resetStatistics(long j) {
|
|
|
|
synchronized (this.statisticsLock) {
|
|
|
|
this.statisticsStartTimeNs = j;
|
|
|
|
this.framesReceived = 0;
|
|
|
|
this.framesDropped = 0;
|
|
|
|
this.framesRendered = 0;
|
|
|
|
this.renderTimeNs = 0;
|
|
|
|
this.renderSwapBufferTimeNs = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public /* synthetic */ void a(RendererCommon.GlDrawer glDrawer, FrameListener frameListener, float f, boolean z2) {
|
|
|
|
if (glDrawer == null) {
|
|
|
|
glDrawer = this.drawer;
|
|
|
|
}
|
|
|
|
this.frameListeners.add(new FrameListenerAndParams(frameListener, f, glDrawer, z2));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addFrameListener(FrameListener frameListener, float f) {
|
|
|
|
addFrameListener(frameListener, f, null, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addFrameListener(FrameListener frameListener, float f, RendererCommon.GlDrawer glDrawer) {
|
|
|
|
addFrameListener(frameListener, f, glDrawer, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addFrameListener(FrameListener frameListener, float f, @Nullable RendererCommon.GlDrawer glDrawer, boolean z2) {
|
|
|
|
postToRenderThread(new l(this, glDrawer, frameListener, f, z2));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearImage() {
|
|
|
|
clearImage(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearImage(float f, float f2, float f3, float f4) {
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
Handler handler = this.renderThreadHandler;
|
|
|
|
if (handler != null) {
|
|
|
|
handler.postAtFrontOfQueue(new f(this, f, f2, f3, f4));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void createEglSurface(SurfaceTexture surfaceTexture) {
|
|
|
|
createEglSurfaceInternal(surfaceTexture);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void createEglSurface(Surface surface) {
|
|
|
|
createEglSurfaceInternal(surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void disableFpsReduction() {
|
|
|
|
setFpsReduction(Float.POSITIVE_INFINITY);
|
|
|
|
}
|
|
|
|
|
|
|
|
public /* synthetic */ void e(CountDownLatch countDownLatch) {
|
|
|
|
synchronized (EglBase.lock) {
|
|
|
|
GLES20.glUseProgram(0);
|
|
|
|
}
|
|
|
|
RendererCommon.GlDrawer glDrawer = this.drawer;
|
|
|
|
if (glDrawer != null) {
|
|
|
|
glDrawer.release();
|
|
|
|
this.drawer = null;
|
|
|
|
}
|
|
|
|
this.frameDrawer.release();
|
|
|
|
this.bitmapTextureFramebuffer.release();
|
|
|
|
if (this.eglBase != null) {
|
|
|
|
logD("eglBase detach and release.");
|
|
|
|
this.eglBase.detachCurrent();
|
|
|
|
this.eglBase.release();
|
|
|
|
this.eglBase = null;
|
|
|
|
}
|
|
|
|
this.frameListeners.clear();
|
|
|
|
countDownLatch.countDown();
|
|
|
|
}
|
|
|
|
|
|
|
|
public /* synthetic */ void f(Looper looper) {
|
|
|
|
logD("Quitting render thread.");
|
|
|
|
looper.quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
public /* synthetic */ void g(Runnable runnable) {
|
|
|
|
EglBase eglBase = this.eglBase;
|
|
|
|
if (eglBase != null) {
|
|
|
|
eglBase.detachCurrent();
|
|
|
|
this.eglBase.releaseSurface();
|
|
|
|
}
|
|
|
|
runnable.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
public /* synthetic */ void h(CountDownLatch countDownLatch, FrameListener frameListener) {
|
|
|
|
countDownLatch.countDown();
|
|
|
|
Iterator<FrameListenerAndParams> it = this.frameListeners.iterator();
|
|
|
|
while (it.hasNext()) {
|
|
|
|
if (it.next().listener == frameListener) {
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void init(@Nullable EglBase.Context context, int[] iArr, RendererCommon.GlDrawer glDrawer) {
|
|
|
|
init(context, iArr, glDrawer, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void init(@Nullable EglBase.Context context, int[] iArr, RendererCommon.GlDrawer glDrawer, boolean z2) {
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
if (this.renderThreadHandler == null) {
|
|
|
|
logD("Initializing EglRenderer");
|
|
|
|
this.drawer = glDrawer;
|
|
|
|
this.usePresentationTimeStamp = z2;
|
2021-08-09 22:50:01 +00:00
|
|
|
HandlerThread handlerThread = new HandlerThread(this.name + TAG);
|
2021-06-27 20:44:35 +00:00
|
|
|
handlerThread.start();
|
|
|
|
HandlerWithExceptionCallback handlerWithExceptionCallback = new HandlerWithExceptionCallback(handlerThread.getLooper(), new AnonymousClass2());
|
|
|
|
this.renderThreadHandler = handlerWithExceptionCallback;
|
|
|
|
ThreadUtils.invokeAtFrontUninterruptibly(handlerWithExceptionCallback, new j(this, context, iArr));
|
|
|
|
this.renderThreadHandler.post(this.eglSurfaceCreationRunnable);
|
|
|
|
resetStatistics(System.nanoTime());
|
|
|
|
this.renderThreadHandler.postDelayed(this.logStatisticsRunnable, TimeUnit.SECONDS.toMillis(4));
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException(this.name + "Already initialized");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override // org.webrtc.VideoSink
|
|
|
|
public void onFrame(VideoFrame videoFrame) {
|
|
|
|
boolean z2;
|
|
|
|
synchronized (this.statisticsLock) {
|
|
|
|
this.framesReceived++;
|
|
|
|
}
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
if (this.renderThreadHandler == null) {
|
|
|
|
logD("Dropping frame - Not initialized or already released.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
synchronized (this.frameLock) {
|
|
|
|
VideoFrame videoFrame2 = this.pendingFrame;
|
|
|
|
z2 = videoFrame2 != null;
|
|
|
|
if (z2) {
|
|
|
|
videoFrame2.release();
|
|
|
|
}
|
|
|
|
this.pendingFrame = videoFrame;
|
|
|
|
videoFrame.retain();
|
|
|
|
this.renderThreadHandler.post(new i(this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (z2) {
|
|
|
|
synchronized (this.statisticsLock) {
|
|
|
|
this.framesDropped++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void pauseVideo() {
|
|
|
|
setFpsReduction(0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void printStackTrace() {
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
Handler handler = this.renderThreadHandler;
|
|
|
|
Thread thread = handler == null ? null : handler.getLooper().getThread();
|
|
|
|
if (thread != null) {
|
|
|
|
StackTraceElement[] stackTrace = thread.getStackTrace();
|
|
|
|
if (stackTrace.length > 0) {
|
|
|
|
logW("EglRenderer stack trace:");
|
|
|
|
for (StackTraceElement stackTraceElement : stackTrace) {
|
|
|
|
logW(stackTraceElement.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void release() {
|
|
|
|
logD("Releasing.");
|
|
|
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
Handler handler = this.renderThreadHandler;
|
|
|
|
if (handler == null) {
|
|
|
|
logD("Already released");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
handler.removeCallbacks(this.logStatisticsRunnable);
|
|
|
|
this.renderThreadHandler.postAtFrontOfQueue(new h(this, countDownLatch));
|
|
|
|
this.renderThreadHandler.post(new k(this, this.renderThreadHandler.getLooper()));
|
|
|
|
this.renderThreadHandler = null;
|
|
|
|
}
|
|
|
|
ThreadUtils.awaitUninterruptibly(countDownLatch);
|
|
|
|
synchronized (this.frameLock) {
|
|
|
|
VideoFrame videoFrame = this.pendingFrame;
|
|
|
|
if (videoFrame != null) {
|
|
|
|
videoFrame.release();
|
|
|
|
this.pendingFrame = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
logD("Releasing done.");
|
|
|
|
}
|
|
|
|
|
|
|
|
public void releaseEglSurface(Runnable runnable) {
|
|
|
|
this.eglSurfaceCreationRunnable.setSurface(null);
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
Handler handler = this.renderThreadHandler;
|
|
|
|
if (handler != null) {
|
|
|
|
handler.removeCallbacks(this.eglSurfaceCreationRunnable);
|
|
|
|
this.renderThreadHandler.postAtFrontOfQueue(new e(this, runnable));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
runnable.run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeFrameListener(FrameListener frameListener) {
|
|
|
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
|
|
|
synchronized (this.handlerLock) {
|
|
|
|
if (this.renderThreadHandler != null) {
|
|
|
|
if (Thread.currentThread() != this.renderThreadHandler.getLooper().getThread()) {
|
|
|
|
postToRenderThread(new g(this, countDownLatch, frameListener));
|
|
|
|
ThreadUtils.awaitUninterruptibly(countDownLatch);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw new RuntimeException("removeFrameListener must not be called on the render thread.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setErrorCallback(ErrorCallback errorCallback) {
|
|
|
|
this.errorCallback = errorCallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setFpsReduction(float f) {
|
|
|
|
logD("setFpsReduction: " + f);
|
|
|
|
synchronized (this.fpsReductionLock) {
|
|
|
|
long j = this.minRenderPeriodNs;
|
|
|
|
if (f <= 0.0f) {
|
2021-08-09 22:50:01 +00:00
|
|
|
this.minRenderPeriodNs = RecyclerView.FOREVER_NS;
|
2021-06-27 20:44:35 +00:00
|
|
|
} else {
|
|
|
|
this.minRenderPeriodNs = (long) (((float) TimeUnit.SECONDS.toNanos(1)) / f);
|
|
|
|
}
|
|
|
|
if (this.minRenderPeriodNs != j) {
|
|
|
|
this.nextFrameTimeNs = System.nanoTime();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setLayoutAspectRatio(float f) {
|
|
|
|
logD("setLayoutAspectRatio: " + f);
|
|
|
|
synchronized (this.layoutLock) {
|
|
|
|
this.layoutAspectRatio = f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMirror(boolean z2) {
|
|
|
|
logD("setMirrorHorizontally: " + z2);
|
|
|
|
synchronized (this.layoutLock) {
|
|
|
|
this.mirrorHorizontally = z2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMirrorVertically(boolean z2) {
|
|
|
|
logD("setMirrorVertically: " + z2);
|
|
|
|
synchronized (this.layoutLock) {
|
|
|
|
this.mirrorVertically = z2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|