diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 22205e77f4..cc338385cd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -676,7 +676,7 @@ import java.util.Collections; MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod(); MediaPeriodHolder newPlayingPeriodHolder = oldPlayingPeriodHolder; while (newPlayingPeriodHolder != null) { - if (shouldKeepPeriodHolder(periodId, periodPositionUs, newPlayingPeriodHolder)) { + if (periodId.equals(newPlayingPeriodHolder.info.id) && newPlayingPeriodHolder.prepared) { queue.removeAfter(newPlayingPeriodHolder); break; } @@ -712,19 +712,6 @@ import java.util.Collections; return periodPositionUs; } - private boolean shouldKeepPeriodHolder( - MediaPeriodId seekPeriodId, long positionUs, MediaPeriodHolder holder) { - if (seekPeriodId.equals(holder.info.id) && holder.prepared) { - playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period); - int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs); - if (nextAdGroupIndex == C.INDEX_UNSET - || period.getAdGroupTimeUs(nextAdGroupIndex) == holder.info.endPositionUs) { - return true; - } - } - return false; - } - private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackException { rendererPositionUs = !queue.hasPlayingPeriod() diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java index c4d69b7e7a..d9dde9d4e8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java @@ -82,13 +82,13 @@ import com.google.android.exoplayer2.util.Assertions; sampleStreams = new SampleStream[rendererCapabilities.length]; mayRetainStreamFlags = new boolean[rendererCapabilities.length]; MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator); - if (info.endPositionUs != C.TIME_END_OF_SOURCE) { + if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) { mediaPeriod = new ClippingMediaPeriod( mediaPeriod, /* enableInitialDiscontinuity= */ true, /* startUs= */ 0, - info.endPositionUs); + info.id.endPositionUs); } this.mediaPeriod = mediaPeriod; } @@ -219,7 +219,7 @@ import com.google.android.exoplayer2.util.Assertions; public void release() { updatePeriodTrackSelectorResult(null); try { - if (info.endPositionUs != C.TIME_END_OF_SOURCE) { + if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) { mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod); } else { mediaSource.releasePeriod(mediaPeriod); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java index fce1780b71..b887e8222e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfo.java @@ -25,18 +25,13 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; public final MediaPeriodId id; /** The start position of the media to play within the media period, in microseconds. */ public final long startPositionUs; - /** - * The end position of the media to play within the media period, in microseconds, or {@link - * C#TIME_END_OF_SOURCE} if the end position is the end of the media period. - */ - public final long endPositionUs; /** * If this is an ad, the position to play in the next content media period. {@link C#TIME_UNSET} * otherwise. */ public final long contentPositionUs; /** - * The duration of the media period, like {@link #endPositionUs} but with {@link + * The duration of the media period, like {@link MediaPeriodId#endPositionUs} but with {@link * C#TIME_END_OF_SOURCE} resolved to the timeline period duration. May be {@link C#TIME_UNSET} if * the end position is not known. */ @@ -55,14 +50,12 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; MediaPeriodInfo( MediaPeriodId id, long startPositionUs, - long endPositionUs, long contentPositionUs, long durationUs, boolean isLastInTimelinePeriod, boolean isFinal) { this.id = id; this.startPositionUs = startPositionUs; - this.endPositionUs = endPositionUs; this.contentPositionUs = contentPositionUs; this.durationUs = durationUs; this.isLastInTimelinePeriod = isLastInTimelinePeriod; @@ -77,7 +70,6 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; return new MediaPeriodInfo( id.copyWithPeriodIndex(periodIndex), startPositionUs, - endPositionUs, contentPositionUs, durationUs, isLastInTimelinePeriod, @@ -89,7 +81,6 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; return new MediaPeriodInfo( id, startPositionUs, - endPositionUs, contentPositionUs, durationUs, isLastInTimelinePeriod, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java index 17a8ddd8d4..010de547a2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java @@ -391,7 +391,12 @@ import com.google.android.exoplayer2.util.Assertions; timeline.getPeriod(periodIndex, period); int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); if (adGroupIndex == C.INDEX_UNSET) { - return new MediaPeriodId(periodIndex, windowSequenceNumber); + int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs); + long endPositionUs = + nextAdGroupIndex == C.INDEX_UNSET + ? C.TIME_END_OF_SOURCE + : period.getAdGroupTimeUs(nextAdGroupIndex); + return new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs); } else { int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex); return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); @@ -450,7 +455,6 @@ import com.google.android.exoplayer2.util.Assertions; private boolean canKeepMediaPeriodHolder(MediaPeriodHolder periodHolder, MediaPeriodInfo info) { MediaPeriodInfo periodHolderInfo = periodHolder.info; return periodHolderInfo.startPositionUs == info.startPositionUs - && periodHolderInfo.endPositionUs == info.endPositionUs && periodHolderInfo.id.equals(info.id); } @@ -593,14 +597,14 @@ import com.google.android.exoplayer2.util.Assertions; mediaPeriodInfo.contentPositionUs, currentPeriodId.windowSequenceNumber); } - } else if (mediaPeriodInfo.endPositionUs != C.TIME_END_OF_SOURCE) { + } else if (mediaPeriodInfo.id.endPositionUs != C.TIME_END_OF_SOURCE) { // Play the next ad group if it's available. - int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(mediaPeriodInfo.endPositionUs); + int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(mediaPeriodInfo.id.endPositionUs); if (nextAdGroupIndex == C.INDEX_UNSET) { // The next ad group can't be played. Play content from the ad group position instead. return getMediaPeriodInfoForContent( currentPeriodId.periodIndex, - mediaPeriodInfo.endPositionUs, + mediaPeriodInfo.id.endPositionUs, currentPeriodId.windowSequenceNumber); } int adIndexInAdGroup = period.getFirstAdIndexToPlay(nextAdGroupIndex); @@ -610,7 +614,7 @@ import com.google.android.exoplayer2.util.Assertions; currentPeriodId.periodIndex, nextAdGroupIndex, adIndexInAdGroup, - mediaPeriodInfo.endPositionUs, + mediaPeriodInfo.id.endPositionUs, currentPeriodId.windowSequenceNumber); } else { // Check if the postroll ad should be played. @@ -639,18 +643,18 @@ import com.google.android.exoplayer2.util.Assertions; private MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info, MediaPeriodId newId) { long startPositionUs = info.startPositionUs; - long endPositionUs = info.endPositionUs; - boolean isLastInPeriod = isLastInPeriod(newId, endPositionUs); + boolean isLastInPeriod = isLastInPeriod(newId); boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod); timeline.getPeriod(newId.periodIndex, period); long durationUs = newId.isAd() ? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup) - : (endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs); + : (newId.endPositionUs == C.TIME_END_OF_SOURCE + ? period.getDurationUs() + : newId.endPositionUs); return new MediaPeriodInfo( newId, startPositionUs, - endPositionUs, info.contentPositionUs, durationUs, isLastInPeriod, @@ -683,7 +687,7 @@ import com.google.android.exoplayer2.util.Assertions; long windowSequenceNumber) { MediaPeriodId id = new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); - boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE); + boolean isLastInPeriod = isLastInPeriod(id); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); long durationUs = timeline @@ -696,7 +700,6 @@ import com.google.android.exoplayer2.util.Assertions; return new MediaPeriodInfo( id, startPositionUs, - C.TIME_END_OF_SOURCE, contentPositionUs, durationUs, isLastInPeriod, @@ -705,21 +708,22 @@ import com.google.android.exoplayer2.util.Assertions; private MediaPeriodInfo getMediaPeriodInfoForContent( int periodIndex, long startPositionUs, long windowSequenceNumber) { - MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber); - timeline.getPeriod(id.periodIndex, period); int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs); - long endUs = + long endPositionUs = nextAdGroupIndex == C.INDEX_UNSET ? C.TIME_END_OF_SOURCE : period.getAdGroupTimeUs(nextAdGroupIndex); - boolean isLastInPeriod = isLastInPeriod(id, endUs); + MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs); + timeline.getPeriod(id.periodIndex, period); + boolean isLastInPeriod = isLastInPeriod(id); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); - long durationUs = endUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endUs; + long durationUs = + endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs; return new MediaPeriodInfo( - id, startPositionUs, endUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline); + id, startPositionUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline); } - private boolean isLastInPeriod(MediaPeriodId id, long endPositionUs) { + private boolean isLastInPeriod(MediaPeriodId id) { int adGroupCount = timeline.getPeriod(id.periodIndex, period).getAdGroupCount(); if (adGroupCount == 0) { return true; @@ -729,7 +733,7 @@ import com.google.android.exoplayer2.util.Assertions; boolean isAd = id.isAd(); if (period.getAdGroupTimeUs(lastAdGroupIndex) != C.TIME_END_OF_SOURCE) { // There's no postroll ad. - return !isAd && endPositionUs == C.TIME_END_OF_SOURCE; + return !isAd && id.endPositionUs == C.TIME_END_OF_SOURCE; } int postrollAdCount = period.getAdCountInAdGroup(lastAdGroupIndex); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 1590235d15..241d19143f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -91,6 +91,15 @@ public interface MediaSource { */ public final long windowSequenceNumber; + /** + * The end position of the media to play within the media period, in microseconds, or {@link + * C#TIME_END_OF_SOURCE} if the end position is the end of the media period. + * + *
Note that this only applies if the media period is for content (i.e., not for an ad) and + * is clipped to the position of the next ad group. + */ + public final long endPositionUs; + /** * Creates a media period identifier for a dummy period which is not part of a buffered sequence * of windows. @@ -109,7 +118,20 @@ public interface MediaSource { * windows this media period is part of. */ public MediaPeriodId(int periodIndex, long windowSequenceNumber) { - this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber); + this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, C.TIME_END_OF_SOURCE); + } + + /** + * Creates a media period identifier for the specified clipped period in the timeline. + * + * @param periodIndex The timeline period index. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. + * @param endPositionUs The end position of the media period within the timeline period, in + * microseconds. + */ + public MediaPeriodId(int periodIndex, long windowSequenceNumber, long endPositionUs) { + this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, endPositionUs); } /** @@ -124,10 +146,20 @@ public interface MediaSource { */ public MediaPeriodId( int periodIndex, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) { + this(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, C.TIME_END_OF_SOURCE); + } + + private MediaPeriodId( + int periodIndex, + int adGroupIndex, + int adIndexInAdGroup, + long windowSequenceNumber, + long endPositionUs) { this.periodIndex = periodIndex; this.adGroupIndex = adGroupIndex; this.adIndexInAdGroup = adIndexInAdGroup; this.windowSequenceNumber = windowSequenceNumber; + this.endPositionUs = endPositionUs; } /** @@ -136,7 +168,8 @@ public interface MediaSource { public MediaPeriodId copyWithPeriodIndex(int newPeriodIndex) { return periodIndex == newPeriodIndex ? this - : new MediaPeriodId(newPeriodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); + : new MediaPeriodId( + newPeriodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, endPositionUs); } /** @@ -159,7 +192,8 @@ public interface MediaSource { return periodIndex == periodId.periodIndex && adGroupIndex == periodId.adGroupIndex && adIndexInAdGroup == periodId.adIndexInAdGroup - && windowSequenceNumber == periodId.windowSequenceNumber; + && windowSequenceNumber == periodId.windowSequenceNumber + && endPositionUs == periodId.endPositionUs; } @Override @@ -169,6 +203,7 @@ public interface MediaSource { result = 31 * result + adGroupIndex; result = 31 * result + adIndexInAdGroup; result = 31 * result + (int) windowSequenceNumber; + result = 31 * result + (int) endPositionUs; return result; }