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,362 +71,321 @@ 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}.
*/
@RunWith(Parameterized.class)
public static class RenderedFirstFrameTest {
private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
private @MonotonicNonNull ExoPlayer player;
private @MonotonicNonNull ImageReader outputImageReader;
@Parameter public boolean playWhenReady; // 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);
@Parameters(name = "playWhenReady={0}") private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
public static ImmutableList<Boolean> parameters() { private @MonotonicNonNull ExoPlayer player;
return ImmutableList.of(true, false); private @MonotonicNonNull ImageReader outputImageReader;
private String testId;
@Before
public void setUp() {
testId = testName.getMethodName();
// 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,
// Use a larger count to avoid ImageReader dropping frames
/* maxImages= */ 10);
}
@After
public void tearDown() {
instrumentation.runOnMainSync(() -> release(player, outputImageReader));
}
@Test
public void exoplayerEffectsPreviewTest_playWhenReadySetToFalse_ensuresFirstFrameRendered()
throws Exception {
AtomicReference<Bitmap> renderedFirstFrameBitmap = new AtomicReference<>();
ConditionVariable hasRenderedFirstFrameCondition = new ConditionVariable();
instrumentation.runOnMainSync(
() -> {
player = new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build();
checkStateNotNull(outputImageReader);
outputImageReader.setOnImageAvailableListener(
imageReader -> {
try (Image image = imageReader.acquireLatestImage()) {
renderedFirstFrameBitmap.set(createArgb8888BitmapFromRgba8888Image(image));
}
hasRenderedFirstFrameCondition.open();
},
Util.createHandlerForCurrentOrMainLooper());
setOutputSurfaceAndSizeOnPlayer(
player,
checkNotNull(findVideoRenderer(player)),
outputImageReader.getSurface(),
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(false);
player.setVideoEffects(ImmutableList.of(createTimestampOverlay()));
// Adding an EventLogger to use its log output in case the test fails.
player.addAnalyticsListener(new EventLogger());
player.setMediaItem(MediaItem.fromUri(MP4_ASSET.uri));
player.prepare();
});
if (!hasRenderedFirstFrameCondition.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant("First frame not rendered in %d ms.", TEST_TIMEOUT_MS));
} }
@After assertThat(renderedFirstFrameBitmap.get()).isNotNull();
public void tearDown() { float averagePixelAbsoluteDifference =
instrumentation.runOnMainSync(() -> release(player, outputImageReader)); getBitmapAveragePixelAbsoluteDifferenceArgb8888(
} /* expected= */ readBitmap(TEST_DIRECTORY + "/first_frame.png"),
/* actual= */ renderedFirstFrameBitmap.get(),
testId);
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
// TODO: b/315800590 - Verify onFirstFrameRendered is invoked only once.
}
@Test @Test
public void exoplayerEffectsPreviewTest_ensuresFirstFrameRendered() throws Exception { public void exoplayerEffectsPreviewTest_ensuresAllFramesRendered() throws Exception {
String testId = // Internal reference: b/264252759.
Util.formatInvariant( assumeTrue(
"exoplayerEffectsPreviewTest_withPlayWhenReady[%b]_ensuresFirstFrameRendered", "This test should run on real devices because OpenGL to ImageReader rendering is"
playWhenReady); + "not always reliable on emulators.",
AtomicReference<Bitmap> renderedFirstFrameBitmap = new AtomicReference<>(); !Util.isRunningOnEmulator());
ConditionVariable hasRenderedFirstFrameCondition = new ConditionVariable();
outputImageReader =
ImageReader.newInstance(
MP4_ASSET.videoFormat.width,
MP4_ASSET.videoFormat.height,
PixelFormat.RGBA_8888,
/* maxImages= */ 1);
instrumentation.runOnMainSync( ArrayList<BitmapPixelTestUtil.ImageBuffer> readImageBuffers = new ArrayList<>();
() -> { AtomicInteger renderedFramesCount = new AtomicInteger();
player = new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build(); ConditionVariable playerEnded = new ConditionVariable();
ConditionVariable readAllOutputFrames = new ConditionVariable();
checkStateNotNull(outputImageReader); instrumentation.runOnMainSync(
outputImageReader.setOnImageAvailableListener( () -> {
imageReader -> { Context context = ApplicationProvider.getApplicationContext();
try (Image image = imageReader.acquireLatestImage()) { Renderer videoRenderer =
renderedFirstFrameBitmap.set(createArgb8888BitmapFromRgba8888Image(image)); new NoFrameDroppedVideoRenderer(context, MediaCodecSelector.DEFAULT);
player =
new ExoPlayer.Builder(context)
.setRenderersFactory(
new DefaultRenderersFactory(context) {
@Override
protected void buildVideoRenderers(
Context context,
@ExtensionRendererMode int extensionRendererMode,
MediaCodecSelector mediaCodecSelector,
boolean enableDecoderFallback,
Handler eventHandler,
VideoRendererEventListener eventListener,
long allowedVideoJoiningTimeMs,
ArrayList<Renderer> out) {
out.add(videoRenderer);
}
})
.build();
checkStateNotNull(outputImageReader);
outputImageReader.setOnImageAvailableListener(
imageReader -> {
try (Image image = imageReader.acquireNextImage()) {
readImageBuffers.add(BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
}
if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) {
readAllOutputFrames.open();
}
},
Util.createHandlerForCurrentOrMainLooper());
setOutputSurfaceAndSizeOnPlayer(
player,
videoRenderer,
outputImageReader.getSurface(),
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(true);
player.setVideoEffects(ImmutableList.of(createTimestampOverlay()));
// Adding an EventLogger to use its log output in case the test fails.
player.addAnalyticsListener(new EventLogger());
player.addListener(
new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
if (playbackState == STATE_ENDED) {
playerEnded.open();
} }
hasRenderedFirstFrameCondition.open(); }
}, });
Util.createHandlerForCurrentOrMainLooper()); player.setMediaItem(MediaItem.fromUri(MP4_ASSET.uri));
player.prepare();
});
setOutputSurfaceAndSizeOnPlayer( if (!playerEnded.block(TEST_TIMEOUT_MS)) {
player, throw new TimeoutException(
findVideoRenderer(player), Util.formatInvariant("Playback not ended in %d ms.", TEST_TIMEOUT_MS));
outputImageReader.getSurface(), }
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(playWhenReady); if (!readAllOutputFrames.block(TEST_TIMEOUT_MS)) {
player.setVideoEffects(ImmutableList.of(createTimestampOverlay())); throw new TimeoutException(
Util.formatInvariant(
"Haven't received all frames in %d ms after playback ends.", TEST_TIMEOUT_MS));
}
// Adding an EventLogger to use its log output in case the test fails. ArrayList<Float> averagePixelDifferences =
player.addAnalyticsListener(new EventLogger()); new ArrayList<>(/* initialCapacity= */ readImageBuffers.size());
player.setMediaItem(MediaItem.fromUri(MP4_ASSET.uri)); for (int i = 0; i < readImageBuffers.size(); i++) {
player.prepare(); Bitmap actualBitmap = createArgb8888BitmapFromRgba8888ImageBuffer(readImageBuffers.get(i));
});
if (!hasRenderedFirstFrameCondition.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant("First frame not rendered in %d ms.", TEST_TIMEOUT_MS));
}
assertThat(renderedFirstFrameBitmap.get()).isNotNull();
float averagePixelAbsoluteDifference = float averagePixelAbsoluteDifference =
getBitmapAveragePixelAbsoluteDifferenceArgb8888( getBitmapAveragePixelAbsoluteDifferenceArgb8888(
/* expected= */ readBitmap(TEST_DIRECTORY + "/first_frame.png"), /* expected= */ readBitmap(
/* actual= */ renderedFirstFrameBitmap.get(), Util.formatInvariant("%s/%s/frame_%d.png", TEST_DIRECTORY, testId, i)),
testId); /* actual= */ actualBitmap,
assertThat(averagePixelAbsoluteDifference) /* testId= */ Util.formatInvariant("%s_frame_%d", testId, i));
averagePixelDifferences.add(averagePixelAbsoluteDifference);
}
for (int i = 0; i < averagePixelDifferences.size(); i++) {
float averagePixelDifference = averagePixelDifferences.get(i);
assertWithMessage(
Util.formatInvariant(
"Frame %d with average pixel difference %f. ", i, averagePixelDifference))
.that(averagePixelDifference)
.isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE); .isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
// TODO: b/315800590 - Verify onFirstFrameRendered is invoked only once.
} }
} }
/** Playback test for {@link Effect}-enabled playback. */ @Test
public static class PlaybackTest { public void exoplayerEffectsPreview_withTimestampWrapper_ensuresAllFramesRendered()
@Rule public final TestName testName = new TestName(); throws Exception {
// Internal reference: b/264252759.
assumeTrue(
"This test should run on real devices because OpenGL to ImageReader rendering is"
+ "not always reliable on emulators.",
!Util.isRunningOnEmulator());
// Force the test to run in foreground to make it faster and avoid ImageReader frame drops. ArrayList<BitmapPixelTestUtil.ImageBuffer> readImageBuffers = new ArrayList<>();
@Rule AtomicInteger renderedFramesCount = new AtomicInteger();
public ActivityScenarioRule<SurfaceTestActivity> rule = ConditionVariable playerEnded = new ConditionVariable();
new ActivityScenarioRule<>(SurfaceTestActivity.class); 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);
private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); instrumentation.runOnMainSync(
private @MonotonicNonNull ExoPlayer player; () -> {
private @MonotonicNonNull ImageReader outputImageReader; Context context = ApplicationProvider.getApplicationContext();
private String testId; Renderer videoRenderer =
new NoFrameDroppedVideoRenderer(context, MediaCodecSelector.DEFAULT);
player =
new ExoPlayer.Builder(context)
.setRenderersFactory(
new DefaultRenderersFactory(context) {
@Override
protected void buildVideoRenderers(
Context context,
@ExtensionRendererMode int extensionRendererMode,
MediaCodecSelector mediaCodecSelector,
boolean enableDecoderFallback,
Handler eventHandler,
VideoRendererEventListener eventListener,
long allowedVideoJoiningTimeMs,
ArrayList<Renderer> out) {
out.add(videoRenderer);
}
})
.build();
@Before checkStateNotNull(outputImageReader);
public void setUpTestId() { outputImageReader.setOnImageAvailableListener(
testId = testName.getMethodName(); imageReader -> {
try (Image image = imageReader.acquireNextImage()) {
readImageBuffers.add(BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
}
if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) {
readAllOutputFrames.open();
}
},
Util.createHandlerForCurrentOrMainLooper());
setOutputSurfaceAndSizeOnPlayer(
player,
videoRenderer,
outputImageReader.getSurface(),
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(true);
player.setVideoEffects(
ImmutableList.of(
new TimestampWrapper(
new Brightness(0.5f), /* startTimeUs= */ 166833, /* endTimeUs= */ 510000)));
// Adding an EventLogger to use its log output in case the test fails.
player.addAnalyticsListener(new EventLogger());
player.addListener(
new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
if (playbackState == STATE_ENDED) {
playerEnded.open();
}
}
});
player.setMediaItem(MediaItem.fromUri(MP4_ASSET.uri));
player.prepare();
});
if (!playerEnded.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant("Playback not ended in %d ms.", TEST_TIMEOUT_MS));
} }
@After if (!readAllOutputFrames.block(TEST_TIMEOUT_MS)) {
public void tearDown() { throw new TimeoutException(
instrumentation.runOnMainSync(() -> release(player, outputImageReader)); Util.formatInvariant(
"Haven't received all frames in %d ms after playback ends.", TEST_TIMEOUT_MS));
} }
@Test ArrayList<Float> averagePixelDifferences =
public void exoplayerEffectsPreviewTest_ensuresAllFramesRendered() throws Exception { new ArrayList<>(/* initialCapacity= */ readImageBuffers.size());
// Internal reference: b/264252759. for (int i = 0; i < readImageBuffers.size(); i++) {
assumeTrue( Bitmap actualBitmap = createArgb8888BitmapFromRgba8888ImageBuffer(readImageBuffers.get(i));
"This test should run on real devices because OpenGL to ImageReader rendering is" float averagePixelAbsoluteDifference =
+ "not always reliable on emulators.", getBitmapAveragePixelAbsoluteDifferenceArgb8888(
!Util.isRunningOnEmulator()); /* expected= */ readBitmap(
Util.formatInvariant("%s/%s/frame_%d.png", TEST_DIRECTORY, testId, i)),
ArrayList<BitmapPixelTestUtil.ImageBuffer> readImageBuffers = new ArrayList<>(); /* actual= */ actualBitmap,
AtomicInteger renderedFramesCount = new AtomicInteger(); /* testId= */ Util.formatInvariant("%s_frame_%d", testId, i));
ConditionVariable playerEnded = new ConditionVariable(); averagePixelDifferences.add(averagePixelAbsoluteDifference);
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(
() -> {
Context context = ApplicationProvider.getApplicationContext();
Renderer videoRenderer =
new NoFrameDroppedVideoRenderer(context, MediaCodecSelector.DEFAULT);
player =
new ExoPlayer.Builder(context)
.setRenderersFactory(
new DefaultRenderersFactory(context) {
@Override
protected void buildVideoRenderers(
Context context,
@ExtensionRendererMode int extensionRendererMode,
MediaCodecSelector mediaCodecSelector,
boolean enableDecoderFallback,
Handler eventHandler,
VideoRendererEventListener eventListener,
long allowedVideoJoiningTimeMs,
ArrayList<Renderer> out) {
out.add(videoRenderer);
}
})
.build();
checkStateNotNull(outputImageReader);
outputImageReader.setOnImageAvailableListener(
imageReader -> {
try (Image image = imageReader.acquireNextImage()) {
readImageBuffers.add(
BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
}
if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) {
readAllOutputFrames.open();
}
},
Util.createHandlerForCurrentOrMainLooper());
setOutputSurfaceAndSizeOnPlayer(
player,
videoRenderer,
outputImageReader.getSurface(),
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(true);
player.setVideoEffects(ImmutableList.of(createTimestampOverlay()));
// Adding an EventLogger to use its log output in case the test fails.
player.addAnalyticsListener(new EventLogger());
player.addListener(
new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
if (playbackState == STATE_ENDED) {
playerEnded.open();
}
}
});
player.setMediaItem(MediaItem.fromUri(MP4_ASSET.uri));
player.prepare();
});
if (!playerEnded.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant("Playback not ended in %d ms.", TEST_TIMEOUT_MS));
}
if (!readAllOutputFrames.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant(
"Haven't received all frames in %d ms after playback ends.", TEST_TIMEOUT_MS));
}
ArrayList<Float> averagePixelDifferences =
new ArrayList<>(/* initialCapacity= */ readImageBuffers.size());
for (int i = 0; i < readImageBuffers.size(); i++) {
Bitmap actualBitmap = createArgb8888BitmapFromRgba8888ImageBuffer(readImageBuffers.get(i));
float averagePixelAbsoluteDifference =
getBitmapAveragePixelAbsoluteDifferenceArgb8888(
/* expected= */ readBitmap(
Util.formatInvariant("%s/%s/frame_%d.png", TEST_DIRECTORY, testId, i)),
/* actual= */ actualBitmap,
/* testId= */ Util.formatInvariant("%s_frame_%d", testId, i));
averagePixelDifferences.add(averagePixelAbsoluteDifference);
}
for (int i = 0; i < averagePixelDifferences.size(); i++) {
float averagePixelDifference = averagePixelDifferences.get(i);
assertWithMessage(
Util.formatInvariant(
"Frame %d with average pixel difference %f. ", i, averagePixelDifference))
.that(averagePixelDifference)
.isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
}
} }
@Test for (int i = 0; i < averagePixelDifferences.size(); i++) {
public void exoplayerEffectsPreview_withTimestampWrapper_ensuresAllFramesRendered() float averagePixelDifference = averagePixelDifferences.get(i);
throws Exception { assertWithMessage(
// Internal reference: b/264252759. Util.formatInvariant(
assumeTrue( "Frame %d with average pixel difference %f. ", i, averagePixelDifference))
"This test should run on real devices because OpenGL to ImageReader rendering is" .that(averagePixelDifference)
+ "not always reliable on emulators.", .isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
!Util.isRunningOnEmulator());
ArrayList<BitmapPixelTestUtil.ImageBuffer> readImageBuffers = new ArrayList<>();
AtomicInteger renderedFramesCount = new AtomicInteger();
ConditionVariable playerEnded = 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(
() -> {
Context context = ApplicationProvider.getApplicationContext();
Renderer videoRenderer =
new NoFrameDroppedVideoRenderer(context, MediaCodecSelector.DEFAULT);
player =
new ExoPlayer.Builder(context)
.setRenderersFactory(
new DefaultRenderersFactory(context) {
@Override
protected void buildVideoRenderers(
Context context,
@ExtensionRendererMode int extensionRendererMode,
MediaCodecSelector mediaCodecSelector,
boolean enableDecoderFallback,
Handler eventHandler,
VideoRendererEventListener eventListener,
long allowedVideoJoiningTimeMs,
ArrayList<Renderer> out) {
out.add(videoRenderer);
}
})
.build();
checkStateNotNull(outputImageReader);
outputImageReader.setOnImageAvailableListener(
imageReader -> {
try (Image image = imageReader.acquireNextImage()) {
readImageBuffers.add(
BitmapPixelTestUtil.copyByteBufferFromRbga8888Image(image));
}
if (renderedFramesCount.incrementAndGet() == MP4_ASSET.videoFrameCount) {
readAllOutputFrames.open();
}
},
Util.createHandlerForCurrentOrMainLooper());
setOutputSurfaceAndSizeOnPlayer(
player,
videoRenderer,
outputImageReader.getSurface(),
new Size(MP4_ASSET.videoFormat.width, MP4_ASSET.videoFormat.height));
player.setPlayWhenReady(true);
player.setVideoEffects(
ImmutableList.of(
new TimestampWrapper(
new Brightness(0.5f), /* startTimeUs= */ 166833, /* endTimeUs= */ 510000)));
// Adding an EventLogger to use its log output in case the test fails.
player.addAnalyticsListener(new EventLogger());
player.addListener(
new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
if (playbackState == STATE_ENDED) {
playerEnded.open();
}
}
});
player.setMediaItem(MediaItem.fromUri(MP4_ASSET.uri));
player.prepare();
});
if (!playerEnded.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant("Playback not ended in %d ms.", TEST_TIMEOUT_MS));
}
if (!readAllOutputFrames.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException(
Util.formatInvariant(
"Haven't received all frames in %d ms after playback ends.", TEST_TIMEOUT_MS));
}
ArrayList<Float> averagePixelDifferences =
new ArrayList<>(/* initialCapacity= */ readImageBuffers.size());
for (int i = 0; i < readImageBuffers.size(); i++) {
Bitmap actualBitmap = createArgb8888BitmapFromRgba8888ImageBuffer(readImageBuffers.get(i));
float averagePixelAbsoluteDifference =
getBitmapAveragePixelAbsoluteDifferenceArgb8888(
/* expected= */ readBitmap(
Util.formatInvariant("%s/%s/frame_%d.png", TEST_DIRECTORY, testId, i)),
/* actual= */ actualBitmap,
/* testId= */ Util.formatInvariant("%s_frame_%d", testId, i));
averagePixelDifferences.add(averagePixelAbsoluteDifference);
}
for (int i = 0; i < averagePixelDifferences.size(); i++) {
float averagePixelDifference = averagePixelDifferences.get(i);
assertWithMessage(
Util.formatInvariant(
"Frame %d with average pixel difference %f. ", i, averagePixelDifference))
.that(averagePixelDifference)
.isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
}
} }
} }