From 40f187e4b47c445af5049a5a49ee4633ce4c1a76 Mon Sep 17 00:00:00 2001 From: dancho Date: Tue, 12 Nov 2024 05:45:58 -0800 Subject: [PATCH] Block calls to FrameExtractor.release Block calls to release() method, and handle calls on the player looper or not. PiperOrigin-RevId: 695697602 --- .../media3/transformer/FrameExtractorTest.java | 11 +++++++++++ .../transformer/ExperimentalFrameExtractor.java | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameExtractorTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameExtractorTest.java index 4f4029a38b..9360693fec 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameExtractorTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameExtractorTest.java @@ -21,6 +21,7 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertThrows; +import android.app.Instrumentation; import android.content.Context; import androidx.media3.common.MediaItem; import androidx.media3.common.util.ConditionVariable; @@ -29,6 +30,7 @@ import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.transformer.ExperimentalFrameExtractor.Frame; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -154,4 +156,13 @@ public class FrameExtractorTest { assertThat(throwableAtomicReference.get()).isNull(); assertThat(frameAtomicReference.get().presentationTimeMs).isEqualTo(0); } + + @Test + public void frameExtractor_releaseOnPlayerLooper_returns() throws Exception { + frameExtractor = new ExperimentalFrameExtractor(context, MediaItem.fromUri(FILE_PATH)); + + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + instrumentation.runOnMainSync(frameExtractor::release); + frameExtractor = null; + } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExperimentalFrameExtractor.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExperimentalFrameExtractor.java index 5653141d45..38eb92aa93 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExperimentalFrameExtractor.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExperimentalFrameExtractor.java @@ -25,6 +25,7 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import android.content.Context; import android.os.Handler; +import android.os.Looper; import androidx.annotation.Nullable; import androidx.media3.common.Effect; import androidx.media3.common.GlObjectsProvider; @@ -32,6 +33,7 @@ import androidx.media3.common.GlTextureInfo; import androidx.media3.common.MediaItem; import androidx.media3.common.PlaybackException; import androidx.media3.common.Player; +import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.NullableType; import androidx.media3.effect.GlEffect; import androidx.media3.effect.GlShaderProgram; @@ -176,9 +178,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * longer required. The frame extractor must not be used after calling this method. */ public void release() { - // TODO: b/350498258 - Block the caller until exoPlayer.release() returns. + if (player.getApplicationLooper() == Looper.myLooper()) { + player.release(); + return; + } + ConditionVariable waitForRelease = new ConditionVariable(); playerApplicationThreadHandler.removeCallbacksAndMessages(null); - playerApplicationThreadHandler.post(player::release); + playerApplicationThreadHandler.post( + () -> { + player.release(); + waitForRelease.open(); + }); + waitForRelease.blockUninterruptible(); } // AnalyticsListener