Search in sources :

Example 71 with MediaPeriodId

use of com.google.android.exoplayer2.source.MediaSource.MediaPeriodId in project ExoPlayer by google.

the class FakeMediaSource method finishSourcePreparation.

private void finishSourcePreparation(boolean sendManifestLoadEvents) {
    refreshSourceInfo(Assertions.checkStateNotNull(timeline));
    if (!timeline.isEmpty() && sendManifestLoadEvents) {
        MediaLoadData mediaLoadData = new MediaLoadData(C.DATA_TYPE_MANIFEST, C.TRACK_TYPE_UNKNOWN, /* trackFormat= */
        null, C.SELECTION_REASON_UNKNOWN, /* trackSelectionData= */
        null, /* mediaStartTimeMs= */
        C.TIME_UNSET, /* mediaEndTimeMs = */
        C.TIME_UNSET);
        long elapsedRealTimeMs = SystemClock.elapsedRealtime();
        MediaSourceEventListener.EventDispatcher eventDispatcher = createEventDispatcher(/* mediaPeriodId= */
        null);
        long loadTaskId = LoadEventInfo.getNewId();
        eventDispatcher.loadStarted(new LoadEventInfo(loadTaskId, FAKE_DATA_SPEC, FAKE_DATA_SPEC.uri, /* responseHeaders= */
        ImmutableMap.of(), elapsedRealTimeMs, /* loadDurationMs= */
        0, /* bytesLoaded= */
        0), mediaLoadData);
        eventDispatcher.loadCompleted(new LoadEventInfo(loadTaskId, FAKE_DATA_SPEC, FAKE_DATA_SPEC.uri, /* responseHeaders= */
        ImmutableMap.of(), elapsedRealTimeMs, /* loadDurationMs= */
        0, /* bytesLoaded= */
        MANIFEST_LOAD_BYTES), mediaLoadData);
    }
}
Also used : MediaLoadData(com.google.android.exoplayer2.source.MediaLoadData) LoadEventInfo(com.google.android.exoplayer2.source.LoadEventInfo) MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener)

Example 72 with MediaPeriodId

use of com.google.android.exoplayer2.source.MediaSource.MediaPeriodId in project ExoPlayer by google.

the class FakeMediaSource method createPeriod.

@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
    assertThat(preparedSource).isTrue();
    assertThat(releasedSource).isFalse();
    int periodIndex = castNonNull(timeline).getIndexOfPeriod(id.periodUid);
    Assertions.checkArgument(periodIndex != C.INDEX_UNSET);
    Period period = timeline.getPeriod(periodIndex, new Period());
    MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher = createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs());
    DrmSessionEventListener.EventDispatcher drmEventDispatcher = createDrmEventDispatcher(period.windowIndex, id);
    MediaPeriod mediaPeriod = createMediaPeriod(id, trackGroupArray, allocator, mediaSourceEventDispatcher, drmSessionManager, drmEventDispatcher, transferListener);
    activeMediaPeriods.add(mediaPeriod);
    createdMediaPeriods.add(id);
    return mediaPeriod;
}
Also used : MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener) MediaPeriod(com.google.android.exoplayer2.source.MediaPeriod) Period(com.google.android.exoplayer2.Timeline.Period) MediaPeriod(com.google.android.exoplayer2.source.MediaPeriod) DrmSessionEventListener(com.google.android.exoplayer2.drm.DrmSessionEventListener)

Example 73 with MediaPeriodId

use of com.google.android.exoplayer2.source.MediaSource.MediaPeriodId in project ExoPlayer by google.

the class MediaPeriodQueue method getMediaPeriodInfoForContent.

private MediaPeriodInfo getMediaPeriodInfoForContent(Timeline timeline, Object periodUid, long startPositionUs, long requestedContentPositionUs, long windowSequenceNumber) {
    timeline.getPeriodByUid(periodUid, period);
    int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs);
    boolean clipPeriodAtContentDuration = false;
    if (nextAdGroupIndex == C.INDEX_UNSET) {
        // Clip SSAI streams when at the end of the period.
        clipPeriodAtContentDuration = period.getAdGroupCount() > 0 && period.isServerSideInsertedAdGroup(period.getRemovedAdGroupCount());
    } else if (period.isServerSideInsertedAdGroup(nextAdGroupIndex) && period.getAdGroupTimeUs(nextAdGroupIndex) == period.durationUs) {
        if (period.hasPlayedAdGroup(nextAdGroupIndex)) {
            // Clip period before played SSAI post-rolls.
            nextAdGroupIndex = C.INDEX_UNSET;
            clipPeriodAtContentDuration = true;
        }
    }
    MediaPeriodId id = new MediaPeriodId(periodUid, windowSequenceNumber, nextAdGroupIndex);
    boolean isLastInPeriod = isLastInPeriod(id);
    boolean isLastInWindow = isLastInWindow(timeline, id);
    boolean isLastInTimeline = isLastInTimeline(timeline, id, isLastInPeriod);
    boolean isFollowedByTransitionToSameStream = nextAdGroupIndex != C.INDEX_UNSET && period.isServerSideInsertedAdGroup(nextAdGroupIndex);
    long endPositionUs = nextAdGroupIndex != C.INDEX_UNSET ? period.getAdGroupTimeUs(nextAdGroupIndex) : clipPeriodAtContentDuration ? period.durationUs : C.TIME_UNSET;
    long durationUs = endPositionUs == C.TIME_UNSET || endPositionUs == C.TIME_END_OF_SOURCE ? period.durationUs : endPositionUs;
    if (durationUs != C.TIME_UNSET && startPositionUs >= durationUs) {
        // Ensure start position doesn't exceed duration.
        startPositionUs = max(0, durationUs - 1);
    }
    return new MediaPeriodInfo(id, startPositionUs, requestedContentPositionUs, endPositionUs, durationUs, isFollowedByTransitionToSameStream, isLastInPeriod, isLastInWindow, isLastInTimeline);
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Example 74 with MediaPeriodId

use of com.google.android.exoplayer2.source.MediaSource.MediaPeriodId in project ExoPlayer by google.

the class MediaPeriodQueue method getFollowingMediaPeriodInfo.

/**
 * Returns the {@link MediaPeriodInfo} for the media period following {@code mediaPeriodHolder}'s
 * media period.
 *
 * @param timeline The current timeline.
 * @param mediaPeriodHolder The media period holder.
 * @param rendererPositionUs The current renderer position in microseconds.
 * @return The following media period's info, or {@code null} if it is not yet possible to get the
 *     next media period info.
 */
@Nullable
private MediaPeriodInfo getFollowingMediaPeriodInfo(Timeline timeline, MediaPeriodHolder mediaPeriodHolder, long rendererPositionUs) {
    // TODO: This method is called repeatedly from ExoPlayerImplInternal.maybeUpdateLoadingPeriod
    // but if the timeline is not ready to provide the next period it can't return a non-null value
    // until the timeline is updated. Store whether the next timeline period is ready when the
    // timeline is updated, to avoid repeatedly checking the same timeline.
    MediaPeriodInfo mediaPeriodInfo = mediaPeriodHolder.info;
    // The expected delay until playback transitions to the new period is equal the duration of
    // media that's currently buffered (assuming no interruptions). This is used to project forward
    // the start position for transitions to new windows.
    long bufferedDurationUs = mediaPeriodHolder.getRendererOffset() + mediaPeriodInfo.durationUs - rendererPositionUs;
    if (mediaPeriodInfo.isLastInTimelinePeriod) {
        int currentPeriodIndex = timeline.getIndexOfPeriod(mediaPeriodInfo.id.periodUid);
        int nextPeriodIndex = timeline.getNextPeriodIndex(currentPeriodIndex, period, window, repeatMode, shuffleModeEnabled);
        if (nextPeriodIndex == C.INDEX_UNSET) {
            // We can't create a next period yet.
            return null;
        }
        // We either start a new period in the same window or the first period in the next window.
        long startPositionUs = 0;
        long contentPositionUs = 0;
        int nextWindowIndex = timeline.getPeriod(nextPeriodIndex, period, /* setIds= */
        true).windowIndex;
        Object nextPeriodUid = checkNotNull(period.uid);
        long windowSequenceNumber = mediaPeriodInfo.id.windowSequenceNumber;
        if (timeline.getWindow(nextWindowIndex, window).firstPeriodIndex == nextPeriodIndex) {
            // We're starting to buffer a new window. When playback transitions to this window we'll
            // want it to be from its default start position, so project the default start position
            // forward by the duration of the buffer, and start buffering from this point.
            contentPositionUs = C.TIME_UNSET;
            @Nullable Pair<Object, Long> defaultPositionUs = timeline.getPeriodPositionUs(window, period, nextWindowIndex, /* windowPositionUs= */
            C.TIME_UNSET, /* defaultPositionProjectionUs= */
            max(0, bufferedDurationUs));
            if (defaultPositionUs == null) {
                return null;
            }
            nextPeriodUid = defaultPositionUs.first;
            startPositionUs = defaultPositionUs.second;
            @Nullable MediaPeriodHolder nextMediaPeriodHolder = mediaPeriodHolder.getNext();
            if (nextMediaPeriodHolder != null && nextMediaPeriodHolder.uid.equals(nextPeriodUid)) {
                windowSequenceNumber = nextMediaPeriodHolder.info.id.windowSequenceNumber;
            } else {
                windowSequenceNumber = nextWindowSequenceNumber++;
            }
        }
        @Nullable MediaPeriodId periodId = resolveMediaPeriodIdForAds(timeline, nextPeriodUid, startPositionUs, windowSequenceNumber, window, period);
        if (contentPositionUs != C.TIME_UNSET && mediaPeriodInfo.requestedContentPositionUs != C.TIME_UNSET) {
            boolean isPrecedingPeriodAnAd = timeline.getPeriodByUid(mediaPeriodInfo.id.periodUid, period).getAdGroupCount() > 0 && period.isServerSideInsertedAdGroup(period.getRemovedAdGroupCount());
            // Handle the requested content position for period transitions within the same window.
            if (periodId.isAd() && isPrecedingPeriodAnAd) {
                // Propagate the requested position to the following ad period in the same window.
                contentPositionUs = mediaPeriodInfo.requestedContentPositionUs;
            } else if (isPrecedingPeriodAnAd) {
                // Use the requested content position of the preceding ad period as the start position.
                startPositionUs = mediaPeriodInfo.requestedContentPositionUs;
            }
        }
        return getMediaPeriodInfo(timeline, periodId, contentPositionUs, startPositionUs);
    }
    MediaPeriodId currentPeriodId = mediaPeriodInfo.id;
    timeline.getPeriodByUid(currentPeriodId.periodUid, period);
    if (currentPeriodId.isAd()) {
        int adGroupIndex = currentPeriodId.adGroupIndex;
        int adCountInCurrentAdGroup = period.getAdCountInAdGroup(adGroupIndex);
        if (adCountInCurrentAdGroup == C.LENGTH_UNSET) {
            return null;
        }
        int nextAdIndexInAdGroup = period.getNextAdIndexToPlay(adGroupIndex, currentPeriodId.adIndexInAdGroup);
        if (nextAdIndexInAdGroup < adCountInCurrentAdGroup) {
            // Play the next ad in the ad group if it's available.
            return getMediaPeriodInfoForAd(timeline, currentPeriodId.periodUid, adGroupIndex, nextAdIndexInAdGroup, mediaPeriodInfo.requestedContentPositionUs, currentPeriodId.windowSequenceNumber);
        } else {
            // Play content from the ad group position.
            long startPositionUs = mediaPeriodInfo.requestedContentPositionUs;
            if (startPositionUs == C.TIME_UNSET) {
                // If we're transitioning from an ad group to content starting from its default position,
                // project the start position forward as if this were a transition to a new window.
                @Nullable Pair<Object, Long> defaultPositionUs = timeline.getPeriodPositionUs(window, period, period.windowIndex, /* windowPositionUs= */
                C.TIME_UNSET, /* defaultPositionProjectionUs= */
                max(0, bufferedDurationUs));
                if (defaultPositionUs == null) {
                    return null;
                }
                startPositionUs = defaultPositionUs.second;
            }
            long minStartPositionUs = getMinStartPositionAfterAdGroupUs(timeline, currentPeriodId.periodUid, currentPeriodId.adGroupIndex);
            return getMediaPeriodInfoForContent(timeline, currentPeriodId.periodUid, max(minStartPositionUs, startPositionUs), mediaPeriodInfo.requestedContentPositionUs, currentPeriodId.windowSequenceNumber);
        }
    } else {
        // Play the next ad group if it's still available.
        int adIndexInAdGroup = period.getFirstAdIndexToPlay(currentPeriodId.nextAdGroupIndex);
        boolean isPlayedServerSideInsertedAd = period.isServerSideInsertedAdGroup(currentPeriodId.nextAdGroupIndex) && period.getAdState(currentPeriodId.nextAdGroupIndex, adIndexInAdGroup) == AdPlaybackState.AD_STATE_PLAYED;
        if (adIndexInAdGroup == period.getAdCountInAdGroup(currentPeriodId.nextAdGroupIndex) || isPlayedServerSideInsertedAd) {
            // The next ad group has no ads left to play or is a played SSAI ad group. Play content from
            // the end position instead.
            long startPositionUs = getMinStartPositionAfterAdGroupUs(timeline, currentPeriodId.periodUid, currentPeriodId.nextAdGroupIndex);
            return getMediaPeriodInfoForContent(timeline, currentPeriodId.periodUid, startPositionUs, /* requestedContentPositionUs= */
            mediaPeriodInfo.durationUs, currentPeriodId.windowSequenceNumber);
        }
        return getMediaPeriodInfoForAd(timeline, currentPeriodId.periodUid, currentPeriodId.nextAdGroupIndex, adIndexInAdGroup, /* contentPositionUs= */
        mediaPeriodInfo.durationUs, currentPeriodId.windowSequenceNumber);
    }
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId) Nullable(androidx.annotation.Nullable) Nullable(androidx.annotation.Nullable)

Example 75 with MediaPeriodId

use of com.google.android.exoplayer2.source.MediaSource.MediaPeriodId in project ExoPlayer by google.

the class MediaPeriodQueue method getMediaPeriodInfoForAd.

private MediaPeriodInfo getMediaPeriodInfoForAd(Timeline timeline, Object periodUid, int adGroupIndex, int adIndexInAdGroup, long contentPositionUs, long windowSequenceNumber) {
    MediaPeriodId id = new MediaPeriodId(periodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
    long durationUs = timeline.getPeriodByUid(id.periodUid, period).getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup);
    long startPositionUs = adIndexInAdGroup == period.getFirstAdIndexToPlay(adGroupIndex) ? period.getAdResumePositionUs() : 0;
    boolean isFollowedByTransitionToSameStream = period.isServerSideInsertedAdGroup(id.adGroupIndex);
    if (durationUs != C.TIME_UNSET && startPositionUs >= durationUs) {
        // Ensure start position doesn't exceed duration.
        startPositionUs = max(0, durationUs - 1);
    }
    return new MediaPeriodInfo(id, startPositionUs, contentPositionUs, /* endPositionUs= */
    C.TIME_UNSET, durationUs, isFollowedByTransitionToSameStream, /* isLastInTimelinePeriod= */
    false, /* isLastInTimelineWindow= */
    false, /* isFinal= */
    false);
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Aggregations

MediaPeriodId (com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)106 Test (org.junit.Test)85 FakeTimeline (com.google.android.exoplayer2.testutil.FakeTimeline)75 Timeline (com.google.android.exoplayer2.Timeline)50 EventTime (com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime)48 FakeMediaSource (com.google.android.exoplayer2.testutil.FakeMediaSource)28 TimelineWindowDefinition (com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition)28 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)27 Nullable (androidx.annotation.Nullable)26 Allocator (com.google.android.exoplayer2.upstream.Allocator)22 SinglePeriodTimeline (com.google.android.exoplayer2.source.SinglePeriodTimeline)19 DrmSessionManager (com.google.android.exoplayer2.drm.DrmSessionManager)17 TransferListener (com.google.android.exoplayer2.upstream.TransferListener)16 TrackGroupArray (com.google.android.exoplayer2.source.TrackGroupArray)15 AdPlaybackState (com.google.android.exoplayer2.source.ads.AdPlaybackState)15 FakeMediaPeriod (com.google.android.exoplayer2.testutil.FakeMediaPeriod)15 TestExoPlayerBuilder (com.google.android.exoplayer2.testutil.TestExoPlayerBuilder)15 ActionSchedule (com.google.android.exoplayer2.testutil.ActionSchedule)13 DrmSessionEventListener (com.google.android.exoplayer2.drm.DrmSessionEventListener)12 MediaPeriod (com.google.android.exoplayer2.source.MediaPeriod)11