diff --git a/libraries/effect/src/main/java/androidx/media3/effect/BitmapTextureManager.java b/libraries/effect/src/main/java/androidx/media3/effect/BitmapTextureManager.java index 83f0d857b6..7512978caf 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/BitmapTextureManager.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/BitmapTextureManager.java @@ -22,7 +22,6 @@ import static androidx.media3.common.util.Assertions.checkState; import android.graphics.Bitmap; import android.opengl.GLES20; import android.opengl.GLUtils; -import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.FrameInfo; import androidx.media3.common.GlObjectsProvider; @@ -43,7 +42,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; *
Public methods in this class can be called from any thread.
*/
@UnstableApi
-/* package */ final class BitmapTextureManager implements TextureManager {
+/* package */ final class BitmapTextureManager extends TextureManager {
private static final String UNSUPPORTED_IMAGE_CONFIGURATION =
"Unsupported Image Configuration: No more than 8 bits of precision should be used for each"
@@ -51,7 +50,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final GlObjectsProvider glObjectsProvider;
private final GlShaderProgram shaderProgram;
- private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
// The queue holds all bitmaps with one or more frames pending to be sent downstream.
private final Queue Public methods in this class can be called from any thread.
*/
-/* package */ final class TexIdTextureManager implements TextureManager {
- private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
+/* package */ final class TexIdTextureManager extends TextureManager {
private final FrameConsumptionManager frameConsumptionManager;
private @MonotonicNonNull OnInputFrameProcessedListener frameProcessedListener;
@@ -53,7 +50,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
GlObjectsProvider glObjectsProvider,
GlShaderProgram shaderProgram,
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
- this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor;
+ super(videoFrameProcessingTaskExecutor);
frameConsumptionManager =
new FrameConsumptionManager(
glObjectsProvider, shaderProgram, videoFrameProcessingTaskExecutor);
@@ -72,11 +69,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
.onInputFrameProcessed(inputTexture.texId, GlUtil.createGlSyncFence()));
}
- @Override
- public void onFlush() {
- videoFrameProcessingTaskExecutor.submit(frameConsumptionManager::onFlush);
- }
-
@Override
public void queueInputTexture(int inputTexId, long presentationTimeUs) {
FrameInfo frameInfo = checkNotNull(this.inputFrameInfo);
@@ -124,12 +116,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
@Override
- public void setOnFlushCompleteListener(@Nullable VideoFrameProcessingTaskExecutor.Task task) {
+ public void release() {
// Do nothing.
}
+ // Methods that must be called on the GL thread.
+
@Override
- public void release() throws VideoFrameProcessingException {
- // Do nothing.
+ protected synchronized void flush() {
+ frameConsumptionManager.onFlush();
+ super.flush();
}
}
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/TextureManager.java b/libraries/effect/src/main/java/androidx/media3/effect/TextureManager.java
index 3bfee8aedd..5deb6489fc 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/TextureManager.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/TextureManager.java
@@ -20,6 +20,7 @@ package androidx.media3.effect;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.view.Surface;
+import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import androidx.media3.common.FrameInfo;
import androidx.media3.common.OnInputFrameProcessedListener;
@@ -27,15 +28,39 @@ import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.util.TimestampIterator;
-/** Handles {@code DefaultVideoFrameProcessor}'s input. */
-/* package */ interface TextureManager extends GlShaderProgram.InputListener {
+/**
+ * Handles {@code DefaultVideoFrameProcessor}'s input.
+ *
+ * All instance methods must be called from either the thread that owns {@code this} instance, or
+ * an internal GL thread.
+ */
+/* package */ abstract class TextureManager implements GlShaderProgram.InputListener {
+
+ protected final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
+
+ private final Object lock;
+
+ // TODO(b/238302341) Remove the use of onFlushCompleteTask, block the calling thread instead.
+ @GuardedBy("lock")
+ @Nullable
+ private VideoFrameProcessingTaskExecutor.Task onFlushCompleteTask;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor}.
+ */
+ public TextureManager(VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
+ this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor;
+ lock = new Object();
+ }
/**
* See {@link DefaultVideoFrameProcessor#setInputDefaultBufferSize}.
*
* Only works when the input is received on a {@link SurfaceTexture}.
*/
- default void setDefaultBufferSize(int width, int height) {
+ public void setDefaultBufferSize(int width, int height) {
throw new UnsupportedOperationException();
}
@@ -48,7 +73,7 @@ import androidx.media3.common.util.TimestampIterator;
* at. The timestamps should be monotonically increasing.
* @param useHdr Whether input and/or output colors are HDR.
*/
- default void queueInputBitmap(
+ public void queueInputBitmap(
Bitmap inputBitmap,
FrameInfo frameInfo,
TimestampIterator inStreamOffsetsUs,
@@ -61,7 +86,7 @@ import androidx.media3.common.util.TimestampIterator;
*
* @see VideoFrameProcessor#queueInputTexture
*/
- default void queueInputTexture(int inputTexId, long presentationTimeUs) {
+ public void queueInputTexture(int inputTexId, long presentationTimeUs) {
throw new UnsupportedOperationException();
}
@@ -70,7 +95,7 @@ import androidx.media3.common.util.TimestampIterator;
*
* @see VideoFrameProcessor#setOnInputFrameProcessedListener
*/
- default void setOnInputFrameProcessedListener(OnInputFrameProcessedListener listener) {
+ public void setOnInputFrameProcessedListener(OnInputFrameProcessedListener listener) {
throw new UnsupportedOperationException();
}
@@ -83,7 +108,7 @@ import androidx.media3.common.util.TimestampIterator;
* Pixels are expanded using the {@link FrameInfo#pixelWidthHeightRatio} so that the output
* frames' pixels have a ratio of 1.
*/
- default void setInputFrameInfo(FrameInfo inputFrameInfo) {
+ public void setInputFrameInfo(FrameInfo inputFrameInfo) {
// Do nothing.
}
@@ -92,28 +117,48 @@ import androidx.media3.common.util.TimestampIterator;
*
* Only works when the input is received on a {@link SurfaceTexture}.
*/
- default Surface getInputSurface() {
+ public Surface getInputSurface() {
throw new UnsupportedOperationException();
}
/** Informs the {@code TextureManager} that a frame will be queued. */
- default void registerInputFrame(FrameInfo frameInfo) {
+ public void registerInputFrame(FrameInfo frameInfo) {
throw new UnsupportedOperationException();
}
/** See {@link VideoFrameProcessor#getPendingInputFrameCount}. */
- int getPendingFrameCount();
+ public abstract int getPendingFrameCount();
/** Signals the end of the current input stream. */
- void signalEndOfCurrentInputStream();
+ public abstract void signalEndOfCurrentInputStream();
/** Sets the task to run on completing flushing, or {@code null} to clear any task. */
- void setOnFlushCompleteListener(@Nullable VideoFrameProcessingTaskExecutor.Task task);
+ public final void setOnFlushCompleteListener(
+ @Nullable VideoFrameProcessingTaskExecutor.Task task) {
+ synchronized (lock) {
+ onFlushCompleteTask = task;
+ }
+ }
+
+ @Override
+ public final void onFlush() {
+ videoFrameProcessingTaskExecutor.submit(this::flush);
+ }
/**
* Releases all resources.
*
* @see VideoFrameProcessor#release()
*/
- void release() throws VideoFrameProcessingException;
+ public abstract void release() throws VideoFrameProcessingException;
+
+ // Methods that must be called on the GL thread.
+
+ protected void flush() {
+ synchronized (lock) {
+ if (onFlushCompleteTask != null) {
+ videoFrameProcessingTaskExecutor.submitWithHighPriority(onFlushCompleteTask);
+ }
+ }
+ }
}