From 90c8f642afcc48380e6e5dbf713255bf805ced1f Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 23 Jun 2023 11:35:26 +0000 Subject: [PATCH] Pass `GlObjectsProvider` to methods By passing this class where it's needed, implementations don't need to store it in a field (reducing boilerplate) and it's clearer that it can't be unset when needed. PiperOrigin-RevId: 542823522 --- .../transformer/MediaPipeShaderProgram.java | 6 +-- .../media3/common/GlObjectsProvider.java | 40 -------------- ...FrameProcessorVideoFrameRenderingTest.java | 6 +-- .../media3/effect/BaseGlShaderProgram.java | 21 ++------ .../media3/effect/BitmapTextureManager.java | 7 ++- .../ChainingGlShaderProgramListener.java | 6 ++- .../DefaultFrameDroppingShaderProgram.java | 20 +++---- .../effect/DefaultGlObjectsProvider.java | 9 +++- .../effect/DefaultVideoFrameProcessor.java | 38 ++++++-------- .../media3/effect/ExternalTextureManager.java | 6 +++ .../effect/FinalShaderProgramWrapper.java | 52 +++++++++---------- .../effect/FrameConsumptionManager.java | 13 +++-- .../media3/effect/GlShaderProgram.java | 23 ++++---- .../androidx/media3/effect/InputSwitcher.java | 22 +++++--- .../SimpleFrameDroppingShaderProgram.java | 6 ++- .../media3/effect/TexIdTextureManager.java | 10 ++-- .../androidx/media3/effect/TexturePool.java | 20 +++---- .../effect/TimestampWrapperShaderProgram.java | 13 ++--- .../ChainingGlShaderProgramListenerTest.java | 15 ++++-- 19 files changed, 147 insertions(+), 186 deletions(-) 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 activeEffects; private final Object lock; private final ColorInfo outputColorInfo; - private final GlObjectsProvider glObjectsProvider; // CountDownLatch to wait for the current input stream to finish processing. private volatile @MonotonicNonNull CountDownLatch latch; @@ -313,6 +313,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { private DefaultVideoFrameProcessor( Context context, + GlObjectsProvider glObjectsProvider, EGLDisplay eglDisplay, EGLContext eglContext, InputSwitcher inputSwitcher, @@ -322,9 +323,9 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ImmutableList intermediateGlShaderPrograms, FinalShaderProgramWrapper finalShaderProgramWrapper, boolean renderFramesAutomatically, - ColorInfo outputColorInfo, - GlObjectsProvider glObjectsProvider) { + ColorInfo outputColorInfo) { this.context = context; + this.glObjectsProvider = glObjectsProvider; this.eglDisplay = eglDisplay; this.eglContext = eglContext; this.inputSwitcher = inputSwitcher; @@ -335,7 +336,6 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { this.activeEffects = new ArrayList<>(); this.lock = new Object(); this.outputColorInfo = outputColorInfo; - this.glObjectsProvider = glObjectsProvider; this.finalShaderProgramWrapper = finalShaderProgramWrapper; finalShaderProgramWrapper.setOnInputStreamProcessedListener( () -> { @@ -461,8 +461,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { inputSwitcher.setDownstreamShaderProgram( getFirst( intermediateGlShaderPrograms, /* defaultValue= */ finalShaderProgramWrapper)); - setGlObjectProviderOnShaderPrograms(intermediateGlShaderPrograms, glObjectsProvider); chainShaderProgramsWithListeners( + glObjectsProvider, intermediateGlShaderPrograms, finalShaderProgramWrapper, videoFrameProcessingTaskExecutor, @@ -521,7 +521,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { !renderFramesAutomatically, "Calling this method is not allowed when renderFramesAutomatically is enabled"); videoFrameProcessingTaskExecutor.submitWithHighPriority( - () -> finalShaderProgramWrapper.renderOutputFrame(renderTimeNs)); + () -> finalShaderProgramWrapper.renderOutputFrame(glObjectsProvider, renderTimeNs)); } @Override @@ -658,7 +658,6 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { videoFrameProcessingTaskExecutor, videoFrameProcessorListenerExecutor, listener, - glObjectsProvider, textureOutputListener, textureOutputCapacity); @@ -681,8 +680,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { inputSwitcher.setDownstreamShaderProgram( getFirst(intermediateGlShaderPrograms, /* defaultValue= */ finalShaderProgramWrapper)); - setGlObjectProviderOnShaderPrograms(intermediateGlShaderPrograms, glObjectsProvider); chainShaderProgramsWithListeners( + glObjectsProvider, intermediateGlShaderPrograms, finalShaderProgramWrapper, videoFrameProcessingTaskExecutor, @@ -691,6 +690,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { return new DefaultVideoFrameProcessor( context, + glObjectsProvider, eglDisplay, eglContext, inputSwitcher, @@ -700,8 +700,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { intermediateGlShaderPrograms, finalShaderProgramWrapper, renderFramesAutomatically, - outputColorInfo, - glObjectsProvider); + outputColorInfo); } /** @@ -766,20 +765,12 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { return shaderProgramListBuilder.build(); } - /** Sets the {@link GlObjectsProvider} on all of the {@linkplain GlShaderProgram}s provided. */ - private static void setGlObjectProviderOnShaderPrograms( - List shaderPrograms, GlObjectsProvider glObjectsProvider) { - for (int i = 0; i < shaderPrograms.size(); i++) { - GlShaderProgram shaderProgram = shaderPrograms.get(i); - shaderProgram.setGlObjectsProvider(glObjectsProvider); - } - } - /** * Chains the given {@link GlShaderProgram} instances using {@link * ChainingGlShaderProgramListener} instances. */ private static void chainShaderProgramsWithListeners( + GlObjectsProvider glObjectsProvider, List shaderPrograms, FinalShaderProgramWrapper finalShaderProgramWrapper, VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor, @@ -792,7 +783,10 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { GlShaderProgram consumingGlShaderProgram = shaderProgramsToChain.get(i + 1); ChainingGlShaderProgramListener chainingGlShaderProgramListener = new ChainingGlShaderProgramListener( - producingGlShaderProgram, consumingGlShaderProgram, videoFrameProcessingTaskExecutor); + glObjectsProvider, + producingGlShaderProgram, + consumingGlShaderProgram, + videoFrameProcessingTaskExecutor); producingGlShaderProgram.setOutputListener(chainingGlShaderProgramListener); producingGlShaderProgram.setErrorListener( videoFrameProcessorListenerExecutor, videoFrameProcessorListener::onError); diff --git a/libraries/effect/src/main/java/androidx/media3/effect/ExternalTextureManager.java b/libraries/effect/src/main/java/androidx/media3/effect/ExternalTextureManager.java index 3276a25fcd..21d5d1c11a 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/ExternalTextureManager.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/ExternalTextureManager.java @@ -23,6 +23,7 @@ import android.view.Surface; 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; @@ -55,6 +56,7 @@ import java.util.concurrent.atomic.AtomicInteger; private static final long SURFACE_TEXTURE_TIMEOUT_MS = Util.DEVICE.contains("emulator") ? 10_000 : 500; + private final GlObjectsProvider glObjectsProvider; private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor; private final ExternalShaderProgram externalShaderProgram; private final int externalTexId; @@ -90,6 +92,7 @@ import java.util.concurrent.atomic.AtomicInteger; /** * Creates a new instance. * + * @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES. * @param externalShaderProgram The {@link ExternalShaderProgram} for which this {@code * ExternalTextureManager} will be set as the {@link InputListener}. * @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor}. @@ -98,9 +101,11 @@ import java.util.concurrent.atomic.AtomicInteger; // The onFrameAvailableListener will not be invoked until the constructor returns. @SuppressWarnings("nullness:method.invocation.invalid") public ExternalTextureManager( + GlObjectsProvider glObjectsProvider, ExternalShaderProgram externalShaderProgram, VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) throws VideoFrameProcessingException { + this.glObjectsProvider = glObjectsProvider; this.externalShaderProgram = externalShaderProgram; this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor; try { @@ -314,6 +319,7 @@ import java.util.concurrent.atomic.AtomicInteger; // Correct the presentation time so that GlShaderPrograms don't see the stream offset. long presentationTimeUs = (frameTimeNs / 1000) + offsetToAddUs; externalShaderProgram.queueInputFrame( + glObjectsProvider, new GlTextureInfo( externalTexId, /* fboId= */ C.INDEX_UNSET, diff --git a/libraries/effect/src/main/java/androidx/media3/effect/FinalShaderProgramWrapper.java b/libraries/effect/src/main/java/androidx/media3/effect/FinalShaderProgramWrapper.java index fa1994bf1c..460c5d96a8 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/FinalShaderProgramWrapper.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/FinalShaderProgramWrapper.java @@ -101,12 +101,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private int outputHeight; @Nullable private DefaultShaderProgram defaultShaderProgram; @Nullable private SurfaceViewWrapper debugSurfaceViewWrapper; - private GlObjectsProvider glObjectsProvider; private InputListener inputListener; private @MonotonicNonNull Size outputSizeBeforeSurfaceTransformation; @Nullable private SurfaceView debugSurfaceView; @Nullable private OnInputStreamProcessedListener onInputStreamProcessedListener; - private boolean frameProcessingStarted; private boolean matrixTransformationsChanged; @GuardedBy("this") @@ -132,7 +130,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor, Executor videoFrameProcessorListenerExecutor, VideoFrameProcessor.Listener videoFrameProcessorListener, - GlObjectsProvider glObjectsProvider, @Nullable DefaultVideoFrameProcessor.TextureOutputListener textureOutputListener, int textureOutputCapacity) { this.context = context; @@ -147,7 +144,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; this.videoFrameProcessingTaskExecutor = videoFrameProcessingTaskExecutor; this.videoFrameProcessorListenerExecutor = videoFrameProcessorListenerExecutor; this.videoFrameProcessorListener = videoFrameProcessorListener; - this.glObjectsProvider = glObjectsProvider; this.textureOutputListener = textureOutputListener; inputListener = new InputListener() {}; @@ -158,15 +154,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; outputTextureTimestamps = new ArrayDeque<>(textureOutputCapacity); } - @Override - public void setGlObjectsProvider(GlObjectsProvider glObjectsProvider) { - checkState( - !frameProcessingStarted, - "The GlObjectsProvider cannot be set after frame processing has started."); - this.glObjectsProvider = glObjectsProvider; - outputTexturePool.setGlObjectsProvider(glObjectsProvider); - } - @Override public void setInputListener(InputListener inputListener) { this.inputListener = inputListener; @@ -192,27 +179,33 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @Override public void signalEndOfCurrentInputStream() { - frameProcessingStarted = true; checkNotNull(onInputStreamProcessedListener).onInputStreamProcessed(); } // Methods that must be called on the GL thread. @Override - public void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { - frameProcessingStarted = true; + public void queueInputFrame( + GlObjectsProvider glObjectsProvider, GlTextureInfo inputTexture, long presentationTimeUs) { videoFrameProcessorListenerExecutor.execute( () -> videoFrameProcessorListener.onOutputFrameAvailableForRendering(presentationTimeUs)); if (textureOutputListener == null) { if (renderFramesAutomatically) { renderFrame( - inputTexture, presentationTimeUs, /* renderTimeNs= */ presentationTimeUs * 1000); + glObjectsProvider, + inputTexture, + presentationTimeUs, + /* renderTimeNs= */ presentationTimeUs * 1000); } else { availableFrames.add(Pair.create(inputTexture, presentationTimeUs)); } } else { checkState(outputTexturePool.freeTextureCount() > 0); - renderFrame(inputTexture, presentationTimeUs, /* renderTimeNs= */ presentationTimeUs * 1000); + renderFrame( + glObjectsProvider, + inputTexture, + presentationTimeUs, + /* renderTimeNs= */ presentationTimeUs * 1000); } maybeOnReadyToAcceptInputFrame(); } @@ -254,7 +247,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @Override public void flush() { - frameProcessingStarted = true; // Drops all frames that aren't rendered yet. availableFrames.clear(); if (defaultShaderProgram != null) { @@ -277,14 +269,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } } - public void renderOutputFrame(long renderTimeNs) { + public void renderOutputFrame(GlObjectsProvider glObjectsProvider, long renderTimeNs) { if (textureOutputListener != null) { return; } - frameProcessingStarted = true; checkState(!renderFramesAutomatically); Pair oldestAvailableFrame = availableFrames.remove(); renderFrame( + glObjectsProvider, /* inputTexture= */ oldestAvailableFrame.first, /* presentationTimeUs= */ oldestAvailableFrame.second, renderTimeNs); @@ -326,10 +318,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } private synchronized void renderFrame( - GlTextureInfo inputTexture, long presentationTimeUs, long renderTimeNs) { + GlObjectsProvider glObjectsProvider, + GlTextureInfo inputTexture, + long presentationTimeUs, + long renderTimeNs) { try { if (renderTimeNs == VideoFrameProcessor.DROP_OUTPUT_FRAME - || !ensureConfigured(inputTexture.getWidth(), inputTexture.getHeight())) { + || !ensureConfigured( + glObjectsProvider, inputTexture.getWidth(), inputTexture.getHeight())) { inputListener.onInputFrameProcessed(inputTexture); return; // Drop frames when requested, or there is no output surface and output texture. } @@ -345,7 +341,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; VideoFrameProcessingException.from(e, presentationTimeUs))); } if (debugSurfaceViewWrapper != null && defaultShaderProgram != null) { - renderFrameToDebugSurface(inputTexture, presentationTimeUs); + renderFrameToDebugSurface(glObjectsProvider, inputTexture, presentationTimeUs); } inputListener.onInputFrameProcessed(inputTexture); @@ -399,7 +395,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * *

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 nextPendingFrame = availableFrames.peek(); @@ -82,15 +89,15 @@ import java.util.Queue; availableFrames.clear(); } - public synchronized void queueInputFrame(GlTextureInfo texture, long presentationTimeUs) { + public synchronized void queueInputFrame(GlTextureInfo inputTexture, long presentationTimeUs) { if (consumingGlShaderProgramInputCapacity > 0) { videoFrameProcessingTaskExecutor.submit( () -> consumingGlShaderProgram.queueInputFrame( - /* inputTexture= */ texture, presentationTimeUs)); + glObjectsProvider, inputTexture, presentationTimeUs)); consumingGlShaderProgramInputCapacity--; } else { - availableFrames.add(Pair.create(texture, presentationTimeUs)); + availableFrames.add(Pair.create(inputTexture, presentationTimeUs)); } } diff --git a/libraries/effect/src/main/java/androidx/media3/effect/GlShaderProgram.java b/libraries/effect/src/main/java/androidx/media3/effect/GlShaderProgram.java index 9299c9fe6a..7cce832618 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/GlShaderProgram.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/GlShaderProgram.java @@ -25,9 +25,9 @@ import java.util.concurrent.Executor; * Processes frames from one OpenGL 2D texture to another. * *

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