diff --git a/library/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/src/main/java/com/google/android/exoplayer2/Timeline.java index 1cc2773ad5..e0ac0d2b2b 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -62,13 +62,7 @@ public interface Timeline { /** * Returns a unique identifier for the period at {@code periodIndex}, or {@code null} if the * period at {@code periodIndex} is not known. The identifier is stable across {@link Timeline} - * instances. - *

- * When the timeline changes the player uses period identifiers to determine what periods are - * unchanged. Implementations that associate an object with each period can return the object for - * the provided index to guarantee uniqueness. Other implementations must be careful to return - * identifiers that can't clash with (for example) identifiers used by other timelines that may be - * concatenated with this one. + * changes. * * @param periodIndex A period index. * @return An identifier for the period, or {@code null} if the period is not known. @@ -79,7 +73,7 @@ public interface Timeline { * Returns the index of the window to which the period with the specified index belongs. * * @param periodIndex The period index. - * @return The index of the corresponding seek window. + * @return The index of the corresponding window. */ int getPeriodWindowIndex(int periodIndex); diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 66d3011f06..ba10f06f02 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -210,17 +210,22 @@ public final class ConcatenatingMediaSource implements MediaSource { @Override public int getIndexOfPeriod(Object id) { - // The id was returned by getPeriodId, so it is always a Pair. + if (!(id instanceof Pair)) { + return NO_PERIOD_INDEX; + } @SuppressWarnings("unchecked") Pair sourceIndexAndPeriodId = (Pair) id; + if (!(sourceIndexAndPeriodId.first instanceof Integer)) { + return NO_PERIOD_INDEX; + } int sourceIndex = sourceIndexAndPeriodId.first; Object periodId = sourceIndexAndPeriodId.second; - int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(periodId); - if (periodIndexInSource != NO_PERIOD_INDEX) { - int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); - return firstPeriodIndexInSource + periodIndexInSource; + if (sourceIndex < 0 || sourceIndex >= timelines.length) { + return NO_PERIOD_INDEX; } - return NO_PERIOD_INDEX; + int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(periodId); + return periodIndexInSource == NO_PERIOD_INDEX ? NO_PERIOD_INDEX + : getFirstPeriodIndexInSource(sourceIndex) + periodIndexInSource; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index ce6aef1c67..3a7c6a1c63 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -298,7 +298,7 @@ import java.util.Arrays; durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0 : largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US; sourceListener.onSourceInfoRefreshed( - new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null); + new SinglePeriodTimeline(durationUs, seekMap.isSeekable()), null); } } @@ -381,7 +381,7 @@ import java.util.Arrays; tracks = new TrackGroupArray(trackArray); prepared = true; sourceListener.onSourceInfoRefreshed( - new SinglePeriodTimeline(0, durationUs, seekMap.isSeekable()), null); + new SinglePeriodTimeline(durationUs, seekMap.isSeekable()), null); callback.onPrepared(this); } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index 67645925d6..e1a0d3c140 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -135,7 +135,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List @Override public void prepareSource(MediaSource.Listener listener) { sourceListener = listener; - timeline = new SinglePeriodTimeline(0, C.UNSET_TIME_US, false); + timeline = new SinglePeriodTimeline(C.UNSET_TIME_US, false); listener.onSourceInfoRefreshed(timeline, null); } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java b/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java index 3544468810..d29cbbb8a3 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java @@ -26,7 +26,8 @@ import com.google.android.exoplayer2.util.Assertions; */ public final class SinglePeriodTimeline implements Timeline { - private final Object id; + private static final Object ID = new Object(); + private final boolean isFinal; private final long durationUs; private final Window window; @@ -35,24 +36,21 @@ public final class SinglePeriodTimeline implements Timeline { * Creates a final timeline with one period of known duration and a window extending from * zero to its duration. * - * @param id The identifier for the period. * @param durationUs The duration of the period, in microseconds. * @param isSeekable Whether seeking is supported within the period. */ - public SinglePeriodTimeline(Object id, long durationUs, boolean isSeekable) { - this(id, durationUs, Window.createWindowFromZero(durationUs, isSeekable)); + public SinglePeriodTimeline(long durationUs, boolean isSeekable) { + this(durationUs, Window.createWindowFromZero(durationUs, isSeekable)); } /** * Creates a final timeline with one period of known duration and a window extending from * zero to its duration. * - * @param id The identifier for the period. * @param durationUs The duration of the period, in microseconds. * @param window The available window within the period. */ - public SinglePeriodTimeline(Object id, long durationUs, Window window) { - this.id = Assertions.checkNotNull(id); + public SinglePeriodTimeline(long durationUs, Window window) { this.durationUs = durationUs; this.window = window; this.isFinal = true; // TODO: Remove. @@ -88,7 +86,7 @@ public final class SinglePeriodTimeline implements Timeline { @Override public Object getPeriodId(int periodIndex) { Assertions.checkIndex(periodIndex, 0, 1); - return id; + return ID; } @Override @@ -99,7 +97,7 @@ public final class SinglePeriodTimeline implements Timeline { @Override public int getIndexOfPeriod(Object id) { - return id.equals(this.id) ? 0 : Timeline.NO_PERIOD_INDEX; + return ID.equals(id) ? 0 : Timeline.NO_PERIOD_INDEX; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index d924aaa0fd..876a89d05b 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -79,7 +79,7 @@ public final class SingleSampleMediaSource implements MediaSource { this.eventHandler = eventHandler; this.eventListener = eventListener; this.eventSourceId = eventSourceId; - timeline = new SinglePeriodTimeline(0, durationUs, true); + timeline = new SinglePeriodTimeline(durationUs, true); } // MediaSource implementation. diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 13bf9f305b..3a9e738a12 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -539,7 +539,12 @@ public final class DashMediaSource implements MediaSource { @Override public int getIndexOfPeriod(Object id) { - return ((Integer) id) - firstPeriodId; + if (!(id instanceof Integer)) { + return NO_PERIOD_INDEX; + } + int periodId = (int) id; + return periodId < firstPeriodId || periodId >= firstPeriodId + getPeriodCount() + ? NO_PERIOD_INDEX : periodId - firstPeriodId; } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index bdb5c928ba..5f62400d01 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -281,7 +281,7 @@ import java.util.List; callback.onPrepared(this); // TODO[playlists]: Calculate the window. - Timeline timeline = new SinglePeriodTimeline(0, durationUs, !isLive); + Timeline timeline = new SinglePeriodTimeline(durationUs, !isLive); sourceListener.onSourceInfoRefreshed(timeline, playlist); } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 6673d47e1b..086ea61689 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -65,8 +65,7 @@ public final class HlsMediaSource implements MediaSource { public void prepareSource(MediaSource.Listener listener) { sourceListener = listener; // TODO: Defer until the playlist has been loaded. - listener.onSourceInfoRefreshed( - new SinglePeriodTimeline(this, C.UNSET_TIME_US, false), null); + listener.onSourceInfoRefreshed(new SinglePeriodTimeline(C.UNSET_TIME_US, false), null); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 0293192fde..2b53390095 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -185,16 +185,16 @@ public final class SsMediaSource implements MediaSource, } if (startTimeUs == Long.MAX_VALUE || manifest.dvrWindowLengthUs == C.UNSET_TIME_US || manifest.dvrWindowLengthUs == 0) { - timeline = new SinglePeriodTimeline(0, C.UNSET_TIME_US, false); + timeline = new SinglePeriodTimeline(C.UNSET_TIME_US, false); } else { long periodDurationUs = startTimeUs + manifest.dvrWindowLengthUs; Window window = Window.createWindow(0, startTimeUs, 0, periodDurationUs, manifest.dvrWindowLengthUs, true); - timeline = new SinglePeriodTimeline(0, periodDurationUs, window); + timeline = new SinglePeriodTimeline(periodDurationUs, window); } } else { boolean isSeekable = manifest.durationUs != C.UNSET_TIME_US; - timeline = new SinglePeriodTimeline(0, manifest.durationUs, isSeekable); + timeline = new SinglePeriodTimeline(manifest.durationUs, isSeekable); } window = timeline.getWindow(0); sourceListener.onSourceInfoRefreshed(timeline, manifest);