Search in sources :

Example 1 with MediaChunk

use of com.google.android.exoplayer2.source.chunk.MediaChunk in project ExoPlayer by google.

the class HlsSampleStreamWrapper method continueLoading.

// SequenceableLoader implementation
@Override
public boolean continueLoading(long positionUs) {
    if (loadingFinished || loader.isLoading()) {
        return false;
    }
    chunkSource.getNextChunk(mediaChunks.isEmpty() ? null : mediaChunks.getLast(), pendingResetPositionUs != C.TIME_UNSET ? pendingResetPositionUs : positionUs, nextChunkHolder);
    boolean endOfStream = nextChunkHolder.endOfStream;
    Chunk loadable = nextChunkHolder.chunk;
    HlsMasterPlaylist.HlsUrl playlistToLoad = nextChunkHolder.playlist;
    nextChunkHolder.clear();
    if (endOfStream) {
        loadingFinished = true;
        return true;
    }
    if (loadable == null) {
        if (playlistToLoad != null) {
            callback.onPlaylistRefreshRequired(playlistToLoad);
        }
        return false;
    }
    if (isMediaChunk(loadable)) {
        pendingResetPositionUs = C.TIME_UNSET;
        HlsMediaChunk mediaChunk = (HlsMediaChunk) loadable;
        mediaChunk.init(this);
        mediaChunks.add(mediaChunk);
    }
    long elapsedRealtimeMs = loader.startLoading(loadable, this, minLoadableRetryCount);
    eventDispatcher.loadStarted(loadable.dataSpec, loadable.type, trackType, loadable.trackFormat, loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs);
    return true;
}
Also used : Chunk(com.google.android.exoplayer2.source.chunk.Chunk) HlsMasterPlaylist(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist) HlsUrl(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl)

Example 2 with MediaChunk

use of com.google.android.exoplayer2.source.chunk.MediaChunk in project ExoPlayer by google.

the class DefaultDashChunkSource method getNextChunk.

@Override
public final void getNextChunk(MediaChunk previous, long playbackPositionUs, ChunkHolder out) {
    if (fatalError != null) {
        return;
    }
    long bufferedDurationUs = previous != null ? (previous.endTimeUs - playbackPositionUs) : 0;
    trackSelection.updateSelectedTrack(bufferedDurationUs);
    RepresentationHolder representationHolder = representationHolders[trackSelection.getSelectedIndex()];
    Representation selectedRepresentation = representationHolder.representation;
    DashSegmentIndex segmentIndex = representationHolder.segmentIndex;
    RangedUri pendingInitializationUri = null;
    RangedUri pendingIndexUri = null;
    if (representationHolder.extractorWrapper.getSampleFormats() == null) {
        pendingInitializationUri = selectedRepresentation.getInitializationUri();
    }
    if (segmentIndex == null) {
        pendingIndexUri = selectedRepresentation.getIndexUri();
    }
    if (pendingInitializationUri != null || pendingIndexUri != null) {
        // We have initialization and/or index requests to make.
        out.chunk = newInitializationChunk(representationHolder, dataSource, trackSelection.getSelectedFormat(), trackSelection.getSelectionReason(), trackSelection.getSelectionData(), pendingInitializationUri, pendingIndexUri);
        return;
    }
    long nowUs = getNowUnixTimeUs();
    int availableSegmentCount = representationHolder.getSegmentCount();
    if (availableSegmentCount == 0) {
        // The index doesn't define any segments.
        out.endOfStream = !manifest.dynamic || (periodIndex < manifest.getPeriodCount() - 1);
        return;
    }
    int firstAvailableSegmentNum = representationHolder.getFirstSegmentNum();
    int lastAvailableSegmentNum;
    if (availableSegmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
        // The index is itself unbounded. We need to use the current time to calculate the range of
        // available segments.
        long liveEdgeTimeUs = nowUs - manifest.availabilityStartTime * 1000;
        long periodStartUs = manifest.getPeriod(periodIndex).startMs * 1000;
        long liveEdgeTimeInPeriodUs = liveEdgeTimeUs - periodStartUs;
        if (manifest.timeShiftBufferDepth != C.TIME_UNSET) {
            long bufferDepthUs = manifest.timeShiftBufferDepth * 1000;
            firstAvailableSegmentNum = Math.max(firstAvailableSegmentNum, representationHolder.getSegmentNum(liveEdgeTimeInPeriodUs - bufferDepthUs));
        }
        // getSegmentNum(liveEdgeTimestampUs) will not be completed yet, so subtract one to get the
        // index of the last completed segment.
        lastAvailableSegmentNum = representationHolder.getSegmentNum(liveEdgeTimeInPeriodUs) - 1;
    } else {
        lastAvailableSegmentNum = firstAvailableSegmentNum + availableSegmentCount - 1;
    }
    int segmentNum;
    if (previous == null) {
        segmentNum = Util.constrainValue(representationHolder.getSegmentNum(playbackPositionUs), firstAvailableSegmentNum, lastAvailableSegmentNum);
    } else {
        segmentNum = previous.getNextChunkIndex();
        if (segmentNum < firstAvailableSegmentNum) {
            // This is before the first chunk in the current manifest.
            fatalError = new BehindLiveWindowException();
            return;
        }
    }
    if (segmentNum > lastAvailableSegmentNum || (missingLastSegment && segmentNum >= lastAvailableSegmentNum)) {
        // This is beyond the last chunk in the current manifest.
        out.endOfStream = !manifest.dynamic || (periodIndex < manifest.getPeriodCount() - 1);
        return;
    }
    int maxSegmentCount = Math.min(maxSegmentsPerLoad, lastAvailableSegmentNum - segmentNum + 1);
    out.chunk = newMediaChunk(representationHolder, dataSource, trackSelection.getSelectedFormat(), trackSelection.getSelectionReason(), trackSelection.getSelectionData(), segmentNum, maxSegmentCount);
}
Also used : BehindLiveWindowException(com.google.android.exoplayer2.source.BehindLiveWindowException) RangedUri(com.google.android.exoplayer2.source.dash.manifest.RangedUri) Representation(com.google.android.exoplayer2.source.dash.manifest.Representation)

Example 3 with MediaChunk

use of com.google.android.exoplayer2.source.chunk.MediaChunk in project ExoPlayer by google.

the class AdaptiveTrackSelection method evaluateQueueSize.

@Override
public int evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk> queue) {
    if (queue.isEmpty()) {
        return 0;
    }
    int queueSize = queue.size();
    long bufferedDurationUs = queue.get(queueSize - 1).endTimeUs - playbackPositionUs;
    if (bufferedDurationUs < minDurationToRetainAfterDiscardUs) {
        return queueSize;
    }
    int idealSelectedIndex = determineIdealSelectedIndex(SystemClock.elapsedRealtime());
    Format idealFormat = getFormat(idealSelectedIndex);
    // track.
    for (int i = 0; i < queueSize; i++) {
        MediaChunk chunk = queue.get(i);
        Format format = chunk.trackFormat;
        long durationBeforeThisChunkUs = chunk.startTimeUs - playbackPositionUs;
        if (durationBeforeThisChunkUs >= minDurationToRetainAfterDiscardUs && format.bitrate < idealFormat.bitrate && format.height != Format.NO_VALUE && format.height < 720 && format.width != Format.NO_VALUE && format.width < 1280 && format.height < idealFormat.height) {
            return i;
        }
    }
    return queueSize;
}
Also used : Format(com.google.android.exoplayer2.Format) MediaChunk(com.google.android.exoplayer2.source.chunk.MediaChunk)

Example 4 with MediaChunk

use of com.google.android.exoplayer2.source.chunk.MediaChunk in project ExoPlayer by google.

the class DefaultSsChunkSource method getNextChunk.

@Override
public final void getNextChunk(MediaChunk previous, long playbackPositionUs, ChunkHolder out) {
    if (fatalError != null) {
        return;
    }
    long bufferedDurationUs = previous != null ? (previous.endTimeUs - playbackPositionUs) : 0;
    trackSelection.updateSelectedTrack(bufferedDurationUs);
    StreamElement streamElement = manifest.streamElements[elementIndex];
    if (streamElement.chunkCount == 0) {
        // There aren't any chunks for us to load.
        out.endOfStream = !manifest.isLive;
        return;
    }
    int chunkIndex;
    if (previous == null) {
        chunkIndex = streamElement.getChunkIndex(playbackPositionUs);
    } else {
        chunkIndex = previous.getNextChunkIndex() - currentManifestChunkOffset;
        if (chunkIndex < 0) {
            // This is before the first chunk in the current manifest.
            fatalError = new BehindLiveWindowException();
            return;
        }
    }
    if (chunkIndex >= streamElement.chunkCount) {
        // This is beyond the last chunk in the current manifest.
        out.endOfStream = !manifest.isLive;
        return;
    }
    long chunkStartTimeUs = streamElement.getStartTimeUs(chunkIndex);
    long chunkEndTimeUs = chunkStartTimeUs + streamElement.getChunkDurationUs(chunkIndex);
    int currentAbsoluteChunkIndex = chunkIndex + currentManifestChunkOffset;
    int trackSelectionIndex = trackSelection.getSelectedIndex();
    ChunkExtractorWrapper extractorWrapper = extractorWrappers[trackSelectionIndex];
    int manifestTrackIndex = trackSelection.getIndexInTrackGroup(trackSelectionIndex);
    Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex);
    out.chunk = newMediaChunk(trackSelection.getSelectedFormat(), dataSource, uri, null, currentAbsoluteChunkIndex, chunkStartTimeUs, chunkEndTimeUs, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), extractorWrapper);
}
Also used : BehindLiveWindowException(com.google.android.exoplayer2.source.BehindLiveWindowException) ChunkExtractorWrapper(com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper) StreamElement(com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement) Uri(android.net.Uri)

Example 5 with MediaChunk

use of com.google.android.exoplayer2.source.chunk.MediaChunk in project ExoPlayer by google.

the class DefaultSsChunkSource method newMediaChunk.

// Private methods.
private static MediaChunk newMediaChunk(Format format, DataSource dataSource, Uri uri, String cacheKey, int chunkIndex, long chunkStartTimeUs, long chunkEndTimeUs, int trackSelectionReason, Object trackSelectionData, ChunkExtractorWrapper extractorWrapper) {
    DataSpec dataSpec = new DataSpec(uri, 0, C.LENGTH_UNSET, cacheKey);
    // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk.
    // To convert them the absolute timestamps, we need to set sampleOffsetUs to chunkStartTimeUs.
    long sampleOffsetUs = chunkStartTimeUs;
    return new ContainerMediaChunk(dataSource, dataSpec, format, trackSelectionReason, trackSelectionData, chunkStartTimeUs, chunkEndTimeUs, chunkIndex, 1, sampleOffsetUs, extractorWrapper);
}
Also used : DataSpec(com.google.android.exoplayer2.upstream.DataSpec) ContainerMediaChunk(com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)

Aggregations

BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)2 Uri (android.net.Uri)1 Format (com.google.android.exoplayer2.Format)1 Chunk (com.google.android.exoplayer2.source.chunk.Chunk)1 ChunkExtractorWrapper (com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper)1 ContainerMediaChunk (com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)1 MediaChunk (com.google.android.exoplayer2.source.chunk.MediaChunk)1 RangedUri (com.google.android.exoplayer2.source.dash.manifest.RangedUri)1 Representation (com.google.android.exoplayer2.source.dash.manifest.Representation)1 HlsMasterPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist)1 HlsUrl (com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl)1 StreamElement (com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement)1 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)1