Search in sources :

Example 1 with StreamElement

use of androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement in project media by androidx.

the class DefaultSsChunkSource method getNextChunk.

@Override
public final void getNextChunk(long playbackPositionUs, long loadPositionUs, List<? extends MediaChunk> queue, ChunkHolder out) {
    if (fatalError != null) {
        return;
    }
    StreamElement streamElement = manifest.streamElements[streamElementIndex];
    if (streamElement.chunkCount == 0) {
        // There aren't any chunks for us to load.
        out.endOfStream = !manifest.isLive;
        return;
    }
    int chunkIndex;
    if (queue.isEmpty()) {
        chunkIndex = streamElement.getChunkIndex(loadPositionUs);
    } else {
        chunkIndex = (int) (queue.get(queue.size() - 1).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 bufferedDurationUs = loadPositionUs - playbackPositionUs;
    long timeToLiveEdgeUs = resolveTimeToLiveEdgeUs(playbackPositionUs);
    MediaChunkIterator[] chunkIterators = new MediaChunkIterator[trackSelection.length()];
    for (int i = 0; i < chunkIterators.length; i++) {
        int trackIndex = trackSelection.getIndexInTrackGroup(i);
        chunkIterators[i] = new StreamElementIterator(streamElement, trackIndex, chunkIndex);
    }
    trackSelection.updateSelectedTrack(playbackPositionUs, bufferedDurationUs, timeToLiveEdgeUs, queue, chunkIterators);
    long chunkStartTimeUs = streamElement.getStartTimeUs(chunkIndex);
    long chunkEndTimeUs = chunkStartTimeUs + streamElement.getChunkDurationUs(chunkIndex);
    long chunkSeekTimeUs = queue.isEmpty() ? loadPositionUs : C.TIME_UNSET;
    int currentAbsoluteChunkIndex = chunkIndex + currentManifestChunkOffset;
    int trackSelectionIndex = trackSelection.getSelectedIndex();
    ChunkExtractor chunkExtractor = chunkExtractors[trackSelectionIndex];
    int manifestTrackIndex = trackSelection.getIndexInTrackGroup(trackSelectionIndex);
    Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex);
    out.chunk = newMediaChunk(trackSelection.getSelectedFormat(), dataSource, uri, currentAbsoluteChunkIndex, chunkStartTimeUs, chunkEndTimeUs, chunkSeekTimeUs, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), chunkExtractor);
}
Also used : BaseMediaChunkIterator(androidx.media3.exoplayer.source.chunk.BaseMediaChunkIterator) MediaChunkIterator(androidx.media3.exoplayer.source.chunk.MediaChunkIterator) BehindLiveWindowException(androidx.media3.exoplayer.source.BehindLiveWindowException) StreamElement(androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement) ChunkExtractor(androidx.media3.exoplayer.source.chunk.ChunkExtractor) BundledChunkExtractor(androidx.media3.exoplayer.source.chunk.BundledChunkExtractor) Uri(android.net.Uri)

Example 2 with StreamElement

use of androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement in project media by androidx.

the class DefaultSsChunkSource method resolveTimeToLiveEdgeUs.

private long resolveTimeToLiveEdgeUs(long playbackPositionUs) {
    if (!manifest.isLive) {
        return C.TIME_UNSET;
    }
    StreamElement currentElement = manifest.streamElements[streamElementIndex];
    int lastChunkIndex = currentElement.chunkCount - 1;
    long lastChunkEndTimeUs = currentElement.getStartTimeUs(lastChunkIndex) + currentElement.getChunkDurationUs(lastChunkIndex);
    return lastChunkEndTimeUs - playbackPositionUs;
}
Also used : StreamElement(androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement)

Example 3 with StreamElement

use of androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement in project media by androidx.

the class SsMediaSource method processManifest.

// Internal methods
private void processManifest() {
    for (int i = 0; i < mediaPeriods.size(); i++) {
        mediaPeriods.get(i).updateManifest(manifest);
    }
    long startTimeUs = Long.MAX_VALUE;
    long endTimeUs = Long.MIN_VALUE;
    for (StreamElement element : manifest.streamElements) {
        if (element.chunkCount > 0) {
            startTimeUs = min(startTimeUs, element.getStartTimeUs(0));
            endTimeUs = max(endTimeUs, element.getStartTimeUs(element.chunkCount - 1) + element.getChunkDurationUs(element.chunkCount - 1));
        }
    }
    Timeline timeline;
    if (startTimeUs == Long.MAX_VALUE) {
        long periodDurationUs = manifest.isLive ? C.TIME_UNSET : 0;
        timeline = new SinglePeriodTimeline(periodDurationUs, /* windowDurationUs= */
        0, /* windowPositionInPeriodUs= */
        0, /* windowDefaultStartPositionUs= */
        0, /* isSeekable= */
        true, /* isDynamic= */
        manifest.isLive, /* useLiveConfiguration= */
        manifest.isLive, manifest, mediaItem);
    } else if (manifest.isLive) {
        if (manifest.dvrWindowLengthUs != C.TIME_UNSET && manifest.dvrWindowLengthUs > 0) {
            startTimeUs = max(startTimeUs, endTimeUs - manifest.dvrWindowLengthUs);
        }
        long durationUs = endTimeUs - startTimeUs;
        long defaultStartPositionUs = durationUs - Util.msToUs(livePresentationDelayMs);
        if (defaultStartPositionUs < MIN_LIVE_DEFAULT_START_POSITION_US) {
            // The default start position is too close to the start of the live window. Set it to the
            // minimum default start position provided the window is at least twice as big. Else set
            // it to the middle of the window.
            defaultStartPositionUs = min(MIN_LIVE_DEFAULT_START_POSITION_US, durationUs / 2);
        }
        timeline = new SinglePeriodTimeline(/* periodDurationUs= */
        C.TIME_UNSET, durationUs, startTimeUs, defaultStartPositionUs, /* isSeekable= */
        true, /* isDynamic= */
        true, /* useLiveConfiguration= */
        true, manifest, mediaItem);
    } else {
        long durationUs = manifest.durationUs != C.TIME_UNSET ? manifest.durationUs : endTimeUs - startTimeUs;
        timeline = new SinglePeriodTimeline(startTimeUs + durationUs, durationUs, startTimeUs, /* windowDefaultStartPositionUs= */
        0, /* isSeekable= */
        true, /* isDynamic= */
        false, /* useLiveConfiguration= */
        false, manifest, mediaItem);
    }
    refreshSourceInfo(timeline);
}
Also used : Timeline(androidx.media3.common.Timeline) SinglePeriodTimeline(androidx.media3.exoplayer.source.SinglePeriodTimeline) SinglePeriodTimeline(androidx.media3.exoplayer.source.SinglePeriodTimeline) StreamElement(androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement)

Example 4 with StreamElement

use of androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement in project media by androidx.

the class SsManifest method copy.

@Override
public final SsManifest copy(List<StreamKey> streamKeys) {
    ArrayList<StreamKey> sortedKeys = new ArrayList<>(streamKeys);
    Collections.sort(sortedKeys);
    StreamElement currentStreamElement = null;
    List<StreamElement> copiedStreamElements = new ArrayList<>();
    List<Format> copiedFormats = new ArrayList<>();
    for (int i = 0; i < sortedKeys.size(); i++) {
        StreamKey key = sortedKeys.get(i);
        StreamElement streamElement = streamElements[key.groupIndex];
        if (streamElement != currentStreamElement && currentStreamElement != null) {
            // We're advancing to a new stream element. Add the current one.
            copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
            copiedFormats.clear();
        }
        currentStreamElement = streamElement;
        copiedFormats.add(streamElement.formats[key.streamIndex]);
    }
    if (currentStreamElement != null) {
        // Add the last stream element.
        copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
    }
    StreamElement[] copiedStreamElementsArray = copiedStreamElements.toArray(new StreamElement[0]);
    return new SsManifest(majorVersion, minorVersion, durationUs, dvrWindowLengthUs, lookAheadCount, isLive, protectionElement, copiedStreamElementsArray);
}
Also used : Format(androidx.media3.common.Format) ArrayList(java.util.ArrayList) StreamKey(androidx.media3.common.StreamKey)

Example 5 with StreamElement

use of androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement in project media by androidx.

the class DefaultSsChunkSource method updateManifest.

@Override
public void updateManifest(SsManifest newManifest) {
    StreamElement currentElement = manifest.streamElements[streamElementIndex];
    int currentElementChunkCount = currentElement.chunkCount;
    StreamElement newElement = newManifest.streamElements[streamElementIndex];
    if (currentElementChunkCount == 0 || newElement.chunkCount == 0) {
        // There's no overlap between the old and new elements because at least one is empty.
        currentManifestChunkOffset += currentElementChunkCount;
    } else {
        long currentElementEndTimeUs = currentElement.getStartTimeUs(currentElementChunkCount - 1) + currentElement.getChunkDurationUs(currentElementChunkCount - 1);
        long newElementStartTimeUs = newElement.getStartTimeUs(0);
        if (currentElementEndTimeUs <= newElementStartTimeUs) {
            // There's no overlap between the old and new elements.
            currentManifestChunkOffset += currentElementChunkCount;
        } else {
            // The new element overlaps with the old one.
            currentManifestChunkOffset += currentElement.getChunkIndex(newElementStartTimeUs);
        }
    }
    manifest = newManifest;
}
Also used : StreamElement(androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement)

Aggregations

StreamElement (androidx.media3.exoplayer.smoothstreaming.manifest.SsManifest.StreamElement)6 Uri (android.net.Uri)1 Format (androidx.media3.common.Format)1 StreamKey (androidx.media3.common.StreamKey)1 Timeline (androidx.media3.common.Timeline)1 BehindLiveWindowException (androidx.media3.exoplayer.source.BehindLiveWindowException)1 SinglePeriodTimeline (androidx.media3.exoplayer.source.SinglePeriodTimeline)1 BaseMediaChunkIterator (androidx.media3.exoplayer.source.chunk.BaseMediaChunkIterator)1 BundledChunkExtractor (androidx.media3.exoplayer.source.chunk.BundledChunkExtractor)1 ChunkExtractor (androidx.media3.exoplayer.source.chunk.ChunkExtractor)1 MediaChunkIterator (androidx.media3.exoplayer.source.chunk.MediaChunkIterator)1 ArrayList (java.util.ArrayList)1