Search in sources :

Example 1 with Part

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Part in project ExoPlayer by google.

the class HlsMediaChunk method loadMedia.

private void loadMedia() throws IOException, InterruptedException {
    // If we previously fed part of this chunk to the extractor, we need to skip it this time. For
    // encrypted content we need to skip the data by reading it through the source, so as to ensure
    // correct decryption of the remainder of the chunk. For clear content, we can request the
    // remainder of the chunk directly.
    DataSpec loadDataSpec;
    boolean skipLoadedBytes;
    if (isEncrypted) {
        loadDataSpec = dataSpec;
        skipLoadedBytes = bytesLoaded != 0;
    } else {
        loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
        skipLoadedBytes = false;
    }
    if (!isMasterTimestampSource) {
        timestampAdjuster.waitUntilInitialized();
    } else if (timestampAdjuster.getFirstSampleTimestampUs() == TimestampAdjuster.DO_NOT_OFFSET) {
        // We're the master and we haven't set the desired first sample timestamp yet.
        timestampAdjuster.setFirstSampleTimestampUs(startTimeUs);
    }
    try {
        ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
        if (extractor == null) {
            // Media segment format is packed audio.
            long id3Timestamp = peekId3PrivTimestamp(input);
            extractor = buildPackedAudioExtractor(id3Timestamp != C.TIME_UNSET ? timestampAdjuster.adjustTsTimestamp(id3Timestamp) : startTimeUs);
        }
        if (skipLoadedBytes) {
            input.skipFully(bytesLoaded);
        }
        try {
            int result = Extractor.RESULT_CONTINUE;
            while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
                result = extractor.read(input, null);
            }
        } finally {
            bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition);
        }
    } finally {
        Util.closeQuietly(dataSource);
    }
    loadCompleted = true;
}
Also used : ExtractorInput(com.google.android.exoplayer2.extractor.ExtractorInput) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput)

Example 2 with Part

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Part 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 3 with Part

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Part in project ExoPlayer by google.

the class HlsMediaSourceTest method loadLivePlaylist_noTargetLiveOffsetDefined_fallbackToThreeTargetDuration.

@Test
public void loadLivePlaylist_noTargetLiveOffsetDefined_fallbackToThreeTargetDuration() throws TimeoutException, ParserException {
    String playlistUri = "fake://foo.bar/media0/playlist.m3u8";
    // The playlist has a duration of 16 seconds but not hold back or part hold back.
    String playlist = "#EXTM3U\n" + "#EXT-X-PROGRAM-DATE-TIME:2020-01-01T00:00:00.0+00:00\n" + "#EXT-X-TARGETDURATION:4\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-MEDIA-SEQUENCE:0\n" + "#EXTINF:4.00000,\n" + "fileSequence0.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence1.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence2.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence3.ts\n" + "#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24";
    // The playlist finishes 1 second before the current time, therefore there's a live edge
    // offset of 1 second.
    SystemClock.setCurrentTimeMillis(Util.parseXsDateTime("2020-01-01T00:00:17.0+00:00"));
    HlsMediaSource.Factory factory = createHlsMediaSourceFactory(playlistUri, playlist);
    MediaItem mediaItem = MediaItem.fromUri(playlistUri);
    HlsMediaSource mediaSource = factory.createMediaSource(mediaItem);
    Timeline timeline = prepareAndWaitForTimeline(mediaSource);
    Timeline.Window window = timeline.getWindow(0, new Timeline.Window());
    // The target live offset is picked from target duration (3 * 4 = 12 seconds) and then expressed
    // in relation to the live edge (12 + 1 seconds).
    assertThat(window.liveConfiguration.targetOffsetMs).isEqualTo(13000);
    assertThat(window.liveConfiguration.minPlaybackSpeed).isEqualTo(1f);
    assertThat(window.liveConfiguration.maxPlaybackSpeed).isEqualTo(1f);
    assertThat(window.defaultPositionUs).isEqualTo(4000000);
}
Also used : Timeline(com.google.android.exoplayer2.Timeline) MediaItem(com.google.android.exoplayer2.MediaItem) Test(org.junit.Test)

Example 4 with Part

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Part in project ExoPlayer by google.

the class HlsMediaSourceTest method loadLivePlaylist_targetLiveOffsetInMediaItem_targetLiveOffsetPickedFromMediaItem.

@Test
public void loadLivePlaylist_targetLiveOffsetInMediaItem_targetLiveOffsetPickedFromMediaItem() throws TimeoutException, ParserException {
    String playlistUri = "fake://foo.bar/media0/playlist.m3u8";
    // The playlist has a hold back of 12 seconds and a part hold back of 3 seconds.
    String playlist = "#EXTM3U\n" + "#EXT-X-PROGRAM-DATE-TIME:2020-01-01T00:00:00.0+00:00\n" + "#EXT-X-TARGETDURATION:4\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-MEDIA-SEQUENCE:0\n" + "#EXTINF:4.00000,\n" + "fileSequence0.ts\n" + "#EXT-X-SERVER-CONTROL:HOLD-BACK=12,PART-HOLD-BACK=3";
    // The playlist finishes 1 second before the current time. This should not affect the target
    // live offset set in the media item.
    SystemClock.setCurrentTimeMillis(Util.parseXsDateTime("2020-01-01T00:00:05.0+00:00"));
    HlsMediaSource.Factory factory = createHlsMediaSourceFactory(playlistUri, playlist);
    MediaItem mediaItem = new MediaItem.Builder().setUri(playlistUri).setLiveConfiguration(new MediaItem.LiveConfiguration.Builder().setTargetOffsetMs(1000).build()).build();
    HlsMediaSource mediaSource = factory.createMediaSource(mediaItem);
    Timeline timeline = prepareAndWaitForTimeline(mediaSource);
    Timeline.Window window = timeline.getWindow(0, new Timeline.Window());
    // The target live offset is picked from the media item and not adjusted.
    assertThat(window.liveConfiguration).isEqualTo(mediaItem.liveConfiguration);
    assertThat(window.defaultPositionUs).isEqualTo(0);
}
Also used : Timeline(com.google.android.exoplayer2.Timeline) MediaItem(com.google.android.exoplayer2.MediaItem) Test(org.junit.Test)

Example 5 with Part

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Part in project ExoPlayer by google.

the class HlsMediaSourceTest method loadLivePlaylist_withPreciseStartTime_targetLiveOffsetFromStartTime.

@Test
public void loadLivePlaylist_withPreciseStartTime_targetLiveOffsetFromStartTime() throws TimeoutException, ParserException {
    String playlistUri = "fake://foo.bar/media0/playlist.m3u8";
    // The playlist has a duration of 16 seconds, and part hold back, hold back and start time
    // defined.
    String playlist = "#EXTM3U\n" + "#EXT-X-PROGRAM-DATE-TIME:2020-01-01T00:00:00.0+00:00\n" + "#EXT-X-TARGETDURATION:4\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-START:TIME-OFFSET=-10,PRECISE=YES\n" + "#EXT-X-MEDIA-SEQUENCE:0\n" + "#EXTINF:4.00000,\n" + "fileSequence0.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence1.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence2.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence3.ts\n" + "#EXT-X-SERVER-CONTROL:HOLD-BACK=12,PART-HOLD-BACK=3";
    // The playlist finishes 1 second before the current time.
    SystemClock.setCurrentTimeMillis(Util.parseXsDateTime("2020-01-01T00:00:17.0+00:00"));
    HlsMediaSource.Factory factory = createHlsMediaSourceFactory(playlistUri, playlist);
    MediaItem mediaItem = MediaItem.fromUri(playlistUri);
    HlsMediaSource mediaSource = factory.createMediaSource(mediaItem);
    Timeline timeline = prepareAndWaitForTimeline(mediaSource);
    Timeline.Window window = timeline.getWindow(0, new Timeline.Window());
    // The target live offset is picked from start time (16 - 10 = 6) and then expressed in relation
    // to the live edge (17 - 7 = 11 seconds).
    assertThat(window.liveConfiguration.targetOffsetMs).isEqualTo(11000);
    // The default position points to the start time.
    assertThat(window.defaultPositionUs).isEqualTo(6000000);
}
Also used : Timeline(com.google.android.exoplayer2.Timeline) MediaItem(com.google.android.exoplayer2.MediaItem) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)14 MediaItem (com.google.android.exoplayer2.MediaItem)11 Timeline (com.google.android.exoplayer2.Timeline)11 Nullable (androidx.annotation.Nullable)6 HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)6 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)6 ArrayList (java.util.ArrayList)6 Segment (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)4 Uri (android.net.Uri)3 MediaPeriodId (com.google.android.exoplayer2.source.MediaSource.MediaPeriodId)3 SurfaceTexture (android.graphics.SurfaceTexture)2 Pair (android.util.Pair)2 Surface (android.view.Surface)2 ApplicationProvider (androidx.test.core.app.ApplicationProvider)2 AndroidJUnit4 (androidx.test.ext.junit.runners.AndroidJUnit4)2 ExoPlayer (com.google.android.exoplayer2.ExoPlayer)2 Player (com.google.android.exoplayer2.Player)2 DrmInitData (com.google.android.exoplayer2.drm.DrmInitData)2 MediaChunkIterator (com.google.android.exoplayer2.source.chunk.MediaChunkIterator)2 RequiresNonNull (org.checkerframework.checker.nullness.qual.RequiresNonNull)2