Commit 65662371 by andrewlewis Committed by tonihei

Mark methods needing to be called on GL thread

Also remove @WorkerThread annotations, as static checks associated with
this annotation aren't useful in this part of the codebase because
almost no methods are called on the main thread.

This change should be a no-op.

PiperOrigin-RevId: 512060367
parent 51f8d103
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
package com.google.android.exoplayer2.effect; package com.google.android.exoplayer2.effect;
import android.content.Context; import android.content.Context;
import androidx.annotation.WorkerThread;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.VideoFrameProcessingException; import com.google.android.exoplayer2.util.VideoFrameProcessingException;
...@@ -39,9 +38,7 @@ public interface ColorLut extends GlEffect { ...@@ -39,9 +38,7 @@ public interface ColorLut extends GlEffect {
/** Releases the OpenGL texture of the LUT. */ /** Releases the OpenGL texture of the LUT. */
void release() throws GlUtil.GlException; void release() throws GlUtil.GlException;
/** This method must be executed on the same thread as other GL commands. */
@Override @Override
@WorkerThread
default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr) default SingleFrameGlShaderProgram toGlShaderProgram(Context context, boolean useHdr)
throws VideoFrameProcessingException { throws VideoFrameProcessingException {
return new ColorLutShaderProgram(context, /* colorLut= */ this, useHdr); return new ColorLutShaderProgram(context, /* colorLut= */ this, useHdr);
......
...@@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull; ...@@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.effect.GlShaderProgram.InputListener; import com.google.android.exoplayer2.effect.GlShaderProgram.InputListener;
import com.google.android.exoplayer2.util.FrameInfo; import com.google.android.exoplayer2.util.FrameInfo;
...@@ -186,7 +185,15 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -186,7 +185,15 @@ import java.util.concurrent.atomic.AtomicInteger;
surface.release(); surface.release();
} }
@WorkerThread private void maybeExecuteAfterFlushTask() {
if (onFlushCompleteTask == null || numberOfFramesToDropOnBecomingAvailable > 0) {
return;
}
videoFrameProcessingTaskExecutor.submitWithHighPriority(onFlushCompleteTask);
}
// Methods that must be called on the GL thread.
private void flush() { private void flush() {
// A frame that is registered before flush may arrive after flush. // A frame that is registered before flush may arrive after flush.
numberOfFramesToDropOnBecomingAvailable = pendingFrames.size() - availableFrameCount; numberOfFramesToDropOnBecomingAvailable = pendingFrames.size() - availableFrameCount;
...@@ -200,14 +207,6 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -200,14 +207,6 @@ import java.util.concurrent.atomic.AtomicInteger;
maybeExecuteAfterFlushTask(); maybeExecuteAfterFlushTask();
} }
private void maybeExecuteAfterFlushTask() {
if (onFlushCompleteTask == null || numberOfFramesToDropOnBecomingAvailable > 0) {
return;
}
videoFrameProcessingTaskExecutor.submitWithHighPriority(onFlushCompleteTask);
}
@WorkerThread
private void maybeQueueFrameToExternalShaderProgram() { private void maybeQueueFrameToExternalShaderProgram() {
if (externalShaderProgramInputCapacity.get() == 0 if (externalShaderProgramInputCapacity.get() == 0
|| availableFrameCount == 0 || availableFrameCount == 0
......
...@@ -32,7 +32,6 @@ import android.view.SurfaceHolder; ...@@ -32,7 +32,6 @@ import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import androidx.annotation.GuardedBy; import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.DebugViewProvider; import com.google.android.exoplayer2.util.DebugViewProvider;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
...@@ -153,6 +152,30 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -153,6 +152,30 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
@Override @Override
public void signalEndOfCurrentInputStream() {
checkState(!streamOffsetUsQueue.isEmpty(), "No input stream to end.");
streamOffsetUsQueue.remove();
if (streamOffsetUsQueue.isEmpty()) {
videoFrameProcessorListenerExecutor.execute(videoFrameProcessorListener::onEnded);
}
}
/**
* Signals that there will be another input stream after all previously appended input streams
* have {@linkplain #signalEndOfCurrentInputStream() ended}.
*
* <p>This method does not need to be called on the GL thread, but the caller must ensure that
* stream offsets are appended in the correct order.
*
* @param streamOffsetUs The presentation timestamp offset, in microseconds.
*/
public void appendStream(long streamOffsetUs) {
streamOffsetUsQueue.add(streamOffsetUs);
}
// Methods that must be called on the GL thread.
@Override
public void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) { public void queueInputFrame(TextureInfo inputTexture, long presentationTimeUs) {
long streamOffsetUs = long streamOffsetUs =
checkStateNotNull(streamOffsetUsQueue.peek(), "No input stream specified."); checkStateNotNull(streamOffsetUsQueue.peek(), "No input stream specified.");
...@@ -174,7 +197,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -174,7 +197,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@WorkerThread
public void releaseOutputFrame(long releaseTimeNs) { public void releaseOutputFrame(long releaseTimeNs) {
checkState(!releaseFramesAutomatically); checkState(!releaseFramesAutomatically);
Pair<TextureInfo, Long> oldestAvailableFrame = availableFrames.remove(); Pair<TextureInfo, Long> oldestAvailableFrame = availableFrames.remove();
...@@ -185,15 +207,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -185,15 +207,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
@Override @Override
public void signalEndOfCurrentInputStream() {
checkState(!streamOffsetUsQueue.isEmpty(), "No input stream to end.");
streamOffsetUsQueue.remove();
if (streamOffsetUsQueue.isEmpty()) {
videoFrameProcessorListenerExecutor.execute(videoFrameProcessorListener::onEnded);
}
}
@Override
public void flush() { public void flush() {
// Drops all frames that aren't released yet. // Drops all frames that aren't released yet.
availableFrames.clear(); availableFrames.clear();
...@@ -205,19 +218,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -205,19 +218,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
@Override @Override
@WorkerThread
public synchronized void release() throws VideoFrameProcessingException {
if (defaultShaderProgram != null) {
defaultShaderProgram.release();
}
try {
GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
} catch (GlUtil.GlException e) {
throw new VideoFrameProcessingException(e);
}
}
@Override
public void setTextureTransformMatrix(float[] textureTransformMatrix) { public void setTextureTransformMatrix(float[] textureTransformMatrix) {
System.arraycopy( System.arraycopy(
/* src= */ textureTransformMatrix, /* src= */ textureTransformMatrix,
...@@ -231,17 +231,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -231,17 +231,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
} }
/** @Override
* Signals that there will be another input stream after all previously appended input streams public synchronized void release() throws VideoFrameProcessingException {
* have {@linkplain #signalEndOfCurrentInputStream() ended}. if (defaultShaderProgram != null) {
* defaultShaderProgram.release();
* <p>This method does not need to be called on the GL thread, but the caller must ensure that }
* stream offsets are appended in the correct order. try {
* GlUtil.destroyEglSurface(eglDisplay, outputEglSurface);
* @param streamOffsetUs The presentation timestamp offset, in microseconds. } catch (GlUtil.GlException e) {
*/ throw new VideoFrameProcessingException(e);
public void appendStream(long streamOffsetUs) { }
streamOffsetUsQueue.add(streamOffsetUs);
} }
/** /**
...@@ -495,12 +494,36 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -495,12 +494,36 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
height = surfaceView.getHeight(); height = surfaceView.getHeight();
} }
@Override
public void surfaceCreated(SurfaceHolder holder) {}
@Override
public synchronized void surfaceChanged(
SurfaceHolder holder, int format, int width, int height) {
this.width = width;
this.height = height;
Surface newSurface = holder.getSurface();
if (surface == null || !surface.equals(newSurface)) {
surface = newSurface;
eglSurface = null;
}
}
@Override
public synchronized void surfaceDestroyed(SurfaceHolder holder) {
surface = null;
eglSurface = null;
width = C.LENGTH_UNSET;
height = C.LENGTH_UNSET;
}
/** /**
* Focuses the wrapped surface view's surface as an {@link EGLSurface}, renders using {@code * Focuses the wrapped surface view's surface as an {@link EGLSurface}, renders using {@code
* renderingTask} and swaps buffers, if the view's holder has a valid surface. Does nothing * renderingTask} and swaps buffers, if the view's holder has a valid surface. Does nothing
* otherwise. * otherwise.
*
* <p>Must be called on the GL thread.
*/ */
@WorkerThread
public synchronized void maybeRenderToSurfaceView(VideoFrameProcessingTask renderingTask) public synchronized void maybeRenderToSurfaceView(VideoFrameProcessingTask renderingTask)
throws GlUtil.GlException, VideoFrameProcessingException { throws GlUtil.GlException, VideoFrameProcessingException {
if (surface == null) { if (surface == null) {
...@@ -519,28 +542,5 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -519,28 +542,5 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Prevents white flashing on the debug SurfaceView when frames are rendered too fast. // Prevents white flashing on the debug SurfaceView when frames are rendered too fast.
GLES20.glFinish(); GLES20.glFinish();
} }
@Override
public void surfaceCreated(SurfaceHolder holder) {}
@Override
public synchronized void surfaceChanged(
SurfaceHolder holder, int format, int width, int height) {
this.width = width;
this.height = height;
Surface newSurface = holder.getSurface();
if (surface == null || !surface.equals(newSurface)) {
surface = newSurface;
eglSurface = null;
}
}
@Override
public synchronized void surfaceDestroyed(SurfaceHolder holder) {
surface = null;
eglSurface = null;
width = C.LENGTH_UNSET;
height = C.LENGTH_UNSET;
}
} }
} }
...@@ -21,7 +21,6 @@ import static java.lang.Math.floor; ...@@ -21,7 +21,6 @@ import static java.lang.Math.floor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLUtils; import android.opengl.GLUtils;
import androidx.annotation.WorkerThread;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.VideoFrameProcessingException; import com.google.android.exoplayer2.util.VideoFrameProcessingException;
...@@ -34,7 +33,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -34,7 +33,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* Forwards a video frame produced from a {@link Bitmap} to a {@link GlShaderProgram} for * Forwards a video frame produced from a {@link Bitmap} to a {@link GlShaderProgram} for
* consumption. * consumption.
* *
* <p>Methods in this class can be called from any thread. * <p>Public methods in this class can be called from any thread.
*/ */
/* package */ final class InternalTextureManager implements GlShaderProgram.InputListener { /* package */ final class InternalTextureManager implements GlShaderProgram.InputListener {
private final GlShaderProgram shaderProgram; private final GlShaderProgram shaderProgram;
...@@ -99,7 +98,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -99,7 +98,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}); });
} }
@WorkerThread // Methods that must be called on the GL thread.
private void setupBitmap(Bitmap bitmap, long durationUs, float frameRate, boolean useHdr) private void setupBitmap(Bitmap bitmap, long durationUs, float frameRate, boolean useHdr)
throws VideoFrameProcessingException { throws VideoFrameProcessingException {
this.useHdr = useHdr; this.useHdr = useHdr;
...@@ -113,7 +113,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -113,7 +113,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
maybeQueueToShaderProgram(); maybeQueueToShaderProgram();
} }
@WorkerThread
private void maybeQueueToShaderProgram() throws VideoFrameProcessingException { private void maybeQueueToShaderProgram() throws VideoFrameProcessingException {
if (pendingBitmaps.isEmpty() || downstreamShaderProgramCapacity == 0) { if (pendingBitmaps.isEmpty() || downstreamShaderProgramCapacity == 0) {
return; return;
...@@ -156,7 +155,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -156,7 +155,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
} }
@WorkerThread
private void maybeSignalEndOfOutput() { private void maybeSignalEndOfOutput() {
if (framesToQueueForCurrentBitmap == 0 if (framesToQueueForCurrentBitmap == 0
&& pendingBitmaps.isEmpty() && pendingBitmaps.isEmpty()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment