From f8d5f5a828d0783725696a27a12b78f577effaa0 Mon Sep 17 00:00:00 2001 From: shahddaghash Date: Mon, 17 Feb 2025 06:00:11 -0800 Subject: [PATCH] Move FrameBlockingMuxer into AndroidTestUtil This allows it to be reused in upcoming tests. PiperOrigin-RevId: 727835985 --- .../media3/transformer/AndroidTestUtil.java | 85 +++++++++++++++++++ .../TransformerPauseResumeTest.java | 85 ++----------------- 2 files changed, 91 insertions(+), 79 deletions(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java index ce966883a5..9f778faeaf 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/AndroidTestUtil.java @@ -34,6 +34,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.media.Image; +import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.opengl.EGLContext; import android.opengl.EGLDisplay; @@ -44,6 +45,7 @@ import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlTextureInfo; +import androidx.media3.common.Metadata; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.GlRect; import androidx.media3.common.util.GlUtil; @@ -58,6 +60,7 @@ import androidx.media3.effect.PassthroughShaderProgram; import androidx.media3.effect.ScaleAndRotateTransformation; import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; +import androidx.media3.muxer.MuxerException; import androidx.media3.test.utils.BitmapPixelTestUtil; import androidx.media3.test.utils.VideoDecodingWrapper; import com.google.common.base.Ascii; @@ -67,6 +70,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; @@ -1221,6 +1225,87 @@ public final class AndroidTestUtil { } } + /** A {@link Muxer.Factory} that creates {@link FrameBlockingMuxer} instances. */ + public static final class FrameBlockingMuxerFactory implements Muxer.Factory { + private final Muxer.Factory wrappedMuxerFactory; + private final FrameBlockingMuxer.Listener listener; + private final long presentationTimeUsToBlockFrame; + + FrameBlockingMuxerFactory( + long presentationTimeUsToBlockFrame, FrameBlockingMuxer.Listener listener) { + this.wrappedMuxerFactory = new DefaultMuxer.Factory(); + this.listener = listener; + this.presentationTimeUsToBlockFrame = presentationTimeUsToBlockFrame; + } + + @Override + public Muxer create(String path) throws MuxerException { + return new FrameBlockingMuxer( + wrappedMuxerFactory.create(path), presentationTimeUsToBlockFrame, listener); + } + + @Override + public ImmutableList getSupportedSampleMimeTypes(@C.TrackType int trackType) { + return wrappedMuxerFactory.getSupportedSampleMimeTypes(trackType); + } + } + + /** A {@link Muxer} that blocks writing video frames after a specific presentation timestamp. */ + public static final class FrameBlockingMuxer implements Muxer { + interface Listener { + void onFrameBlocked(); + } + + private final Muxer wrappedMuxer; + private final FrameBlockingMuxer.Listener listener; + private final long presentationTimeUsToBlockFrame; + + private boolean notifiedListener; + private int videoTrackId; + + private FrameBlockingMuxer( + Muxer wrappedMuxer, + long presentationTimeUsToBlockFrame, + FrameBlockingMuxer.Listener listener) { + this.wrappedMuxer = wrappedMuxer; + this.listener = listener; + this.presentationTimeUsToBlockFrame = presentationTimeUsToBlockFrame; + } + + @Override + public int addTrack(Format format) throws MuxerException { + int trackId = wrappedMuxer.addTrack(format); + if (MimeTypes.isVideo(format.sampleMimeType)) { + videoTrackId = trackId; + } + return trackId; + } + + @Override + public void writeSampleData(int trackId, ByteBuffer data, MediaCodec.BufferInfo bufferInfo) + throws MuxerException { + if (trackId == videoTrackId + && bufferInfo.presentationTimeUs >= presentationTimeUsToBlockFrame) { + if (!notifiedListener) { + listener.onFrameBlocked(); + notifiedListener = true; + } + return; + } + wrappedMuxer.writeSampleData(trackId, data, bufferInfo); + } + + @Override + public void addMetadataEntry(Metadata.Entry metadataEntry) { + wrappedMuxer.addMetadataEntry(metadataEntry); + } + + @Override + public void close() throws MuxerException { + wrappedMuxer.close(); + } + } + /** * Implementation of {@link ByteBufferGlEffect.Processor} that counts how many frames are copied * to CPU memory. diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java index 76c1c77fe5..8c393f3889 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerPauseResumeTest.java @@ -23,25 +23,19 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assume.assumeFalse; import android.content.Context; -import android.media.MediaCodec.BufferInfo; import android.os.Build; import androidx.media3.common.C; import androidx.media3.common.Effect; -import androidx.media3.common.Format; import androidx.media3.common.MediaItem; -import androidx.media3.common.Metadata; -import androidx.media3.common.MimeTypes; import androidx.media3.common.audio.AudioProcessor; import androidx.media3.common.audio.SonicAudioProcessor; import androidx.media3.common.util.Util; import androidx.media3.effect.RgbFilter; -import androidx.media3.muxer.MuxerException; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import java.io.File; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -58,7 +52,7 @@ import org.junit.runner.RunWith; public class TransformerPauseResumeTest { @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - private static final long DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME = 5_000_000L; + private static final long PRESENTATION_TIME_US_TO_BLOCK_FRAME = 5_000_000L; private static final int DEFAULT_TIMEOUT_SECONDS = 120; private static final int MP4_ASSET_FRAME_COUNT = 932; @@ -402,9 +396,12 @@ public class TransformerPauseResumeTest { .build(); } - private static Transformer buildBlockingTransformer(FrameBlockingMuxer.Listener listener) { + private static Transformer buildBlockingTransformer( + AndroidTestUtil.FrameBlockingMuxer.Listener listener) { return new Transformer.Builder(getApplicationContext()) - .setMuxerFactory(new FrameBlockingMuxerFactory(listener)) + .setMuxerFactory( + new AndroidTestUtil.FrameBlockingMuxerFactory( + PRESENTATION_TIME_US_TO_BLOCK_FRAME, listener)) .build(); } @@ -417,74 +414,4 @@ public class TransformerPauseResumeTest { || (Util.SDK_INT == 28 && Ascii.equalsIgnoreCase(Build.MODEL, "vivo 1901")) || (Util.SDK_INT == 28 && Ascii.equalsIgnoreCase(Build.MODEL, "vivo 1906")); } - - private static final class FrameBlockingMuxerFactory implements Muxer.Factory { - private final Muxer.Factory wrappedMuxerFactory; - private final FrameBlockingMuxer.Listener listener; - - public FrameBlockingMuxerFactory(FrameBlockingMuxer.Listener listener) { - this.wrappedMuxerFactory = new DefaultMuxer.Factory(); - this.listener = listener; - } - - @Override - public Muxer create(String path) throws MuxerException { - return new FrameBlockingMuxer(wrappedMuxerFactory.create(path), listener); - } - - @Override - public ImmutableList getSupportedSampleMimeTypes(@C.TrackType int trackType) { - return wrappedMuxerFactory.getSupportedSampleMimeTypes(trackType); - } - } - - private static final class FrameBlockingMuxer implements Muxer { - interface Listener { - void onFrameBlocked(); - } - - private final Muxer wrappedMuxer; - private final FrameBlockingMuxer.Listener listener; - - private boolean notifiedListener; - private int videoTrackId; - - private FrameBlockingMuxer(Muxer wrappedMuxer, FrameBlockingMuxer.Listener listener) { - this.wrappedMuxer = wrappedMuxer; - this.listener = listener; - } - - @Override - public int addTrack(Format format) throws MuxerException { - int trackId = wrappedMuxer.addTrack(format); - if (MimeTypes.isVideo(format.sampleMimeType)) { - videoTrackId = trackId; - } - return trackId; - } - - @Override - public void writeSampleData(int trackId, ByteBuffer data, BufferInfo bufferInfo) - throws MuxerException { - if (trackId == videoTrackId - && bufferInfo.presentationTimeUs >= DEFAULT_PRESENTATION_TIME_US_TO_BLOCK_FRAME) { - if (!notifiedListener) { - listener.onFrameBlocked(); - notifiedListener = true; - } - return; - } - wrappedMuxer.writeSampleData(trackId, data, bufferInfo); - } - - @Override - public void addMetadataEntry(Metadata.Entry metadataEntry) { - wrappedMuxer.addMetadataEntry(metadataEntry); - } - - @Override - public void close() throws MuxerException { - wrappedMuxer.close(); - } - } }