mirror of
https://github.com/samsonjs/media.git
synced 2026-03-28 09:55:48 +00:00
Support isAtomic flag in DynamicConcatenatingMediaSource.
This feature is supported in the ConcatenatingMediaSource and is easily copied to this media source. Also adding tests to check whether the atomic property works in normal concatenation and in also in nested use. Also fixes a bug where timeline methods of the DeferredTimeline were not correctly forwarded. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=184526881
This commit is contained in:
parent
fe98477045
commit
784e8a6344
5 changed files with 197 additions and 80 deletions
|
|
@ -47,7 +47,8 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
|
|||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mediaSource = new DynamicConcatenatingMediaSource(new FakeShuffleOrder(0));
|
||||
mediaSource =
|
||||
new DynamicConcatenatingMediaSource(/* isAtomic= */ false, new FakeShuffleOrder(0));
|
||||
testRunner = new MediaSourceTestRunner(mediaSource, null);
|
||||
}
|
||||
|
||||
|
|
@ -627,6 +628,92 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
|
|||
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0));
|
||||
}
|
||||
|
||||
public void testAtomicTimelineWindowOrder() throws IOException {
|
||||
// Release default test runner with non-atomic media source and replace with new test runner.
|
||||
testRunner.release();
|
||||
DynamicConcatenatingMediaSource mediaSource =
|
||||
new DynamicConcatenatingMediaSource(/* isAtomic= */ true, new FakeShuffleOrder(0));
|
||||
testRunner = new MediaSourceTestRunner(mediaSource, null);
|
||||
mediaSource.addMediaSources(Arrays.<MediaSource>asList(createMediaSources(3)));
|
||||
Timeline timeline = testRunner.prepareSource();
|
||||
TimelineAsserts.assertWindowIds(timeline, 111, 222, 333);
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 2, 3);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ false, C.INDEX_UNSET, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true, C.INDEX_UNSET, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ false, 2, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ true, 2, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ false, 2, 0, 1);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ true, 2, 0, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ false, 1, 2, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true, 1, 2, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ false, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ true, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ false, 1, 2, 0);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ true, 1, 2, 0);
|
||||
assertThat(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ false)).isEqualTo(0);
|
||||
assertThat(timeline.getFirstWindowIndex(/* shuffleModeEnabled= */ true)).isEqualTo(0);
|
||||
assertThat(timeline.getLastWindowIndex(/* shuffleModeEnabled= */ false)).isEqualTo(2);
|
||||
assertThat(timeline.getLastWindowIndex(/* shuffleModeEnabled= */ true)).isEqualTo(2);
|
||||
}
|
||||
|
||||
public void testNestedTimeline() throws IOException {
|
||||
DynamicConcatenatingMediaSource nestedSource1 =
|
||||
new DynamicConcatenatingMediaSource(/* isAtomic= */ false, new FakeShuffleOrder(0));
|
||||
DynamicConcatenatingMediaSource nestedSource2 =
|
||||
new DynamicConcatenatingMediaSource(/* isAtomic= */ true, new FakeShuffleOrder(0));
|
||||
mediaSource.addMediaSource(nestedSource1);
|
||||
mediaSource.addMediaSource(nestedSource2);
|
||||
testRunner.prepareSource();
|
||||
FakeMediaSource[] childSources = createMediaSources(4);
|
||||
nestedSource1.addMediaSource(childSources[0]);
|
||||
testRunner.assertTimelineChangeBlocking();
|
||||
nestedSource1.addMediaSource(childSources[1]);
|
||||
testRunner.assertTimelineChangeBlocking();
|
||||
nestedSource2.addMediaSource(childSources[2]);
|
||||
testRunner.assertTimelineChangeBlocking();
|
||||
nestedSource2.addMediaSource(childSources[3]);
|
||||
Timeline timeline = testRunner.assertTimelineChangeBlocking();
|
||||
|
||||
TimelineAsserts.assertWindowIds(timeline, 111, 222, 333, 444);
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 2, 3, 4);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ false, C.INDEX_UNSET, 0, 1, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ false, 0, 1, 3, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ false, 3, 0, 1, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ false, 1, 2, 3, C.INDEX_UNSET);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ false, 0, 1, 3, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ false, 1, 2, 3, 0);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true, 1, 3, C.INDEX_UNSET, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ true, 0, 1, 3, 2);
|
||||
TimelineAsserts.assertPreviousWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ true, 1, 3, 0, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_OFF, /* shuffleModeEnabled= */ true, C.INDEX_UNSET, 0, 3, 1);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ONE, /* shuffleModeEnabled= */ true, 0, 1, 3, 2);
|
||||
TimelineAsserts.assertNextWindowIndices(
|
||||
timeline, Player.REPEAT_MODE_ALL, /* shuffleModeEnabled= */ true, 2, 0, 3, 1);
|
||||
}
|
||||
|
||||
public void testRemoveChildSourceWithActiveMediaPeriod() throws IOException {
|
||||
FakeMediaSource childSource = createFakeMediaSource();
|
||||
mediaSource.addMediaSource(childSource);
|
||||
|
|
|
|||
|
|
@ -27,14 +27,18 @@ import com.google.android.exoplayer2.Timeline;
|
|||
|
||||
private final int childCount;
|
||||
private final ShuffleOrder shuffleOrder;
|
||||
private final boolean isAtomic;
|
||||
|
||||
/**
|
||||
* Sets up a concatenated timeline with a shuffle order of child timelines.
|
||||
*
|
||||
* @param isAtomic Whether the child timelines shall be treated as atomic, i.e., treated as a
|
||||
* single item for repeating and shuffling.
|
||||
* @param shuffleOrder A shuffle order of child timelines. The number of child timelines must
|
||||
* match the number of elements in the shuffle order.
|
||||
*/
|
||||
public AbstractConcatenatedTimeline(ShuffleOrder shuffleOrder) {
|
||||
public AbstractConcatenatedTimeline(boolean isAtomic, ShuffleOrder shuffleOrder) {
|
||||
this.isAtomic = isAtomic;
|
||||
this.shuffleOrder = shuffleOrder;
|
||||
this.childCount = shuffleOrder.getLength();
|
||||
}
|
||||
|
|
@ -42,6 +46,11 @@ import com.google.android.exoplayer2.Timeline;
|
|||
@Override
|
||||
public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled) {
|
||||
if (isAtomic) {
|
||||
// Adapt repeat and shuffle mode to atomic concatenation.
|
||||
repeatMode = repeatMode == Player.REPEAT_MODE_ONE ? Player.REPEAT_MODE_ALL : repeatMode;
|
||||
shuffleModeEnabled = false;
|
||||
}
|
||||
// Find next window within current child.
|
||||
int childIndex = getChildIndexByWindowIndex(windowIndex);
|
||||
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
|
||||
|
|
@ -71,6 +80,11 @@ import com.google.android.exoplayer2.Timeline;
|
|||
@Override
|
||||
public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled) {
|
||||
if (isAtomic) {
|
||||
// Adapt repeat and shuffle mode to atomic concatenation.
|
||||
repeatMode = repeatMode == Player.REPEAT_MODE_ONE ? Player.REPEAT_MODE_ALL : repeatMode;
|
||||
shuffleModeEnabled = false;
|
||||
}
|
||||
// Find previous window within current child.
|
||||
int childIndex = getChildIndexByWindowIndex(windowIndex);
|
||||
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
|
||||
|
|
@ -103,6 +117,9 @@ import com.google.android.exoplayer2.Timeline;
|
|||
if (childCount == 0) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
if (isAtomic) {
|
||||
shuffleModeEnabled = false;
|
||||
}
|
||||
// Find last non-empty child.
|
||||
int lastChildIndex = shuffleModeEnabled ? shuffleOrder.getLastIndex() : childCount - 1;
|
||||
while (getTimelineByChildIndex(lastChildIndex).isEmpty()) {
|
||||
|
|
@ -121,6 +138,9 @@ import com.google.android.exoplayer2.Timeline;
|
|||
if (childCount == 0) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
if (isAtomic) {
|
||||
shuffleModeEnabled = false;
|
||||
}
|
||||
// Find first non-empty child.
|
||||
int firstChildIndex = shuffleModeEnabled ? shuffleOrder.getFirstIndex() : 0;
|
||||
while (getTimelineByChildIndex(firstChildIndex).isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source;
|
|||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
|
|
@ -173,10 +172,9 @@ public final class ConcatenatingMediaSource extends CompositeMediaSource<Integer
|
|||
private final Timeline[] timelines;
|
||||
private final int[] sourcePeriodOffsets;
|
||||
private final int[] sourceWindowOffsets;
|
||||
private final boolean isAtomic;
|
||||
|
||||
public ConcatenatedTimeline(Timeline[] timelines, boolean isAtomic, ShuffleOrder shuffleOrder) {
|
||||
super(shuffleOrder);
|
||||
super(isAtomic, shuffleOrder);
|
||||
int[] sourcePeriodOffsets = new int[timelines.length];
|
||||
int[] sourceWindowOffsets = new int[timelines.length];
|
||||
long periodCount = 0;
|
||||
|
|
@ -193,7 +191,6 @@ public final class ConcatenatingMediaSource extends CompositeMediaSource<Integer
|
|||
this.timelines = timelines;
|
||||
this.sourcePeriodOffsets = sourcePeriodOffsets;
|
||||
this.sourceWindowOffsets = sourceWindowOffsets;
|
||||
this.isAtomic = isAtomic;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -206,34 +203,6 @@ public final class ConcatenatingMediaSource extends CompositeMediaSource<Integer
|
|||
return sourcePeriodOffsets[sourcePeriodOffsets.length - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled) {
|
||||
if (isAtomic && repeatMode == Player.REPEAT_MODE_ONE) {
|
||||
repeatMode = Player.REPEAT_MODE_ALL;
|
||||
}
|
||||
return super.getNextWindowIndex(windowIndex, repeatMode, !isAtomic && shuffleModeEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode,
|
||||
boolean shuffleModeEnabled) {
|
||||
if (isAtomic && repeatMode == Player.REPEAT_MODE_ONE) {
|
||||
repeatMode = Player.REPEAT_MODE_ALL;
|
||||
}
|
||||
return super.getPreviousWindowIndex(windowIndex, repeatMode, !isAtomic && shuffleModeEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLastWindowIndex(boolean shuffleModeEnabled) {
|
||||
return super.getLastWindowIndex(!isAtomic && shuffleModeEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstWindowIndex(boolean shuffleModeEnabled) {
|
||||
return super.getFirstWindowIndex(!isAtomic && shuffleModeEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getChildIndexByPeriodIndex(int periodIndex) {
|
||||
return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex + 1, false, false) + 1;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
|
|||
private final MediaSourceHolder query;
|
||||
private final Map<MediaPeriod, MediaSourceHolder> mediaSourceByMediaPeriod;
|
||||
private final List<DeferredMediaPeriod> deferredMediaPeriods;
|
||||
private final boolean isAtomic;
|
||||
|
||||
private ExoPlayer player;
|
||||
private Listener listener;
|
||||
|
|
@ -70,22 +71,35 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
|
|||
* Creates a new dynamic concatenating media source.
|
||||
*/
|
||||
public DynamicConcatenatingMediaSource() {
|
||||
this(new DefaultShuffleOrder(0));
|
||||
this(/* isAtomic= */ false, new DefaultShuffleOrder(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dynamic concatenating media source.
|
||||
*
|
||||
* @param isAtomic Whether the concatenating media source will be treated as atomic, i.e., treated
|
||||
* as a single item for repeating and shuffling.
|
||||
*/
|
||||
public DynamicConcatenatingMediaSource(boolean isAtomic) {
|
||||
this(isAtomic, new DefaultShuffleOrder(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dynamic concatenating media source with a custom shuffle order.
|
||||
*
|
||||
* @param isAtomic Whether the concatenating media source will be treated as atomic, i.e., treated
|
||||
* as a single item for repeating and shuffling.
|
||||
* @param shuffleOrder The {@link ShuffleOrder} to use when shuffling the child media sources.
|
||||
* This shuffle order must be empty.
|
||||
*/
|
||||
public DynamicConcatenatingMediaSource(ShuffleOrder shuffleOrder) {
|
||||
public DynamicConcatenatingMediaSource(boolean isAtomic, ShuffleOrder shuffleOrder) {
|
||||
this.shuffleOrder = shuffleOrder;
|
||||
this.mediaSourceByMediaPeriod = new IdentityHashMap<>();
|
||||
this.mediaSourcesPublic = new ArrayList<>();
|
||||
this.mediaSourceHolders = new ArrayList<>();
|
||||
this.deferredMediaPeriods = new ArrayList<>(1);
|
||||
this.query = new MediaSourceHolder(null, null, -1, -1, -1);
|
||||
this.isAtomic = isAtomic;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -446,8 +460,10 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
|
|||
|
||||
private void maybeNotifyListener(@Nullable EventDispatcher actionOnCompletion) {
|
||||
if (!preventListenerNotification) {
|
||||
listener.onSourceInfoRefreshed(this,
|
||||
new ConcatenatedTimeline(mediaSourceHolders, windowCount, periodCount, shuffleOrder),
|
||||
listener.onSourceInfoRefreshed(
|
||||
this,
|
||||
new ConcatenatedTimeline(
|
||||
mediaSourceHolders, windowCount, periodCount, shuffleOrder, isAtomic),
|
||||
null);
|
||||
if (actionOnCompletion != null) {
|
||||
player.createMessage(this).setType(MSG_ON_COMPLETION).setPayload(actionOnCompletion).send();
|
||||
|
|
@ -652,9 +668,13 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
|
|||
private final int[] uids;
|
||||
private final SparseIntArray childIndexByUid;
|
||||
|
||||
public ConcatenatedTimeline(Collection<MediaSourceHolder> mediaSourceHolders, int windowCount,
|
||||
int periodCount, ShuffleOrder shuffleOrder) {
|
||||
super(shuffleOrder);
|
||||
public ConcatenatedTimeline(
|
||||
Collection<MediaSourceHolder> mediaSourceHolders,
|
||||
int windowCount,
|
||||
int periodCount,
|
||||
ShuffleOrder shuffleOrder,
|
||||
boolean isAtomic) {
|
||||
super(isAtomic, shuffleOrder);
|
||||
this.windowCount = windowCount;
|
||||
this.periodCount = periodCount;
|
||||
int childCount = mediaSourceHolders.size();
|
||||
|
|
@ -728,61 +748,39 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
|
|||
* Timeline used as placeholder for an unprepared media source. After preparation, a copy of the
|
||||
* DeferredTimeline is used to keep the originally assigned first period ID.
|
||||
*/
|
||||
private static final class DeferredTimeline extends Timeline {
|
||||
private static final class DeferredTimeline extends ForwardingTimeline {
|
||||
|
||||
private static final Object DUMMY_ID = new Object();
|
||||
private static final Period period = new Period();
|
||||
private static final DummyTimeline dummyTimeline = new DummyTimeline();
|
||||
|
||||
private final Timeline timeline;
|
||||
private final Object replacedID;
|
||||
private final Object replacedId;
|
||||
|
||||
public DeferredTimeline() {
|
||||
timeline = null;
|
||||
replacedID = null;
|
||||
this(dummyTimeline, /* replacedId= */ null);
|
||||
}
|
||||
|
||||
private DeferredTimeline(Timeline timeline, Object replacedID) {
|
||||
this.timeline = timeline;
|
||||
this.replacedID = replacedID;
|
||||
private DeferredTimeline(Timeline timeline, Object replacedId) {
|
||||
super(timeline);
|
||||
this.replacedId = replacedId;
|
||||
}
|
||||
|
||||
public DeferredTimeline cloneWithNewTimeline(Timeline timeline) {
|
||||
return new DeferredTimeline(timeline, replacedID == null && timeline.getPeriodCount() > 0
|
||||
? timeline.getPeriod(0, period, true).uid : replacedID);
|
||||
return new DeferredTimeline(
|
||||
timeline,
|
||||
replacedId == null && timeline.getPeriodCount() > 0
|
||||
? timeline.getPeriod(0, period, true).uid
|
||||
: replacedId);
|
||||
}
|
||||
|
||||
public Timeline getTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWindowCount() {
|
||||
return timeline == null ? 1 : timeline.getWindowCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||
long defaultPositionProjectionUs) {
|
||||
return timeline == null
|
||||
// Dynamic window to indicate pending timeline updates.
|
||||
? window.set(setIds ? DUMMY_ID : null, C.TIME_UNSET, C.TIME_UNSET, false, true, 0,
|
||||
C.TIME_UNSET, 0, 0, 0)
|
||||
: timeline.getWindow(windowIndex, window, setIds, defaultPositionProjectionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPeriodCount() {
|
||||
return timeline == null ? 1 : timeline.getPeriodCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||
if (timeline == null) {
|
||||
return period.set(setIds ? DUMMY_ID : null, setIds ? DUMMY_ID : null, 0, C.TIME_UNSET,
|
||||
C.TIME_UNSET);
|
||||
}
|
||||
timeline.getPeriod(periodIndex, period, setIds);
|
||||
if (period.uid == replacedID) {
|
||||
if (period.uid == replacedId) {
|
||||
period.uid = DUMMY_ID;
|
||||
}
|
||||
return period;
|
||||
|
|
@ -790,11 +788,54 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
|
|||
|
||||
@Override
|
||||
public int getIndexOfPeriod(Object uid) {
|
||||
return timeline == null ? (uid == DUMMY_ID ? 0 : C.INDEX_UNSET)
|
||||
: timeline.getIndexOfPeriod(uid == DUMMY_ID ? replacedID : uid);
|
||||
return timeline.getIndexOfPeriod(uid == DUMMY_ID ? replacedId : uid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Dummy placeholder timeline with one dynamic window with a period of indeterminate duration. */
|
||||
private static final class DummyTimeline extends Timeline {
|
||||
|
||||
@Override
|
||||
public int getWindowCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getWindow(int windowIndex, Window window, boolean setIds,
|
||||
long defaultPositionProjectionUs) {
|
||||
// Dynamic window to indicate pending timeline updates.
|
||||
return window.set(
|
||||
/* id= */ null,
|
||||
/* presentationStartTimeMs= */ C.TIME_UNSET,
|
||||
/* windowStartTimeMs= */ C.TIME_UNSET,
|
||||
/* isSeekable= */ false,
|
||||
/* isDynamic= */ true,
|
||||
/* defaultPositionUs= */ 0,
|
||||
/* durationUs= */ C.TIME_UNSET,
|
||||
/* firstPeriodIndex= */ 0,
|
||||
/* lastPeriodIndex= */ 0,
|
||||
/* positionInFirstPeriodUs= */ 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPeriodCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
|
||||
return period.set(
|
||||
/* id= */ null,
|
||||
/* uid= */ null,
|
||||
/* windowIndex= */ 0,
|
||||
/* durationUs = */ C.TIME_UNSET,
|
||||
/* positionInWindowUs= */ C.TIME_UNSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfPeriod(Object uid) {
|
||||
return uid == null ? 0 : C.INDEX_UNSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
|||
private final int loopCount;
|
||||
|
||||
public LoopingTimeline(Timeline childTimeline, int loopCount) {
|
||||
super(new UnshuffledShuffleOrder(loopCount));
|
||||
super(/* isAtomic= */ false, new UnshuffledShuffleOrder(loopCount));
|
||||
this.childTimeline = childTimeline;
|
||||
childPeriodCount = childTimeline.getPeriodCount();
|
||||
childWindowCount = childTimeline.getWindowCount();
|
||||
|
|
|
|||
Loading…
Reference in a new issue