From b7746609898ec9c7bfaa3590417f5db1efd4d07a Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 3 Jan 2017 12:57:18 -0800 Subject: [PATCH] Add multi-period ExoPlayer unit test ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=143475824 --- .../android/exoplayer2/ExoPlayerTest.java | 153 ++++++++++++++---- 1 file changed, 124 insertions(+), 29 deletions(-) diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 0f6f3b07b1..c00f90f662 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -21,7 +21,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.SampleStream; -import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; @@ -49,16 +48,9 @@ public final class ExoPlayerTest extends TestCase { */ private static final int TIMEOUT_MS = 10000; - /** - * Tests playback of a source that exposes a single period. - */ - public void testPlayToEnd() throws Exception { - PlayerWrapper playerWrapper = new PlayerWrapper(); - Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, null, - Format.NO_VALUE, Format.NO_VALUE, 1280, 720, Format.NO_VALUE, null, null); - playerWrapper.setup(new SinglePeriodTimeline(0, false), null, format); - playerWrapper.blockUntilEnded(TIMEOUT_MS); - } + private static final Format TEST_VIDEO_FORMAT = Format.createVideoSampleFormat(null, + MimeTypes.VIDEO_H264, null, Format.NO_VALUE, Format.NO_VALUE, 1280, 720, Format.NO_VALUE, + null, null); /** * Tests playback of a source that exposes an empty timeline. Playback is expected to end without @@ -68,6 +60,42 @@ public final class ExoPlayerTest extends TestCase { PlayerWrapper playerWrapper = new PlayerWrapper(); playerWrapper.setup(Timeline.EMPTY, null, null); playerWrapper.blockUntilEnded(TIMEOUT_MS); + assertEquals(0, playerWrapper.positionDiscontinuityCount); + assertEquals(0, playerWrapper.videoRenderer.formatReadCount); + assertEquals(0, playerWrapper.videoRenderer.bufferReadCount); + assertFalse(playerWrapper.videoRenderer.isEnded); + } + + /** + * Tests playback of a source that exposes a single period. + */ + public void testPlaySinglePeriodTimeline() throws Exception { + PlayerWrapper playerWrapper = new PlayerWrapper(); + Timeline timeline = new FakeTimeline( + new TimelineWindowDefinition(false, false, 0)); + playerWrapper.setup(timeline, null, TEST_VIDEO_FORMAT); + playerWrapper.blockUntilEnded(TIMEOUT_MS); + assertEquals(0, playerWrapper.positionDiscontinuityCount); + assertEquals(1, playerWrapper.videoRenderer.formatReadCount); + assertEquals(1, playerWrapper.videoRenderer.bufferReadCount); + assertTrue(playerWrapper.videoRenderer.isEnded); + } + + /** + * Tests playback of a source that exposes three periods. + */ + public void testPlayMultiPeriodTimeline() throws Exception { + PlayerWrapper playerWrapper = new PlayerWrapper(); + Timeline timeline = new FakeTimeline( + new TimelineWindowDefinition(false, false, 0), + new TimelineWindowDefinition(false, false, 0), + new TimelineWindowDefinition(false, false, 0)); + playerWrapper.setup(timeline, null, TEST_VIDEO_FORMAT); + playerWrapper.blockUntilEnded(TIMEOUT_MS); + assertEquals(2, playerWrapper.positionDiscontinuityCount); + assertEquals(3, playerWrapper.videoRenderer.formatReadCount); + assertEquals(1, playerWrapper.videoRenderer.bufferReadCount); + assertTrue(playerWrapper.videoRenderer.isEnded); } /** @@ -82,9 +110,12 @@ public final class ExoPlayerTest extends TestCase { private Timeline expectedTimeline; private Object expectedManifest; private Format expectedFormat; + private FakeVideoRenderer videoRenderer; private ExoPlayer player; private Exception exception; + private int positionDiscontinuityCount; + public PlayerWrapper() { endedCountDownLatch = new CountDownLatch(1); playerThread = new HandlerThread("ExoPlayerTest thread"); @@ -113,8 +144,8 @@ public final class ExoPlayerTest extends TestCase { @Override public void run() { try { - Renderer fakeRenderer = new FakeVideoRenderer(expectedFormat); - player = ExoPlayerFactory.newInstance(new Renderer[] {fakeRenderer}, + videoRenderer = new FakeVideoRenderer(expectedFormat); + player = ExoPlayerFactory.newInstance(new Renderer[] {videoRenderer}, new DefaultTrackSelector()); player.addListener(PlayerWrapper.this); player.setPlayWhenReady(true); @@ -184,8 +215,66 @@ public final class ExoPlayerTest extends TestCase { @Override public void onPositionDiscontinuity() { - // Should never happen. - handleError(new IllegalStateException("Received position discontinuity")); + positionDiscontinuityCount++; + } + + } + + private static final class TimelineWindowDefinition { + + public final boolean isSeekable; + public final boolean isDynamic; + public final long durationUs; + + public TimelineWindowDefinition(boolean isSeekable, boolean isDynamic, long durationUs) { + this.isSeekable = isSeekable; + this.isDynamic = isDynamic; + this.durationUs = durationUs; + } + + } + + private static final class FakeTimeline extends Timeline { + + private final TimelineWindowDefinition[] windowDefinitions; + + public FakeTimeline(TimelineWindowDefinition... windowDefinitions) { + this.windowDefinitions = windowDefinitions; + } + + @Override + public int getWindowCount() { + return windowDefinitions.length; + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + TimelineWindowDefinition windowDefinition = windowDefinitions[windowIndex]; + Object id = setIds ? windowIndex : null; + return window.set(id, C.TIME_UNSET, C.TIME_UNSET, windowDefinition.isSeekable, + windowDefinition.isDynamic, 0, windowDefinition.durationUs, windowIndex, windowIndex, 0); + } + + @Override + public int getPeriodCount() { + return windowDefinitions.length; + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex]; + Object id = setIds ? periodIndex : null; + return period.set(id, id, periodIndex, windowDefinition.durationUs, 0); + } + + @Override + public int getIndexOfPeriod(Object uid) { + if (!(uid instanceof Integer)) { + return C.INDEX_UNSET; + } + int index = (Integer) uid; + return index >= 0 && index < windowDefinitions.length ? index : C.INDEX_UNSET; } } @@ -228,7 +317,6 @@ public final class ExoPlayerTest extends TestCase { Assertions.checkIndex(index, 0, timeline.getPeriodCount()); assertTrue(preparedSource); assertFalse(releasedSource); - assertEquals(0, index); assertEquals(0, positionUs); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(format); activeMediaPeriods.add(mediaPeriod); @@ -332,7 +420,7 @@ public final class ExoPlayerTest extends TestCase { @Override public long getNextLoadPositionUs() { assertTrue(preparedPeriod); - return 0; + return C.TIME_END_OF_SOURCE; } @Override @@ -352,7 +440,6 @@ public final class ExoPlayerTest extends TestCase { private final Format format; private boolean readFormat; - private boolean readEndOfStream; public FakeSampleStream(Format format) { this.format = format; @@ -365,10 +452,8 @@ public final class ExoPlayerTest extends TestCase { @Override public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { - Assertions.checkState(!readEndOfStream); if (readFormat) { buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); - readEndOfStream = true; return C.RESULT_BUFFER_READ; } formatHolder.format = format; @@ -390,12 +475,14 @@ public final class ExoPlayerTest extends TestCase { /** * Fake {@link Renderer} that supports any video format. The renderer verifies that it reads a - * given {@link Format} then a buffer with the end of stream flag set. + * given {@link Format}. */ private static final class FakeVideoRenderer extends BaseRenderer { private final Format expectedFormat; + private int formatReadCount; + private int bufferReadCount; private boolean isEnded; public FakeVideoRenderer(Format expectedFormat) { @@ -403,6 +490,11 @@ public final class ExoPlayerTest extends TestCase { this.expectedFormat = expectedFormat; } + @Override + protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { + isEnded = false; + } + @Override public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { if (isEnded) { @@ -411,20 +503,23 @@ public final class ExoPlayerTest extends TestCase { // Verify the format matches the expected format. FormatHolder formatHolder = new FormatHolder(); - readSource(formatHolder, null); - assertEquals(expectedFormat, formatHolder.format); - - // Verify that we get an end-of-stream buffer. DecoderInputBuffer buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); - readSource(null, buffer); - assertTrue(buffer.isEndOfStream()); - isEnded = true; + int result = readSource(formatHolder, buffer); + if (result == C.RESULT_FORMAT_READ) { + formatReadCount++; + assertEquals(expectedFormat, formatHolder.format); + } else if (result == C.RESULT_BUFFER_READ) { + bufferReadCount++; + if (buffer.isEndOfStream()) { + isEnded = true; + } + } } @Override public boolean isReady() { - return isEnded; + return isSourceReady(); } @Override