Add performance test for composition previewing

PiperOrigin-RevId: 576509031
This commit is contained in:
claincly 2023-10-25 06:19:18 -07:00 committed by Copybara-Service
parent e91ce868ad
commit 3204da41fe
2 changed files with 109 additions and 67 deletions

View file

@ -0,0 +1,107 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.transformer.mh.performance;
import android.os.ConditionVariable;
import androidx.annotation.Nullable;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.util.NullableType;
import androidx.media3.exoplayer.DecoderCounters;
import androidx.media3.exoplayer.analytics.AnalyticsListener;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** A listener for testing previewing performance. */
/* package */ class PerformanceTestListener implements Player.Listener, AnalyticsListener {
private final ConditionVariable playerReady;
private final ConditionVariable playerEnded;
private final AtomicReference<@NullableType PlaybackException> playbackException;
private final long testTimeoutMs;
private @MonotonicNonNull DecoderCounters decoderCounters;
/**
* Creates a new instance.
*
* @param testTimeoutMs The timeout value in milliseconds for which {@link
* #waitUntilPlayerReady()} and {@link #waitUntilPlayerEnded()} waits.
*/
public PerformanceTestListener(long testTimeoutMs) {
playerReady = new ConditionVariable();
playerEnded = new ConditionVariable();
playbackException = new AtomicReference<>();
this.testTimeoutMs = testTimeoutMs;
}
/** Waits until the {@link Player player} is {@linkplain Player#STATE_READY ready}. */
public void waitUntilPlayerReady() throws TimeoutException, PlaybackException {
waitOrThrow(playerReady);
}
/** Waits until the {@link Player player} is {@linkplain Player#STATE_ENDED ended}. */
public void waitUntilPlayerEnded() throws PlaybackException, TimeoutException {
waitOrThrow(playerEnded);
}
/**
* Returns the {@link DecoderCounters} from {@link AnalyticsListener#onVideoEnabled(EventTime,
* DecoderCounters)}, {@code null} if not available.
*/
@Nullable
public DecoderCounters getDecoderCounters() {
return decoderCounters;
}
// Player.Listener methods
@Override
public void onPlaybackStateChanged(int playbackState) {
if (playbackState == Player.STATE_READY) {
playerReady.open();
} else if (playbackState == Player.STATE_ENDED) {
playerEnded.open();
}
}
@Override
public void onPlayerError(PlaybackException error) {
playbackException.set(error);
playerReady.open();
playerEnded.open();
}
// AnalyticsListener methods
@Override
public void onVideoEnabled(EventTime eventTime, DecoderCounters decoderCounters) {
this.decoderCounters = decoderCounters;
}
// Internal methods
private void waitOrThrow(ConditionVariable conditionVariable)
throws TimeoutException, PlaybackException {
if (!conditionVariable.block(testTimeoutMs)) {
throw new TimeoutException();
}
@Nullable PlaybackException playbackException = this.playbackException.get();
if (playbackException != null) {
throw playbackException;
}
}
}

View file

@ -21,17 +21,12 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.Instrumentation;
import android.graphics.SurfaceTexture;
import android.os.ConditionVariable;
import android.os.SystemClock;
import android.view.Surface;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.util.NullableType;
import androidx.media3.exoplayer.DecoderCounters;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.analytics.AnalyticsListener;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -40,7 +35,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Range;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.After;
import org.junit.Test;
@ -72,7 +66,7 @@ public class VideoEffectsPreviewPerformanceTest {
*/
@Test
public void exoplayerEffectsPreviewTest() throws PlaybackException, TimeoutException {
TestListener listener = new TestListener();
PerformanceTestListener listener = new PerformanceTestListener(TEST_TIMEOUT_MS);
instrumentation.runOnMainSync(
() -> {
player = new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build();
@ -106,7 +100,7 @@ public class VideoEffectsPreviewPerformanceTest {
// Playback realtime should take 2 seconds, plus/minus error margin.
assertThat(playbackDurationMs).isIn(Range.closed(1950L, 2050L));
DecoderCounters decoderCounters = checkNotNull(listener.decoderCounters);
DecoderCounters decoderCounters = checkNotNull(listener.getDecoderCounters());
assertThat(decoderCounters.droppedBufferCount).isEqualTo(0);
assertThat(decoderCounters.skippedInputBufferCount).isEqualTo(0);
assertThat(decoderCounters.skippedOutputBufferCount).isEqualTo(0);
@ -121,63 +115,4 @@ public class VideoEffectsPreviewPerformanceTest {
.build())
.build();
}
private static class TestListener implements Player.Listener, AnalyticsListener {
private final ConditionVariable playerReady;
private final ConditionVariable playerEnded;
private final AtomicReference<@NullableType PlaybackException> playbackException;
private @MonotonicNonNull DecoderCounters decoderCounters;
public TestListener() {
playerReady = new ConditionVariable();
playerEnded = new ConditionVariable();
playbackException = new AtomicReference<>();
}
public void waitUntilPlayerReady() throws TimeoutException, PlaybackException {
waitOrThrow(playerReady);
}
public void waitUntilPlayerEnded() throws PlaybackException, TimeoutException {
waitOrThrow(playerEnded);
}
// Player.Listener methods
@Override
public void onPlaybackStateChanged(int playbackState) {
if (playbackState == Player.STATE_READY) {
playerReady.open();
} else if (playbackState == Player.STATE_ENDED) {
playerEnded.open();
}
}
@Override
public void onPlayerError(PlaybackException error) {
playbackException.set(error);
playerReady.open();
playerEnded.open();
}
// AnalyticsListener methods
@Override
public void onVideoEnabled(EventTime eventTime, DecoderCounters decoderCounters) {
this.decoderCounters = decoderCounters;
}
// Internal methods
private void waitOrThrow(ConditionVariable conditionVariable)
throws TimeoutException, PlaybackException {
if (!conditionVariable.block(TEST_TIMEOUT_MS)) {
throw new TimeoutException();
}
@Nullable PlaybackException playbackException = this.playbackException.get();
if (playbackException != null) {
throw playbackException;
}
}
}
}