diff --git a/demos/transformer/src/withMediaPipe/java/androidx/media3/demo/transformer/MediaPipeShaderProgram.java b/demos/transformer/src/withMediaPipe/java/androidx/media3/demo/transformer/MediaPipeShaderProgram.java index 48f216da75..a9ac32d2d2 100644 --- a/demos/transformer/src/withMediaPipe/java/androidx/media3/demo/transformer/MediaPipeShaderProgram.java +++ b/demos/transformer/src/withMediaPipe/java/androidx/media3/demo/transformer/MediaPipeShaderProgram.java @@ -161,10 +161,8 @@ import java.util.concurrent.Future; } @Override - public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {} - - @Override - public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { + public void queueInputFrame( + GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) { AppTextureFrame appTextureFrame = new AppTextureFrame( inputTexture.getTexId(), inputTexture.getWidth(), inputTexture.getHeight()); diff --git a/libraries/common/src/main/java/androidx/media3/common/GlObjectsProvider.java b/libraries/common/src/main/java/androidx/media3/common/GlObjectsProvider.java index 3507acd94b..9e180556a5 100644 --- a/libraries/common/src/main/java/androidx/media3/common/GlObjectsProvider.java +++ b/libraries/common/src/main/java/androidx/media3/common/GlObjectsProvider.java @@ -22,7 +22,6 @@ import android.opengl.EGLDisplay; import android.opengl.EGLSurface; import androidx.annotation.IntRange; import androidx.annotation.RequiresApi; -import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil.GlException; import androidx.media3.common.util.UnstableApi; @@ -30,45 +29,6 @@ import androidx.media3.common.util.UnstableApi; /** Provider to customize the creation and maintenance of GL objects. */ @UnstableApi public interface GlObjectsProvider { - /** - * @deprecated Please use {@code DefaultGlObjectsProvider} in {@code androidx.media3.effect}. - */ - @Deprecated - GlObjectsProvider DEFAULT = - new GlObjectsProvider() { - @Override - @RequiresApi(17) - public EGLContext createEglContext( - EGLDisplay eglDisplay, int openGlVersion, int[] configAttributes) throws GlException { - return GlUtil.createEglContext( - EGL14.EGL_NO_CONTEXT, eglDisplay, openGlVersion, configAttributes); - } - - @Override - @RequiresApi(17) - public EGLSurface createEglSurface( - EGLDisplay eglDisplay, - Object surface, - @C.ColorTransfer int colorTransfer, - boolean isEncoderInputSurface) - throws GlException { - return GlUtil.createEglSurface(eglDisplay, surface, colorTransfer, isEncoderInputSurface); - } - - @Override - @RequiresApi(17) - public EGLSurface createFocusedPlaceholderEglSurface( - EGLContext eglContext, EGLDisplay eglDisplay) throws GlException { - return GlUtil.createFocusedPlaceholderEglSurface(eglContext, eglDisplay); - } - - @Override - public GlTextureInfo createBuffersForTexture(int texId, int width, int height) - throws GlException { - int fboId = GlUtil.createFboForTexture(texId); - return new GlTextureInfo(texId, fboId, /* rboId= */ C.INDEX_UNSET, width, height); - } - }; /** * Creates a new {@link EGLContext} for the specified {@link EGLDisplay}. diff --git a/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java b/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java index fdb8d3a426..204e3ce25c 100644 --- a/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java +++ b/libraries/effect/src/androidTest/java/androidx/media3/effect/DefaultVideoFrameProcessorVideoFrameRenderingTest.java @@ -412,10 +412,8 @@ public final class DefaultVideoFrameProcessorVideoFrameRenderingTest { public void setErrorListener(Executor executor, ErrorListener errorListener) {} @Override - public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {} - - @Override - public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { + public void queueInputFrame( + GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) { // No input is queued in these tests. The BlankFrameProducer is used to produce frames. throw new UnsupportedOperationException(); } diff --git a/libraries/effect/src/main/java/androidx/media3/effect/BaseGlShaderProgram.java b/libraries/effect/src/main/java/androidx/media3/effect/BaseGlShaderProgram.java index 4484d5fd01..0626326448 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/BaseGlShaderProgram.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/BaseGlShaderProgram.java @@ -15,8 +15,6 @@ */ package androidx.media3.effect; -import static androidx.media3.common.util.Assertions.checkState; - import androidx.annotation.CallSuper; import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlTextureInfo; @@ -49,7 +47,6 @@ public abstract class BaseGlShaderProgram implements GlShaderProgram { private OutputListener outputListener; private ErrorListener errorListener; private Executor errorListenerExecutor; - private boolean frameProcessingStarted; /** * Creates a {@code BaseGlShaderProgram} instance. @@ -119,20 +116,12 @@ public abstract class BaseGlShaderProgram implements GlShaderProgram { } @Override - public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) { - checkState( - !frameProcessingStarted, - "The GlObjectsProvider cannot be set after frame processing has started."); - outputTexturePool.setGlObjectsProvider(glObjectsProvider); - } - - @Override - public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { + public void queueInputFrame( + GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) { try { Size outputTextureSize = configure(inputTexture.getWidth(), inputTexture.getHeight()); outputTexturePool.ensureConfigured( - outputTextureSize.getWidth(), outputTextureSize.getHeight()); - frameProcessingStarted = true; + glObjectsProvider, outputTextureSize.getWidth(), outputTextureSize.getHeight()); // Focus on the next free buffer. GlTextureInfo outputTexture = outputTexturePool.useTexture(); @@ -152,21 +141,18 @@ public abstract class BaseGlShaderProgram implements GlShaderProgram { @Override public void releaseOutputFrame(GlTextureInfo outputTexture) { - frameProcessingStarted = true; outputTexturePool.freeTexture(outputTexture); inputListener.onReadyToAcceptInputFrame(); } @Override public void signalEndOfCurrentInputStream() { - frameProcessingStarted = true; outputListener.onCurrentOutputStreamEnded(); } @Override @CallSuper public void flush() { - frameProcessingStarted = true; outputTexturePool.freeAllTextures(); inputListener.onFlush(); for (int i = 0; i < outputTexturePool.capacity(); i++) { @@ -177,7 +163,6 @@ public abstract class BaseGlShaderProgram implements GlShaderProgram { @Override @CallSuper public void release() throws VideoFrameProcessingException { - frameProcessingStarted = true; try { outputTexturePool.deleteAllTextures(); } catch (GlUtil.GlException e) { 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 f6d0a1a2a8..5a7a3c5377 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/BitmapTextureManager.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/BitmapTextureManager.java @@ -25,6 +25,7 @@ import android.opengl.GLUtils; import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.FrameInfo; +import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlTextureInfo; import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.util.GlUtil; @@ -47,6 +48,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; "Unsupported Image Configuration: No more than 8 bits of precision should be used for each" + " RGB channel."; + 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. @@ -62,14 +64,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Creates a new instance. * + * @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES. * @param shaderProgram The {@link GlShaderProgram} for which this {@code BitmapTextureManager} * will be set as the {@link GlShaderProgram.InputListener}. * @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor} that the * methods of this class run on. */ public BitmapTextureManager( + GlObjectsProvider glObjectsProvider, GlShaderProgram shaderProgram, VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) { + this.glObjectsProvider = glObjectsProvider; this.shaderProgram = shaderProgram; this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor; pendingBitmaps = new LinkedBlockingQueue<>(); @@ -187,7 +192,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; framesToQueueForCurrentBitmap--; downstreamShaderProgramCapacity--; shaderProgram.queueInputFrame( - checkNotNull(currentGlTextureInfo), round(currentPresentationTimeUs)); + glObjectsProvider, checkNotNull(currentGlTextureInfo), round(currentPresentationTimeUs)); currentPresentationTimeUs += currentBitmapInfo.frameDurationUs; if (framesToQueueForCurrentBitmap == 0) { diff --git a/libraries/effect/src/main/java/androidx/media3/effect/ChainingGlShaderProgramListener.java b/libraries/effect/src/main/java/androidx/media3/effect/ChainingGlShaderProgramListener.java index 32682aea84..8fdd7d7edf 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/ChainingGlShaderProgramListener.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/ChainingGlShaderProgramListener.java @@ -15,6 +15,7 @@ */ package androidx.media3.effect; +import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlTextureInfo; import androidx.media3.effect.GlShaderProgram.InputListener; import androidx.media3.effect.GlShaderProgram.OutputListener; @@ -35,6 +36,7 @@ import androidx.media3.effect.GlShaderProgram.OutputListener; /** * Creates a new instance. * + * @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES. * @param producingGlShaderProgram The {@link GlShaderProgram} for which this listener will be set * as {@link OutputListener}. * @param consumingGlShaderProgram The {@link GlShaderProgram} for which this listener will be set @@ -45,12 +47,14 @@ import androidx.media3.effect.GlShaderProgram.OutputListener; * releasing the {@link VideoFrameProcessingTaskExecutor}. */ public ChainingGlShaderProgramListener( + GlObjectsProvider glObjectsProvider, GlShaderProgram producingGlShaderProgram, GlShaderProgram consumingGlShaderProgram, VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) { this.producingGlShaderProgram = producingGlShaderProgram; frameConsumptionManager = - new FrameConsumptionManager(consumingGlShaderProgram, videoFrameProcessingTaskExecutor); + new FrameConsumptionManager( + glObjectsProvider, consumingGlShaderProgram, videoFrameProcessingTaskExecutor); this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor; } diff --git a/libraries/effect/src/main/java/androidx/media3/effect/DefaultFrameDroppingShaderProgram.java b/libraries/effect/src/main/java/androidx/media3/effect/DefaultFrameDroppingShaderProgram.java index 7882ad2ef7..eadfe7105d 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/DefaultFrameDroppingShaderProgram.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/DefaultFrameDroppingShaderProgram.java @@ -44,7 +44,6 @@ import androidx.media3.common.util.Size; */ /* package */ final class DefaultFrameDroppingShaderProgram extends FrameCacheGlShaderProgram { - private final GlObjectsProvider glObjectsProvider; private final boolean useHdr; private final long targetFrameDeltaUs; @@ -69,25 +68,25 @@ import androidx.media3.common.util.Size; this.targetFrameDeltaUs = (long) (C.MICROS_PER_SECOND / targetFrameRate); lastQueuedPresentationTimeUs = C.TIME_UNSET; previousPresentationTimeUs = C.TIME_UNSET; - glObjectsProvider = new DefaultGlObjectsProvider(/* sharedEglContext= */ null); } @Override - public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { + public void queueInputFrame( + GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) { framesReceived++; if (framesReceived == 1) { - copyTextureToPreviousFrame(inputTexture, presentationTimeUs); - queuePreviousFrame(); + copyTextureToPreviousFrame(glObjectsProvider, inputTexture, presentationTimeUs); + queuePreviousFrame(glObjectsProvider); getInputListener().onInputFrameProcessed(inputTexture); getInputListener().onReadyToAcceptInputFrame(); return; } if (shouldQueuePreviousFrame(presentationTimeUs)) { - queuePreviousFrame(); + queuePreviousFrame(glObjectsProvider); } - copyTextureToPreviousFrame(inputTexture, presentationTimeUs); + copyTextureToPreviousFrame(glObjectsProvider, inputTexture, presentationTimeUs); getInputListener().onInputFrameProcessed(inputTexture); getInputListener().onReadyToAcceptInputFrame(); } @@ -129,7 +128,8 @@ import androidx.media3.common.util.Size; framesReceived = 0; } - private void copyTextureToPreviousFrame(GlTextureInfo newTexture, long presentationTimeUs) { + private void copyTextureToPreviousFrame( + GlObjectsProvider glObjectsProvider, GlTextureInfo newTexture, long presentationTimeUs) { try { if (previousTexture == null) { int texId = GlUtil.createTexture(newTexture.getWidth(), newTexture.getHeight(), useHdr); @@ -171,12 +171,12 @@ import androidx.media3.common.util.Size; < abs(currentFrameTimeDeltaUs - targetFrameDeltaUs); } - private void queuePreviousFrame() { + private void queuePreviousFrame(GlObjectsProvider glObjectsProvider) { try { GlTextureInfo previousTexture = checkNotNull(this.previousTexture); Size outputTextureSize = configure(previousTexture.getWidth(), previousTexture.getHeight()); outputTexturePool.ensureConfigured( - outputTextureSize.getWidth(), outputTextureSize.getHeight()); + glObjectsProvider, outputTextureSize.getWidth(), outputTextureSize.getHeight()); // Focus on the next free buffer. GlTextureInfo outputTexture = outputTexturePool.useTexture(); diff --git a/libraries/effect/src/main/java/androidx/media3/effect/DefaultGlObjectsProvider.java b/libraries/effect/src/main/java/androidx/media3/effect/DefaultGlObjectsProvider.java index fa97b79695..274adfa9b8 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/DefaultGlObjectsProvider.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/DefaultGlObjectsProvider.java @@ -39,10 +39,15 @@ public final class DefaultGlObjectsProvider implements GlObjectsProvider { private final EGLContext sharedEglContext; + /** Creates an instance with no shared EGL context. */ + public DefaultGlObjectsProvider() { + this(/* sharedEglContext= */ null); + } + /** - * Creates an instance. + * Creates an instance with the specified shared EGL context. * - * @param sharedEglContext The {@link EGLContext} with which to share data. + * @param sharedEglContext The context with which to share data, or {@code null} if none. */ public DefaultGlObjectsProvider(@Nullable EGLContext sharedEglContext) { this.sharedEglContext = sharedEglContext != null ? sharedEglContext : EGL14.EGL_NO_CONTEXT; diff --git a/libraries/effect/src/main/java/androidx/media3/effect/DefaultVideoFrameProcessor.java b/libraries/effect/src/main/java/androidx/media3/effect/DefaultVideoFrameProcessor.java index 6bc1e29e6e..e4b56e3304 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/DefaultVideoFrameProcessor.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/DefaultVideoFrameProcessor.java @@ -102,7 +102,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { /** Creates an instance. */ public Builder() { enableColorTransfers = true; - glObjectsProvider = GlObjectsProvider.DEFAULT; + glObjectsProvider = new DefaultGlObjectsProvider(); } /** @@ -119,7 +119,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { /** * Sets the {@link GlObjectsProvider}. * - *
The default value is {@link GlObjectsProvider#DEFAULT}. + *
The default value is a {@link DefaultGlObjectsProvider}.
*/
@CanIgnoreReturnValue
public Builder setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
@@ -285,6 +285,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
private static final long RELEASE_WAIT_TIME_MS = 500;
private final Context context;
+ private final GlObjectsProvider glObjectsProvider;
private final EGLDisplay eglDisplay;
private final EGLContext eglContext;
private final InputSwitcher inputSwitcher;
@@ -303,7 +304,6 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
private final List Returns {@code false} if {@code outputSurfaceInfo} is unset.
*/
- private synchronized boolean ensureConfigured(int inputWidth, int inputHeight)
+ private synchronized boolean ensureConfigured(
+ GlObjectsProvider glObjectsProvider, int inputWidth, int inputHeight)
throws VideoFrameProcessingException, GlUtil.GlException {
// Clear extra or outdated resources.
boolean inputSizeChanged =
@@ -455,7 +452,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/* isEncoderInputSurface= */ renderFramesAutomatically);
}
if (textureOutputListener != null) {
- outputTexturePool.ensureConfigured(outputWidth, outputHeight);
+ outputTexturePool.ensureConfigured(glObjectsProvider, outputWidth, outputHeight);
}
@Nullable
@@ -522,7 +519,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return defaultShaderProgram;
}
- private void renderFrameToDebugSurface(GlTextureInfo inputTexture, long presentationTimeUs) {
+ private void renderFrameToDebugSurface(
+ GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) {
DefaultShaderProgram defaultShaderProgram = checkNotNull(this.defaultShaderProgram);
SurfaceViewWrapper debugSurfaceViewWrapper = checkNotNull(this.debugSurfaceViewWrapper);
try {
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/FrameConsumptionManager.java b/libraries/effect/src/main/java/androidx/media3/effect/FrameConsumptionManager.java
index 7957504b6b..51141e0d1e 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/FrameConsumptionManager.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/FrameConsumptionManager.java
@@ -19,6 +19,7 @@ import android.util.Pair;
import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
+import androidx.media3.common.GlObjectsProvider;
import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.VideoFrameProcessor;
import java.util.ArrayDeque;
@@ -32,6 +33,8 @@ import java.util.Queue;
*/
/* package */ final class FrameConsumptionManager implements GlShaderProgram.InputListener {
+
+ private final GlObjectsProvider glObjectsProvider;
private final GlShaderProgram consumingGlShaderProgram;
private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
@@ -44,12 +47,15 @@ import java.util.Queue;
/**
* Creates a new instance.
*
+ * @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES.
* @param consumingGlShaderProgram The {@link GlShaderProgram} that frames are queued to.
* @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor}.
*/
public FrameConsumptionManager(
+ GlObjectsProvider glObjectsProvider,
GlShaderProgram consumingGlShaderProgram,
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
+ this.glObjectsProvider = glObjectsProvider;
this.consumingGlShaderProgram = consumingGlShaderProgram;
this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor;
availableFrames = new ArrayDeque<>();
@@ -66,6 +72,7 @@ import java.util.Queue;
videoFrameProcessingTaskExecutor.submit(
() ->
consumingGlShaderProgram.queueInputFrame(
+ glObjectsProvider,
/* inputTexture= */ pendingFrame.first,
/* presentationTimeUs= */ pendingFrame.second));
@Nullable Pair The {@code GlShaderProgram} consumes input frames it accepts via {@link
- * #queueInputFrame(GlTextureInfo, long)} and surrenders each texture back to the caller via its
- * {@linkplain InputListener#onInputFrameProcessed(GlTextureInfo) listener} once the texture's
- * contents have been processed.
+ * #queueInputFrame(GlObjectsProvider, GlTextureInfo, long)} and surrenders each texture back to the
+ * caller via its {@linkplain InputListener#onInputFrameProcessed(GlTextureInfo) listener} once the
+ * texture's contents have been processed.
*
* The {@code GlShaderProgram} produces output frames asynchronously and notifies its owner when
* they are available via its {@linkplain OutputListener#onOutputFrameAvailable(GlTextureInfo, long)
@@ -57,8 +57,8 @@ public interface GlShaderProgram {
/**
* Called when the {@link GlShaderProgram} is ready to accept another input frame.
*
- * For each time this method is called, {@link #queueInputFrame(GlTextureInfo, long)} can be
- * called once.
+ * For each time this method is called, {@link #queueInputFrame(GlObjectsProvider,
+ * GlTextureInfo, long)} can be called once.
*/
default void onReadyToAcceptInputFrame() {}
@@ -69,7 +69,7 @@ public interface GlShaderProgram {
* #onReadyToAcceptInputFrame ready to accept another input frame} when this method is called.
*
* @param inputTexture The {@link GlTextureInfo} that was used to {@linkplain
- * #queueInputFrame(GlTextureInfo, long) queue} the input frame.
+ * #queueInputFrame(GlObjectsProvider, GlTextureInfo, long) queue} the input frame.
*/
default void onInputFrameProcessed(GlTextureInfo inputTexture) {}
@@ -149,13 +149,6 @@ public interface GlShaderProgram {
*/
void setErrorListener(Executor executor, ErrorListener errorListener);
- /**
- * Sets the {@link GlObjectsProvider}.
- *
- * This method should not be called after any of the frame processing methods.
- */
- void setGlObjectsProvider(GlObjectsProvider glObjectsProvider);
-
/**
* Processes an input frame if possible.
*
@@ -166,10 +159,12 @@ public interface GlShaderProgram {
* This method must only be called when the {@code GlShaderProgram} can {@linkplain
* InputListener#onReadyToAcceptInputFrame() accept an input frame}.
*
+ * @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES.
* @param inputTexture A {@link GlTextureInfo} describing the texture containing the input frame.
* @param presentationTimeUs The presentation timestamp of the input frame, in microseconds.
*/
- void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs);
+ void queueInputFrame(
+ GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs);
/**
* Notifies the {@code GlShaderProgram} that the frame on the given output texture is no longer
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java b/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java
index 0704f2aadd..058492ed8d 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java
@@ -92,9 +92,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
inputColorInfo,
outputColorInfo,
enableColorTransfers);
- samplingShaderProgram.setGlObjectsProvider(glObjectsProvider);
textureManager =
- new ExternalTextureManager(samplingShaderProgram, videoFrameProcessingTaskExecutor);
+ new ExternalTextureManager(
+ glObjectsProvider, samplingShaderProgram, videoFrameProcessingTaskExecutor);
inputs.put(inputType, new Input(textureManager, samplingShaderProgram));
break;
case VideoFrameProcessor.INPUT_TYPE_BITMAP:
@@ -107,9 +107,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputColorInfo,
enableColorTransfers,
inputType);
- samplingShaderProgram.setGlObjectsProvider(glObjectsProvider);
textureManager =
- new BitmapTextureManager(samplingShaderProgram, videoFrameProcessingTaskExecutor);
+ new BitmapTextureManager(
+ glObjectsProvider, samplingShaderProgram, videoFrameProcessingTaskExecutor);
inputs.put(inputType, new Input(textureManager, samplingShaderProgram));
break;
case VideoFrameProcessor.INPUT_TYPE_TEXTURE_ID:
@@ -122,9 +122,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputColorInfo,
enableColorTransfers,
inputType);
- samplingShaderProgram.setGlObjectsProvider(glObjectsProvider);
textureManager =
- new TexIdTextureManager(samplingShaderProgram, videoFrameProcessingTaskExecutor);
+ new TexIdTextureManager(
+ glObjectsProvider, samplingShaderProgram, videoFrameProcessingTaskExecutor);
inputs.put(inputType, new Input(textureManager, samplingShaderProgram));
break;
default:
@@ -155,6 +155,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (inputType == newInputType) {
input.setChainingListener(
new GatedChainingListenerWrapper(
+ glObjectsProvider,
input.samplingGlShaderProgram,
this.downstreamShaderProgram,
videoFrameProcessingTaskExecutor));
@@ -235,15 +236,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
implements GlShaderProgram.OutputListener, GlShaderProgram.InputListener {
private final ChainingGlShaderProgramListener chainingGlShaderProgramListener;
- private boolean isActive = false;
+
+ private boolean isActive;
public GatedChainingListenerWrapper(
+ GlObjectsProvider glObjectsProvider,
GlShaderProgram producingGlShaderProgram,
GlShaderProgram consumingGlShaderProgram,
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
this.chainingGlShaderProgramListener =
new ChainingGlShaderProgramListener(
- producingGlShaderProgram, consumingGlShaderProgram, videoFrameProcessingTaskExecutor);
+ glObjectsProvider,
+ producingGlShaderProgram,
+ consumingGlShaderProgram,
+ videoFrameProcessingTaskExecutor);
}
@Override
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/SimpleFrameDroppingShaderProgram.java b/libraries/effect/src/main/java/androidx/media3/effect/SimpleFrameDroppingShaderProgram.java
index b34350dbf8..32ac809e42 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/SimpleFrameDroppingShaderProgram.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/SimpleFrameDroppingShaderProgram.java
@@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.Math.round;
import android.content.Context;
+import androidx.media3.common.GlObjectsProvider;
import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.VideoFrameProcessingException;
@@ -54,10 +55,11 @@ import androidx.media3.common.VideoFrameProcessingException;
}
@Override
- public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
+ public void queueInputFrame(
+ GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) {
framesReceived++;
if (framesReceived % n == 0) {
- super.queueInputFrame(inputTexture, presentationTimeUs);
+ super.queueInputFrame(glObjectsProvider, inputTexture, presentationTimeUs);
} else {
getInputListener().onInputFrameProcessed(inputTexture);
getInputListener().onReadyToAcceptInputFrame();
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/TexIdTextureManager.java b/libraries/effect/src/main/java/androidx/media3/effect/TexIdTextureManager.java
index b6dba66d4e..ca70633955 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/TexIdTextureManager.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/TexIdTextureManager.java
@@ -21,13 +21,14 @@ import android.opengl.GLES10;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.FrameInfo;
+import androidx.media3.common.GlObjectsProvider;
import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.OnInputFrameProcessedListener;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
- * Forwards a video frames made available via {@linkplain GLES10#GL_TEXTURE_2D traditional GLES
- * texture} to a {@link GlShaderProgram} for consumption.
+ * Forwards frames made available via {@linkplain GLES10#GL_TEXTURE_2D traditional GLES textures} to
+ * a {@link GlShaderProgram} for consumption.
*
* Public methods in this class can be called from any thread.
*/
@@ -41,16 +42,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* Creates a new instance.
*
+ * @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES.
* @param shaderProgram The {@link GlShaderProgram} for which this {@code texIdTextureManager}
* will be set as the {@link GlShaderProgram.InputListener}.
* @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor}.
*/
public TexIdTextureManager(
+ GlObjectsProvider glObjectsProvider,
GlShaderProgram shaderProgram,
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor;
frameConsumptionManager =
- new FrameConsumptionManager(shaderProgram, videoFrameProcessingTaskExecutor);
+ new FrameConsumptionManager(
+ glObjectsProvider, shaderProgram, videoFrameProcessingTaskExecutor);
}
@Override
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/TexturePool.java b/libraries/effect/src/main/java/androidx/media3/effect/TexturePool.java
index 78f8f5eb50..cd30021388 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/TexturePool.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/TexturePool.java
@@ -32,8 +32,6 @@ import java.util.Queue;
private final int capacity;
private final boolean useHighPrecisionColorComponents;
- private GlObjectsProvider glObjectsProvider;
-
/**
* Creates a {@code TexturePool} instance.
*
@@ -47,14 +45,6 @@ import java.util.Queue;
freeTextures = new ArrayDeque<>(capacity);
inUseTextures = new ArrayDeque<>(capacity);
-
- glObjectsProvider = new DefaultGlObjectsProvider(/* sharedEglContext= */ null);
- }
-
- /** Sets the {@link GlObjectsProvider}. */
- public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
- checkState(!isConfigured());
- this.glObjectsProvider = glObjectsProvider;
}
/** Returns whether the instance has been {@linkplain #ensureConfigured configured}. */
@@ -80,15 +70,16 @@ import java.util.Queue;
*
* Reconfigures backing textures as needed.
*/
- public void ensureConfigured(int width, int height) throws GlUtil.GlException {
+ public void ensureConfigured(GlObjectsProvider glObjectsProvider, int width, int height)
+ throws GlUtil.GlException {
if (!isConfigured()) {
- createTextures(width, height);
+ createTextures(glObjectsProvider, width, height);
return;
}
GlTextureInfo texture = getIteratorToAllTextures().next();
if (texture.getWidth() != width || texture.getHeight() != height) {
deleteAllTextures();
- createTextures(width, height);
+ createTextures(glObjectsProvider, width, height);
}
}
@@ -147,7 +138,8 @@ import java.util.Queue;
inUseTextures.clear();
}
- private void createTextures(int width, int height) throws GlUtil.GlException {
+ private void createTextures(GlObjectsProvider glObjectsProvider, int width, int height)
+ throws GlUtil.GlException {
checkState(freeTextures.isEmpty());
checkState(inUseTextures.isEmpty());
for (int i = 0; i < capacity; i++) {
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/TimestampWrapperShaderProgram.java b/libraries/effect/src/main/java/androidx/media3/effect/TimestampWrapperShaderProgram.java
index d7fb91dcd1..fe53605ce7 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/TimestampWrapperShaderProgram.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/TimestampWrapperShaderProgram.java
@@ -72,21 +72,16 @@ import java.util.concurrent.Executor;
}
@Override
- public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) {
- copyGlShaderProgram.setGlObjectsProvider(glObjectsProvider);
- wrappedGlShaderProgram.setGlObjectsProvider(glObjectsProvider);
- }
-
- @Override
- public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) {
+ public void queueInputFrame(
+ GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) {
// TODO(b/277726418) Properly report shader program capacity when switching from wrapped shader
// program to copying shader program.
if (presentationTimeUs >= startTimeUs && presentationTimeUs <= endTimeUs) {
pendingWrappedGlShaderProgramFrames++;
- wrappedGlShaderProgram.queueInputFrame(inputTexture, presentationTimeUs);
+ wrappedGlShaderProgram.queueInputFrame(glObjectsProvider, inputTexture, presentationTimeUs);
} else {
pendingCopyGlShaderProgramFrames++;
- copyGlShaderProgram.queueInputFrame(inputTexture, presentationTimeUs);
+ copyGlShaderProgram.queueInputFrame(glObjectsProvider, inputTexture, presentationTimeUs);
}
}
diff --git a/libraries/effect/src/test/java/androidx/media3/effect/ChainingGlShaderProgramListenerTest.java b/libraries/effect/src/test/java/androidx/media3/effect/ChainingGlShaderProgramListenerTest.java
index 42217dd3e0..6bdd05a148 100644
--- a/libraries/effect/src/test/java/androidx/media3/effect/ChainingGlShaderProgramListenerTest.java
+++ b/libraries/effect/src/test/java/androidx/media3/effect/ChainingGlShaderProgramListenerTest.java
@@ -19,6 +19,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import androidx.media3.common.C;
+import androidx.media3.common.GlObjectsProvider;
import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.util.Util;
@@ -37,10 +38,12 @@ public final class ChainingGlShaderProgramListenerTest {
private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor =
new VideoFrameProcessingTaskExecutor(
Util.newSingleThreadExecutor("Test"), mockFrameProcessorListener);
+ private final GlObjectsProvider mockGlObjectsProvider = mock(GlObjectsProvider.class);
private final GlShaderProgram mockProducingGlShaderProgram = mock(GlShaderProgram.class);
private final GlShaderProgram mockConsumingGlShaderProgram = mock(GlShaderProgram.class);
private final ChainingGlShaderProgramListener chainingGlShaderProgramListener =
new ChainingGlShaderProgramListener(
+ mockGlObjectsProvider,
mockProducingGlShaderProgram,
mockConsumingGlShaderProgram,
videoFrameProcessingTaskExecutor);
@@ -83,7 +86,8 @@ public final class ChainingGlShaderProgramListenerTest {
chainingGlShaderProgramListener.onOutputFrameAvailable(texture, presentationTimeUs);
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
- verify(mockConsumingGlShaderProgram).queueInputFrame(texture, presentationTimeUs);
+ verify(mockConsumingGlShaderProgram)
+ .queueInputFrame(mockGlObjectsProvider, texture, presentationTimeUs);
}
@Test
@@ -102,7 +106,8 @@ public final class ChainingGlShaderProgramListenerTest {
chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
- verify(mockConsumingGlShaderProgram).queueInputFrame(texture, presentationTimeUs);
+ verify(mockConsumingGlShaderProgram)
+ .queueInputFrame(mockGlObjectsProvider, texture, presentationTimeUs);
}
@Test
@@ -131,8 +136,10 @@ public final class ChainingGlShaderProgramListenerTest {
chainingGlShaderProgramListener.onReadyToAcceptInputFrame();
Thread.sleep(EXECUTOR_WAIT_TIME_MS);
- verify(mockConsumingGlShaderProgram).queueInputFrame(firstTexture, firstPresentationTimeUs);
- verify(mockConsumingGlShaderProgram).queueInputFrame(secondTexture, secondPresentationTimeUs);
+ verify(mockConsumingGlShaderProgram)
+ .queueInputFrame(mockGlObjectsProvider, firstTexture, firstPresentationTimeUs);
+ verify(mockConsumingGlShaderProgram)
+ .queueInputFrame(mockGlObjectsProvider, secondTexture, secondPresentationTimeUs);
}
@Test