diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 68552c99ed..9fc499f251 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.HashMap; @@ -152,12 +153,14 @@ public final class ConcatenatingMediaSource implements MediaSource { public ConcatenatedTimeline(Timeline[] timelines) { int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; - int periodCount = 0; + long periodCount = 0; int windowCount = 0; for (int i = 0; i < timelines.length; i++) { Timeline timeline = timelines[i]; periodCount += timeline.getPeriodCount(); - sourcePeriodOffsets[i] = periodCount; + Assertions.checkState(periodCount <= Integer.MAX_VALUE, + "ConcatenatingMediaSource children contain too many periods"); + sourcePeriodOffsets[i] = (int) periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index b26ae3a6ac..8b14c78234 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -29,6 +29,13 @@ 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; @@ -50,8 +57,8 @@ public final class LoopingMediaSource implements MediaSource { * * @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 value that can achieved without causing the number of - * periods exposed by the source to exceed {@link Integer#MAX_VALUE}. + * 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}. */ public LoopingMediaSource(MediaSource childSource, int loopCount) { Assertions.checkArgument(loopCount > 0); @@ -101,8 +108,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 overflow. - int maxLoopCount = Integer.MAX_VALUE / childPeriodCount; + // 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);