From 6048ca2faa7e6fa500661ca4282bef2ddb7596e2 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 14 Feb 2022 12:39:14 +0000 Subject: [PATCH] Make usage of live minDurationForQualityIncrease more consistent We have two ways to choose the minDurationForQualityIncreaseMs value in AdaptiveTrackSelection: use the configured value for non-live or when enough buffered data is available, or use a fraction of the available duration to allow switching when playing close to the live edge. The decision point when to use which value isn't quite consistent because we compare against availableDurationUs before making the adjustments. This means there is range of values where no up-switching is possible despite perfect buffering. Fix this by choosing the minimum of both values. Issue: google/ExoPlayer#9784 #minor-release PiperOrigin-RevId: 428474332 --- .../trackselection/AdaptiveTrackSelection.java | 11 ++++++----- .../trackselection/AdaptiveTrackSelectionTest.java | 12 +++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java index 40dfa34a12..0d1c02e80f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelection.java @@ -16,6 +16,7 @@ package androidx.media3.exoplayer.trackselection; import static java.lang.Math.max; +import static java.lang.Math.min; import androidx.annotation.CallSuper; import androidx.annotation.Nullable; @@ -605,10 +606,8 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { } private long minDurationForQualityIncreaseUs(long availableDurationUs, long chunkDurationUs) { - boolean isAvailableDurationTooShort = - availableDurationUs != C.TIME_UNSET - && availableDurationUs <= minDurationForQualityIncreaseUs; - if (!isAvailableDurationTooShort) { + if (availableDurationUs == C.TIME_UNSET) { + // We are not in a live stream. Use the configured value. return minDurationForQualityIncreaseUs; } if (chunkDurationUs != C.TIME_UNSET) { @@ -619,7 +618,9 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { // actually achievable. availableDurationUs -= chunkDurationUs; } - return (long) (availableDurationUs * bufferedFractionToLiveEdgeForQualityIncrease); + long adjustedMinDurationForQualityIncreaseUs = + (long) (availableDurationUs * bufferedFractionToLiveEdgeForQualityIncrease); + return min(adjustedMinDurationForQualityIncreaseUs, minDurationForQualityIncreaseUs); } /** diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java index f2915110f9..b8cc647d9f 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/AdaptiveTrackSelectionTest.java @@ -175,7 +175,9 @@ public final class AdaptiveTrackSelectionTest { when(mockBandwidthMeter.getBitrateEstimate()).thenReturn(1000L, 2000L); AdaptiveTrackSelection adaptiveTrackSelection = prepareAdaptiveTrackSelectionWithBufferedFractionToLiveEdgeForQualiyIncrease( - trackGroup, /* bufferedFractionToLiveEdgeForQualityIncrease= */ 0.75f); + trackGroup, + /* bufferedFractionToLiveEdgeForQualityIncrease= */ 0.75f, + /* minDurationForQualityIncreaseMs= */ 5000); // Not buffered close to live edge yet. adaptiveTrackSelection.updateSelectedTrack( @@ -188,6 +190,8 @@ public final class AdaptiveTrackSelectionTest { assertThat(adaptiveTrackSelection.getSelectedFormat()).isEqualTo(format2); // Buffered all possible chunks (except for newly added chunk of 2 seconds). + // Intentionally choose a situation where availableDurationUs > minDurationForQualityIncreaseMs + // to ensure the live calculation is used regardless. adaptiveTrackSelection.updateSelectedTrack( /* playbackPositionUs= */ 0, /* bufferedDurationUs= */ 3_600_000, @@ -768,14 +772,16 @@ public final class AdaptiveTrackSelectionTest { private AdaptiveTrackSelection prepareAdaptiveTrackSelectionWithBufferedFractionToLiveEdgeForQualiyIncrease( - TrackGroup trackGroup, float bufferedFractionToLiveEdgeForQualityIncrease) { + TrackGroup trackGroup, + float bufferedFractionToLiveEdgeForQualityIncrease, + long minDurationForQualityIncreaseMs) { return prepareTrackSelection( new AdaptiveTrackSelection( trackGroup, selectedAllTracksInGroup(trackGroup), TrackSelection.TYPE_UNSET, mockBandwidthMeter, - AdaptiveTrackSelection.DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS, + minDurationForQualityIncreaseMs, AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS, AdaptiveTrackSelection.DEFAULT_MAX_WIDTH_TO_DISCARD,