Skip to content

Commit

Permalink
Select base URL on demand when a new chunk is created
Browse files Browse the repository at this point in the history
Instead of selecting the base URL initially or when a load error occurs, it is now selected when a chunk or initialization chunk is created. The selected base URL is then assigned to `RepresentationHolder.lastUsedBaseUrl` that is excluded in case of a load error. For a next chunk another base URL will be selected by using the `BaseUrlExclusionList`.

#minor-release #exo-fixit

PiperOrigin-RevId: 395721221
  • Loading branch information
marcbaechinger authored and ojw28 committed Sep 9, 2021
1 parent 0c4bb23 commit 9e3ef81
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 20 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
* DASH
* Use identical cache keys for downloading and playing DASH segments
([#9370](https://github.com/google/ExoPlayer/issues/9370)).
* Fix base URL selection and load error handling when base URLs are shared
across adaptation sets.
* Remove deprecated symbols:
* Remove `Renderer.VIDEO_SCALING_MODE_*` constants. Use identically named
constants in `C` instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ public void getNextChunk(
if (segmentNum < firstAvailableSegmentNum) {
chunkIterators[i] = MediaChunkIterator.EMPTY;
} else {
representationHolder = updateSelectedBaseUrl(/* trackIndex= */ i);
chunkIterators[i] =
new RepresentationSegmentIterator(
representationHolder, segmentNum, lastAvailableSegmentNum, nowPeriodTimeUs);
Expand All @@ -350,12 +351,11 @@ public void getNextChunk(
playbackPositionUs, bufferedDurationUs, availableLiveDurationUs, queue, chunkIterators);

RepresentationHolder representationHolder =
representationHolders[trackSelection.getSelectedIndex()];

updateSelectedBaseUrl(trackSelection.getSelectedIndex());
if (representationHolder.chunkExtractor != null) {
Representation selectedRepresentation = representationHolder.representation;
RangedUri pendingInitializationUri = null;
RangedUri pendingIndexUri = null;
@Nullable RangedUri pendingInitializationUri = null;
@Nullable RangedUri pendingIndexUri = null;
if (representationHolder.chunkExtractor.getSampleFormats() == null) {
pendingInitializationUri = selectedRepresentation.getInitializationUri();
}
Expand Down Expand Up @@ -495,18 +495,26 @@ public boolean onChunkLoadError(

int trackIndex = trackSelection.indexOf(chunk.trackFormat);
RepresentationHolder representationHolder = representationHolders[trackIndex];
@Nullable
BaseUrl newBaseUrl =
baseUrlExclusionList.selectBaseUrl(representationHolder.representation.baseUrls);
if (newBaseUrl != null && !representationHolder.selectedBaseUrl.equals(newBaseUrl)) {
// The base URL has changed since the failing chunk was created. Request a replacement chunk,
// which will use the new base URL.
return true;
}

LoadErrorHandlingPolicy.FallbackOptions fallbackOptions =
createFallbackOptions(trackSelection, representationHolder.representation.baseUrls);
if (!fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK)
&& !fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION)) {
// No more alternatives remaining.
return false;
}
@Nullable
LoadErrorHandlingPolicy.FallbackSelection fallbackSelection =
loadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo);
if (fallbackSelection == null) {
// Policy indicated to not use any fallback.
if (fallbackSelection == null || !fallbackOptions.isFallbackAvailable(fallbackSelection.type)) {
// Policy indicated to not use any fallback or a fallback type that is not available.
return false;
}

Expand All @@ -518,17 +526,7 @@ public boolean onChunkLoadError(
} else if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION) {
baseUrlExclusionList.exclude(
representationHolder.selectedBaseUrl, fallbackSelection.exclusionDurationMs);
for (int i = 0; i < representationHolders.length; i++) {
@Nullable
BaseUrl baseUrl =
baseUrlExclusionList.selectBaseUrl(representationHolders[i].representation.baseUrls);
if (baseUrl != null) {
if (i == trackIndex) {
cancelLoad = true;
}
representationHolders[i] = representationHolders[i].copyWithNewSelectedBaseUrl(baseUrl);
}
}
cancelLoad = true;
}
return cancelLoad;
}
Expand Down Expand Up @@ -610,9 +608,9 @@ protected Chunk newInitializationChunk(
DataSource dataSource,
Format trackFormat,
@C.SelectionReason int trackSelectionReason,
Object trackSelectionData,
@Nullable Object trackSelectionData,
@Nullable RangedUri initializationUri,
RangedUri indexUri) {
@Nullable RangedUri indexUri) {
Representation representation = representationHolder.representation;
@Nullable RangedUri requestUri;
if (initializationUri != null) {
Expand Down Expand Up @@ -719,6 +717,18 @@ protected Chunk newMediaChunk(
}
}

private RepresentationHolder updateSelectedBaseUrl(int trackIndex) {
RepresentationHolder representationHolder = representationHolders[trackIndex];
@Nullable
BaseUrl selectedBaseUrl =
baseUrlExclusionList.selectBaseUrl(representationHolder.representation.baseUrls);
if (selectedBaseUrl != null && !selectedBaseUrl.equals(representationHolder.selectedBaseUrl)) {
representationHolder = representationHolder.copyWithNewSelectedBaseUrl(selectedBaseUrl);
representationHolders[trackIndex] = representationHolder;
}
return representationHolder;
}

// Protected classes.

/** {@link MediaChunkIterator} wrapping a {@link RepresentationHolder}. */
Expand Down

0 comments on commit 9e3ef81

Please sign in to comment.