Search in sources :

Example 96 with MediaPeriodId

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

the class ExoPlayerImplInternal method handleLoadingMediaPeriodChanged.

private void handleLoadingMediaPeriodChanged(boolean loadingTrackSelectionChanged) {
    MediaPeriodHolder loadingMediaPeriodHolder = queue.getLoadingPeriod();
    MediaPeriodId loadingMediaPeriodId = loadingMediaPeriodHolder == null ? playbackInfo.periodId : loadingMediaPeriodHolder.info.id;
    boolean loadingMediaPeriodChanged = !playbackInfo.loadingMediaPeriodId.equals(loadingMediaPeriodId);
    if (loadingMediaPeriodChanged) {
        playbackInfo = playbackInfo.copyWithLoadingMediaPeriodId(loadingMediaPeriodId);
    }
    playbackInfo.bufferedPositionUs = loadingMediaPeriodHolder == null ? playbackInfo.positionUs : loadingMediaPeriodHolder.getBufferedPositionUs();
    playbackInfo.totalBufferedDurationUs = getTotalBufferedDurationUs();
    if ((loadingMediaPeriodChanged || loadingTrackSelectionChanged) && loadingMediaPeriodHolder != null && loadingMediaPeriodHolder.prepared) {
        updateLoadControlTrackSelection(loadingMediaPeriodHolder.getTrackGroups(), loadingMediaPeriodHolder.getTrackSelectorResult());
    }
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)

Example 97 with MediaPeriodId

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

the class ExoPlayerImplInternal method handlePositionDiscontinuity.

@CheckResult
private PlaybackInfo handlePositionDiscontinuity(MediaPeriodId mediaPeriodId, long positionUs, long requestedContentPositionUs, long discontinuityStartPositionUs, boolean reportDiscontinuity, @DiscontinuityReason int discontinuityReason) {
    deliverPendingMessageAtStartPositionRequired = deliverPendingMessageAtStartPositionRequired || positionUs != playbackInfo.positionUs || !mediaPeriodId.equals(playbackInfo.periodId);
    resetPendingPauseAtEndOfPeriod();
    TrackGroupArray trackGroupArray = playbackInfo.trackGroups;
    TrackSelectorResult trackSelectorResult = playbackInfo.trackSelectorResult;
    List<Metadata> staticMetadata = playbackInfo.staticMetadata;
    if (mediaSourceList.isPrepared()) {
        @Nullable MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
        trackGroupArray = playingPeriodHolder == null ? TrackGroupArray.EMPTY : playingPeriodHolder.getTrackGroups();
        trackSelectorResult = playingPeriodHolder == null ? emptyTrackSelectorResult : playingPeriodHolder.getTrackSelectorResult();
        staticMetadata = extractMetadataFromTrackSelectionArray(trackSelectorResult.selections);
        // Ensure the media period queue requested content position matches the new playback info.
        if (playingPeriodHolder != null && playingPeriodHolder.info.requestedContentPositionUs != requestedContentPositionUs) {
            playingPeriodHolder.info = playingPeriodHolder.info.copyWithRequestedContentPositionUs(requestedContentPositionUs);
        }
    } else if (!mediaPeriodId.equals(playbackInfo.periodId)) {
        // Reset previously kept track info if unprepared and the period changes.
        trackGroupArray = TrackGroupArray.EMPTY;
        trackSelectorResult = emptyTrackSelectorResult;
        staticMetadata = ImmutableList.of();
    }
    if (reportDiscontinuity) {
        playbackInfoUpdate.setPositionDiscontinuity(discontinuityReason);
    }
    return playbackInfo.copyWithNewPosition(mediaPeriodId, positionUs, requestedContentPositionUs, discontinuityStartPositionUs, getTotalBufferedDurationUs(), trackGroupArray, trackSelectorResult, staticMetadata);
}
Also used : TrackSelectorResult(com.google.android.exoplayer2.trackselection.TrackSelectorResult) TrackGroupArray(com.google.android.exoplayer2.source.TrackGroupArray) Metadata(com.google.android.exoplayer2.metadata.Metadata) Nullable(androidx.annotation.Nullable) CheckResult(androidx.annotation.CheckResult)

Example 98 with MediaPeriodId

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

the class ExoPlayerImplInternal method resolvePositionForPlaylistChange.

private static PositionUpdateForPlaylistChange resolvePositionForPlaylistChange(Timeline timeline, PlaybackInfo playbackInfo, @Nullable SeekPosition pendingInitialSeekPosition, MediaPeriodQueue queue, @RepeatMode int repeatMode, boolean shuffleModeEnabled, Timeline.Window window, Timeline.Period period) {
    if (timeline.isEmpty()) {
        return new PositionUpdateForPlaylistChange(PlaybackInfo.getDummyPeriodForEmptyTimeline(), /* periodPositionUs= */
        0, /* requestedContentPositionUs= */
        C.TIME_UNSET, /* forceBufferingState= */
        false, /* endPlayback= */
        true, /* setTargetLiveOffset= */
        false);
    }
    MediaPeriodId oldPeriodId = playbackInfo.periodId;
    Object newPeriodUid = oldPeriodId.periodUid;
    boolean isUsingPlaceholderPeriod = isUsingPlaceholderPeriod(playbackInfo, period);
    long oldContentPositionUs = playbackInfo.periodId.isAd() || isUsingPlaceholderPeriod ? playbackInfo.requestedContentPositionUs : playbackInfo.positionUs;
    long newContentPositionUs = oldContentPositionUs;
    int startAtDefaultPositionWindowIndex = C.INDEX_UNSET;
    boolean forceBufferingState = false;
    boolean endPlayback = false;
    boolean setTargetLiveOffset = false;
    if (pendingInitialSeekPosition != null) {
        // Resolve initial seek position.
        @Nullable Pair<Object, Long> periodPosition = resolveSeekPositionUs(timeline, pendingInitialSeekPosition, /* trySubsequentPeriods= */
        true, repeatMode, shuffleModeEnabled, window, period);
        if (periodPosition == null) {
            // The initial seek in the empty old timeline is invalid in the new timeline.
            endPlayback = true;
            startAtDefaultPositionWindowIndex = timeline.getFirstWindowIndex(shuffleModeEnabled);
        } else {
            // The pending seek has been resolved successfully in the new timeline.
            if (pendingInitialSeekPosition.windowPositionUs == C.TIME_UNSET) {
                startAtDefaultPositionWindowIndex = timeline.getPeriodByUid(periodPosition.first, period).windowIndex;
            } else {
                newPeriodUid = periodPosition.first;
                newContentPositionUs = periodPosition.second;
                // Use explicit initial seek as new target live offset.
                setTargetLiveOffset = true;
            }
            forceBufferingState = playbackInfo.playbackState == Player.STATE_ENDED;
        }
    } else if (playbackInfo.timeline.isEmpty()) {
        // Resolve to default position if the old timeline is empty and no seek is requested above.
        startAtDefaultPositionWindowIndex = timeline.getFirstWindowIndex(shuffleModeEnabled);
    } else if (timeline.getIndexOfPeriod(newPeriodUid) == C.INDEX_UNSET) {
        // The current period isn't in the new timeline. Attempt to resolve a subsequent period whose
        // window we can restart from.
        @Nullable Object subsequentPeriodUid = resolveSubsequentPeriod(window, period, repeatMode, shuffleModeEnabled, newPeriodUid, playbackInfo.timeline, timeline);
        if (subsequentPeriodUid == null) {
            // We failed to resolve a suitable restart position but the timeline is not empty.
            endPlayback = true;
            startAtDefaultPositionWindowIndex = timeline.getFirstWindowIndex(shuffleModeEnabled);
        } else {
            // We resolved a subsequent period. Start at the default position in the corresponding
            // window.
            startAtDefaultPositionWindowIndex = timeline.getPeriodByUid(subsequentPeriodUid, period).windowIndex;
        }
    } else if (oldContentPositionUs == C.TIME_UNSET) {
        // The content was requested to start from its default position and we haven't used the
        // resolved position yet. Re-resolve in case the default position changed.
        startAtDefaultPositionWindowIndex = timeline.getPeriodByUid(newPeriodUid, period).windowIndex;
    } else if (isUsingPlaceholderPeriod) {
        // We previously requested a content position for a placeholder period, but haven't used it
        // yet. Re-resolve the requested window position to the period position in case it changed.
        playbackInfo.timeline.getPeriodByUid(oldPeriodId.periodUid, period);
        if (playbackInfo.timeline.getWindow(period.windowIndex, window).firstPeriodIndex == playbackInfo.timeline.getIndexOfPeriod(oldPeriodId.periodUid)) {
            // Only need to resolve the first period in a window because subsequent periods must start
            // at position 0 and don't need to be resolved.
            long windowPositionUs = oldContentPositionUs + period.getPositionInWindowUs();
            int windowIndex = timeline.getPeriodByUid(newPeriodUid, period).windowIndex;
            Pair<Object, Long> periodPositionUs = timeline.getPeriodPositionUs(window, period, windowIndex, windowPositionUs);
            newPeriodUid = periodPositionUs.first;
            newContentPositionUs = periodPositionUs.second;
        }
        // Use an explicitly requested content position as new target live offset.
        setTargetLiveOffset = true;
    }
    // Set period uid for default positions and resolve position for ad resolution.
    long contentPositionForAdResolutionUs = newContentPositionUs;
    if (startAtDefaultPositionWindowIndex != C.INDEX_UNSET) {
        Pair<Object, Long> defaultPositionUs = timeline.getPeriodPositionUs(window, period, startAtDefaultPositionWindowIndex, /* windowPositionUs= */
        C.TIME_UNSET);
        newPeriodUid = defaultPositionUs.first;
        contentPositionForAdResolutionUs = defaultPositionUs.second;
        newContentPositionUs = C.TIME_UNSET;
    }
    // Ensure ad insertion metadata is up to date.
    MediaPeriodId periodIdWithAds = queue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(timeline, newPeriodUid, contentPositionForAdResolutionUs);
    boolean earliestCuePointIsUnchangedOrLater = periodIdWithAds.nextAdGroupIndex == C.INDEX_UNSET || (oldPeriodId.nextAdGroupIndex != C.INDEX_UNSET && periodIdWithAds.nextAdGroupIndex >= oldPeriodId.nextAdGroupIndex);
    // Drop update if we keep playing the same content (MediaPeriod.periodUid are identical) and
    // the only change is that MediaPeriodId.nextAdGroupIndex increased. This postpones a potential
    // discontinuity until we reach the former next ad group position.
    boolean sameOldAndNewPeriodUid = oldPeriodId.periodUid.equals(newPeriodUid);
    boolean onlyNextAdGroupIndexIncreased = sameOldAndNewPeriodUid && !oldPeriodId.isAd() && !periodIdWithAds.isAd() && earliestCuePointIsUnchangedOrLater;
    // Drop update if the change is from/to server-side inserted ads at the same content position to
    // avoid any unintentional renderer reset.
    boolean isInStreamAdChange = isIgnorableServerSideAdInsertionPeriodChange(isUsingPlaceholderPeriod, oldPeriodId, oldContentPositionUs, periodIdWithAds, timeline.getPeriodByUid(newPeriodUid, period), newContentPositionUs);
    MediaPeriodId newPeriodId = onlyNextAdGroupIndexIncreased || isInStreamAdChange ? oldPeriodId : periodIdWithAds;
    long periodPositionUs = contentPositionForAdResolutionUs;
    if (newPeriodId.isAd()) {
        if (newPeriodId.equals(oldPeriodId)) {
            periodPositionUs = playbackInfo.positionUs;
        } else {
            timeline.getPeriodByUid(newPeriodId.periodUid, period);
            periodPositionUs = newPeriodId.adIndexInAdGroup == period.getFirstAdIndexToPlay(newPeriodId.adGroupIndex) ? period.getAdResumePositionUs() : 0;
        }
    }
    return new PositionUpdateForPlaylistChange(newPeriodId, periodPositionUs, newContentPositionUs, forceBufferingState, endPlayback, setTargetLiveOffset);
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId) Nullable(androidx.annotation.Nullable)

Example 99 with MediaPeriodId

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

the class SsMediaPeriodTest method getSteamKeys_isCompatibleWithSsManifestFilter.

@Test
public void getSteamKeys_isCompatibleWithSsManifestFilter() {
    SsManifest testManifest = createSsManifest(createStreamElement(/* name= */
    "video", C.TRACK_TYPE_VIDEO, createVideoFormat(/* bitrate= */
    200000), createVideoFormat(/* bitrate= */
    400000), createVideoFormat(/* bitrate= */
    800000)), createStreamElement(/* name= */
    "audio", C.TRACK_TYPE_AUDIO, createAudioFormat(/* bitrate= */
    48000), createAudioFormat(/* bitrate= */
    96000)), createStreamElement(/* name= */
    "text", C.TRACK_TYPE_TEXT, createTextFormat(/* language= */
    "eng")));
    FilterableManifestMediaPeriodFactory<SsManifest> mediaPeriodFactory = (manifest, periodIndex) -> {
        MediaPeriodId mediaPeriodId = new MediaPeriodId(/* periodUid= */
        new Object());
        return new SsMediaPeriod(manifest, mock(SsChunkSource.Factory.class), mock(TransferListener.class), mock(CompositeSequenceableLoaderFactory.class), mock(DrmSessionManager.class), new DrmSessionEventListener.EventDispatcher().withParameters(/* windowIndex= */
        0, mediaPeriodId), mock(LoadErrorHandlingPolicy.class), new MediaSourceEventListener.EventDispatcher().withParameters(/* windowIndex= */
        0, mediaPeriodId, /* mediaTimeOffsetMs= */
        0), mock(LoaderErrorThrower.class), mock(Allocator.class));
    };
    MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration(mediaPeriodFactory, testManifest);
}
Also used : MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId) TransferListener(com.google.android.exoplayer2.upstream.TransferListener) SsTestUtils.createSsManifest(com.google.android.exoplayer2.source.smoothstreaming.SsTestUtils.createSsManifest) RunWith(org.junit.runner.RunWith) CompositeSequenceableLoaderFactory(com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory) Test(org.junit.Test) AndroidJUnit4(androidx.test.ext.junit.runners.AndroidJUnit4) Format(com.google.android.exoplayer2.Format) MediaPeriodAsserts(com.google.android.exoplayer2.testutil.MediaPeriodAsserts) DrmSessionEventListener(com.google.android.exoplayer2.drm.DrmSessionEventListener) MimeTypes(com.google.android.exoplayer2.util.MimeTypes) LoadErrorHandlingPolicy(com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy) SsManifest(com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest) FilterableManifestMediaPeriodFactory(com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory) SsTestUtils.createStreamElement(com.google.android.exoplayer2.source.smoothstreaming.SsTestUtils.createStreamElement) DrmSessionManager(com.google.android.exoplayer2.drm.DrmSessionManager) MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener) Mockito.mock(org.mockito.Mockito.mock) C(com.google.android.exoplayer2.C) Allocator(com.google.android.exoplayer2.upstream.Allocator) LoaderErrorThrower(com.google.android.exoplayer2.upstream.LoaderErrorThrower) MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener) MediaPeriodId(com.google.android.exoplayer2.source.MediaSource.MediaPeriodId) DrmSessionEventListener(com.google.android.exoplayer2.drm.DrmSessionEventListener) SsTestUtils.createSsManifest(com.google.android.exoplayer2.source.smoothstreaming.SsTestUtils.createSsManifest) SsManifest(com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest) Test(org.junit.Test)

Example 100 with MediaPeriodId

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

the class SsMediaSource method createPeriod.

@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
    MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher = createEventDispatcher(id);
    DrmSessionEventListener.EventDispatcher drmEventDispatcher = createDrmEventDispatcher(id);
    SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory, mediaTransferListener, compositeSequenceableLoaderFactory, drmSessionManager, drmEventDispatcher, loadErrorHandlingPolicy, mediaSourceEventDispatcher, manifestLoaderErrorThrower, allocator);
    mediaPeriods.add(period);
    return period;
}
Also used : EventDispatcher(com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher) MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener) DrmSessionEventListener(com.google.android.exoplayer2.drm.DrmSessionEventListener)

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