use of com.google.android.exoplayer2.source.dash.DashSegmentIndex 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);
}
use of com.google.android.exoplayer2.source.dash.DashSegmentIndex in project ExoPlayer by google.
the class DashMediaSource method getAvailableStartTimeInManifestUs.
private static long getAvailableStartTimeInManifestUs(Period period, long periodDurationUs, long nowUnixTimeUs) {
long periodStartTimeInManifestUs = Util.msToUs(period.startMs);
long availableStartTimeInManifestUs = periodStartTimeInManifestUs;
boolean haveAudioVideoAdaptationSets = hasVideoOrAudioAdaptationSets(period);
for (int i = 0; i < period.adaptationSets.size(); i++) {
AdaptationSet adaptationSet = period.adaptationSets.get(i);
List<Representation> representations = adaptationSet.representations;
// or video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029
if ((haveAudioVideoAdaptationSets && adaptationSet.type == C.TRACK_TYPE_TEXT) || representations.isEmpty()) {
continue;
}
@Nullable DashSegmentIndex index = representations.get(0).getIndex();
if (index == null) {
return periodStartTimeInManifestUs;
}
long availableSegmentCount = index.getAvailableSegmentCount(periodDurationUs, nowUnixTimeUs);
if (availableSegmentCount == 0) {
return periodStartTimeInManifestUs;
}
long firstAvailableSegmentNum = index.getFirstAvailableSegmentNum(periodDurationUs, nowUnixTimeUs);
long adaptationSetAvailableStartTimeInManifestUs = periodStartTimeInManifestUs + index.getTimeUs(firstAvailableSegmentNum);
availableStartTimeInManifestUs = max(availableStartTimeInManifestUs, adaptationSetAvailableStartTimeInManifestUs);
}
return availableStartTimeInManifestUs;
}
use of com.google.android.exoplayer2.source.dash.DashSegmentIndex in project ExoPlayer by google.
the class DashDownloader method getSegmentIndex.
@Nullable
private DashSegmentIndex getSegmentIndex(DataSource dataSource, int trackType, Representation representation, boolean removing) throws IOException, InterruptedException {
DashSegmentIndex index = representation.getIndex();
if (index != null) {
return index;
}
RunnableFutureTask<@NullableType ChunkIndex, IOException> runnable = new RunnableFutureTask<@NullableType ChunkIndex, IOException>() {
@Override
@NullableType
protected ChunkIndex doWork() throws IOException {
return DashUtil.loadChunkIndex(dataSource, trackType, representation);
}
};
@Nullable ChunkIndex seekMap = execute(runnable, removing);
return seekMap == null ? null : new DashWrappingSegmentIndex(seekMap, representation.presentationTimeOffsetUs);
}
use of com.google.android.exoplayer2.source.dash.DashSegmentIndex in project ExoPlayer by google.
the class DashMediaSource method getAvailableEndTimeInManifestUs.
private static long getAvailableEndTimeInManifestUs(Period period, long periodDurationUs, long nowUnixTimeUs) {
long periodStartTimeInManifestUs = Util.msToUs(period.startMs);
long availableEndTimeInManifestUs = Long.MAX_VALUE;
boolean haveAudioVideoAdaptationSets = hasVideoOrAudioAdaptationSets(period);
for (int i = 0; i < period.adaptationSets.size(); i++) {
AdaptationSet adaptationSet = period.adaptationSets.get(i);
List<Representation> representations = adaptationSet.representations;
// or video adaptation set. See: https://github.com/google/ExoPlayer/issues/4029
if ((haveAudioVideoAdaptationSets && adaptationSet.type == C.TRACK_TYPE_TEXT) || representations.isEmpty()) {
continue;
}
@Nullable DashSegmentIndex index = representations.get(0).getIndex();
if (index == null) {
return periodStartTimeInManifestUs + periodDurationUs;
}
long availableSegmentCount = index.getAvailableSegmentCount(periodDurationUs, nowUnixTimeUs);
if (availableSegmentCount == 0) {
return periodStartTimeInManifestUs;
}
long firstAvailableSegmentNum = index.getFirstAvailableSegmentNum(periodDurationUs, nowUnixTimeUs);
long lastAvailableSegmentNum = firstAvailableSegmentNum + availableSegmentCount - 1;
long adaptationSetAvailableEndTimeInManifestUs = periodStartTimeInManifestUs + index.getTimeUs(lastAvailableSegmentNum) + index.getDurationUs(lastAvailableSegmentNum, periodDurationUs);
availableEndTimeInManifestUs = min(availableEndTimeInManifestUs, adaptationSetAvailableEndTimeInManifestUs);
}
return availableEndTimeInManifestUs;
}
use of com.google.android.exoplayer2.source.dash.DashSegmentIndex in project ExoPlayer by google.
the class DashDownloader method addSegmentsForAdaptationSet.
private void addSegmentsForAdaptationSet(DataSource dataSource, AdaptationSet adaptationSet, long periodStartUs, long periodDurationUs, boolean removing, ArrayList<Segment> out) throws IOException, InterruptedException {
for (int i = 0; i < adaptationSet.representations.size(); i++) {
Representation representation = adaptationSet.representations.get(i);
DashSegmentIndex index;
try {
index = getSegmentIndex(dataSource, adaptationSet.type, representation, removing);
if (index == null) {
// Loading succeeded but there was no index.
throw new DownloadException("Missing segment index");
}
} catch (IOException e) {
if (!removing) {
throw e;
}
// Generating an incomplete segment list is allowed. Advance to the next representation.
continue;
}
long segmentCount = index.getSegmentCount(periodDurationUs);
if (segmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
throw new DownloadException("Unbounded segment index");
}
String baseUrl = castNonNull(baseUrlExclusionList.selectBaseUrl(representation.baseUrls)).url;
@Nullable RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri != null) {
out.add(createSegment(representation, baseUrl, periodStartUs, initializationUri));
}
@Nullable RangedUri indexUri = representation.getIndexUri();
if (indexUri != null) {
out.add(createSegment(representation, baseUrl, periodStartUs, indexUri));
}
long firstSegmentNum = index.getFirstSegmentNum();
long lastSegmentNum = firstSegmentNum + segmentCount - 1;
for (long j = firstSegmentNum; j <= lastSegmentNum; j++) {
out.add(createSegment(representation, baseUrl, periodStartUs + index.getTimeUs(j), index.getSegmentUrl(j)));
}
}
}
Aggregations