Allow FakeMediaSource to specify the FakeSampleStream data

PiperOrigin-RevId: 319420451
This commit is contained in:
ibaker 2020-07-02 17:34:10 +01:00 committed by Oliver Woodman
parent 8d131cad7b
commit 752fe1b679
15 changed files with 534 additions and 328 deletions

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
@ -617,7 +619,13 @@ public final class ExoPlayerTest {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher); FakeMediaPeriod mediaPeriod =
new FakeMediaPeriod(
trackGroupArray,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher,
drmSessionManager,
/* deferOnPrepared= */ false);
mediaPeriod.setSeekToUsOffset(10); mediaPeriod.setSeekToUsOffset(10);
return mediaPeriod; return mediaPeriod;
} }
@ -653,7 +661,11 @@ public final class ExoPlayerTest {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher); FakeMediaPeriod mediaPeriod =
new FakeMediaPeriod(
trackGroupArray,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher);
mediaPeriod.setDiscontinuityPositionUs(10); mediaPeriod.setDiscontinuityPositionUs(10);
return mediaPeriod; return mediaPeriod;
} }
@ -680,7 +692,11 @@ public final class ExoPlayerTest {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher); FakeMediaPeriod mediaPeriod =
new FakeMediaPeriod(
trackGroupArray,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher);
// Set a discontinuity at the position this period is supposed to start at anyway. // Set a discontinuity at the position this period is supposed to start at anyway.
mediaPeriod.setDiscontinuityPositionUs( mediaPeriod.setDiscontinuityPositionUs(
timeline.getWindow(/* windowIndex= */ 0, new Window()).positionInFirstPeriodUs); timeline.getWindow(/* windowIndex= */ 0, new Window()).positionInFirstPeriodUs);
@ -929,8 +945,9 @@ public final class ExoPlayerTest {
fakeMediaPeriodHolder[0] = fakeMediaPeriodHolder[0] =
new FakeMediaPeriod( new FakeMediaPeriod(
trackGroupArray, trackGroupArray,
drmSessionManager, TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher, eventDispatcher,
drmSessionManager,
/* deferOnPrepared= */ true); /* deferOnPrepared= */ true);
createPeriodCalledCountDownLatch.countDown(); createPeriodCalledCountDownLatch.countDown();
return fakeMediaPeriodHolder[0]; return fakeMediaPeriodHolder[0];
@ -980,8 +997,9 @@ public final class ExoPlayerTest {
fakeMediaPeriodHolder[0] = fakeMediaPeriodHolder[0] =
new FakeMediaPeriod( new FakeMediaPeriod(
trackGroupArray, trackGroupArray,
drmSessionManager, TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher, eventDispatcher,
drmSessionManager,
/* deferOnPrepared= */ true); /* deferOnPrepared= */ true);
createPeriodCalledCountDownLatch.countDown(); createPeriodCalledCountDownLatch.countDown();
return fakeMediaPeriodHolder[0]; return fakeMediaPeriodHolder[0];
@ -3708,7 +3726,10 @@ public final class ExoPlayerTest {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, eventDispatcher) { return new FakeMediaPeriod(
trackGroupArray,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher) {
@Override @Override
public long getBufferedPositionUs() { public long getBufferedPositionUs() {
// Pretend not to have buffered data yet. // Pretend not to have buffered data yet.
@ -6410,7 +6431,10 @@ public final class ExoPlayerTest {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, eventDispatcher) { return new FakeMediaPeriod(
trackGroupArray,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher) {
private final List<Allocation> allocations = new ArrayList<>(); private final List<Allocation> allocations = new ArrayList<>();
@ -6486,7 +6510,12 @@ public final class ExoPlayerTest {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, drmSessionManager, eventDispatcher) { return new FakeMediaPeriod(
trackGroupArray,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
eventDispatcher,
drmSessionManager,
/* deferOnPrepared= */ false) {
private Loader loader = new Loader("oomLoader"); private Loader loader = new Loader("oomLoader");
@Override @Override
@ -6505,14 +6534,13 @@ public final class ExoPlayerTest {
// Create 3 samples without end of stream signal to test that all 3 samples are // Create 3 samples without end of stream signal to test that all 3 samples are
// still played before the exception is thrown. // still played before the exception is thrown.
return new FakeSampleStream( return new FakeSampleStream(
selection.getSelectedFormat(),
drmSessionManager, drmSessionManager,
eventDispatcher, eventDispatcher,
positionUs, selection.getSelectedFormat(),
/* timeUsIncrement= */ 0, ImmutableList.of(
new FakeSampleStream.FakeSampleStreamItem(new byte[] {0}), oneByteSample(positionUs),
new FakeSampleStream.FakeSampleStreamItem(new byte[] {0}), oneByteSample(positionUs),
new FakeSampleStream.FakeSampleStreamItem(new byte[] {0})) { oneByteSample(positionUs))) {
@Override @Override
public void maybeThrowError() throws IOException { public void maybeThrowError() throws IOException {
@ -6676,10 +6704,21 @@ public final class ExoPlayerTest {
/* windowOffsetInFirstPeriodUs= */ 1_234_567, /* windowOffsetInFirstPeriodUs= */ 1_234_567,
AdPlaybackState.NONE)); AdPlaybackState.NONE));
ExoPlayer player = new TestExoPlayer.Builder(context).setRenderers(renderer).build(); ExoPlayer player = new TestExoPlayer.Builder(context).setRenderers(renderer).build();
long firstSampleTimeUs = 4_567_890 + 1_234_567;
FakeMediaSource firstMediaSource = FakeMediaSource firstMediaSource =
new FakeMediaSource(/* timeline= */ null, ExoPlayerTestRunner.VIDEO_FORMAT); new FakeMediaSource(
/* timeline= */ null,
DrmSessionManager.DUMMY,
(unusedFormat, unusedMediaPeriodId) ->
ImmutableList.of(oneByteSample(firstSampleTimeUs), END_OF_STREAM_ITEM),
ExoPlayerTestRunner.VIDEO_FORMAT);
FakeMediaSource secondMediaSource = FakeMediaSource secondMediaSource =
new FakeMediaSource(timelineWithOffsets, ExoPlayerTestRunner.VIDEO_FORMAT); new FakeMediaSource(
timelineWithOffsets,
DrmSessionManager.DUMMY,
(unusedFormat, unusedMediaPeriodId) ->
ImmutableList.of(oneByteSample(firstSampleTimeUs), END_OF_STREAM_ITEM),
ExoPlayerTestRunner.VIDEO_FORMAT);
player.setMediaSources(ImmutableList.of(firstMediaSource, secondMediaSource)); player.setMediaSources(ImmutableList.of(firstMediaSource, secondMediaSource));
// Start playback and wait until player is idly waiting for an update of the first source. // Start playback and wait until player is idly waiting for an update of the first source.
@ -6697,7 +6736,6 @@ public final class ExoPlayerTest {
assertThat(rendererStreamOffsetsUs).hasSize(2); assertThat(rendererStreamOffsetsUs).hasSize(2);
assertThat(firstBufferTimesUsWithOffset).hasSize(2); assertThat(firstBufferTimesUsWithOffset).hasSize(2);
// Assert that the offsets and buffer times match the expected sample time. // Assert that the offsets and buffer times match the expected sample time.
long firstSampleTimeUs = 4_567_890 + 1_234_567;
assertThat(firstBufferTimesUsWithOffset.get(0)) assertThat(firstBufferTimesUsWithOffset.get(0))
.isEqualTo(rendererStreamOffsetsUs.get(0) + firstSampleTimeUs); .isEqualTo(rendererStreamOffsetsUs.get(0) + firstSampleTimeUs);
assertThat(firstBufferTimesUsWithOffset.get(1)) assertThat(firstBufferTimesUsWithOffset.get(1))

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.analytics; package com.google.android.exoplayer2.analytics;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.view.Surface; import android.view.Surface;
@ -57,6 +59,7 @@ import com.google.android.exoplayer2.testutil.FakeVideoRenderer;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@ -822,10 +825,10 @@ public final class AnalyticsCollectorTest {
.containsExactly(window0Period1Seq0, period1Seq0) .containsExactly(window0Period1Seq0, period1Seq0)
.inOrder(); .inOrder();
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)) assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED))
.containsExactly(window0Period1Seq0, window1Period0Seq1, period1Seq0) .containsExactly(window0Period1Seq0, window1Period0Seq1)
.inOrder(); .inOrder();
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)) assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME))
.containsExactly(window0Period1Seq0, window1Period0Seq1, period1Seq0) .containsExactly(window0Period1Seq0, window1Period0Seq1)
.inOrder(); .inOrder();
assertThat(listener.getEvents(EVENT_VIDEO_FRAME_PROCESSING_OFFSET)) assertThat(listener.getEvents(EVENT_VIDEO_FRAME_PROCESSING_OFFSET))
.containsExactly(window0Period1Seq0, period1Seq0) .containsExactly(window0Period1Seq0, period1Seq0)
@ -926,14 +929,15 @@ public final class AnalyticsCollectorTest {
@Test @Test
public void adPlayback() throws Exception { public void adPlayback() throws Exception {
long contentDurationsUs = 10 * C.MICROS_PER_SECOND; long contentDurationsUs = 11 * C.MICROS_PER_SECOND;
long windowOffsetInFirstPeriodUs =
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
AtomicReference<AdPlaybackState> adPlaybackState = AtomicReference<AdPlaybackState> adPlaybackState =
new AtomicReference<>( new AtomicReference<>(
FakeTimeline.createAdPlaybackState( FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */ /* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */
0, windowOffsetInFirstPeriodUs,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US windowOffsetInFirstPeriodUs + 5 * C.MICROS_PER_SECOND,
+ 5 * C.MICROS_PER_SECOND,
C.TIME_END_OF_SOURCE)); C.TIME_END_OF_SOURCE));
AtomicInteger playedAdCount = new AtomicInteger(0); AtomicInteger playedAdCount = new AtomicInteger(0);
Timeline adTimeline = Timeline adTimeline =
@ -946,7 +950,23 @@ public final class AnalyticsCollectorTest {
contentDurationsUs, contentDurationsUs,
adPlaybackState.get())); adPlaybackState.get()));
FakeMediaSource fakeMediaSource = FakeMediaSource fakeMediaSource =
new FakeMediaSource(adTimeline, ExoPlayerTestRunner.VIDEO_FORMAT); new FakeMediaSource(
adTimeline,
DrmSessionManager.DUMMY,
(unusedFormat, mediaPeriodId) -> {
if (mediaPeriodId.isAd()) {
return ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM);
} else {
// Provide a single sample before and after the midroll ad and another after the
// postroll.
return ImmutableList.of(
oneByteSample(windowOffsetInFirstPeriodUs + C.MICROS_PER_SECOND),
oneByteSample(windowOffsetInFirstPeriodUs + 6 * C.MICROS_PER_SECOND),
oneByteSample(windowOffsetInFirstPeriodUs + contentDurationsUs),
END_OF_STREAM_ITEM);
}
},
ExoPlayerTestRunner.VIDEO_FORMAT);
ActionSchedule actionSchedule = ActionSchedule actionSchedule =
new ActionSchedule.Builder(TAG) new ActionSchedule.Builder(TAG)
.executeRunnable( .executeRunnable(
@ -965,7 +985,7 @@ public final class AnalyticsCollectorTest {
adPlaybackState adPlaybackState
.get() .get()
.withPlayedAd( .withPlayedAd(
playedAdCount.getAndIncrement(), /* adGroupIndex= */ playedAdCount.getAndIncrement(),
/* adIndexInAdGroup= */ 0)); /* adIndexInAdGroup= */ 0));
fakeMediaSource.setNewSourceInfo( fakeMediaSource.setNewSourceInfo(
new FakeTimeline( new FakeTimeline(
@ -974,7 +994,7 @@ public final class AnalyticsCollectorTest {
/* id= */ 0, /* id= */ 0,
/* isSeekable= */ true, /* isSeekable= */ true,
/* isDynamic= */ false, /* isDynamic= */ false,
/* durationUs =*/ 10 * C.MICROS_PER_SECOND, contentDurationsUs,
adPlaybackState.get())), adPlaybackState.get())),
/* sendManifestLoadEvents= */ false); /* sendManifestLoadEvents= */ false);
} }
@ -1185,6 +1205,8 @@ public final class AnalyticsCollectorTest {
@Test @Test
public void seekAfterMidroll() throws Exception { public void seekAfterMidroll() throws Exception {
long windowOffsetInFirstPeriodUs =
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
Timeline adTimeline = Timeline adTimeline =
new FakeTimeline( new FakeTimeline(
new TimelineWindowDefinition( new TimelineWindowDefinition(
@ -1195,10 +1217,23 @@ public final class AnalyticsCollectorTest {
10 * C.MICROS_PER_SECOND, 10 * C.MICROS_PER_SECOND,
FakeTimeline.createAdPlaybackState( FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */ /* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US windowOffsetInFirstPeriodUs + 5 * C.MICROS_PER_SECOND)));
+ 5 * C.MICROS_PER_SECOND)));
FakeMediaSource fakeMediaSource = FakeMediaSource fakeMediaSource =
new FakeMediaSource(adTimeline, ExoPlayerTestRunner.VIDEO_FORMAT); new FakeMediaSource(
adTimeline,
DrmSessionManager.DUMMY,
(unusedFormat, mediaPeriodId) -> {
if (mediaPeriodId.isAd()) {
return ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM);
} else {
// Provide a sample before the midroll and another after the seek point below (6s).
return ImmutableList.of(
oneByteSample(windowOffsetInFirstPeriodUs + C.MICROS_PER_SECOND),
oneByteSample(windowOffsetInFirstPeriodUs + 7 * C.MICROS_PER_SECOND),
END_OF_STREAM_ITEM);
}
},
ExoPlayerTestRunner.VIDEO_FORMAT);
ActionSchedule actionSchedule = ActionSchedule actionSchedule =
new ActionSchedule.Builder(TAG) new ActionSchedule.Builder(TAG)
.pause() .pause()

View file

@ -19,6 +19,7 @@ import static com.google.android.exoplayer2.RendererCapabilities.ADAPTIVE_NOT_SE
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED; import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED;
import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_NOT_SUPPORTED; import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_NOT_SUPPORTED;
import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_SUPPORTED; import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_SUPPORTED;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -33,9 +34,11 @@ import com.google.android.exoplayer2.decoder.DecoderException;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleDecoder;
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.testutil.FakeSampleStream; import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -103,7 +106,11 @@ public class DecoderAudioRendererTest {
audioRenderer.enable( audioRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {FORMAT}, new Format[] {FORMAT},
new FakeSampleStream(FORMAT, /* eventDispatcher= */ null, /* shouldOutputSample= */ false), new FakeSampleStream(
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null,
FORMAT,
ImmutableList.of(END_OF_STREAM_ITEM)),
/* positionUs= */ 0, /* positionUs= */ 0,
/* joining= */ false, /* joining= */ false,
/* mayRenderStartOfStream= */ true, /* mayRenderStartOfStream= */ true,

View file

@ -15,6 +15,9 @@
*/ */
package com.google.android.exoplayer2.audio; package com.google.android.exoplayer2.audio;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.format;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
@ -33,8 +36,8 @@ import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.testutil.FakeSampleStream; import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Before; import org.junit.Before;
@ -108,19 +111,18 @@ public class MediaCodecAudioRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ AUDIO_AAC,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ AUDIO_AAC,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 50),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 100),
new FakeSampleStreamItem(changedFormat), format(changedFormat),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 150),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 200),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 250),
FakeSampleStreamItem.END_OF_STREAM_ITEM); END_OF_STREAM_ITEM));
mediaCodecAudioRenderer.enable( mediaCodecAudioRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -156,19 +158,18 @@ public class MediaCodecAudioRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ AUDIO_AAC,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ AUDIO_AAC,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 50),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 100),
new FakeSampleStreamItem(changedFormat), format(changedFormat),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 150),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 200),
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 250),
FakeSampleStreamItem.END_OF_STREAM_ITEM); END_OF_STREAM_ITEM));
mediaCodecAudioRenderer.enable( mediaCodecAudioRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -224,13 +225,10 @@ public class MediaCodecAudioRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ AUDIO_AAC,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ AUDIO_AAC,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME),
FakeSampleStreamItem.END_OF_STREAM_ITEM);
exceptionThrowingRenderer.enable( exceptionThrowingRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,

View file

@ -32,6 +32,7 @@ import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamI
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -145,13 +146,12 @@ public class MetadataRendererTest {
renderer.replaceStream( renderer.replaceStream(
new Format[] {EMSG_FORMAT}, new Format[] {EMSG_FORMAT},
new FakeSampleStream( new FakeSampleStream(
EMSG_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, EMSG_FORMAT,
/* timeUsIncrement= */ 0, ImmutableList.of(
new FakeSampleStreamItem(input), FakeSampleStreamItem.sample(/* timeUs= */ 0, /* flags= */ 0, input),
FakeSampleStreamItem.END_OF_STREAM_ITEM), FakeSampleStreamItem.END_OF_STREAM_ITEM)),
/* offsetUs= */ 0L); /* offsetUs= */ 0L);
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the format renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the format
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the data renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the data

View file

@ -503,14 +503,14 @@ public class DownloadHelperTest {
int periodIndex = TEST_TIMELINE.getIndexOfPeriod(id.periodUid); int periodIndex = TEST_TIMELINE.getIndexOfPeriod(id.periodUid);
return new FakeMediaPeriod( return new FakeMediaPeriod(
trackGroupArrays[periodIndex], trackGroupArrays[periodIndex],
TEST_TIMELINE.getWindow(0, new Timeline.Window()).positionInFirstPeriodUs,
new EventDispatcher() new EventDispatcher()
.withParameters(/* windowIndex= */ 0, id, /* mediaTimeOffsetMs= */ 0)) { .withParameters(/* windowIndex= */ 0, id, /* mediaTimeOffsetMs= */ 0)) {
@Override @Override
public List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) { public List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) {
List<StreamKey> result = new ArrayList<>(); List<StreamKey> result = new ArrayList<>();
for (TrackSelection trackSelection : trackSelections) { for (TrackSelection trackSelection : trackSelections) {
int groupIndex = int groupIndex = trackGroupArrays[periodIndex].indexOf(trackSelection.getTrackGroup());
trackGroupArrays[periodIndex].indexOf(trackSelection.getTrackGroup());
for (int i = 0; i < trackSelection.length(); i++) { for (int i = 0; i < trackSelection.length(); i++) {
result.add( result.add(
new StreamKey(periodIndex, groupIndex, trackSelection.getIndexInTrackGroup(i))); new StreamKey(periodIndex, groupIndex, trackSelection.getIndexInTrackGroup(i)));

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2.source;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -22,11 +24,13 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.testutil.FakeMediaPeriod; import com.google.android.exoplayer2.testutil.FakeMediaPeriod;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection; import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.common.collect.ImmutableList;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.junit.Test; import org.junit.Test;
@ -47,8 +51,10 @@ public final class MergingMediaPeriodTest {
public void getTrackGroups_returnsAllChildTrackGroups() throws Exception { public void getTrackGroups_returnsAllChildTrackGroups() throws Exception {
MergingMediaPeriod mergingMediaPeriod = MergingMediaPeriod mergingMediaPeriod =
prepareMergingPeriod( prepareMergingPeriod(
new MergingPeriodDefinition(/* timeOffsetUs= */ 0, childFormat11, childFormat12), new MergingPeriodDefinition(
new MergingPeriodDefinition(/* timeOffsetUs= */ 0, childFormat21, childFormat22)); /* timeOffsetUs= */ 0, /* singleSampleTimeUs= */ 0, childFormat11, childFormat12),
new MergingPeriodDefinition(
/* timeOffsetUs= */ 0, /* singleSampleTimeUs= */ 0, childFormat21, childFormat22));
assertThat(mergingMediaPeriod.getTrackGroups().length).isEqualTo(4); assertThat(mergingMediaPeriod.getTrackGroups().length).isEqualTo(4);
assertThat(mergingMediaPeriod.getTrackGroups().get(0).getFormat(0)).isEqualTo(childFormat11); assertThat(mergingMediaPeriod.getTrackGroups().get(0).getFormat(0)).isEqualTo(childFormat11);
@ -61,8 +67,10 @@ public final class MergingMediaPeriodTest {
public void selectTracks_createsSampleStreamsFromChildPeriods() throws Exception { public void selectTracks_createsSampleStreamsFromChildPeriods() throws Exception {
MergingMediaPeriod mergingMediaPeriod = MergingMediaPeriod mergingMediaPeriod =
prepareMergingPeriod( prepareMergingPeriod(
new MergingPeriodDefinition(/* timeOffsetUs= */ 0, childFormat11, childFormat12), new MergingPeriodDefinition(
new MergingPeriodDefinition(/* timeOffsetUs= */ 0, childFormat21, childFormat22)); /* timeOffsetUs= */ 0, /* singleSampleTimeUs= */ 0, childFormat11, childFormat12),
new MergingPeriodDefinition(
/* timeOffsetUs= */ 0, /* singleSampleTimeUs= */ 0, childFormat21, childFormat22));
TrackSelection selectionForChild1 = TrackSelection selectionForChild1 =
new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(1), /* track= */ 0); new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(1), /* track= */ 0);
@ -97,8 +105,16 @@ public final class MergingMediaPeriodTest {
throws Exception { throws Exception {
MergingMediaPeriod mergingMediaPeriod = MergingMediaPeriod mergingMediaPeriod =
prepareMergingPeriod( prepareMergingPeriod(
new MergingPeriodDefinition(/* timeOffsetUs= */ 0, childFormat11, childFormat12), new MergingPeriodDefinition(
new MergingPeriodDefinition(/* timeOffsetUs= */ -3000, childFormat21, childFormat22)); /* timeOffsetUs= */ 0,
/* singleSampleTimeUs= */ 123_000,
childFormat11,
childFormat12),
new MergingPeriodDefinition(
/* timeOffsetUs= */ -3000,
/* singleSampleTimeUs= */ 456_000,
childFormat21,
childFormat22));
TrackSelection selectionForChild1 = TrackSelection selectionForChild1 =
new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(0), /* track= */ 0); new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(0), /* track= */ 0);
@ -122,14 +138,14 @@ public final class MergingMediaPeriodTest {
assertThat(childMediaPeriod1.selectTracksPositionUs).isEqualTo(0); assertThat(childMediaPeriod1.selectTracksPositionUs).isEqualTo(0);
assertThat(streams[0].readData(formatHolder, inputBuffer, /* formatRequired= */ false)) assertThat(streams[0].readData(formatHolder, inputBuffer, /* formatRequired= */ false))
.isEqualTo(C.RESULT_BUFFER_READ); .isEqualTo(C.RESULT_BUFFER_READ);
assertThat(inputBuffer.timeUs).isEqualTo(0L); assertThat(inputBuffer.timeUs).isEqualTo(123_000L);
FakeMediaPeriodWithSelectTracksPosition childMediaPeriod2 = FakeMediaPeriodWithSelectTracksPosition childMediaPeriod2 =
(FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(1); (FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(1);
assertThat(childMediaPeriod2.selectTracksPositionUs).isEqualTo(3000L); assertThat(childMediaPeriod2.selectTracksPositionUs).isEqualTo(3000L);
assertThat(streams[1].readData(formatHolder, inputBuffer, /* formatRequired= */ false)) assertThat(streams[1].readData(formatHolder, inputBuffer, /* formatRequired= */ false))
.isEqualTo(C.RESULT_BUFFER_READ); .isEqualTo(C.RESULT_BUFFER_READ);
assertThat(inputBuffer.timeUs).isEqualTo(0L); assertThat(inputBuffer.timeUs).isEqualTo(456_000 - 3000);
} }
private MergingMediaPeriod prepareMergingPeriod(MergingPeriodDefinition... definitions) private MergingMediaPeriod prepareMergingPeriod(MergingPeriodDefinition... definitions)
@ -137,10 +153,11 @@ public final class MergingMediaPeriodTest {
MediaPeriod[] mediaPeriods = new MediaPeriod[definitions.length]; MediaPeriod[] mediaPeriods = new MediaPeriod[definitions.length];
long[] timeOffsetsUs = new long[definitions.length]; long[] timeOffsetsUs = new long[definitions.length];
for (int i = 0; i < definitions.length; i++) { for (int i = 0; i < definitions.length; i++) {
timeOffsetsUs[i] = definitions[i].timeOffsetUs; MergingPeriodDefinition definition = definitions[i];
TrackGroup[] trackGroups = new TrackGroup[definitions[i].formats.length]; timeOffsetsUs[i] = definition.timeOffsetUs;
for (int j = 0; j < definitions[i].formats.length; j++) { TrackGroup[] trackGroups = new TrackGroup[definition.formats.length];
trackGroups[j] = new TrackGroup(definitions[i].formats[j]); for (int j = 0; j < definition.formats.length; j++) {
trackGroups[j] = new TrackGroup(definition.formats[j]);
} }
mediaPeriods[i] = mediaPeriods[i] =
new FakeMediaPeriodWithSelectTracksPosition( new FakeMediaPeriodWithSelectTracksPosition(
@ -149,7 +166,10 @@ public final class MergingMediaPeriodTest {
.withParameters( .withParameters(
/* windowIndex= */ i, /* windowIndex= */ i,
new MediaPeriodId(/* periodUid= */ i), new MediaPeriodId(/* periodUid= */ i),
/* mediaTimeOffsetMs= */ 0)); /* mediaTimeOffsetMs= */ 0),
/* trackDataFactory= */ (unusedFormat, unusedMediaPeriodId) ->
ImmutableList.of(
oneByteSample(definition.singleSampleTimeUs), END_OF_STREAM_ITEM));
} }
MergingMediaPeriod mergingMediaPeriod = MergingMediaPeriod mergingMediaPeriod =
new MergingMediaPeriod( new MergingMediaPeriod(
@ -179,8 +199,15 @@ public final class MergingMediaPeriodTest {
public long selectTracksPositionUs; public long selectTracksPositionUs;
public FakeMediaPeriodWithSelectTracksPosition( public FakeMediaPeriodWithSelectTracksPosition(
TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher) { TrackGroupArray trackGroupArray,
super(trackGroupArray, eventDispatcher); EventDispatcher eventDispatcher,
TrackDataFactory trackDataFactory) {
super(
trackGroupArray,
trackDataFactory,
eventDispatcher,
DrmSessionManager.DUMMY,
/* deferOnPrepared= */ false);
selectTracksPositionUs = C.TIME_UNSET; selectTracksPositionUs = C.TIME_UNSET;
} }
@ -199,11 +226,13 @@ public final class MergingMediaPeriodTest {
private static final class MergingPeriodDefinition { private static final class MergingPeriodDefinition {
public long timeOffsetUs; public final long timeOffsetUs;
public Format[] formats; public final long singleSampleTimeUs;
public final Format[] formats;
public MergingPeriodDefinition(long timeOffsetUs, Format... formats) { public MergingPeriodDefinition(long timeOffsetUs, long singleSampleTimeUs, Format... formats) {
this.timeOffsetUs = timeOffsetUs; this.timeOffsetUs = timeOffsetUs;
this.singleSampleTimeUs = singleSampleTimeUs;
this.formats = formats; this.formats = formats;
} }
} }

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.video; package com.google.android.exoplayer2.video;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@ -39,6 +40,7 @@ import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.testutil.FakeSampleStream; import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem; import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import java.util.concurrent.Phaser; import java.util.concurrent.Phaser;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -183,12 +185,10 @@ public final class DecoderVideoRendererTest {
public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception { public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
renderer.enable( renderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -212,12 +212,10 @@ public final class DecoderVideoRendererTest {
throws Exception { throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
renderer.enable( renderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -240,12 +238,10 @@ public final class DecoderVideoRendererTest {
public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception { public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
renderer.enable( renderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -271,22 +267,18 @@ public final class DecoderVideoRendererTest {
public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception { public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStreamItem.END_OF_STREAM_ITEM);
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStreamItem.END_OF_STREAM_ITEM);
renderer.enable( renderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {H264_FORMAT}, new Format[] {H264_FORMAT},
@ -317,22 +309,18 @@ public final class DecoderVideoRendererTest {
public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception { public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStreamItem.END_OF_STREAM_ITEM);
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ H264_FORMAT,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStreamItem.END_OF_STREAM_ITEM);
renderer.enable( renderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {H264_FORMAT}, new Format[] {H264_FORMAT},

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.video; package com.google.android.exoplayer2.video;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.format;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
@ -45,6 +47,7 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep
import com.google.android.exoplayer2.testutil.FakeSampleStream; import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem; import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Before; import org.junit.Before;
@ -126,15 +129,14 @@ public class MediaCodecVideoRendererTest {
public void render_dropsLateBuffer() throws Exception { public void render_dropsLateBuffer() throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50_000, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), // First buffer. oneByteSample(/* timeUs= */ 0), // First buffer.
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), // Late buffer. oneByteSample(/* timeUs= */ 50_000), // Late buffer.
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), // Last buffer. oneByteSample(/* timeUs= */ 100_000), // Last buffer.
FakeSampleStreamItem.END_OF_STREAM_ITEM); FakeSampleStreamItem.END_OF_STREAM_ITEM));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {VIDEO_H264}, new Format[] {VIDEO_H264},
@ -163,13 +165,11 @@ public class MediaCodecVideoRendererTest {
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {VIDEO_H264}, new Format[] {VIDEO_H264},
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 0, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM)),
FakeSampleStreamItem.END_OF_STREAM_ITEM),
/* positionUs= */ 0, /* positionUs= */ 0,
/* joining= */ false, /* joining= */ false,
/* mayRenderStartOfStream= */ true, /* mayRenderStartOfStream= */ true,
@ -201,12 +201,10 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ pAsp1,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ pAsp1,
/* timeUsIncrement= */ 5000, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -220,16 +218,12 @@ public class MediaCodecVideoRendererTest {
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
mediaCodecVideoRenderer.render(/* positionUs= */ 250, SystemClock.elapsedRealtime() * 1000); mediaCodecVideoRenderer.render(/* positionUs= */ 250, SystemClock.elapsedRealtime() * 1000);
fakeSampleStream.addFakeSampleStreamItem(new FakeSampleStreamItem(pAsp2)); fakeSampleStream.addFakeSampleStreamItem(format(pAsp2));
fakeSampleStream.addFakeSampleStreamItem( fakeSampleStream.addFakeSampleStreamItem(oneByteSample(/* timeUs= */ 5_000));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME)); fakeSampleStream.addFakeSampleStreamItem(oneByteSample(/* timeUs= */ 10_000));
fakeSampleStream.addFakeSampleStreamItem( fakeSampleStream.addFakeSampleStreamItem(format(pAsp3));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME)); fakeSampleStream.addFakeSampleStreamItem(oneByteSample(/* timeUs= */ 15_000));
fakeSampleStream.addFakeSampleStreamItem(new FakeSampleStreamItem(pAsp3)); fakeSampleStream.addFakeSampleStreamItem(oneByteSample(/* timeUs= */ 20_000));
fakeSampleStream.addFakeSampleStreamItem(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
fakeSampleStream.addFakeSampleStreamItem(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM); fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM);
mediaCodecVideoRenderer.setCurrentStreamFinal(); mediaCodecVideoRenderer.setCurrentStreamFinal();
@ -251,12 +245,10 @@ public class MediaCodecVideoRendererTest {
throws Exception { throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {VIDEO_H264}, new Format[] {VIDEO_H264},
@ -270,8 +262,7 @@ public class MediaCodecVideoRendererTest {
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
mediaCodecVideoRenderer.resetPosition(0); mediaCodecVideoRenderer.resetPosition(0);
mediaCodecVideoRenderer.setCurrentStreamFinal(); mediaCodecVideoRenderer.setCurrentStreamFinal();
fakeSampleStream.addFakeSampleStreamItem( fakeSampleStream.addFakeSampleStreamItem(oneByteSample(/* timeUs= */ 0));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM); fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM);
int positionUs = 10; int positionUs = 10;
do { do {
@ -286,12 +277,10 @@ public class MediaCodecVideoRendererTest {
public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception { public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -313,12 +302,10 @@ public class MediaCodecVideoRendererTest {
throws Exception { throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -339,12 +326,10 @@ public class MediaCodecVideoRendererTest {
public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception { public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
@ -366,22 +351,20 @@ public class MediaCodecVideoRendererTest {
public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception { public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
FakeSampleStreamItem.END_OF_STREAM_ITEM); FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
FakeSampleStreamItem.END_OF_STREAM_ITEM); FakeSampleStreamItem.END_OF_STREAM_ITEM));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {VIDEO_H264}, new Format[] {VIDEO_H264},
@ -410,22 +393,20 @@ public class MediaCodecVideoRendererTest {
public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception { public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
FakeSampleStreamItem.END_OF_STREAM_ITEM); FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ VIDEO_H264,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(new byte[] {0}, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
FakeSampleStreamItem.END_OF_STREAM_ITEM); FakeSampleStreamItem.END_OF_STREAM_ITEM));
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,
new Format[] {VIDEO_H264}, new Format[] {VIDEO_H264},
@ -458,26 +439,23 @@ public class MediaCodecVideoRendererTest {
public void onVideoFrameProcessingOffset_isCalledAfterOutputFormatChanges() public void onVideoFrameProcessingOffset_isCalledAfterOutputFormatChanges()
throws ExoPlaybackException { throws ExoPlaybackException {
Format mp4Uhd = VIDEO_H264.buildUpon().setWidth(3840).setHeight(2160).build(); Format mp4Uhd = VIDEO_H264.buildUpon().setWidth(3840).setHeight(2160).build();
byte[] sampleData = new byte[0];
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ mp4Uhd,
DrmSessionManager.DUMMY, DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* initialFormat= */ mp4Uhd,
/* timeUsIncrement= */ 50, ImmutableList.of(
new FakeSampleStreamItem(mp4Uhd), oneByteSample(/* timeUs= */ 0),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), format(VIDEO_H264),
new FakeSampleStreamItem(VIDEO_H264), oneByteSample(/* timeUs= */ 50),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 100),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), format(mp4Uhd),
new FakeSampleStreamItem(mp4Uhd), oneByteSample(/* timeUs= */ 150),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 200),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 250),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), format(VIDEO_H264),
new FakeSampleStreamItem(VIDEO_H264), oneByteSample(/* timeUs= */ 300),
new FakeSampleStreamItem(sampleData, C.BUFFER_FLAG_KEY_FRAME), FakeSampleStreamItem.END_OF_STREAM_ITEM));
FakeSampleStreamItem.END_OF_STREAM_ITEM);
mediaCodecVideoRenderer.enable( mediaCodecVideoRenderer.enable(
RendererConfiguration.DEFAULT, RendererConfiguration.DEFAULT,

View file

@ -58,7 +58,14 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
FakeChunkSource.Factory chunkSourceFactory, FakeChunkSource.Factory chunkSourceFactory,
long durationUs, long durationUs,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
super(trackGroupArray, eventDispatcher); super(
trackGroupArray,
/* trackDataFactory= */ (unusedFormat, unusedMediaPeriodId) -> {
throw new RuntimeException("unused track data");
},
eventDispatcher,
DrmSessionManager.DUMMY,
/* deferOnPrepared= */ false);
this.allocator = allocator; this.allocator = allocator;
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
this.transferListener = transferListener; this.transferListener = transferListener;

View file

@ -38,7 +38,13 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
Timeline timeline, Timeline timeline,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
FakeChunkSource.Factory chunkSourceFactory) { FakeChunkSource.Factory chunkSourceFactory) {
super(timeline, DrmSessionManager.DUMMY, trackGroupArray); super(
timeline,
DrmSessionManager.DUMMY,
/* trackDataFactory= */ (unusedFormat, unusedMediaPeriodId) -> {
throw new RuntimeException("Unused TrackDataFactory");
},
trackGroupArray);
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
} }

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
@ -22,17 +24,22 @@ import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.LoadEventInfo; import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
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.testutil.FakeSampleStream.FakeSampleStreamItem;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -52,6 +59,7 @@ public class FakeMediaPeriod implements MediaPeriod {
private final List<SampleStream> sampleStreams; private final List<SampleStream> sampleStreams;
private final DrmSessionManager drmSessionManager; private final DrmSessionManager drmSessionManager;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final TrackDataFactory trackDataFactory;
private final long fakePreparationLoadTaskId; private final long fakePreparationLoadTaskId;
@Nullable private Handler playerHandler; @Nullable private Handler playerHandler;
@ -64,48 +72,71 @@ public class FakeMediaPeriod implements MediaPeriod {
private long discontinuityPositionUs; private long discontinuityPositionUs;
/** /**
* Constructs a FakeMediaPeriod. * Constructs a FakeMediaPeriod with a single sample for each track in {@code trackGroupArray}.
* *
* @param trackGroupArray The track group array. * @param trackGroupArray The track group array.
* @param singleSampleTimeUs The timestamp to use for the single sample in each track, in
* microseconds.
* @param eventDispatcher A dispatcher for media source events. * @param eventDispatcher A dispatcher for media source events.
*/ */
public FakeMediaPeriod(TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher) { public FakeMediaPeriod(
this(trackGroupArray, DrmSessionManager.DUMMY, eventDispatcher, /* deferOnPrepared */ false); TrackGroupArray trackGroupArray, long singleSampleTimeUs, EventDispatcher eventDispatcher) {
this(
trackGroupArray,
TrackDataFactory.singleSampleWithTimeUs(singleSampleTimeUs),
eventDispatcher,
DrmSessionManager.DUMMY,
/* deferOnPrepared= */ false);
} }
/** /**
* Constructs a FakeMediaPeriod. * Constructs a FakeMediaPeriod with a single sample for each track in {@code trackGroupArray}.
* *
* @param trackGroupArray The track group array. * @param trackGroupArray The track group array.
* @param singleSampleTimeUs The timestamp to use for the single sample in each track, in
* microseconds.
* @param eventDispatcher A dispatcher for media source events.
* @param drmSessionManager The {@link DrmSessionManager} used for DRM interactions. * @param drmSessionManager The {@link DrmSessionManager} used for DRM interactions.
* @param eventDispatcher A dispatcher for media source events. * @param deferOnPrepared Whether {@link Callback#onPrepared(MediaPeriod)} should be called only
* after {@link #setPreparationComplete()} has been called. If {@code false}
*/ */
public FakeMediaPeriod( public FakeMediaPeriod(
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
long singleSampleTimeUs,
EventDispatcher eventDispatcher,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher) { boolean deferOnPrepared) {
this(trackGroupArray, drmSessionManager, eventDispatcher, /* deferOnPrepared */ false); this(
trackGroupArray,
TrackDataFactory.singleSampleWithTimeUs(singleSampleTimeUs),
eventDispatcher,
drmSessionManager,
deferOnPrepared);
} }
/** /**
* Constructs a FakeMediaPeriod. * Constructs a FakeMediaPeriod.
* *
* @param trackGroupArray The track group array. * @param trackGroupArray The track group array.
* @param drmSessionManager The DrmSessionManager used for DRM interactions. * @param trackDataFactory A source for the underlying sample data for each track in {@code
* trackGroupArray}.
* @param eventDispatcher A dispatcher for media source events. * @param eventDispatcher A dispatcher for media source events.
* @param deferOnPrepared Whether {@link MediaPeriod.Callback#onPrepared(MediaPeriod)} should be * @param drmSessionManager The DrmSessionManager used for DRM interactions.
* called only after {@link #setPreparationComplete()} has been called. If {@code false} * @param deferOnPrepared Whether {@link Callback#onPrepared(MediaPeriod)} should be called only
* preparation completes immediately. * after {@link #setPreparationComplete()} has been called. If {@code false} preparation
* completes immediately.
*/ */
public FakeMediaPeriod( public FakeMediaPeriod(
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
DrmSessionManager drmSessionManager, TrackDataFactory trackDataFactory,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
DrmSessionManager drmSessionManager,
boolean deferOnPrepared) { boolean deferOnPrepared) {
this.trackGroupArray = trackGroupArray; this.trackGroupArray = trackGroupArray;
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.deferOnPrepared = deferOnPrepared; this.deferOnPrepared = deferOnPrepared;
this.trackDataFactory = trackDataFactory;
discontinuityPositionUs = C.TIME_UNSET; discontinuityPositionUs = C.TIME_UNSET;
sampleStreams = new ArrayList<>(); sampleStreams = new ArrayList<>();
fakePreparationLoadTaskId = LoadEventInfo.getNewId(); fakePreparationLoadTaskId = LoadEventInfo.getNewId();
@ -282,13 +313,16 @@ public class FakeMediaPeriod implements MediaPeriod {
TrackSelection selection, TrackSelection selection,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher) { EventDispatcher eventDispatcher) {
return new FakeSampleStream( FakeSampleStream sampleStream =
selection.getSelectedFormat(), new FakeSampleStream(
drmSessionManager, drmSessionManager,
eventDispatcher, eventDispatcher,
positionUs, selection.getSelectedFormat(),
/* timeUsIncrement= */ 0, trackDataFactory.create(
FakeSampleStream.SINGLE_SAMPLE_THEN_END_OF_STREAM); selection.getSelectedFormat(),
Assertions.checkNotNull(eventDispatcher.mediaPeriodId)));
sampleStream.seekTo(positionUs);
return sampleStream;
} }
/** /**
@ -300,8 +334,7 @@ public class FakeMediaPeriod implements MediaPeriod {
*/ */
protected void seekSampleStream(SampleStream sampleStream, long positionUs) { protected void seekSampleStream(SampleStream sampleStream, long positionUs) {
// Queue a single sample from the seek position again. // Queue a single sample from the seek position again.
((FakeSampleStream) sampleStream) ((FakeSampleStream) sampleStream).seekTo(positionUs);
.resetSampleStreamItems(positionUs, FakeSampleStream.SINGLE_SAMPLE_THEN_END_OF_STREAM);
} }
/** /**
@ -334,4 +367,27 @@ public class FakeMediaPeriod implements MediaPeriod {
/* mediaStartTimeUs= */ 0, /* mediaStartTimeUs= */ 0,
/* mediaEndTimeUs = */ C.TIME_UNSET); /* mediaEndTimeUs = */ C.TIME_UNSET);
} }
/** A factory to create the test data for a particular track. */
public interface TrackDataFactory {
/**
* Returns the list of {@link FakeSampleStreamItem}s that will be passed to {@link
* FakeSampleStream#FakeSampleStream(DrmSessionManager, EventDispatcher, Format, List)}.
*
* @param format The format of the track to provide data for.
* @param mediaPeriodId The {@link MediaPeriodId} to provide data for.
* @return The track data in the form of {@link FakeSampleStreamItem}s.
*/
List<FakeSampleStreamItem> create(Format format, MediaPeriodId mediaPeriodId);
/**
* Returns a factory that always provides a single sample with {@code time=sampleTimeUs} and
* then end-of-stream.
*/
static TrackDataFactory singleSampleWithTimeUs(long sampleTimeUs) {
return (unusedFormat, unusedMediaPeriodId) ->
ImmutableList.of(oneByteSample(sampleTimeUs), END_OF_STREAM_ITEM);
}
}
} }

View file

@ -36,6 +36,7 @@ import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
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.testutil.FakeMediaPeriod.TrackDataFactory;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
@ -46,6 +47,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Fake {@link MediaSource} that provides a given timeline. Creating the period will return a {@link * Fake {@link MediaSource} that provides a given timeline. Creating the period will return a {@link
@ -78,6 +80,7 @@ public class FakeMediaSource extends BaseMediaSource {
private static final int MANIFEST_LOAD_BYTES = 100; private static final int MANIFEST_LOAD_BYTES = 100;
private final TrackGroupArray trackGroupArray; private final TrackGroupArray trackGroupArray;
@Nullable private final FakeMediaPeriod.TrackDataFactory trackDataFactory;
private final ArrayList<FakeMediaPeriod> activeMediaPeriods; private final ArrayList<FakeMediaPeriod> activeMediaPeriods;
private final ArrayList<MediaPeriodId> createdMediaPeriods; private final ArrayList<MediaPeriodId> createdMediaPeriods;
private final DrmSessionManager drmSessionManager; private final DrmSessionManager drmSessionManager;
@ -107,18 +110,35 @@ public class FakeMediaSource extends BaseMediaSource {
*/ */
public FakeMediaSource( public FakeMediaSource(
@Nullable Timeline timeline, DrmSessionManager drmSessionManager, Format... formats) { @Nullable Timeline timeline, DrmSessionManager drmSessionManager, Format... formats) {
this(timeline, drmSessionManager, buildTrackGroupArray(formats)); this(timeline, drmSessionManager, /* trackDataFactory= */ null, buildTrackGroupArray(formats));
}
/**
* Creates a {@link FakeMediaSource}. This media source creates {@link FakeMediaPeriod}s with a
* {@link TrackGroupArray} using the given {@link Format}s. It passes {@code drmSessionManager}
* and {@code trackDataFactory} into the created periods. The provided {@link Timeline} may be
* null to prevent an immediate source info refresh message when preparing the media source. It
* can be manually set later using {@link #setNewSourceInfo(Timeline)}.
*/
public FakeMediaSource(
@Nullable Timeline timeline,
DrmSessionManager drmSessionManager,
@Nullable FakeMediaPeriod.TrackDataFactory trackDataFactory,
Format... formats) {
this(timeline, drmSessionManager, trackDataFactory, buildTrackGroupArray(formats));
} }
/** /**
* Creates a {@link FakeMediaSource}. This media source creates {@link FakeMediaPeriod}s with the * Creates a {@link FakeMediaSource}. This media source creates {@link FakeMediaPeriod}s with the
* given {@link TrackGroupArray}. The provided {@link Timeline} may be null to prevent an * provided {@link TrackGroupArray}, {@link DrmSessionManager} and {@link
* FakeMediaPeriod.TrackDataFactory}. The provided {@link Timeline} may be null to prevent an
* immediate source info refresh message when preparing the media source. It can be manually set * immediate source info refresh message when preparing the media source. It can be manually set
* later using {@link #setNewSourceInfo(Timeline)}. * later using {@link #setNewSourceInfo(Timeline)}.
*/ */
public FakeMediaSource( public FakeMediaSource(
@Nullable Timeline timeline, @Nullable Timeline timeline,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
@Nullable FakeMediaPeriod.TrackDataFactory trackDataFactory,
TrackGroupArray trackGroupArray) { TrackGroupArray trackGroupArray) {
if (timeline != null) { if (timeline != null) {
this.timeline = timeline; this.timeline = timeline;
@ -127,6 +147,7 @@ public class FakeMediaSource extends BaseMediaSource {
this.activeMediaPeriods = new ArrayList<>(); this.activeMediaPeriods = new ArrayList<>();
this.createdMediaPeriods = new ArrayList<>(); this.createdMediaPeriods = new ArrayList<>();
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.trackDataFactory = trackDataFactory;
} }
@Nullable @Nullable
@ -292,6 +313,7 @@ public class FakeMediaSource extends BaseMediaSource {
* May be null if no listener is available. * May be null if no listener is available.
* @return A new {@link FakeMediaPeriod}. * @return A new {@link FakeMediaPeriod}.
*/ */
@RequiresNonNull("this.timeline")
protected FakeMediaPeriod createFakeMediaPeriod( protected FakeMediaPeriod createFakeMediaPeriod(
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
@ -299,8 +321,17 @@ public class FakeMediaSource extends BaseMediaSource {
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
long positionInWindowUs =
timeline.getPeriodByUid(id.periodUid, new Period()).getPositionInWindowUs();
long defaultFirstSampleTimeUs = positionInWindowUs >= 0 || id.isAd() ? 0 : -positionInWindowUs;
return new FakeMediaPeriod( return new FakeMediaPeriod(
trackGroupArray, drmSessionManager, eventDispatcher, /* deferOnPrepared= */ false); trackGroupArray,
trackDataFactory != null
? trackDataFactory
: TrackDataFactory.singleSampleWithTimeUs(defaultFirstSampleTimeUs),
eventDispatcher,
drmSessionManager,
/* deferOnPrepared= */ false);
} }
private void finishSourcePreparation(boolean sendManifestLoadEvents) { private void finishSourcePreparation(boolean sendManifestLoadEvents) {

View file

@ -15,9 +15,11 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.C.BufferFlags;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
@ -29,9 +31,11 @@ import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.Iterables;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayDeque; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
@ -40,11 +44,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
*/ */
public class FakeSampleStream implements SampleStream { public class FakeSampleStream implements SampleStream {
private static class SampleInfo {
private final byte[] data;
@C.BufferFlags private final int flags;
private final long timeUs;
private SampleInfo(byte[] data, @C.BufferFlags int flags, long timeUs) {
this.data = Arrays.copyOf(data, data.length);
this.flags = flags;
this.timeUs = timeUs;
}
}
/** Item to customize a return value of {@link FakeSampleStream#readData}. */ /** Item to customize a return value of {@link FakeSampleStream#readData}. */
public static final class FakeSampleStreamItem { public static final class FakeSampleStreamItem {
@Nullable Format format;
@Nullable byte[] sampleData;
int flags;
/** /**
* Item that designates the end of stream has been reached. * Item that designates the end of stream has been reached.
@ -52,118 +65,126 @@ public class FakeSampleStream implements SampleStream {
* <p>When this item is read, readData will repeatedly return end of stream. * <p>When this item is read, readData will repeatedly return end of stream.
*/ */
public static final FakeSampleStreamItem END_OF_STREAM_ITEM = public static final FakeSampleStreamItem END_OF_STREAM_ITEM =
new FakeSampleStreamItem(new byte[] {}, C.BUFFER_FLAG_END_OF_STREAM); sample(
/* timeUs= */ Long.MAX_VALUE,
C.BUFFER_FLAG_END_OF_STREAM,
/* sampleData= */ new byte[] {});
/** Creates an item representing the provided format. */
public static FakeSampleStreamItem format(Format format) {
return new FakeSampleStreamItem(format, /* sampleInfo= */ null);
}
/** /**
* Item that, when {@link #readData(FormatHolder, DecoderInputBuffer, boolean)} is called, will * Creates an item representing a sample with the provided timestamp.
* return {@link C#RESULT_FORMAT_READ} with the new format.
* *
* @param format The format to be returned. * <p>The sample will contain a single byte of data.
*
* @param timeUs The timestamp of the sample.
*/ */
public FakeSampleStreamItem(Format format) { public static FakeSampleStreamItem oneByteSample(long timeUs) {
return oneByteSample(timeUs, /* flags= */ 0);
}
/**
* Creates an item representing a sample with the provided timestamp and flags.
*
* <p>The sample will contain a single byte of data.
*
* @param timeUs The timestamp of the sample.
* @param flags The buffer flags that will be set when reading this sample through {@link
* FakeSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)}.
*/
public static FakeSampleStreamItem oneByteSample(long timeUs, @BufferFlags int flags) {
return sample(timeUs, flags, new byte[] {0});
}
/**
* Creates an item representing a sample with the provided timestamp, flags and data.
*
* @param timeUs The timestamp of the sample.
* @param flags The buffer flags that will be set when reading this sample through {@link
* FakeSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)}.
* @param sampleData The sample data.
*/
public static FakeSampleStreamItem sample(
long timeUs, @BufferFlags int flags, byte[] sampleData) {
return new FakeSampleStreamItem(
/* format= */ null, new SampleInfo(sampleData.clone(), flags, timeUs));
}
@Nullable private final Format format;
@Nullable private final SampleInfo sampleInfo;
/**
* Creates an instance. Exactly one of {@code format} or {@code sampleInfo} must be non-null.
*/
private FakeSampleStreamItem(@Nullable Format format, @Nullable SampleInfo sampleInfo) {
Assertions.checkArgument((format == null) != (sampleInfo == null));
this.format = format; this.format = format;
} this.sampleInfo = sampleInfo;
/**
* Item that, when {@link #readData(FormatHolder, DecoderInputBuffer, boolean)} is called, will
* return {@link C#RESULT_BUFFER_READ} with the sample data.
*
* @param sampleData The sample data to be read.
*/
public FakeSampleStreamItem(byte[] sampleData) {
this.sampleData = sampleData.clone();
}
/**
* Item that, when {@link #readData(FormatHolder, DecoderInputBuffer, boolean)} is called, will
* return {@link C#RESULT_BUFFER_READ} with the sample data.
*
* @param sampleData The sample data to be read.
* @param flags The buffer flags to be set.
*/
public FakeSampleStreamItem(byte[] sampleData, int flags) {
this.sampleData = sampleData.clone();
this.flags = flags;
} }
} }
/** Constant array for use when a single sample is to be output, followed by the end of stream. */
public static final FakeSampleStreamItem[] SINGLE_SAMPLE_THEN_END_OF_STREAM =
new FakeSampleStreamItem[] {
new FakeSampleStreamItem(new byte[] {0}), FakeSampleStreamItem.END_OF_STREAM_ITEM
};
private final Format initialFormat; private final Format initialFormat;
private final ArrayDeque<FakeSampleStreamItem> fakeSampleStreamItems; private final List<FakeSampleStreamItem> fakeSampleStreamItems;
private final int timeUsIncrement;
private final DrmSessionManager drmSessionManager; private final DrmSessionManager drmSessionManager;
@Nullable private final EventDispatcher eventDispatcher; @Nullable private final EventDispatcher eventDispatcher;
private int sampleItemIndex;
private @MonotonicNonNull Format downstreamFormat; private @MonotonicNonNull Format downstreamFormat;
private long timeUs;
private boolean readEOSBuffer; private boolean readEOSBuffer;
@Nullable private DrmSession currentDrmSession; @Nullable private DrmSession currentDrmSession;
/** /**
* Creates fake sample stream which outputs the given {@link Format}, optionally one sample with * Creates a fake sample stream which outputs the given {@link Format} followed by the provided
* zero bytes, then end of stream. * {@link FakeSampleStreamItem items}.
* *
* @param format The {@link Format} to output.
* @param eventDispatcher An {@link EventDispatcher} to notify of read events.
* @param shouldOutputSample Whether the sample stream should output a sample.
*/
public FakeSampleStream(
Format format, @Nullable EventDispatcher eventDispatcher, boolean shouldOutputSample) {
this(
format,
DrmSessionManager.DUMMY,
eventDispatcher,
/* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 0,
shouldOutputSample
? SINGLE_SAMPLE_THEN_END_OF_STREAM
: new FakeSampleStreamItem[] {FakeSampleStreamItem.END_OF_STREAM_ITEM});
}
/**
* Creates a fake sample stream which outputs the given {@link Format}, any amount of {@link
* FakeSampleStreamItem items}, then end of stream.
*
* @param format The {@link Format} to output.
* @param drmSessionManager A {@link DrmSessionManager} for DRM interactions. * @param drmSessionManager A {@link DrmSessionManager} for DRM interactions.
* @param eventDispatcher An {@link EventDispatcher} to notify of read events. * @param eventDispatcher An {@link EventDispatcher} to notify of read events.
* @param firstSampleTimeUs The time at which samples will start being output, in microseconds. * @param initialFormat The first {@link Format} to output.
* @param timeUsIncrement The time each sample should increase by, in microseconds.
* @param fakeSampleStreamItems The {@link FakeSampleStreamItem items} to customize the return * @param fakeSampleStreamItems The {@link FakeSampleStreamItem items} to customize the return
* values of {@link #readData(FormatHolder, DecoderInputBuffer, boolean)}. Note that once an * values of {@link #readData(FormatHolder, DecoderInputBuffer, boolean)}. This is assumed to
* EOS buffer has been read, that will return every time readData is called. * be in ascending order of sampleTime. Note that once an EOS buffer has been read, that will
* return every time readData is called. This should usually end with {@link
* FakeSampleStreamItem#END_OF_STREAM_ITEM}.
*/ */
public FakeSampleStream( public FakeSampleStream(
Format format,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
@Nullable EventDispatcher eventDispatcher, @Nullable EventDispatcher eventDispatcher,
long firstSampleTimeUs, Format initialFormat,
int timeUsIncrement, List<FakeSampleStreamItem> fakeSampleStreamItems) {
FakeSampleStreamItem... fakeSampleStreamItems) {
this.initialFormat = format;
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.fakeSampleStreamItems = new ArrayDeque<>(Arrays.asList(fakeSampleStreamItems)); this.initialFormat = initialFormat;
this.timeUs = firstSampleTimeUs; this.fakeSampleStreamItems = new ArrayList<>(fakeSampleStreamItems);
this.timeUsIncrement = timeUsIncrement;
} }
/** /**
* Clears and assigns new samples provided by this sample stream. * Seeks inside this sample stream.
* *
* @param timeUs The time at which samples will start being output, in microseconds. * <p>Seeks to just before the first sample with {@code sampleTime >= timeUs}, or to the end of
* @param fakeSampleStreamItems The {@link FakeSampleStreamItem items} to provide. * the stream otherwise.
*/ */
public void resetSampleStreamItems(long timeUs, FakeSampleStreamItem... fakeSampleStreamItems) { public void seekTo(long timeUs) {
this.fakeSampleStreamItems.clear(); Format applicableFormat = initialFormat;
this.fakeSampleStreamItems.addAll(Arrays.asList(fakeSampleStreamItems)); for (int i = 0; i < fakeSampleStreamItems.size(); i++) {
this.timeUs = timeUs; @Nullable SampleInfo sampleInfo = fakeSampleStreamItems.get(i).sampleInfo;
readEOSBuffer = false; if (sampleInfo == null) {
applicableFormat = Assertions.checkNotNull(fakeSampleStreamItems.get(i).format);
continue;
}
if (sampleInfo.timeUs >= timeUs) {
sampleItemIndex = i;
readEOSBuffer = false;
if (downstreamFormat != null && !applicableFormat.equals(downstreamFormat)) {
notifyEventDispatcher(applicableFormat);
}
return;
}
}
sampleItemIndex = fakeSampleStreamItems.size();
readEOSBuffer = true;
} }
/** /**
@ -177,10 +198,10 @@ public class FakeSampleStream implements SampleStream {
@Override @Override
public boolean isReady() { public boolean isReady() {
if (fakeSampleStreamItems.isEmpty()) { if (sampleItemIndex == fakeSampleStreamItems.size()) {
return readEOSBuffer || downstreamFormat == null; return readEOSBuffer || downstreamFormat == null;
} }
if (fakeSampleStreamItems.peek().format != null) { if (fakeSampleStreamItems.get(sampleItemIndex).format != null) {
// A format can be read. // A format can be read.
return true; return true;
} }
@ -200,29 +221,28 @@ public class FakeSampleStream implements SampleStream {
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
if (!fakeSampleStreamItems.isEmpty()) { if (sampleItemIndex < fakeSampleStreamItems.size()) {
FakeSampleStreamItem fakeSampleStreamItem = fakeSampleStreamItems.remove(); FakeSampleStreamItem fakeSampleStreamItem = fakeSampleStreamItems.get(sampleItemIndex);
sampleItemIndex++;
if (fakeSampleStreamItem.format != null) { if (fakeSampleStreamItem.format != null) {
onFormatResult(fakeSampleStreamItem.format, formatHolder); onFormatResult(fakeSampleStreamItem.format, formatHolder);
return C.RESULT_FORMAT_READ; return C.RESULT_FORMAT_READ;
} else { } else {
byte[] sampleData = Assertions.checkNotNull(fakeSampleStreamItem.sampleData); SampleInfo sampleInfo = Assertions.checkNotNull(fakeSampleStreamItem.sampleInfo);
if (fakeSampleStreamItem.flags != 0) { if (sampleInfo.flags != 0) {
buffer.setFlags(fakeSampleStreamItem.flags); buffer.setFlags(sampleInfo.flags);
if (buffer.isEndOfStream()) { if (buffer.isEndOfStream()) {
readEOSBuffer = true; readEOSBuffer = true;
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
} }
if (!mayReadSample()) { if (!mayReadSample()) {
// Put the item back so we can consume it next time. sampleItemIndex--;
fakeSampleStreamItems.addFirst(fakeSampleStreamItem);
return C.RESULT_NOTHING_READ; return C.RESULT_NOTHING_READ;
} }
buffer.timeUs = timeUs; buffer.timeUs = sampleInfo.timeUs;
timeUs += timeUsIncrement; buffer.ensureSpaceForWrite(sampleInfo.data.length);
buffer.ensureSpaceForWrite(sampleData.length); buffer.data.put(sampleInfo.data);
buffer.data.put(sampleData);
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
} }
@ -237,7 +257,7 @@ public class FakeSampleStream implements SampleStream {
downstreamFormat = newFormat; downstreamFormat = newFormat;
@Nullable DrmInitData newDrmInitData = newFormat.drmInitData; @Nullable DrmInitData newDrmInitData = newFormat.drmInitData;
outputFormatHolder.drmSession = currentDrmSession; outputFormatHolder.drmSession = currentDrmSession;
notifyEventDispatcher(outputFormatHolder); notifyEventDispatcher(newFormat);
if (!isFirstFormat && Util.areEqual(oldDrmInitData, newDrmInitData)) { if (!isFirstFormat && Util.areEqual(oldDrmInitData, newDrmInitData)) {
// Nothing to do. // Nothing to do.
return; return;
@ -260,11 +280,16 @@ public class FakeSampleStream implements SampleStream {
private boolean mayReadSample() { private boolean mayReadSample() {
@Nullable DrmSession drmSession = this.currentDrmSession; @Nullable DrmSession drmSession = this.currentDrmSession;
@Nullable
FakeSampleStreamItem nextSample =
Iterables.get(fakeSampleStreamItems, sampleItemIndex, /* defaultValue= */ null);
boolean nextSampleIsClear =
nextSample != null
&& nextSample.sampleInfo != null
&& (nextSample.sampleInfo.flags & C.BUFFER_FLAG_ENCRYPTED) == 0;
return drmSession == null return drmSession == null
|| drmSession.getState() == DrmSession.STATE_OPENED_WITH_KEYS || drmSession.getState() == DrmSession.STATE_OPENED_WITH_KEYS
|| (!fakeSampleStreamItems.isEmpty() || (nextSampleIsClear && drmSession.playClearSamplesWithoutKeys());
&& (fakeSampleStreamItems.peek().flags & C.BUFFER_FLAG_ENCRYPTED) == 0
&& drmSession.playClearSamplesWithoutKeys());
} }
@Override @Override
@ -276,6 +301,7 @@ public class FakeSampleStream implements SampleStream {
@Override @Override
public int skipData(long positionUs) { public int skipData(long positionUs) {
// TODO: Implement this.
return 0; return 0;
} }
@ -287,14 +313,22 @@ public class FakeSampleStream implements SampleStream {
} }
} }
private void notifyEventDispatcher(FormatHolder formatHolder) { private void notifyEventDispatcher(Format format) {
if (eventDispatcher != null) { if (eventDispatcher != null) {
@Nullable SampleInfo sampleInfo = null;
for (int i = sampleItemIndex; i < fakeSampleStreamItems.size(); i++) {
sampleInfo = fakeSampleStreamItems.get(i).sampleInfo;
if (sampleInfo != null) {
break;
}
}
long nextSampleTimeUs = sampleInfo != null ? sampleInfo.timeUs : C.TIME_END_OF_SOURCE;
eventDispatcher.downstreamFormatChanged( eventDispatcher.downstreamFormatChanged(
C.TRACK_TYPE_UNKNOWN, C.TRACK_TYPE_UNKNOWN,
formatHolder.format, format,
C.SELECTION_REASON_UNKNOWN, C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null, /* trackSelectionData= */ null,
/* mediaTimeUs= */ timeUs); /* mediaTimeUs= */ nextSampleTimeUs);
} }
} }
} }

View file

@ -37,8 +37,7 @@ public final class FakeTimeline extends Timeline {
public static final long DEFAULT_WINDOW_DURATION_US = 10 * C.MICROS_PER_SECOND; public static final long DEFAULT_WINDOW_DURATION_US = 10 * C.MICROS_PER_SECOND;
/** Default offset of a window in its first period in microseconds. */ /** Default offset of a window in its first period in microseconds. */
public static final long DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US = public static final long DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US = 123 * C.MICROS_PER_SECOND;
10_000 * C.MICROS_PER_SECOND;
public final int periodCount; public final int periodCount;
public final Object id; public final Object id;
@ -187,7 +186,7 @@ public final class FakeTimeline extends Timeline {
public static final MediaItem FAKE_MEDIA_ITEM = public static final MediaItem FAKE_MEDIA_ITEM =
new MediaItem.Builder().setMediaId("FakeTimeline").setUri(Uri.EMPTY).build(); new MediaItem.Builder().setMediaId("FakeTimeline").setUri(Uri.EMPTY).build();
private static final long AD_DURATION_US = 10 * C.MICROS_PER_SECOND; private static final long AD_DURATION_US = 5 * C.MICROS_PER_SECOND;
private final TimelineWindowDefinition[] windowDefinitions; private final TimelineWindowDefinition[] windowDefinitions;
private final Object[] manifests; private final Object[] manifests;