Add multi-period ExoPlayer unit test
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=143475824
This commit is contained in:
parent
dbfb187b6a
commit
b774660989
@ -21,7 +21,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
|||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.SampleStream;
|
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.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
@ -49,16 +48,9 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
*/
|
*/
|
||||||
private static final int TIMEOUT_MS = 10000;
|
private static final int TIMEOUT_MS = 10000;
|
||||||
|
|
||||||
/**
|
private static final Format TEST_VIDEO_FORMAT = Format.createVideoSampleFormat(null,
|
||||||
* Tests playback of a source that exposes a single period.
|
MimeTypes.VIDEO_H264, null, Format.NO_VALUE, Format.NO_VALUE, 1280, 720, Format.NO_VALUE,
|
||||||
*/
|
null, null);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests playback of a source that exposes an empty timeline. Playback is expected to end without
|
* 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 playerWrapper = new PlayerWrapper();
|
||||||
playerWrapper.setup(Timeline.EMPTY, null, null);
|
playerWrapper.setup(Timeline.EMPTY, null, null);
|
||||||
playerWrapper.blockUntilEnded(TIMEOUT_MS);
|
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 Timeline expectedTimeline;
|
||||||
private Object expectedManifest;
|
private Object expectedManifest;
|
||||||
private Format expectedFormat;
|
private Format expectedFormat;
|
||||||
|
private FakeVideoRenderer videoRenderer;
|
||||||
private ExoPlayer player;
|
private ExoPlayer player;
|
||||||
private Exception exception;
|
private Exception exception;
|
||||||
|
|
||||||
|
private int positionDiscontinuityCount;
|
||||||
|
|
||||||
public PlayerWrapper() {
|
public PlayerWrapper() {
|
||||||
endedCountDownLatch = new CountDownLatch(1);
|
endedCountDownLatch = new CountDownLatch(1);
|
||||||
playerThread = new HandlerThread("ExoPlayerTest thread");
|
playerThread = new HandlerThread("ExoPlayerTest thread");
|
||||||
@ -113,8 +144,8 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Renderer fakeRenderer = new FakeVideoRenderer(expectedFormat);
|
videoRenderer = new FakeVideoRenderer(expectedFormat);
|
||||||
player = ExoPlayerFactory.newInstance(new Renderer[] {fakeRenderer},
|
player = ExoPlayerFactory.newInstance(new Renderer[] {videoRenderer},
|
||||||
new DefaultTrackSelector());
|
new DefaultTrackSelector());
|
||||||
player.addListener(PlayerWrapper.this);
|
player.addListener(PlayerWrapper.this);
|
||||||
player.setPlayWhenReady(true);
|
player.setPlayWhenReady(true);
|
||||||
@ -184,8 +215,66 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity() {
|
public void onPositionDiscontinuity() {
|
||||||
// Should never happen.
|
positionDiscontinuityCount++;
|
||||||
handleError(new IllegalStateException("Received position discontinuity"));
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
Assertions.checkIndex(index, 0, timeline.getPeriodCount());
|
||||||
assertTrue(preparedSource);
|
assertTrue(preparedSource);
|
||||||
assertFalse(releasedSource);
|
assertFalse(releasedSource);
|
||||||
assertEquals(0, index);
|
|
||||||
assertEquals(0, positionUs);
|
assertEquals(0, positionUs);
|
||||||
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(format);
|
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(format);
|
||||||
activeMediaPeriods.add(mediaPeriod);
|
activeMediaPeriods.add(mediaPeriod);
|
||||||
@ -332,7 +420,7 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
@Override
|
@Override
|
||||||
public long getNextLoadPositionUs() {
|
public long getNextLoadPositionUs() {
|
||||||
assertTrue(preparedPeriod);
|
assertTrue(preparedPeriod);
|
||||||
return 0;
|
return C.TIME_END_OF_SOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -352,7 +440,6 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
private final Format format;
|
private final Format format;
|
||||||
|
|
||||||
private boolean readFormat;
|
private boolean readFormat;
|
||||||
private boolean readEndOfStream;
|
|
||||||
|
|
||||||
public FakeSampleStream(Format format) {
|
public FakeSampleStream(Format format) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
@ -365,10 +452,8 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
Assertions.checkState(!readEndOfStream);
|
|
||||||
if (readFormat) {
|
if (readFormat) {
|
||||||
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
readEndOfStream = true;
|
|
||||||
return C.RESULT_BUFFER_READ;
|
return C.RESULT_BUFFER_READ;
|
||||||
}
|
}
|
||||||
formatHolder.format = format;
|
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
|
* 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 static final class FakeVideoRenderer extends BaseRenderer {
|
||||||
|
|
||||||
private final Format expectedFormat;
|
private final Format expectedFormat;
|
||||||
|
|
||||||
|
private int formatReadCount;
|
||||||
|
private int bufferReadCount;
|
||||||
private boolean isEnded;
|
private boolean isEnded;
|
||||||
|
|
||||||
public FakeVideoRenderer(Format expectedFormat) {
|
public FakeVideoRenderer(Format expectedFormat) {
|
||||||
@ -403,6 +490,11 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
this.expectedFormat = expectedFormat;
|
this.expectedFormat = expectedFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||||
|
isEnded = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||||
if (isEnded) {
|
if (isEnded) {
|
||||||
@ -411,20 +503,23 @@ public final class ExoPlayerTest extends TestCase {
|
|||||||
|
|
||||||
// Verify the format matches the expected format.
|
// Verify the format matches the expected format.
|
||||||
FormatHolder formatHolder = new FormatHolder();
|
FormatHolder formatHolder = new FormatHolder();
|
||||||
readSource(formatHolder, null);
|
|
||||||
assertEquals(expectedFormat, formatHolder.format);
|
|
||||||
|
|
||||||
// Verify that we get an end-of-stream buffer.
|
|
||||||
DecoderInputBuffer buffer =
|
DecoderInputBuffer buffer =
|
||||||
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
readSource(null, buffer);
|
int result = readSource(formatHolder, buffer);
|
||||||
assertTrue(buffer.isEndOfStream());
|
if (result == C.RESULT_FORMAT_READ) {
|
||||||
isEnded = true;
|
formatReadCount++;
|
||||||
|
assertEquals(expectedFormat, formatHolder.format);
|
||||||
|
} else if (result == C.RESULT_BUFFER_READ) {
|
||||||
|
bufferReadCount++;
|
||||||
|
if (buffer.isEndOfStream()) {
|
||||||
|
isEnded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return isEnded;
|
return isSourceReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user