Search in sources :

Example 31 with HlsMediaPlaylist

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

the class HlsChunkSource method createMediaChunkIterators.

/**
 * Returns an array of {@link MediaChunkIterator}s for upcoming media chunks.
 *
 * @param previous The previous media chunk. May be null.
 * @param loadPositionUs The position at which the iterators will start.
 * @return Array of {@link MediaChunkIterator}s for each track.
 */
public MediaChunkIterator[] createMediaChunkIterators(@Nullable HlsMediaChunk previous, long loadPositionUs) {
    int oldTrackIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat);
    MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
    for (int i = 0; i < chunkIterators.length; i++) {
        int trackIndex = trackSelection.getIndexInTrackGroup(i);
        Uri playlistUrl = playlistUrls[trackIndex];
        if (!playlistTracker.isSnapshotValid(playlistUrl)) {
            chunkIterators[i] = MediaChunkIterator.EMPTY;
            continue;
        }
        @Nullable HlsMediaPlaylist playlist = playlistTracker.getPlaylistSnapshot(playlistUrl, /* isForPlayback= */
        false);
        // Playlist snapshot is valid (checked by if() above) so playlist must be non-null.
        checkNotNull(playlist);
        long startOfPlaylistInPeriodUs = playlist.startTimeUs - playlistTracker.getInitialStartTimeUs();
        boolean switchingTrack = trackIndex != oldTrackIndex;
        Pair<Long, Integer> chunkMediaSequenceAndPartIndex = getNextMediaSequenceAndPartIndex(previous, switchingTrack, playlist, startOfPlaylistInPeriodUs, loadPositionUs);
        long chunkMediaSequence = chunkMediaSequenceAndPartIndex.first;
        int partIndex = chunkMediaSequenceAndPartIndex.second;
        chunkIterators[i] = new HlsMediaPlaylistSegmentIterator(playlist.baseUri, startOfPlaylistInPeriodUs, getSegmentBaseList(playlist, chunkMediaSequence, partIndex));
    }
    return chunkIterators;
}
Also used : BaseMediaChunkIterator(com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator) MediaChunkIterator(com.google.android.exoplayer2.source.chunk.MediaChunkIterator) HlsMediaPlaylist(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist) Uri(android.net.Uri) Nullable(androidx.annotation.Nullable)

Example 32 with HlsMediaPlaylist

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

the class DefaultHlsPlaylistTracker method getLoadedPlaylistStartTimeUs.

private long getLoadedPlaylistStartTimeUs(@Nullable HlsMediaPlaylist oldPlaylist, HlsMediaPlaylist loadedPlaylist) {
    if (loadedPlaylist.hasProgramDateTime) {
        return loadedPlaylist.startTimeUs;
    }
    long primarySnapshotStartTimeUs = primaryMediaPlaylistSnapshot != null ? primaryMediaPlaylistSnapshot.startTimeUs : 0;
    if (oldPlaylist == null) {
        return primarySnapshotStartTimeUs;
    }
    int oldPlaylistSize = oldPlaylist.segments.size();
    Segment firstOldOverlappingSegment = getFirstOldOverlappingSegment(oldPlaylist, loadedPlaylist);
    if (firstOldOverlappingSegment != null) {
        return oldPlaylist.startTimeUs + firstOldOverlappingSegment.relativeStartTimeUs;
    } else if (oldPlaylistSize == loadedPlaylist.mediaSequence - oldPlaylist.mediaSequence) {
        return oldPlaylist.getEndTimeUs();
    } else {
        // No segments overlap, we assume the new playlist start coincides with the primary playlist.
        return primarySnapshotStartTimeUs;
    }
}
Also used : Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)

Example 33 with HlsMediaPlaylist

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

the class HlsMediaPlaylistParserTest method parseMediaPlaylist.

@Test
public void parseMediaPlaylist() throws Exception {
    Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
    String playlistString = "#EXTM3U\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-PLAYLIST-TYPE:VOD\n" + "#EXT-X-START:TIME-OFFSET=-25\n" + "#EXT-X-TARGETDURATION:8\n" + "#EXT-X-MEDIA-SEQUENCE:2679\n" + "#EXT-X-DISCONTINUITY-SEQUENCE:4\n" + "#EXT-X-ALLOW-CACHE:YES\n" + "\n" + "#EXTINF:7.975,\n" + "#EXT-X-BYTERANGE:51370@0\n" + "https://priv.example.com/fileSequence2679.ts\n" + "\n" + "#EXT-X-KEY:METHOD=AES-128," + "URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n" + "#EXTINF:7.975,segment title\n" + "#EXT-X-BYTERANGE:51501@2147483648\n" + "https://priv.example.com/fileSequence2680.ts\n" + "\n" + "#EXT-X-KEY:METHOD=NONE\n" + "#EXTINF:7.941,segment title .,:/# with interesting chars\n" + // @2147535149
    "#EXT-X-BYTERANGE:51501\n" + "https://priv.example.com/fileSequence2681.ts\n" + "\n" + "#EXT-X-DISCONTINUITY\n" + "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2682\"\n" + // Trailing comma is omitted.
    "#EXTINF:7.975\n" + // @2147586650
    "#EXT-X-BYTERANGE:51740\n" + "https://priv.example.com/fileSequence2682.ts\n" + "\n" + "#EXTINF:7.975,\n" + "https://priv.example.com/fileSequence2683.ts\n" + "\n" + // 2.002 tests correct rounding, see https://github.com/google/ExoPlayer/issues/9575.
    "#EXTINF:2.002,\n" + "https://priv.example.com/fileSequence2684.ts\n" + "#EXT-X-ENDLIST";
    InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
    HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
    HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
    assertThat(mediaPlaylist.playlistType).isEqualTo(HlsMediaPlaylist.PLAYLIST_TYPE_VOD);
    assertThat(mediaPlaylist.startOffsetUs).isEqualTo(mediaPlaylist.durationUs - 25000000);
    assertThat(mediaPlaylist.mediaSequence).isEqualTo(2679);
    assertThat(mediaPlaylist.version).isEqualTo(3);
    assertThat(mediaPlaylist.hasEndTag).isTrue();
    assertThat(mediaPlaylist.protectionSchemes).isNull();
    assertThat(mediaPlaylist.targetDurationUs).isEqualTo(8000000);
    assertThat(mediaPlaylist.partTargetDurationUs).isEqualTo(C.TIME_UNSET);
    List<Segment> segments = mediaPlaylist.segments;
    assertThat(segments).isNotNull();
    assertThat(segments).hasSize(6);
    Segment segment = segments.get(0);
    assertThat(mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence).isEqualTo(4);
    assertThat(segment.durationUs).isEqualTo(7975000);
    assertThat(segment.title).isEqualTo("");
    assertThat(segment.fullSegmentEncryptionKeyUri).isNull();
    assertThat(segment.encryptionIV).isNull();
    assertThat(segment.byteRangeLength).isEqualTo(51370);
    assertThat(segment.byteRangeOffset).isEqualTo(0);
    assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2679.ts");
    segment = segments.get(1);
    assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0);
    assertThat(segment.durationUs).isEqualTo(7975000);
    assertThat(segment.title).isEqualTo("segment title");
    assertThat(segment.fullSegmentEncryptionKeyUri).isEqualTo("https://priv.example.com/key.php?r=2680");
    assertThat(segment.encryptionIV).isEqualTo("0x1566B");
    assertThat(segment.byteRangeLength).isEqualTo(51501);
    assertThat(segment.byteRangeOffset).isEqualTo(2147483648L);
    assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2680.ts");
    segment = segments.get(2);
    assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0);
    assertThat(segment.durationUs).isEqualTo(7941000);
    assertThat(segment.title).isEqualTo("segment title .,:/# with interesting chars");
    assertThat(segment.fullSegmentEncryptionKeyUri).isNull();
    assertThat(segment.encryptionIV).isEqualTo(null);
    assertThat(segment.byteRangeLength).isEqualTo(51501);
    assertThat(segment.byteRangeOffset).isEqualTo(2147535149L);
    assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2681.ts");
    segment = segments.get(3);
    assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1);
    assertThat(segment.durationUs).isEqualTo(7975000);
    assertThat(segment.title).isEqualTo("");
    assertThat(segment.fullSegmentEncryptionKeyUri).isEqualTo("https://priv.example.com/key.php?r=2682");
    // 0xA7A == 2682.
    assertThat(segment.encryptionIV).isNotNull();
    assertThat(segment.encryptionIV).ignoringCase().isEqualTo("A7A");
    assertThat(segment.byteRangeLength).isEqualTo(51740);
    assertThat(segment.byteRangeOffset).isEqualTo(2147586650L);
    assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2682.ts");
    segment = segments.get(4);
    assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1);
    assertThat(segment.durationUs).isEqualTo(7975000);
    assertThat(segment.title).isEqualTo("");
    assertThat(segment.fullSegmentEncryptionKeyUri).isEqualTo("https://priv.example.com/key.php?r=2682");
    // 0xA7B == 2683.
    assertThat(segment.encryptionIV).isNotNull();
    assertThat(segment.encryptionIV).ignoringCase().isEqualTo("A7B");
    assertThat(segment.byteRangeLength).isEqualTo(C.LENGTH_UNSET);
    assertThat(segment.byteRangeOffset).isEqualTo(0);
    assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts");
    segment = segments.get(5);
    assertThat(segment.durationUs).isEqualTo(2002000);
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) Uri(android.net.Uri) Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment) Test(org.junit.Test)

Example 34 with HlsMediaPlaylist

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

the class HlsMediaPlaylistParserTest method mapTag.

@Test
public void mapTag() throws IOException {
    Uri playlistUri = Uri.parse("https://example.com/test3.m3u8");
    String playlistString = "#EXTM3U\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-TARGETDURATION:5\n" + "#EXT-X-MEDIA-SEQUENCE:10\n" + "#EXTINF:5.005,\n" + "02/00/27.ts\n" + "#EXT-X-MAP:URI=\"init1.ts\"" + "#EXTINF:5.005,\n" + "02/00/32.ts\n" + "#EXTINF:5.005,\n" + "02/00/42.ts\n" + "#EXT-X-MAP:URI=\"init2.ts\"" + "#EXTINF:5.005,\n" + "02/00/47.ts\n";
    InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
    HlsMediaPlaylist playlist = (HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
    List<Segment> segments = playlist.segments;
    assertThat(segments.get(0).initializationSegment).isNull();
    assertThat(segments.get(1).initializationSegment).isSameInstanceAs(segments.get(2).initializationSegment);
    assertThat(segments.get(1).initializationSegment.url).isEqualTo("init1.ts");
    assertThat(segments.get(3).initializationSegment.url).isEqualTo("init2.ts");
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) Uri(android.net.Uri) Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment) Test(org.junit.Test)

Example 35 with HlsMediaPlaylist

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

the class DefaultHlsPlaylistTrackerTest method runPlaylistTrackerAndCollectMediaPlaylists.

private static List<HlsMediaPlaylist> runPlaylistTrackerAndCollectMediaPlaylists(DataSource.Factory dataSourceFactory, Uri multivariantPlaylistUri, int awaitedMediaPlaylistCount) throws TimeoutException {
    DefaultHlsPlaylistTracker defaultHlsPlaylistTracker = new DefaultHlsPlaylistTracker(dataType -> dataSourceFactory.createDataSource(), new DefaultLoadErrorHandlingPolicy(), new DefaultHlsPlaylistParserFactory());
    List<HlsMediaPlaylist> mediaPlaylists = new ArrayList<>();
    AtomicInteger playlistCounter = new AtomicInteger();
    defaultHlsPlaylistTracker.start(multivariantPlaylistUri, new MediaSourceEventListener.EventDispatcher(), mediaPlaylist -> {
        mediaPlaylists.add(mediaPlaylist);
        playlistCounter.addAndGet(1);
    });
    RobolectricUtil.runMainLooperUntil(() -> playlistCounter.get() >= awaitedMediaPlaylistCount);
    defaultHlsPlaylistTracker.stop();
    return mediaPlaylists;
}
Also used : MediaSourceEventListener(com.google.android.exoplayer2.source.MediaSourceEventListener) DefaultLoadErrorHandlingPolicy(com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ArrayList(java.util.ArrayList)

Aggregations

HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)20 Uri (android.net.Uri)18 Segment (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)18 Test (org.junit.Test)18 InputStream (java.io.InputStream)11 ArrayList (java.util.ArrayList)11 Nullable (androidx.annotation.Nullable)9 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)9 ByteArrayInputStream (java.io.ByteArrayInputStream)9 HlsPlaylistParser (com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser)4 IOException (java.io.IOException)3 ParserException (com.google.android.exoplayer2.ParserException)2 BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)2 BaseMediaChunkIterator (com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator)2 MediaChunkIterator (com.google.android.exoplayer2.source.chunk.MediaChunkIterator)2 FakeDataSource (com.google.android.exoplayer2.testutil.FakeDataSource)2 SystemClock (android.os.SystemClock)1 Pair (android.util.Pair)1 VisibleForTesting (androidx.annotation.VisibleForTesting)1 AndroidJUnit4 (androidx.test.ext.junit.runners.AndroidJUnit4)1