From f2c13d9f446d38a1525efa84dff1916ab47ae4ad Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 19 Apr 2021 23:26:49 +0100 Subject: [PATCH] Misc cleanup / clarification for bandwidth improvements PiperOrigin-RevId: 369315524 --- .../AdaptiveTrackSelection.java | 31 +++++++++++++------ .../upstream/TimeToFirstByteEstimator.java | 2 +- 2 files changed, 23 insertions(+), 10 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 18a71cbf2f..cef8f7fa64 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 @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.trackselection; +import static java.lang.Math.max; + import androidx.annotation.CallSuper; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; @@ -329,7 +331,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { List queue, MediaChunkIterator[] mediaChunkIterators) { long nowMs = clock.elapsedRealtime(); - long chunkDurationUs = getChunkDurationUs(mediaChunkIterators, queue); + long chunkDurationUs = getNextChunkDurationUs(mediaChunkIterators, queue); // Make initial selection if (reason == C.SELECTION_REASON_UNKNOWN) { @@ -406,7 +408,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { if (playoutBufferedDurationBeforeLastChunkUs < minDurationToRetainAfterDiscardUs) { return queueSize; } - int idealSelectedIndex = determineIdealSelectedIndex(nowMs, getChunkDurationUs(queue)); + int idealSelectedIndex = determineIdealSelectedIndex(nowMs, getLastChunkDurationUs(queue)); Format idealFormat = getFormat(idealSelectedIndex); // If the chunks contain video, discard from the first SD chunk beyond // minDurationToRetainAfterDiscardUs whose resolution and bitrate are both lower than the ideal @@ -498,24 +500,34 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { : minDurationForQualityIncreaseUs; } - private long getChunkDurationUs( + /** + * Returns a best estimate of the duration of the next chunk, in microseconds, or {@link + * C#TIME_UNSET} if an estimate could not be determined. + */ + private long getNextChunkDurationUs( MediaChunkIterator[] mediaChunkIterators, List queue) { - // First, try to get the chunk duration for currently selected format. + // Try to get the next chunk duration for the currently selected format. if (selectedIndex < mediaChunkIterators.length && mediaChunkIterators[selectedIndex].next()) { MediaChunkIterator iterator = mediaChunkIterators[selectedIndex]; return iterator.getChunkEndTimeUs() - iterator.getChunkStartTimeUs(); } - // Second, try to get the chunk duration for another format. + // Try to get the next chunk duration for another format, on the assumption that chunks + // belonging to different formats are likely to have identical or similar durations. for (MediaChunkIterator iterator : mediaChunkIterators) { if (iterator.next()) { return iterator.getChunkEndTimeUs() - iterator.getChunkStartTimeUs(); } } - // Third, try to get chunk duration for previous chunk in the queue. - return getChunkDurationUs(queue); + // Try to get chunk duration for last chunk in the queue, on the assumption that the next chunk + // is likely to have a similar duration. + return getLastChunkDurationUs(queue); } - private long getChunkDurationUs(List queue) { + /** + * Returns the duration of the last chunk in the queue, in microseconds, or {@link C#TIME_UNSET} + * if the queue is empty or if the last chunk has an undefined start or end time. + */ + private long getLastChunkDurationUs(List queue) { if (queue.isEmpty()) { return C.TIME_UNSET; } @@ -552,7 +564,8 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { if (timeToFirstByteEstimateUs == C.TIME_UNSET || chunkDurationUs == C.TIME_UNSET) { return (long) (cautiousBandwidthEstimate / playbackSpeed); } - float availableTimeToLoadUs = chunkDurationUs / playbackSpeed - timeToFirstByteEstimateUs; + float availableTimeToLoadUs = + max(chunkDurationUs / playbackSpeed - timeToFirstByteEstimateUs, 0); return (long) (cautiousBandwidthEstimate * availableTimeToLoadUs / chunkDurationUs); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java index fce1f29ea3..7a8b38018a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/TimeToFirstByteEstimator.java @@ -25,7 +25,7 @@ public interface TimeToFirstByteEstimator { */ long getTimeToFirstByteEstimateUs(); - /** Resets the estimator. The estimator should drop all samples and reset to its initial state. */ + /** Resets the estimator. */ void reset(); /**