From 727a4c0912e02dca3308a1ca1cc10e24d64bab04 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/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java index c09fb930b0..35a56682bf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.trackselection; import static java.lang.Math.max; +import static java.lang.Math.min; import androidx.annotation.CallSuper; import androidx.annotation.Nullable; @@ -602,10 +603,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) { @@ -616,7 +615,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/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java index 6b453b5f5a..0e94959229 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelectionTest.java @@ -174,7 +174,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( @@ -187,6 +189,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, @@ -767,14 +771,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,