Simplify DefaultLoadControl
DefaultLoadControl applies the same min buffer duration to audio and video. By default, min buffer is set equal to max buffer (50 seconds). PiperOrigin-RevId: 297324489
This commit is contained in:
parent
31f0302505
commit
f34930ab0d
@ -3,6 +3,9 @@
|
||||
### dev-v2 (not yet released) ###
|
||||
|
||||
* Core library:
|
||||
* The `DefaultLoadControl` default minimum buffer is set to 50 seconds,
|
||||
equal to the default maximum buffer. `DefaultLoadControl` applies the
|
||||
same behavior for audio and video.
|
||||
* Add API in `AnalyticsListener` to report video frame processing offset.
|
||||
`MediaCodecVideoRenderer` reports the event.
|
||||
* Add fields `videoFrameProcessingOffsetUsSum` and
|
||||
|
@ -29,14 +29,12 @@ 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. This value is only applied to playbacks without video.
|
||||
* times, in milliseconds.
|
||||
*/
|
||||
public static final int DEFAULT_MIN_BUFFER_MS = 15000;
|
||||
public static final int DEFAULT_MIN_BUFFER_MS = 50000;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@ -90,8 +88,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
public static final class Builder {
|
||||
|
||||
private DefaultAllocator allocator;
|
||||
private int minBufferAudioMs;
|
||||
private int minBufferVideoMs;
|
||||
private int minBufferMs;
|
||||
private int maxBufferMs;
|
||||
private int bufferForPlaybackMs;
|
||||
private int bufferForPlaybackAfterRebufferMs;
|
||||
@ -103,8 +100,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
/** Constructs a new instance. */
|
||||
public Builder() {
|
||||
minBufferAudioMs = DEFAULT_MIN_BUFFER_MS;
|
||||
minBufferVideoMs = DEFAULT_MAX_BUFFER_MS;
|
||||
minBufferMs = DEFAULT_MIN_BUFFER_MS;
|
||||
maxBufferMs = DEFAULT_MAX_BUFFER_MS;
|
||||
bufferForPlaybackMs = DEFAULT_BUFFER_FOR_PLAYBACK_MS;
|
||||
bufferForPlaybackAfterRebufferMs = DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
|
||||
@ -158,8 +154,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
"minBufferMs",
|
||||
"bufferForPlaybackAfterRebufferMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferMs, "maxBufferMs", "minBufferMs");
|
||||
this.minBufferAudioMs = minBufferMs;
|
||||
this.minBufferVideoMs = minBufferMs;
|
||||
this.minBufferMs = minBufferMs;
|
||||
this.maxBufferMs = maxBufferMs;
|
||||
this.bufferForPlaybackMs = bufferForPlaybackMs;
|
||||
this.bufferForPlaybackAfterRebufferMs = bufferForPlaybackAfterRebufferMs;
|
||||
@ -222,8 +217,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
}
|
||||
return new DefaultLoadControl(
|
||||
allocator,
|
||||
minBufferAudioMs,
|
||||
minBufferVideoMs,
|
||||
minBufferMs,
|
||||
maxBufferMs,
|
||||
bufferForPlaybackMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
@ -236,8 +230,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
private final DefaultAllocator allocator;
|
||||
|
||||
private final long minBufferAudioUs;
|
||||
private final long minBufferVideoUs;
|
||||
private final long minBufferUs;
|
||||
private final long maxBufferUs;
|
||||
private final long bufferForPlaybackUs;
|
||||
private final long bufferForPlaybackAfterRebufferUs;
|
||||
@ -248,7 +241,6 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
private int targetBufferBytes;
|
||||
private boolean isBuffering;
|
||||
private boolean hasVideo;
|
||||
|
||||
/** Constructs a new instance, using the {@code DEFAULT_*} constants defined in this class. */
|
||||
@SuppressWarnings("deprecation")
|
||||
@ -261,8 +253,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
public DefaultLoadControl(DefaultAllocator allocator) {
|
||||
this(
|
||||
allocator,
|
||||
/* minBufferAudioMs= */ DEFAULT_MIN_BUFFER_MS,
|
||||
/* minBufferVideoMs= */ DEFAULT_MAX_BUFFER_MS,
|
||||
DEFAULT_MIN_BUFFER_MS,
|
||||
DEFAULT_MAX_BUFFER_MS,
|
||||
DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
|
||||
@ -284,8 +275,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
boolean prioritizeTimeOverSizeThresholds) {
|
||||
this(
|
||||
allocator,
|
||||
/* minBufferAudioMs= */ minBufferMs,
|
||||
/* minBufferVideoMs= */ minBufferMs,
|
||||
minBufferMs,
|
||||
maxBufferMs,
|
||||
bufferForPlaybackMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
@ -297,8 +287,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
|
||||
protected DefaultLoadControl(
|
||||
DefaultAllocator allocator,
|
||||
int minBufferAudioMs,
|
||||
int minBufferVideoMs,
|
||||
int minBufferMs,
|
||||
int maxBufferMs,
|
||||
int bufferForPlaybackMs,
|
||||
int bufferForPlaybackAfterRebufferMs,
|
||||
@ -309,27 +298,17 @@ public class DefaultLoadControl implements LoadControl {
|
||||
assertGreaterOrEqual(bufferForPlaybackMs, 0, "bufferForPlaybackMs", "0");
|
||||
assertGreaterOrEqual(
|
||||
bufferForPlaybackAfterRebufferMs, 0, "bufferForPlaybackAfterRebufferMs", "0");
|
||||
assertGreaterOrEqual(minBufferMs, bufferForPlaybackMs, "minBufferMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferAudioMs, bufferForPlaybackMs, "minBufferAudioMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferVideoMs, bufferForPlaybackMs, "minBufferVideoMs", "bufferForPlaybackMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferAudioMs,
|
||||
minBufferMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
"minBufferAudioMs",
|
||||
"minBufferMs",
|
||||
"bufferForPlaybackAfterRebufferMs");
|
||||
assertGreaterOrEqual(
|
||||
minBufferVideoMs,
|
||||
bufferForPlaybackAfterRebufferMs,
|
||||
"minBufferVideoMs",
|
||||
"bufferForPlaybackAfterRebufferMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferAudioMs, "maxBufferMs", "minBufferAudioMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferVideoMs, "maxBufferMs", "minBufferVideoMs");
|
||||
assertGreaterOrEqual(maxBufferMs, minBufferMs, "maxBufferMs", "minBufferMs");
|
||||
assertGreaterOrEqual(backBufferDurationMs, 0, "backBufferDurationMs", "0");
|
||||
|
||||
this.allocator = allocator;
|
||||
this.minBufferAudioUs = C.msToUs(minBufferAudioMs);
|
||||
this.minBufferVideoUs = C.msToUs(minBufferVideoMs);
|
||||
this.minBufferUs = C.msToUs(minBufferMs);
|
||||
this.maxBufferUs = C.msToUs(maxBufferMs);
|
||||
this.bufferForPlaybackUs = C.msToUs(bufferForPlaybackMs);
|
||||
this.bufferForPlaybackAfterRebufferUs = C.msToUs(bufferForPlaybackAfterRebufferMs);
|
||||
@ -351,7 +330,6 @@ public class DefaultLoadControl implements LoadControl {
|
||||
@Override
|
||||
public void onTracksSelected(Renderer[] renderers, TrackGroupArray trackGroups,
|
||||
TrackSelectionArray trackSelections) {
|
||||
hasVideo = hasVideo(renderers, trackSelections);
|
||||
targetBufferBytes =
|
||||
targetBufferBytesOverwrite == C.LENGTH_UNSET
|
||||
? calculateTargetBufferBytes(renderers, trackSelections)
|
||||
@ -387,7 +365,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
@Override
|
||||
public boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed) {
|
||||
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferBytes;
|
||||
long minBufferUs = hasVideo ? minBufferVideoUs : minBufferAudioUs;
|
||||
long minBufferUs = this.minBufferUs;
|
||||
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.
|
||||
@ -467,15 +445,6 @@ 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);
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ import org.junit.runner.RunWith;
|
||||
public class DefaultLoadControlTest {
|
||||
|
||||
private static final float SPEED = 1f;
|
||||
private static final long MIN_BUFFER_US = C.msToUs(DefaultLoadControl.DEFAULT_MIN_BUFFER_MS);
|
||||
private static final long MAX_BUFFER_US = C.msToUs(DefaultLoadControl.DEFAULT_MAX_BUFFER_MS);
|
||||
private static final long MIN_BUFFER_US = MAX_BUFFER_US / 2;
|
||||
private static final int TARGET_BUFFER_BYTES = C.DEFAULT_BUFFER_SEGMENT_SIZE * 2;
|
||||
|
||||
private Builder builder;
|
||||
@ -48,16 +48,20 @@ public class DefaultLoadControlTest {
|
||||
createDefaultLoadControl();
|
||||
|
||||
assertThat(loadControl.shouldContinueLoading(/* bufferedDurationUs= */ 0, SPEED)).isTrue();
|
||||
assertThat(loadControl.shouldContinueLoading(MIN_BUFFER_US, SPEED)).isTrue();
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US - 1, SPEED)).isTrue();
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US, SPEED)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotContinueLoadingOnceBufferingStopped_untilBelowMinBuffer() {
|
||||
builder.setBufferDurationsMs(
|
||||
/* minBufferMs= */ (int) C.usToMs(MIN_BUFFER_US),
|
||||
/* maxBufferMs= */ (int) C.usToMs(MAX_BUFFER_US),
|
||||
/* bufferForPlaybackMs= */ 0,
|
||||
/* bufferForPlaybackAfterRebufferMs= */ 0);
|
||||
createDefaultLoadControl();
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US, SPEED)).isFalse();
|
||||
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US, SPEED)).isFalse();
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US - 1, SPEED)).isFalse();
|
||||
assertThat(loadControl.shouldContinueLoading(MIN_BUFFER_US, SPEED)).isFalse();
|
||||
assertThat(loadControl.shouldContinueLoading(MIN_BUFFER_US - 1, SPEED)).isTrue();
|
||||
@ -72,14 +76,19 @@ public class DefaultLoadControlTest {
|
||||
/* bufferForPlaybackMs= */ 0,
|
||||
/* bufferForPlaybackAfterRebufferMs= */ 0);
|
||||
createDefaultLoadControl();
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US, SPEED)).isFalse();
|
||||
|
||||
assertThat(loadControl.shouldContinueLoading(MAX_BUFFER_US, SPEED)).isFalse();
|
||||
assertThat(loadControl.shouldContinueLoading(5 * C.MICROS_PER_SECOND, SPEED)).isFalse();
|
||||
assertThat(loadControl.shouldContinueLoading(500L, SPEED)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldContinueLoadingWithTargetBufferBytesReached_untilMinBufferReached() {
|
||||
builder.setBufferDurationsMs(
|
||||
/* minBufferMs= */ (int) C.usToMs(MIN_BUFFER_US),
|
||||
/* maxBufferMs= */ (int) C.usToMs(MAX_BUFFER_US),
|
||||
/* bufferForPlaybackMs= */ 0,
|
||||
/* bufferForPlaybackAfterRebufferMs= */ 0);
|
||||
createDefaultLoadControl();
|
||||
makeSureTargetBufferBytesReached();
|
||||
|
||||
@ -93,6 +102,7 @@ public class DefaultLoadControlTest {
|
||||
public void shouldNeverContinueLoading_ifMaxBufferReachedAndNotPrioritizeTimeOverSize() {
|
||||
builder.setPrioritizeTimeOverSizeThresholds(false);
|
||||
createDefaultLoadControl();
|
||||
|
||||
// Put loadControl in buffering state.
|
||||
assertThat(loadControl.shouldContinueLoading(/* bufferedDurationUs= */ 0, SPEED)).isTrue();
|
||||
makeSureTargetBufferBytesReached();
|
||||
@ -105,6 +115,11 @@ public class DefaultLoadControlTest {
|
||||
|
||||
@Test
|
||||
public void shouldContinueLoadingWithMinBufferReached_inFastPlayback() {
|
||||
builder.setBufferDurationsMs(
|
||||
/* minBufferMs= */ (int) C.usToMs(MIN_BUFFER_US),
|
||||
/* maxBufferMs= */ (int) C.usToMs(MAX_BUFFER_US),
|
||||
/* bufferForPlaybackMs= */ 0,
|
||||
/* bufferForPlaybackAfterRebufferMs= */ 0);
|
||||
createDefaultLoadControl();
|
||||
|
||||
// At normal playback speed, we stop buffering when the buffer reaches the minimum.
|
||||
@ -130,8 +145,7 @@ public class DefaultLoadControlTest {
|
||||
}
|
||||
|
||||
private void createDefaultLoadControl() {
|
||||
builder.setAllocator(allocator);
|
||||
builder.setTargetBufferBytes(TARGET_BUFFER_BYTES);
|
||||
builder.setAllocator(allocator).setTargetBufferBytes(TARGET_BUFFER_BYTES);
|
||||
loadControl = builder.createDefaultLoadControl();
|
||||
loadControl.onTracksSelected(new Renderer[0], null, null);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user