Update default min duration for playbacks with video to match max duration.
Experiments show this is beneficial for rebuffers with only minor impact on battery usage. Configurations which explicitly set a minimum buffer duration are unaffected. Issue:#2083 PiperOrigin-RevId: 244823642
This commit is contained in:
parent
d89f3eeb29
commit
9725132e3c
@ -120,6 +120,8 @@
|
||||
order when in shuffle mode.
|
||||
* Allow handling of custom commands via `registerCustomCommandReceiver`.
|
||||
* Add ability to include an extras `Bundle` when reporting a custom error.
|
||||
* LoadControl: Set minimum buffer for playbacks with video equal to maximum
|
||||
buffer ([#2083](https://github.com/google/ExoPlayer/issues/2083)).
|
||||
|
||||
### 2.9.6 ###
|
||||
|
||||
|
@ -29,12 +29,14 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
/**
|
||||
* The default minimum duration of media that the player will attempt to ensure is buffered at all
|
||||
* times, in milliseconds.
|
||||
* times, in milliseconds. This value is only applied to playbacks without video.
|
||||
*/
|
||||
public static final int DEFAULT_MIN_BUFFER_MS = 15000;
|
||||
|
||||
/**
|
||||
* The default maximum duration of media that the player will attempt to buffer, in milliseconds.
|
||||
* For playbacks with video, this is also the default minimum duration of media that the player
|
||||
* will attempt to ensure is buffered.
|
||||
*/
|
||||
public static final int DEFAULT_MAX_BUFFER_MS = 50000;
|
||||
|
||||
@ -69,7 +71,8 @@ public class DefaultLoadControl implements LoadControl {
|
||||
public static final class Builder {
|
||||
|
||||
private DefaultAllocator allocator;
|
||||
private int minBufferMs;
|
||||
private int minBufferAudioMs;
|
||||
private int minBufferVideoMs;
|
||||
private int maxBufferMs;
|
||||
private int bufferForPlaybackMs;
|
||||
private int bufferForPlaybackAfterRebufferMs;
|
||||
@ -81,7 +84,8 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
/** Constructs a new instance. */
|
||||
public Builder() {
|
||||
minBufferMs = DEFAULT_MIN_BUFFER_MS;
|
||||
minBufferAudioMs = DEFAULT_MIN_BUFFER_MS;
|
||||
minBufferVideoMs = DEFAULT_MAX_BUFFER_MS;
|
||||
maxBufferMs = DEFAULT_MAX_BUFFER_MS;
|
||||
bufferForPlaybackMs = DEFAULT_BUFFER_FOR_PLAYBACK_MS;
|
||||
bufferForPlaybackAfterRebufferMs = DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
|
||||
@ -125,7 +129,18 @@ public class DefaultLoadControl implements LoadControl {
|
||||
int bufferForPlaybackMs,
|
||||
int bufferForPlaybackAfterRebufferMs) {
|
||||
Assertions.checkState(!createDefaultLoadControlCalled);
|
||||
this.minBufferMs = minBufferMs;
|
||||
assertGreaterOrEqual(bufferForPlaybackMs, 0, "bufferForPlaybackMs", "0");
|
||||
assertGreaterOrEqual(
|
||||
bufferForPlaybackAfterRebufferMs, 0, "bufferForPlaybackAfterRebufferMs", "0");
|
||||
assertGreaterOrEqual(minBufferMs, bufferForPlaybackMs, "minBufferMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
"minBufferMs",
|
||||
"bufferForPlaybackAfterRebufferMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferMs, "maxBufferMs", "minBufferMs");
|
||||
this.minBufferAudioMs = minBufferMs;
|
||||
this.minBufferVideoMs = minBufferMs;
|
||||
this.maxBufferMs = maxBufferMs;
|
||||
this.bufferForPlaybackMs = bufferForPlaybackMs;
|
||||
this.bufferForPlaybackAfterRebufferMs = bufferForPlaybackAfterRebufferMs;
|
||||
@ -173,6 +188,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
*/
|
||||
public Builder setBackBuffer(int backBufferDurationMs, boolean retainBackBufferFromKeyframe) {
|
||||
Assertions.checkState(!createDefaultLoadControlCalled);
|
||||
assertGreaterOrEqual(backBufferDurationMs, 0, "backBufferDurationMs", "0");
|
||||
this.backBufferDurationMs = backBufferDurationMs;
|
||||
this.retainBackBufferFromKeyframe = retainBackBufferFromKeyframe;
|
||||
return this;
|
||||
@ -187,7 +203,8 @@ public class DefaultLoadControl implements LoadControl {
|
||||
}
|
||||
return new DefaultLoadControl(
|
||||
allocator,
|
||||
minBufferMs,
|
||||
minBufferAudioMs,
|
||||
minBufferVideoMs,
|
||||
maxBufferMs,
|
||||
bufferForPlaybackMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
@ -200,7 +217,8 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
private final DefaultAllocator allocator;
|
||||
|
||||
private final long minBufferUs;
|
||||
private final long minBufferAudioUs;
|
||||
private final long minBufferVideoUs;
|
||||
private final long maxBufferUs;
|
||||
private final long bufferForPlaybackUs;
|
||||
private final long bufferForPlaybackAfterRebufferUs;
|
||||
@ -211,6 +229,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
private int targetBufferSize;
|
||||
private boolean isBuffering;
|
||||
private boolean hasVideo;
|
||||
|
||||
/** Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class. */
|
||||
@SuppressWarnings("deprecation")
|
||||
@ -220,16 +239,18 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
/** @deprecated Use {@link Builder} instead. */
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public DefaultLoadControl(DefaultAllocator allocator) {
|
||||
this(
|
||||
allocator,
|
||||
DEFAULT_MIN_BUFFER_MS,
|
||||
/* minBufferAudioMs= */ DEFAULT_MIN_BUFFER_MS,
|
||||
/* minBufferVideoMs= */ DEFAULT_MAX_BUFFER_MS,
|
||||
DEFAULT_MAX_BUFFER_MS,
|
||||
DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
|
||||
DEFAULT_TARGET_BUFFER_BYTES,
|
||||
DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS);
|
||||
DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS,
|
||||
DEFAULT_BACK_BUFFER_DURATION_MS,
|
||||
DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME);
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Builder} instead. */
|
||||
@ -244,7 +265,8 @@ public class DefaultLoadControl implements LoadControl {
|
||||
boolean prioritizeTimeOverSizeThresholds) {
|
||||
this(
|
||||
allocator,
|
||||
minBufferMs,
|
||||
/* minBufferAudioMs= */ minBufferMs,
|
||||
/* minBufferVideoMs= */ minBufferMs,
|
||||
maxBufferMs,
|
||||
bufferForPlaybackMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
@ -256,7 +278,8 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
protected DefaultLoadControl(
|
||||
DefaultAllocator allocator,
|
||||
int minBufferMs,
|
||||
int minBufferAudioMs,
|
||||
int minBufferVideoMs,
|
||||
int maxBufferMs,
|
||||
int bufferForPlaybackMs,
|
||||
int bufferForPlaybackAfterRebufferMs,
|
||||
@ -267,17 +290,27 @@ public class DefaultLoadControl implements LoadControl {
|
||||
assertGreaterOrEqual(bufferForPlaybackMs, 0, "bufferForPlaybackMs", "0");
|
||||
assertGreaterOrEqual(
|
||||
bufferForPlaybackAfterRebufferMs, 0, "bufferForPlaybackAfterRebufferMs", "0");
|
||||
assertGreaterOrEqual(minBufferMs, bufferForPlaybackMs, "minBufferMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferMs,
|
||||
minBufferAudioMs, bufferForPlaybackMs, "minBufferAudioMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferVideoMs, bufferForPlaybackMs, "minBufferVideoMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferAudioMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
"minBufferMs",
|
||||
"minBufferAudioMs",
|
||||
"bufferForPlaybackAfterRebufferMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferMs, "maxBufferMs", "minBufferMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferVideoMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
"minBufferVideoMs",
|
||||
"bufferForPlaybackAfterRebufferMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferAudioMs, "maxBufferMs", "minBufferAudioMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferVideoMs, "maxBufferMs", "minBufferVideoMs");
|
||||
assertGreaterOrEqual(backBufferDurationMs, 0, "backBufferDurationMs", "0");
|
||||
|
||||
this.allocator = allocator;
|
||||
this.minBufferUs = C.msToUs(minBufferMs);
|
||||
this.minBufferAudioUs = C.msToUs(minBufferAudioMs);
|
||||
this.minBufferVideoUs = C.msToUs(minBufferVideoMs);
|
||||
this.maxBufferUs = C.msToUs(maxBufferMs);
|
||||
this.bufferForPlaybackUs = C.msToUs(bufferForPlaybackMs);
|
||||
this.bufferForPlaybackAfterRebufferUs = C.msToUs(bufferForPlaybackAfterRebufferMs);
|
||||
@ -295,6 +328,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
@Override
|
||||
public void onTracksSelected(Renderer[] renderers, TrackGroupArray trackGroups,
|
||||
TrackSelectionArray trackSelections) {
|
||||
hasVideo = hasVideo(renderers, trackSelections);
|
||||
targetBufferSize =
|
||||
targetBufferBytesOverwrite == C.LENGTH_UNSET
|
||||
? calculateTargetBufferSize(renderers, trackSelections)
|
||||
@ -330,7 +364,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
@Override
|
||||
public boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed) {
|
||||
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
||||
long minBufferUs = this.minBufferUs;
|
||||
long minBufferUs = hasVideo ? minBufferVideoUs : minBufferAudioUs;
|
||||
if (playbackSpeed > 1) {
|
||||
// The playback speed is faster than real time, so scale up the minimum required media
|
||||
// duration to keep enough media buffered for a playout duration of minBufferUs.
|
||||
@ -384,6 +418,15 @@ public class DefaultLoadControl implements LoadControl {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasVideo(Renderer[] renderers, TrackSelectionArray trackSelectionArray) {
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
if (renderers[i].getTrackType() == C.TRACK_TYPE_VIDEO && trackSelectionArray.get(i) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void assertGreaterOrEqual(int value1, int value2, String name1, String name2) {
|
||||
Assertions.checkArgument(value1 >= value2, name1 + " cannot be less than " + name2);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user