Increase the maxImage on ImageReader, hoping less flaky tests

PiperOrigin-RevId: 679528425
This commit is contained in:
claincly 2024-09-27 04:00:21 -07:00 committed by Copybara-Service
parent b9aed0a937
commit e0e9f5b057

View File

@ -17,6 +17,7 @@
package androidx.media3.transformer.mh.performance; package androidx.media3.transformer.mh.performance;
import static androidx.media3.common.Player.STATE_ENDED; import static androidx.media3.common.Player.STATE_ENDED;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.test.utils.BitmapPixelTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE; import static androidx.media3.test.utils.BitmapPixelTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE;
import static androidx.media3.test.utils.BitmapPixelTestUtil.createArgb8888BitmapFromRgba8888Image; import static androidx.media3.test.utils.BitmapPixelTestUtil.createArgb8888BitmapFromRgba8888Image;
@ -58,6 +59,7 @@ import androidx.media3.test.utils.BitmapPixelTestUtil;
import androidx.media3.transformer.SurfaceTestActivity; import androidx.media3.transformer.SurfaceTestActivity;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.platform.app.InstrumentationRegistry;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
@ -69,38 +71,44 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.rules.TestName; import org.junit.rules.TestName;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
/** Pixel tests for {@link ExoPlayer#setVideoEffects}. */ /** Pixel tests for {@link ExoPlayer#setVideoEffects}. */
// These tests are in the performance package even though they are not performance tests so that // These tests are in the performance package even though they are not performance tests so that
// they are not run on all devices. This is because they use ImageReader, which has a tendency to // they are not run on all devices. This is because they use ImageReader, which has a tendency to
// drop frames. // drop frames.
@RunWith(Enclosed.class) @RunWith(AndroidJUnit4.class)
public class EffectPlaybackPixelTest { public class EffectPlaybackPixelTest {
private static final String TEST_DIRECTORY = "test-generated-goldens/ExoPlayerPlaybackTest"; private static final String TEST_DIRECTORY = "test-generated-goldens/ExoPlayerPlaybackTest";
private static final long TEST_TIMEOUT_MS = 10_000; private static final long TEST_TIMEOUT_MS = 10_000;
/** /** Playback test for {@link Effect}-enabled playback. */
* The test asserts the first frame is rendered for {@link Player#setPlayWhenReady playWhenReady} @Rule public final TestName testName = new TestName();
* is set to either {@code true} or {@code false}.
*/ // Force the test to run in foreground to make it faster and avoid ImageReader frame drops.
@RunWith(Parameterized.class) @Rule
public static class RenderedFirstFrameTest { public ActivityScenarioRule<SurfaceTestActivity> rule =
new ActivityScenarioRule<>(SurfaceTestActivity.class);
private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
private @MonotonicNonNull ExoPlayer player; private @MonotonicNonNull ExoPlayer player;
private @MonotonicNonNull ImageReader outputImageReader; private @MonotonicNonNull ImageReader outputImageReader;
private String testId;
@Parameter public boolean playWhenReady; @Before
public void setUp() {
@Parameters(name = "playWhenReady={0}") testId = testName.getMethodName();
public static ImmutableList<Boolean> parameters() { // Setting maxImages=10 ensures image reader gets all rendered frames from
return ImmutableList.of(true, false); // VideoFrameProcessor. Using maxImages=10 runs successfully on a Pixel3.
outputImageReader =
ImageReader.newInstance(
MP4_ASSET.videoFormat.width,
MP4_ASSET.videoFormat.height,
PixelFormat.RGBA_8888,
// Use a larger count to avoid ImageReader dropping frames
/* maxImages= */ 10);
} }
@After @After
@ -109,24 +117,14 @@ public class EffectPlaybackPixelTest {
} }
@Test @Test
public void exoplayerEffectsPreviewTest_ensuresFirstFrameRendered() throws Exception { public void exoplayerEffectsPreviewTest_playWhenReadySetToFalse_ensuresFirstFrameRendered()
String testId = throws Exception {
Util.formatInvariant(
"exoplayerEffectsPreviewTest_withPlayWhenReady[%b]_ensuresFirstFrameRendered",
playWhenReady);
AtomicReference<Bitmap> renderedFirstFrameBitmap = new AtomicReference<>(); AtomicReference<Bitmap> renderedFirstFrameBitmap = new AtomicReference<>();
ConditionVariable hasRenderedFirstFrameCondition = new ConditionVariable(); ConditionVariable hasRenderedFirstFrameCondition = new ConditionVariable();
outputImageReader =
ImageReader.newInstance(
MP4_ASSET.videoFormat.width,
MP4_ASSET.videoFormat.height,
PixelFormat.RGBA_8888,
/* maxImages= */ 1);
instrumentation.runOnMainSync( instrumentation.runOnMainSync(
() -> { () -> {
player = new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build(); player = new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build();
checkStateNotNull(outputImageReader); checkStateNotNull(outputImageReader);
outputImageReader.setOnImageAvailableListener( outputImageReader.setOnImageAvailableListener(
imageReader -> { imageReader -> {
@ -139,11 +137,11 @@ public class EffectPlaybackPixelTest {
setOutputSurfaceAndSizeOnPlayer( setOutputSurfaceAndSizeOnPlayer(
player, player,
findVideoRenderer(player), checkNotNull(findVideoRenderer(player)),
outputImageReader.getSurface(), outputImageReader.getSurface(),
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height)); new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(playWhenReady); player.setPlayWhenReady(false);
player.setVideoEffects(ImmutableList.of(createTimestampOverlay())); player.setVideoEffects(ImmutableList.of(createTimestampOverlay()));
// Adding an EventLogger to use its log output in case the test fails. // Adding an EventLogger to use its log output in case the test fails.
@ -163,35 +161,9 @@ public class EffectPlaybackPixelTest {
/* expected= */ readBitmap(TEST_DIRECTORY + "/first_frame.png"), /* expected= */ readBitmap(TEST_DIRECTORY + "/first_frame.png"),
/* actual= */ renderedFirstFrameBitmap.get(), /* actual= */ renderedFirstFrameBitmap.get(),
testId); testId);
assertThat(averagePixelAbsoluteDifference) assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
.isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
// TODO: b/315800590 - Verify onFirstFrameRendered is invoked only once. // TODO: b/315800590 - Verify onFirstFrameRendered is invoked only once.
} }
}
/** Playback test for {@link Effect}-enabled playback. */
public static class PlaybackTest {
@Rule public final TestName testName = new TestName();
// Force the test to run in foreground to make it faster and avoid ImageReader frame drops.
@Rule
public ActivityScenarioRule<SurfaceTestActivity> rule =
new ActivityScenarioRule<>(SurfaceTestActivity.class);
private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
private @MonotonicNonNull ExoPlayer player;
private @MonotonicNonNull ImageReader outputImageReader;
private String testId;
@Before
public void setUpTestId() {
testId = testName.getMethodName();
}
@After
public void tearDown() {
instrumentation.runOnMainSync(() -> release(player, outputImageReader));
}
@Test @Test
public void exoplayerEffectsPreviewTest_ensuresAllFramesRendered() throws Exception { public void exoplayerEffectsPreviewTest_ensuresAllFramesRendered() throws Exception {
@ -205,14 +177,6 @@ public class EffectPlaybackPixelTest {
AtomicInteger renderedFramesCount = new AtomicInteger(); AtomicInteger renderedFramesCount = new AtomicInteger();
ConditionVariable playerEnded = new ConditionVariable(); ConditionVariable playerEnded = new ConditionVariable();
ConditionVariable readAllOutputFrames = new ConditionVariable(); ConditionVariable readAllOutputFrames = new ConditionVariable();
// Setting maxImages=10 ensures image reader gets all rendered frames from
// VideoFrameProcessor. Using maxImages=10 runs successfully on a Pixel3.
outputImageReader =
ImageReader.newInstance(
MP4_ASSET.videoFormat.width,
MP4_ASSET.videoFormat.height,
PixelFormat.RGBA_8888,
/* maxImages= */ 10);
instrumentation.runOnMainSync( instrumentation.runOnMainSync(
() -> { () -> {
@ -242,8 +206,7 @@ public class EffectPlaybackPixelTest {
outputImageReader.setOnImageAvailableListener( outputImageReader.setOnImageAvailableListener(
imageReader -> { imageReader -> {
try (Image image = imageReader.acquireNextImage()) { try (Image image = imageReader.acquireNextImage()) {
readImageBuffers.add( readImageBuffers.add(BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
} }
if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) { if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) {
readAllOutputFrames.open(); readAllOutputFrames.open();
@ -358,8 +321,7 @@ public class EffectPlaybackPixelTest {
outputImageReader.setOnImageAvailableListener( outputImageReader.setOnImageAvailableListener(
imageReader -> { imageReader -> {
try (Image image = imageReader.acquireNextImage()) { try (Image image = imageReader.acquireNextImage()) {
readImageBuffers.add( readImageBuffers.add(BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
} }
if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) { if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) {
readAllOutputFrames.open(); readAllOutputFrames.open();
@ -426,7 +388,6 @@ public class EffectPlaybackPixelTest {
.isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE); .isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
} }
} }
}
@Nullable @Nullable
private static MediaCodecVideoRenderer findVideoRenderer(ExoPlayer player) { private static MediaCodecVideoRenderer findVideoRenderer(ExoPlayer player) {