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);
}
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;
}
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);
}
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);
}
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;
}
Aggregations