Move FrameBlockingMuxer into AndroidTestUtil

This allows it to be reused in upcoming tests.

PiperOrigin-RevId: 727835985
(cherry picked from commit f8d5f5a828d0783725696a27a12b78f577effaa0)
This commit is contained in:
shahddaghash 2025-02-17 06:00:11 -08:00 committed by oceanjules
parent 4a8d28cef8
commit ed05bc67c3
2 changed files with 91 additions and 79 deletions

View File

@ -34,6 +34,7 @@ import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Bitmap.Config; import android.graphics.Bitmap.Config;
import android.media.Image; import android.media.Image;
import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.opengl.EGLContext; import android.opengl.EGLContext;
import android.opengl.EGLDisplay; import android.opengl.EGLDisplay;
@ -44,6 +45,7 @@ import androidx.media3.common.ColorInfo;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlObjectsProvider;
import androidx.media3.common.GlTextureInfo; import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.GlRect; import androidx.media3.common.util.GlRect;
import androidx.media3.common.util.GlUtil; import androidx.media3.common.util.GlUtil;
@ -58,6 +60,7 @@ import androidx.media3.effect.PassthroughShaderProgram;
import androidx.media3.effect.ScaleAndRotateTransformation; import androidx.media3.effect.ScaleAndRotateTransformation;
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
import androidx.media3.muxer.MuxerException;
import androidx.media3.test.utils.BitmapPixelTestUtil; import androidx.media3.test.utils.BitmapPixelTestUtil;
import androidx.media3.test.utils.VideoDecodingWrapper; import androidx.media3.test.utils.VideoDecodingWrapper;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
@ -67,6 +70,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger; 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<String> 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 * Implementation of {@link ByteBufferGlEffect.Processor} that counts how many frames are copied
* to CPU memory. * to CPU memory.

View File

@ -23,25 +23,19 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeFalse;
import android.content.Context; import android.content.Context;
import android.media.MediaCodec.BufferInfo;
import android.os.Build; import android.os.Build;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Effect; import androidx.media3.common.Effect;
import androidx.media3.common.Format;
import androidx.media3.common.MediaItem; 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.AudioProcessor;
import androidx.media3.common.audio.SonicAudioProcessor; import androidx.media3.common.audio.SonicAudioProcessor;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.effect.RgbFilter; import androidx.media3.effect.RgbFilter;
import androidx.media3.muxer.MuxerException;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.platform.app.InstrumentationRegistry;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.File; import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -58,7 +52,7 @@ import org.junit.runner.RunWith;
public class TransformerPauseResumeTest { public class TransformerPauseResumeTest {
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @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 DEFAULT_TIMEOUT_SECONDS = 120;
private static final int MP4_ASSET_FRAME_COUNT = 932; private static final int MP4_ASSET_FRAME_COUNT = 932;
@ -402,9 +396,12 @@ public class TransformerPauseResumeTest {
.build(); .build();
} }
private static Transformer buildBlockingTransformer(FrameBlockingMuxer.Listener listener) { private static Transformer buildBlockingTransformer(
AndroidTestUtil.FrameBlockingMuxer.Listener listener) {
return new Transformer.Builder(getApplicationContext()) return new Transformer.Builder(getApplicationContext())
.setMuxerFactory(new FrameBlockingMuxerFactory(listener)) .setMuxerFactory(
new AndroidTestUtil.FrameBlockingMuxerFactory(
PRESENTATION_TIME_US_TO_BLOCK_FRAME, listener))
.build(); .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 1901"))
|| (Util.SDK_INT == 28 && Ascii.equalsIgnoreCase(Build.MODEL, "vivo 1906")); || (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<String> 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();
}
}
} }