Search in sources :

Example 1 with HlsUrl

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

the class HlsChunkSource method getNextChunk.

/**
   * Returns the next chunk to load.
   * <p>
   * If a chunk is available then {@link HlsChunkHolder#chunk} is set. If the end of the stream has
   * been reached then {@link HlsChunkHolder#endOfStream} is set. If a chunk is not available but
   * the end of the stream has not been reached, {@link HlsChunkHolder#playlist} is set to
   * contain the {@link HlsUrl} that refers to the playlist that needs refreshing.
   *
   * @param previous The most recently loaded media chunk.
   * @param playbackPositionUs The current playback position. If {@code previous} is null then this
   *     parameter is the position from which playback is expected to start (or restart) and hence
   *     should be interpreted as a seek position.
   * @param out A holder to populate.
   */
public void getNextChunk(HlsMediaChunk previous, long playbackPositionUs, HlsChunkHolder out) {
    int oldVariantIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat);
    // Use start time of the previous chunk rather than its end time because switching format will
    // require downloading overlapping segments.
    long bufferedDurationUs = previous == null ? 0 : Math.max(0, previous.startTimeUs - playbackPositionUs);
    // Select the variant.
    trackSelection.updateSelectedTrack(bufferedDurationUs);
    int selectedVariantIndex = trackSelection.getSelectedIndexInTrackGroup();
    boolean switchingVariant = oldVariantIndex != selectedVariantIndex;
    HlsUrl selectedUrl = variants[selectedVariantIndex];
    if (!playlistTracker.isSnapshotValid(selectedUrl)) {
        out.playlist = selectedUrl;
        // Retry when playlist is refreshed.
        return;
    }
    HlsMediaPlaylist mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl);
    // Select the chunk.
    int chunkMediaSequence;
    if (previous == null || switchingVariant) {
        long targetPositionUs = previous == null ? playbackPositionUs : previous.startTimeUs;
        if (!mediaPlaylist.hasEndTag && targetPositionUs > mediaPlaylist.getEndTimeUs()) {
            // If the playlist is too old to contain the chunk, we need to refresh it.
            chunkMediaSequence = mediaPlaylist.mediaSequence + mediaPlaylist.segments.size();
        } else {
            chunkMediaSequence = Util.binarySearchFloor(mediaPlaylist.segments, targetPositionUs - mediaPlaylist.startTimeUs, true, !playlistTracker.isLive() || previous == null) + mediaPlaylist.mediaSequence;
            if (chunkMediaSequence < mediaPlaylist.mediaSequence && previous != null) {
                // We try getting the next chunk without adapting in case that's the reason for falling
                // behind the live window.
                selectedVariantIndex = oldVariantIndex;
                selectedUrl = variants[selectedVariantIndex];
                mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl);
                chunkMediaSequence = previous.getNextChunkIndex();
            }
        }
    } else {
        chunkMediaSequence = previous.getNextChunkIndex();
    }
    if (chunkMediaSequence < mediaPlaylist.mediaSequence) {
        fatalError = new BehindLiveWindowException();
        return;
    }
    int chunkIndex = chunkMediaSequence - mediaPlaylist.mediaSequence;
    if (chunkIndex >= mediaPlaylist.segments.size()) {
        if (mediaPlaylist.hasEndTag) {
            out.endOfStream = true;
        } else /* Live */
        {
            out.playlist = selectedUrl;
        }
        return;
    }
    // Handle encryption.
    HlsMediaPlaylist.Segment segment = mediaPlaylist.segments.get(chunkIndex);
    // Check if encryption is specified.
    if (segment.isEncrypted) {
        Uri keyUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.encryptionKeyUri);
        if (!keyUri.equals(encryptionKeyUri)) {
            // Encryption is specified and the key has changed.
            out.chunk = newEncryptionKeyChunk(keyUri, segment.encryptionIV, selectedVariantIndex, trackSelection.getSelectionReason(), trackSelection.getSelectionData());
            return;
        }
        if (!Util.areEqual(segment.encryptionIV, encryptionIvString)) {
            setEncryptionData(keyUri, segment.encryptionIV, encryptionKey);
        }
    } else {
        clearEncryptionData();
    }
    DataSpec initDataSpec = null;
    Segment initSegment = mediaPlaylist.initializationSegment;
    if (initSegment != null) {
        Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
        initDataSpec = new DataSpec(initSegmentUri, initSegment.byterangeOffset, initSegment.byterangeLength, null);
    }
    // Compute start time of the next chunk.
    long startTimeUs = mediaPlaylist.startTimeUs + segment.relativeStartTimeUs;
    int discontinuitySequence = mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence;
    TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(discontinuitySequence);
    // Configure the data source and spec for the chunk.
    Uri chunkUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.url);
    DataSpec dataSpec = new DataSpec(chunkUri, segment.byterangeOffset, segment.byterangeLength, null);
    out.chunk = new HlsMediaChunk(mediaDataSource, dataSpec, initDataSpec, selectedUrl, muxedCaptionFormats, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), startTimeUs, startTimeUs + segment.durationUs, chunkMediaSequence, discontinuitySequence, isTimestampMaster, timestampAdjuster, previous, encryptionKey, encryptionIv);
}
Also used : Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment) HlsUrl(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl) BehindLiveWindowException(com.google.android.exoplayer2.source.BehindLiveWindowException) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) HlsMediaPlaylist(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist) TimestampAdjuster(com.google.android.exoplayer2.util.TimestampAdjuster) Uri(android.net.Uri) Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)

Example 2 with HlsUrl

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

the class HlsPlaylistTracker method createBundles.

private void createBundles(List<HlsUrl> urls) {
    int listSize = urls.size();
    long currentTimeMs = SystemClock.elapsedRealtime();
    for (int i = 0; i < listSize; i++) {
        HlsUrl url = urls.get(i);
        MediaPlaylistBundle bundle = new MediaPlaylistBundle(url, currentTimeMs);
        playlistBundles.put(url, bundle);
    }
}
Also used : HlsUrl(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl)

Example 3 with HlsUrl

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

the class HlsMediaPeriod method buildAndPrepareSampleStreamWrappers.

// Internal methods.
private void buildAndPrepareSampleStreamWrappers() {
    HlsMasterPlaylist masterPlaylist = playlistTracker.getMasterPlaylist();
    // Build the default stream wrapper.
    List<HlsUrl> selectedVariants = new ArrayList<>(masterPlaylist.variants);
    ArrayList<HlsUrl> definiteVideoVariants = new ArrayList<>();
    ArrayList<HlsUrl> definiteAudioOnlyVariants = new ArrayList<>();
    for (int i = 0; i < selectedVariants.size(); i++) {
        HlsUrl variant = selectedVariants.get(i);
        if (variant.format.height > 0 || variantHasExplicitCodecWithPrefix(variant, "avc")) {
            definiteVideoVariants.add(variant);
        } else if (variantHasExplicitCodecWithPrefix(variant, "mp4a")) {
            definiteAudioOnlyVariants.add(variant);
        }
    }
    if (!definiteVideoVariants.isEmpty()) {
        // We've identified some variants as definitely containing video. Assume variants within the
        // master playlist are marked consistently, and hence that we have the full set. Filter out
        // any other variants, which are likely to be audio only.
        selectedVariants = definiteVideoVariants;
    } else if (definiteAudioOnlyVariants.size() < selectedVariants.size()) {
        // We've identified some variants, but not all, as being audio only. Filter them out to leave
        // the remaining variants, which are likely to contain video.
        selectedVariants.removeAll(definiteAudioOnlyVariants);
    } else {
    // Leave the enabled variants unchanged. They're likely either all video or all audio.
    }
    List<HlsUrl> audioRenditions = masterPlaylist.audios;
    List<HlsUrl> subtitleRenditions = masterPlaylist.subtitles;
    sampleStreamWrappers = new HlsSampleStreamWrapper[1 + /* variants */
    audioRenditions.size() + subtitleRenditions.size()];
    int currentWrapperIndex = 0;
    pendingPrepareCount = sampleStreamWrappers.length;
    Assertions.checkArgument(!selectedVariants.isEmpty());
    HlsUrl[] variants = new HlsMasterPlaylist.HlsUrl[selectedVariants.size()];
    selectedVariants.toArray(variants);
    HlsSampleStreamWrapper sampleStreamWrapper = buildSampleStreamWrapper(C.TRACK_TYPE_DEFAULT, variants, masterPlaylist.muxedAudioFormat, masterPlaylist.muxedCaptionFormats);
    sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper;
    sampleStreamWrapper.setIsTimestampMaster(true);
    sampleStreamWrapper.continuePreparing();
    // Build audio stream wrappers.
    for (int i = 0; i < audioRenditions.size(); i++) {
        sampleStreamWrapper = buildSampleStreamWrapper(C.TRACK_TYPE_AUDIO, new HlsUrl[] { audioRenditions.get(i) }, null, Collections.<Format>emptyList());
        sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper;
        sampleStreamWrapper.continuePreparing();
    }
    // Build subtitle stream wrappers.
    for (int i = 0; i < subtitleRenditions.size(); i++) {
        HlsUrl url = subtitleRenditions.get(i);
        sampleStreamWrapper = buildSampleStreamWrapper(C.TRACK_TYPE_TEXT, new HlsUrl[] { url }, null, Collections.<Format>emptyList());
        sampleStreamWrapper.prepareSingleTrack(url.format);
        sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper;
    }
}
Also used : Format(com.google.android.exoplayer2.Format) HlsUrl(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl) ArrayList(java.util.ArrayList) HlsMasterPlaylist(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist)

Aggregations

HlsUrl (com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl)3 Uri (android.net.Uri)1 Format (com.google.android.exoplayer2.Format)1 BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)1 HlsMasterPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist)1 HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)1 Segment (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)1 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)1 TimestampAdjuster (com.google.android.exoplayer2.util.TimestampAdjuster)1 ArrayList (java.util.ArrayList)1