use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class ExoPlayerImplInternal method getPlaceholderFirstMediaPeriodPositionUs.
private Pair<MediaPeriodId, Long> getPlaceholderFirstMediaPeriodPositionUs(Timeline timeline) {
if (timeline.isEmpty()) {
return Pair.create(PlaybackInfo.getDummyPeriodForEmptyTimeline(), 0L);
}
int firstWindowIndex = timeline.getFirstWindowIndex(shuffleModeEnabled);
Pair<Object, Long> firstPeriodAndPositionUs = timeline.getPeriodPositionUs(window, period, firstWindowIndex, /* windowPositionUs= */
C.TIME_UNSET);
// Add ad metadata if any and propagate the window sequence number to new period id.
MediaPeriodId firstPeriodId = queue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(timeline, firstPeriodAndPositionUs.first, /* positionUs= */
0);
long positionUs = firstPeriodAndPositionUs.second;
if (firstPeriodId.isAd()) {
timeline.getPeriodByUid(firstPeriodId.periodUid, period);
positionUs = firstPeriodId.adIndexInAdGroup == period.getFirstAdIndexToPlay(firstPeriodId.adGroupIndex) ? period.getAdResumePositionUs() : 0;
}
return Pair.create(firstPeriodId, positionUs);
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class ExoPlayerImplInternal method handleMediaSourceListInfoRefreshed.
private void handleMediaSourceListInfoRefreshed(Timeline timeline, boolean isSourceRefresh) throws ExoPlaybackException {
PositionUpdateForPlaylistChange positionUpdate = resolvePositionForPlaylistChange(timeline, playbackInfo, pendingInitialSeekPosition, queue, repeatMode, shuffleModeEnabled, window, period);
MediaPeriodId newPeriodId = positionUpdate.periodId;
long newRequestedContentPositionUs = positionUpdate.requestedContentPositionUs;
boolean forceBufferingState = positionUpdate.forceBufferingState;
long newPositionUs = positionUpdate.periodPositionUs;
boolean periodPositionChanged = !playbackInfo.periodId.equals(newPeriodId) || newPositionUs != playbackInfo.positionUs;
try {
if (positionUpdate.endPlayback) {
if (playbackInfo.playbackState != Player.STATE_IDLE) {
setState(Player.STATE_ENDED);
}
resetInternal(/* resetRenderers= */
false, /* resetPosition= */
false, /* releaseMediaSourceList= */
false, /* resetError= */
true);
}
if (!periodPositionChanged) {
// We can keep the current playing period. Update the rest of the queued periods.
if (!queue.updateQueuedPeriods(timeline, rendererPositionUs, getMaxRendererReadPositionUs())) {
seekToCurrentPosition(/* sendDiscontinuity= */
false);
}
} else if (!timeline.isEmpty()) {
// Something changed. Seek to new start position.
@Nullable MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
while (periodHolder != null) {
// Update the new playing media period info if it already exists.
if (periodHolder.info.id.equals(newPeriodId)) {
periodHolder.info = queue.getUpdatedMediaPeriodInfo(timeline, periodHolder.info);
periodHolder.updateClipping();
}
periodHolder = periodHolder.getNext();
}
newPositionUs = seekToPeriodPosition(newPeriodId, newPositionUs, forceBufferingState);
}
} finally {
updatePlaybackSpeedSettingsForNewPeriod(/* newTimeline= */
timeline, newPeriodId, /* oldTimeline= */
playbackInfo.timeline, /* oldPeriodId= */
playbackInfo.periodId, /* positionForTargetOffsetOverrideUs */
positionUpdate.setTargetLiveOffset ? newPositionUs : C.TIME_UNSET);
if (periodPositionChanged || newRequestedContentPositionUs != playbackInfo.requestedContentPositionUs) {
Object oldPeriodUid = playbackInfo.periodId.periodUid;
Timeline oldTimeline = playbackInfo.timeline;
boolean reportDiscontinuity = periodPositionChanged && isSourceRefresh && !oldTimeline.isEmpty() && !oldTimeline.getPeriodByUid(oldPeriodUid, period).isPlaceholder;
playbackInfo = handlePositionDiscontinuity(newPeriodId, newPositionUs, newRequestedContentPositionUs, playbackInfo.discontinuityStartPositionUs, reportDiscontinuity, timeline.getIndexOfPeriod(oldPeriodUid) == C.INDEX_UNSET ? Player.DISCONTINUITY_REASON_REMOVE : Player.DISCONTINUITY_REASON_SKIP);
}
resetPendingPauseAtEndOfPeriod();
resolvePendingMessagePositions(/* newTimeline= */
timeline, /* previousTimeline= */
playbackInfo.timeline);
playbackInfo = playbackInfo.copyWithTimeline(timeline);
if (!timeline.isEmpty()) {
// Retain pending seek position only while the timeline is still empty.
pendingInitialSeekPosition = null;
}
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */
false);
}
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class ExoPlayerImpl method maskTimelineAndPosition.
private PlaybackInfo maskTimelineAndPosition(PlaybackInfo playbackInfo, Timeline timeline, @Nullable Pair<Object, Long> periodPositionUs) {
Assertions.checkArgument(timeline.isEmpty() || periodPositionUs != null);
Timeline oldTimeline = playbackInfo.timeline;
// Mask the timeline.
playbackInfo = playbackInfo.copyWithTimeline(timeline);
if (timeline.isEmpty()) {
// Reset periodId and loadingPeriodId.
MediaPeriodId dummyMediaPeriodId = PlaybackInfo.getDummyPeriodForEmptyTimeline();
long positionUs = Util.msToUs(maskingWindowPositionMs);
playbackInfo = playbackInfo.copyWithNewPosition(dummyMediaPeriodId, positionUs, /* requestedContentPositionUs= */
positionUs, /* discontinuityStartPositionUs= */
positionUs, /* totalBufferedDurationUs= */
0, TrackGroupArray.EMPTY, emptyTrackSelectorResult, /* staticMetadata= */
ImmutableList.of());
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(dummyMediaPeriodId);
playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
return playbackInfo;
}
Object oldPeriodUid = playbackInfo.periodId.periodUid;
boolean playingPeriodChanged = !oldPeriodUid.equals(castNonNull(periodPositionUs).first);
MediaPeriodId newPeriodId = playingPeriodChanged ? new MediaPeriodId(periodPositionUs.first) : playbackInfo.periodId;
long newContentPositionUs = periodPositionUs.second;
long oldContentPositionUs = Util.msToUs(getContentPosition());
if (!oldTimeline.isEmpty()) {
oldContentPositionUs -= oldTimeline.getPeriodByUid(oldPeriodUid, period).getPositionInWindowUs();
}
if (playingPeriodChanged || newContentPositionUs < oldContentPositionUs) {
checkState(!newPeriodId.isAd());
// The playing period changes or a backwards seek within the playing period occurs.
playbackInfo = playbackInfo.copyWithNewPosition(newPeriodId, /* positionUs= */
newContentPositionUs, /* requestedContentPositionUs= */
newContentPositionUs, /* discontinuityStartPositionUs= */
newContentPositionUs, /* totalBufferedDurationUs= */
0, playingPeriodChanged ? TrackGroupArray.EMPTY : playbackInfo.trackGroups, playingPeriodChanged ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult, playingPeriodChanged ? ImmutableList.of() : playbackInfo.staticMetadata);
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(newPeriodId);
playbackInfo.bufferedPositionUs = newContentPositionUs;
} else if (newContentPositionUs == oldContentPositionUs) {
// Period position remains unchanged.
int loadingPeriodIndex = timeline.getIndexOfPeriod(playbackInfo.loadingMediaPeriodId.periodUid);
if (loadingPeriodIndex == C.INDEX_UNSET || timeline.getPeriod(loadingPeriodIndex, period).windowIndex != timeline.getPeriodByUid(newPeriodId.periodUid, period).windowIndex) {
// Discard periods after the playing period, if the loading period is discarded or the
// playing and loading period are not in the same window.
timeline.getPeriodByUid(newPeriodId.periodUid, period);
long maskedBufferedPositionUs = newPeriodId.isAd() ? period.getAdDurationUs(newPeriodId.adGroupIndex, newPeriodId.adIndexInAdGroup) : period.durationUs;
playbackInfo = playbackInfo.copyWithNewPosition(newPeriodId, /* positionUs= */
playbackInfo.positionUs, /* requestedContentPositionUs= */
playbackInfo.positionUs, playbackInfo.discontinuityStartPositionUs, /* totalBufferedDurationUs= */
maskedBufferedPositionUs - playbackInfo.positionUs, playbackInfo.trackGroups, playbackInfo.trackSelectorResult, playbackInfo.staticMetadata);
playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(newPeriodId);
playbackInfo.bufferedPositionUs = maskedBufferedPositionUs;
}
} else {
checkState(!newPeriodId.isAd());
// A forward seek within the playing period (timeline did not change).
long maskedTotalBufferedDurationUs = max(0, playbackInfo.totalBufferedDurationUs - (newContentPositionUs - oldContentPositionUs));
long maskedBufferedPositionUs = playbackInfo.bufferedPositionUs;
if (playbackInfo.loadingMediaPeriodId.equals(playbackInfo.periodId)) {
maskedBufferedPositionUs = newContentPositionUs + maskedTotalBufferedDurationUs;
}
playbackInfo = playbackInfo.copyWithNewPosition(newPeriodId, /* positionUs= */
newContentPositionUs, /* requestedContentPositionUs= */
newContentPositionUs, /* discontinuityStartPositionUs= */
newContentPositionUs, maskedTotalBufferedDurationUs, playbackInfo.trackGroups, playbackInfo.trackSelectorResult, playbackInfo.staticMetadata);
playbackInfo.bufferedPositionUs = maskedBufferedPositionUs;
}
return playbackInfo;
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class MediaPeriodQueue method getUpdatedMediaPeriodInfo.
/**
* Returns new media period info based on specified {@code mediaPeriodInfo} but taking into
* account the current timeline. This method must only be called if the period is still part of
* the current timeline.
*
* @param timeline The current timeline used to update the media period.
* @param info Media period info for a media period based on an old timeline.
* @return The updated media period info for the current timeline.
*/
public MediaPeriodInfo getUpdatedMediaPeriodInfo(Timeline timeline, MediaPeriodInfo info) {
MediaPeriodId id = info.id;
boolean isLastInPeriod = isLastInPeriod(id);
boolean isLastInWindow = isLastInWindow(timeline, id);
boolean isLastInTimeline = isLastInTimeline(timeline, id, isLastInPeriod);
timeline.getPeriodByUid(info.id.periodUid, period);
long endPositionUs = id.isAd() || id.nextAdGroupIndex == C.INDEX_UNSET ? C.TIME_UNSET : period.getAdGroupTimeUs(id.nextAdGroupIndex);
long durationUs = id.isAd() ? period.getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup) : (endPositionUs == C.TIME_UNSET || endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs);
boolean isFollowedByTransitionToSameStream = id.isAd() ? period.isServerSideInsertedAdGroup(id.adGroupIndex) : (id.nextAdGroupIndex != C.INDEX_UNSET && period.isServerSideInsertedAdGroup(id.nextAdGroupIndex));
return new MediaPeriodInfo(id, info.startPositionUs, info.requestedContentPositionUs, endPositionUs, durationUs, isFollowedByTransitionToSameStream, isLastInPeriod, isLastInWindow, isLastInTimeline);
}
use of com.google.android.exoplayer2.Timeline in project ExoPlayer by google.
the class MediaSourceList method prepareChildSource.
private void prepareChildSource(MediaSourceHolder holder) {
MediaSource mediaSource = holder.mediaSource;
MediaSource.MediaSourceCaller caller = (source, timeline) -> mediaSourceListInfoListener.onPlaylistUpdateRequested();
ForwardingEventListener eventListener = new ForwardingEventListener(holder);
childSources.put(holder, new MediaSourceAndListener(mediaSource, caller, eventListener));
mediaSource.addEventListener(Util.createHandlerForCurrentOrMainLooper(), eventListener);
mediaSource.addDrmEventListener(Util.createHandlerForCurrentOrMainLooper(), eventListener);
mediaSource.prepareSource(caller, mediaTransferListener, playerId);
}
Aggregations