Infinite loops using new Timeline features

Using the new getNextWindowIndex method of Timeline, LoopingMediaSource now
uses a InfinitelyLoopingTimeline which does not unroll the windows to
157 million iterations but just starts from the beginning. If an explicit
number of iterations is given, we still unroll.

This change also allows multi-window timebars to show infinitely looping
playlists correctly.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=154817554
This commit is contained in:
tonihei 2017-05-02 04:09:00 -07:00 committed by Oliver Woodman
parent 94ffbb2b6a
commit ab30d715c7

View File

@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.source;
import android.util.Log;
import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
@ -29,13 +28,6 @@ import java.io.IOException;
*/
public final class LoopingMediaSource implements MediaSource {
/**
* The maximum number of periods that can be exposed by the source. The value of this constant is
* large enough to cause indefinite looping in practice (the total duration of the looping source
* will be approximately five years if the duration of each period is one second).
*/
public static final int MAX_EXPOSED_PERIODS = 157680000;
private static final String TAG = "LoopingMediaSource";
private final MediaSource childSource;
@ -56,9 +48,7 @@ public final class LoopingMediaSource implements MediaSource {
* Loops the provided source a specified number of times.
*
* @param childSource The {@link MediaSource} to loop.
* @param loopCount The desired number of loops. Must be strictly positive. The actual number of
* loops will be capped at the maximum that can achieved without causing the number of
* periods exposed by the source to exceed {@link #MAX_EXPOSED_PERIODS}.
* @param loopCount The desired number of loops. Must be strictly positive.
*/
public LoopingMediaSource(MediaSource childSource, int loopCount) {
Assertions.checkArgument(loopCount > 0);
@ -72,7 +62,9 @@ public final class LoopingMediaSource implements MediaSource {
@Override
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
childPeriodCount = timeline.getPeriodCount();
listener.onSourceInfoRefreshed(new LoopingTimeline(timeline, loopCount), manifest);
Timeline loopingTimeline = loopCount != Integer.MAX_VALUE
? new LoopingTimeline(timeline, loopCount) : new InfinitelyLoopingTimeline(timeline);
listener.onSourceInfoRefreshed(loopingTimeline, manifest);
}
});
}
@ -84,7 +76,9 @@ public final class LoopingMediaSource implements MediaSource {
@Override
public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) {
return childSource.createPeriod(index % childPeriodCount, allocator, positionUs);
return loopCount != Integer.MAX_VALUE
? childSource.createPeriod(index % childPeriodCount, allocator, positionUs)
: childSource.createPeriod(index, allocator, positionUs);
}
@Override
@ -108,17 +102,9 @@ public final class LoopingMediaSource implements MediaSource {
this.childTimeline = childTimeline;
childPeriodCount = childTimeline.getPeriodCount();
childWindowCount = childTimeline.getWindowCount();
// This is the maximum number of loops that can be performed without exceeding
// MAX_EXPOSED_PERIODS periods.
int maxLoopCount = MAX_EXPOSED_PERIODS / childPeriodCount;
if (loopCount > maxLoopCount) {
if (loopCount != Integer.MAX_VALUE) {
Log.w(TAG, "Capped loops to avoid overflow: " + loopCount + " -> " + maxLoopCount);
}
this.loopCount = maxLoopCount;
} else {
this.loopCount = loopCount;
}
this.loopCount = loopCount;
Assertions.checkState(loopCount <= Integer.MAX_VALUE / childPeriodCount,
"LoopingMediaSource contains too many periods");
}
@Override
@ -169,4 +155,49 @@ public final class LoopingMediaSource implements MediaSource {
}
private static final class InfinitelyLoopingTimeline extends Timeline {
private final Timeline childTimeline;
public InfinitelyLoopingTimeline(Timeline childTimeline) {
this.childTimeline = childTimeline;
}
@Override
public int getWindowCount() {
return childTimeline.getWindowCount();
}
@Override
public int getNextWindowIndex(int currentWindowIndex, @ExoPlayer.RepeatMode int repeatMode) {
return currentWindowIndex < getWindowCount() - 1 ? currentWindowIndex + 1 : 0;
}
@Override
public int getPreviousWindowIndex(int currentWindowIndex,
@ExoPlayer.RepeatMode int repeatMode) {
return currentWindowIndex > 0 ? currentWindowIndex - 1 : getWindowCount() - 1;
}
@Override
public Window getWindow(int windowIndex, Window window, boolean setIds,
long defaultPositionProjectionUs) {
return childTimeline.getWindow(windowIndex, window, setIds, defaultPositionProjectionUs);
}
@Override
public int getPeriodCount() {
return childTimeline.getPeriodCount();
}
@Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
return childTimeline.getPeriod(periodIndex, period, setIds);
}
@Override
public int getIndexOfPeriod(Object uid) {
return childTimeline.getIndexOfPeriod(uid);
}
}
}