From 26f10effc2656a388f3c98ad51b70994589eba9a Mon Sep 17 00:00:00 2001 From: dancho Date: Tue, 19 Nov 2024 03:06:28 -0800 Subject: [PATCH] Add frame extractor tests for decoder counters. Right now, decoders produce an unspecified (but large) number of frames. This will be resolved in a follow-up PiperOrigin-RevId: 697945076 --- .../transformer/FrameExtractorTest.java | 46 +++++++++++++++++++ .../ExperimentalFrameExtractor.java | 11 +++++ 2 files changed, 57 insertions(+) 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 0127262b73..41c3405597 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameExtractorTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/FrameExtractorTest.java @@ -28,10 +28,12 @@ import static org.junit.Assert.assertThrows; import android.app.Instrumentation; import android.content.Context; import android.graphics.Bitmap; +import androidx.annotation.Nullable; import androidx.media3.common.MediaItem; import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.NullableType; import androidx.media3.effect.Presentation; +import androidx.media3.exoplayer.DecoderCounters; import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.transformer.ExperimentalFrameExtractor.Frame; import androidx.test.core.app.ApplicationProvider; @@ -106,6 +108,12 @@ public class FrameExtractorTest { assertThat(frame.presentationTimeMs).isEqualTo(8_531); assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD); + assertThat( + frameExtractor + .getDecoderCounters() + .get(TIMEOUT_SECONDS, SECONDS) + .renderedOutputBufferCount) + .isAtLeast(4); } @Test @@ -128,6 +136,12 @@ public class FrameExtractorTest { assertThat(frame.presentationTimeMs).isEqualTo(8_531); assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD); + assertThat( + frameExtractor + .getDecoderCounters() + .get(TIMEOUT_SECONDS, SECONDS) + .renderedOutputBufferCount) + .isAtLeast(4); } @Test @@ -151,6 +165,12 @@ public class FrameExtractorTest { assertThat(frame.presentationTimeMs).isEqualTo(lastVideoFramePresentationTimeMs); assertBitmapsAreSimilar(expectedBitmap, actualBitmap, PSNR_THRESHOLD); + assertThat( + frameExtractor + .getDecoderCounters() + .get(TIMEOUT_SECONDS, SECONDS) + .renderedOutputBufferCount) + .isAtLeast(3); } @Test @@ -182,6 +202,14 @@ public class FrameExtractorTest { assertBitmapsAreSimilar(expectedBitmap, frame.bitmap, PSNR_THRESHOLD); assertThat(frame.presentationTimeMs).isEqualTo(expectedFramePositionsMs.get(i)); } + // TODO: b/350498258 - some decoders break right after extracting all the frames for this test. + // Fix and remove this hack. + @Nullable + DecoderCounters decoderCounters = + frameExtractor.getDecoderCounters().get(TIMEOUT_SECONDS, SECONDS); + if (decoderCounters != null) { + assertThat(decoderCounters.renderedOutputBufferCount).isAtLeast(7); + } } @Test @@ -204,6 +232,12 @@ public class FrameExtractorTest { assertThat(frame7.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(7_031); assertThat(frame2.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(2_032); assertThat(frame8.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(8_031); + assertThat( + frameExtractor + .getDecoderCounters() + .get(TIMEOUT_SECONDS, SECONDS) + .renderedOutputBufferCount) + .isAtLeast(10); } @Test @@ -230,6 +264,12 @@ public class FrameExtractorTest { assertThat(frame7.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(8_331); assertThat(frame2.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(0); assertThat(frame8.get(TIMEOUT_SECONDS, SECONDS).presentationTimeMs).isEqualTo(8_331); + assertThat( + frameExtractor + .getDecoderCounters() + .get(TIMEOUT_SECONDS, SECONDS) + .renderedOutputBufferCount) + .isAtLeast(8); } @Test @@ -284,6 +324,12 @@ public class FrameExtractorTest { assertThat(throwableAtomicReference.get()).isNull(); assertThat(frameAtomicReference.get().presentationTimeMs).isEqualTo(0); + assertThat( + frameExtractor + .getDecoderCounters() + .get(TIMEOUT_SECONDS, SECONDS) + .renderedOutputBufferCount) + .isAtLeast(1); } @Test 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 8a7e938956..99a7cfc75e 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExperimentalFrameExtractor.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExperimentalFrameExtractor.java @@ -30,6 +30,7 @@ import android.opengl.GLES20; import android.os.Handler; import android.os.Looper; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.media3.common.Effect; import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlTextureInfo; @@ -43,6 +44,7 @@ import androidx.media3.effect.GlEffect; import androidx.media3.effect.GlShaderProgram; import androidx.media3.effect.MatrixTransformation; import androidx.media3.effect.PassthroughShaderProgram; +import androidx.media3.exoplayer.DecoderCounters; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.SeekParameters; import androidx.media3.exoplayer.analytics.AnalyticsListener; @@ -275,6 +277,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } } + @VisibleForTesting + /* package */ ListenableFuture<@NullableType DecoderCounters> getDecoderCounters() { + SettableFuture<@NullableType DecoderCounters> decoderCountersSettableFuture = + SettableFuture.create(); + playerApplicationThreadHandler.post( + () -> decoderCountersSettableFuture.set(player.getVideoDecoderCounters())); + return decoderCountersSettableFuture; + } + private ImmutableList buildVideoEffects(List effects) { ImmutableList.Builder listBuilder = new ImmutableList.Builder<>(); listBuilder.addAll(effects);