Search in sources :

Example 31 with Timeline

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);
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Example 32 with Timeline

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);
    }
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Example 33 with Timeline

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;
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Example 34 with Timeline

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);
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Example 35 with Timeline

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);
}
Also used : DefaultShuffleOrder(com.google.android.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder) Util(com.google.android.exoplayer2.util.Util) LoadEventInfo(com.google.android.exoplayer2.source.LoadEventInfo) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) PlayerId(com.google.android.exoplayer2.analytics.PlayerId) DrmSessionEventListener(com.google.android.exoplayer2.drm.DrmSessionEventListener) Log(com.google.android.exoplayer2.util.Log) Handler(android.os.Handler) MediaPeriod(com.google.android.exoplayer2.source.MediaPeriod) Map(java.util.Map) ShuffleOrder(com.google.android.exoplayer2.source.ShuffleOrder) MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener) MediaSource(com.google.android.exoplayer2.source.MediaSource) Allocator(com.google.android.exoplayer2.upstream.Allocator) TransferListener(com.google.android.exoplayer2.upstream.TransferListener) IdentityHashMap(java.util.IdentityHashMap) Iterator(java.util.Iterator) Set(java.util.Set) IOException(java.io.IOException) Math.min(java.lang.Math.min) DrmSession(com.google.android.exoplayer2.drm.DrmSession) List(java.util.List) Nullable(androidx.annotation.Nullable) MaskingMediaPeriod(com.google.android.exoplayer2.source.MaskingMediaPeriod) MaskingMediaSource(com.google.android.exoplayer2.source.MaskingMediaSource) Math.max(java.lang.Math.max) MediaLoadData(com.google.android.exoplayer2.source.MediaLoadData) AnalyticsCollector(com.google.android.exoplayer2.analytics.AnalyticsCollector) Assertions(com.google.android.exoplayer2.util.Assertions) MediaSource(com.google.android.exoplayer2.source.MediaSource) MaskingMediaSource(com.google.android.exoplayer2.source.MaskingMediaSource)

Aggregations

Test (org.junit.Test)347 FakeTimeline (com.google.android.exoplayer2.testutil.FakeTimeline)246 Timeline (com.google.android.exoplayer2.Timeline)163 FakeMediaSource (com.google.android.exoplayer2.testutil.FakeMediaSource)140 SinglePeriodTimeline (com.google.android.exoplayer2.source.SinglePeriodTimeline)125 NoUidTimeline (com.google.android.exoplayer2.testutil.NoUidTimeline)110 TestExoPlayerBuilder (com.google.android.exoplayer2.testutil.TestExoPlayerBuilder)109 TimelineWindowDefinition (com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition)89 MediaPeriodId (com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)85 TrackGroupArray (com.google.android.exoplayer2.source.TrackGroupArray)79 ActionSchedule (com.google.android.exoplayer2.testutil.ActionSchedule)74 ExoPlayerTestRunner (com.google.android.exoplayer2.testutil.ExoPlayerTestRunner)60 Format (com.google.android.exoplayer2.Format)49 MediaSource (com.google.android.exoplayer2.source.MediaSource)47 AdPlaybackState (com.google.android.exoplayer2.source.ads.AdPlaybackState)44 ConcatenatingMediaSource (com.google.android.exoplayer2.source.ConcatenatingMediaSource)38 PlayerRunnable (com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable)36 EventTime (com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime)35 MediaItem (com.google.android.exoplayer2.MediaItem)34 RendererCapabilities (com.google.android.exoplayer2.RendererCapabilities)33