Allow to configure maximum buffer size in DefaultLoadControl.
This adds a parameter to configure a maximum buffer size in bytes. If left at its default of C.LENGTH_UNSET, the target buffer is determined using a overridable method based on the track selection. Also adding a parameter to decide whether to prioritize time or size constraints. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=179048554
This commit is contained in:
parent
236df9a571
commit
1e36c76654
@ -31,6 +31,8 @@
|
|||||||
* DefaultTrackSelector: Support undefined language text track selection when the
|
* DefaultTrackSelector: Support undefined language text track selection when the
|
||||||
preferred language is not available
|
preferred language is not available
|
||||||
([#2980](https://github.com/google/ExoPlayer/issues/2980)).
|
([#2980](https://github.com/google/ExoPlayer/issues/2980)).
|
||||||
|
* Add options to `DefaultLoadControl` to set maximum buffer size in bytes and
|
||||||
|
to choose whether size or time constraints are prioritized.
|
||||||
* Use surfaceless context for secure `DummySurface`, if available
|
* Use surfaceless context for secure `DummySurface`, if available
|
||||||
([#3558](https://github.com/google/ExoPlayer/issues/3558)).
|
([#3558](https://github.com/google/ExoPlayer/issues/3558)).
|
||||||
* FLV: Fix playback of live streams that do not contain an audio track
|
* FLV: Fix playback of live streams that do not contain an audio track
|
||||||
|
@ -51,12 +51,23 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
*/
|
*/
|
||||||
public static final int DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = 5000;
|
public static final int DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default target buffer size in bytes. When set to {@link C#LENGTH_UNSET}, the load control
|
||||||
|
* automatically determines its target buffer size.
|
||||||
|
*/
|
||||||
|
public static final int DEFAULT_TARGET_BUFFER_BYTES = C.LENGTH_UNSET;
|
||||||
|
|
||||||
|
/** The default prioritization of buffer time constraints over size constraints. */
|
||||||
|
public static final boolean DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS = true;
|
||||||
|
|
||||||
private final DefaultAllocator allocator;
|
private final DefaultAllocator allocator;
|
||||||
|
|
||||||
private final long minBufferUs;
|
private final long minBufferUs;
|
||||||
private final long maxBufferUs;
|
private final long maxBufferUs;
|
||||||
private final long bufferForPlaybackUs;
|
private final long bufferForPlaybackUs;
|
||||||
private final long bufferForPlaybackAfterRebufferUs;
|
private final long bufferForPlaybackAfterRebufferUs;
|
||||||
|
private final int targetBufferBytesOverwrite;
|
||||||
|
private final boolean prioritizeTimeOverSizeThresholds;
|
||||||
private final PriorityTaskManager priorityTaskManager;
|
private final PriorityTaskManager priorityTaskManager;
|
||||||
|
|
||||||
private int targetBufferSize;
|
private int targetBufferSize;
|
||||||
@ -75,8 +86,14 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
* @param allocator The {@link DefaultAllocator} used by the loader.
|
* @param allocator The {@link DefaultAllocator} used by the loader.
|
||||||
*/
|
*/
|
||||||
public DefaultLoadControl(DefaultAllocator allocator) {
|
public DefaultLoadControl(DefaultAllocator allocator) {
|
||||||
this(allocator, DEFAULT_MIN_BUFFER_MS, DEFAULT_MAX_BUFFER_MS, DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
this(
|
||||||
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
|
allocator,
|
||||||
|
DEFAULT_MIN_BUFFER_MS,
|
||||||
|
DEFAULT_MAX_BUFFER_MS,
|
||||||
|
DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS,
|
||||||
|
DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||||
|
DEFAULT_TARGET_BUFFER_BYTES,
|
||||||
|
DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,10 +109,27 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
* @param bufferForPlaybackAfterRebufferMs The default duration of media that must be buffered for
|
* @param bufferForPlaybackAfterRebufferMs The default duration of media that must be buffered for
|
||||||
* playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be caused by
|
* playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be caused by
|
||||||
* buffer depletion rather than a user action.
|
* buffer depletion rather than a user action.
|
||||||
|
* @param targetBufferBytes The target buffer size in bytes. If set to {@link C#LENGTH_UNSET}, the
|
||||||
|
* target buffer size will be calculated using {@link #calculateTargetBufferSize(Renderer[],
|
||||||
|
* TrackSelectionArray)}.
|
||||||
|
* @param prioritizeTimeOverSizeThresholds Whether the load control prioritizes buffer time
|
||||||
*/
|
*/
|
||||||
public DefaultLoadControl(DefaultAllocator allocator, int minBufferMs, int maxBufferMs,
|
public DefaultLoadControl(
|
||||||
long bufferForPlaybackMs, long bufferForPlaybackAfterRebufferMs) {
|
DefaultAllocator allocator,
|
||||||
this(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs,
|
int minBufferMs,
|
||||||
|
int maxBufferMs,
|
||||||
|
int bufferForPlaybackMs,
|
||||||
|
int bufferForPlaybackAfterRebufferMs,
|
||||||
|
int targetBufferBytes,
|
||||||
|
boolean prioritizeTimeOverSizeThresholds) {
|
||||||
|
this(
|
||||||
|
allocator,
|
||||||
|
minBufferMs,
|
||||||
|
maxBufferMs,
|
||||||
|
bufferForPlaybackMs,
|
||||||
|
bufferForPlaybackAfterRebufferMs,
|
||||||
|
targetBufferBytes,
|
||||||
|
prioritizeTimeOverSizeThresholds,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,18 +146,30 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
* @param bufferForPlaybackAfterRebufferMs The default duration of media that must be buffered for
|
* @param bufferForPlaybackAfterRebufferMs The default duration of media that must be buffered for
|
||||||
* playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be caused by
|
* playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be caused by
|
||||||
* buffer depletion rather than a user action.
|
* buffer depletion rather than a user action.
|
||||||
* @param priorityTaskManager If not null, registers itself as a task with priority
|
* @param targetBufferBytes The target buffer size in bytes. If set to {@link C#LENGTH_UNSET}, the
|
||||||
* {@link C#PRIORITY_PLAYBACK} during loading periods, and unregisters itself during draining
|
* target buffer size will be calculated using {@link #calculateTargetBufferSize(Renderer[],
|
||||||
* periods.
|
* TrackSelectionArray)}.
|
||||||
|
* @param prioritizeTimeOverSizeThresholds Whether the load control prioritizes buffer time
|
||||||
|
* constraints over buffer size constraints.
|
||||||
|
* @param priorityTaskManager If not null, registers itself as a task with priority {@link
|
||||||
|
* C#PRIORITY_PLAYBACK} during loading periods, and unregisters itself during draining
|
||||||
*/
|
*/
|
||||||
public DefaultLoadControl(DefaultAllocator allocator, int minBufferMs, int maxBufferMs,
|
public DefaultLoadControl(
|
||||||
long bufferForPlaybackMs, long bufferForPlaybackAfterRebufferMs,
|
DefaultAllocator allocator,
|
||||||
|
int minBufferMs,
|
||||||
|
int maxBufferMs,
|
||||||
|
int bufferForPlaybackMs,
|
||||||
|
int bufferForPlaybackAfterRebufferMs,
|
||||||
|
int targetBufferBytes,
|
||||||
|
boolean prioritizeTimeOverSizeThresholds,
|
||||||
PriorityTaskManager priorityTaskManager) {
|
PriorityTaskManager priorityTaskManager) {
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
minBufferUs = minBufferMs * 1000L;
|
minBufferUs = minBufferMs * 1000L;
|
||||||
maxBufferUs = maxBufferMs * 1000L;
|
maxBufferUs = maxBufferMs * 1000L;
|
||||||
|
targetBufferBytesOverwrite = targetBufferBytes;
|
||||||
bufferForPlaybackUs = bufferForPlaybackMs * 1000L;
|
bufferForPlaybackUs = bufferForPlaybackMs * 1000L;
|
||||||
bufferForPlaybackAfterRebufferUs = bufferForPlaybackAfterRebufferMs * 1000L;
|
bufferForPlaybackAfterRebufferUs = bufferForPlaybackAfterRebufferMs * 1000L;
|
||||||
|
this.prioritizeTimeOverSizeThresholds = prioritizeTimeOverSizeThresholds;
|
||||||
this.priorityTaskManager = priorityTaskManager;
|
this.priorityTaskManager = priorityTaskManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,12 +181,10 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
@Override
|
@Override
|
||||||
public void onTracksSelected(Renderer[] renderers, TrackGroupArray trackGroups,
|
public void onTracksSelected(Renderer[] renderers, TrackGroupArray trackGroups,
|
||||||
TrackSelectionArray trackSelections) {
|
TrackSelectionArray trackSelections) {
|
||||||
targetBufferSize = 0;
|
targetBufferSize =
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
targetBufferBytesOverwrite == C.LENGTH_UNSET
|
||||||
if (trackSelections.get(i) != null) {
|
? calculateTargetBufferSize(renderers, trackSelections)
|
||||||
targetBufferSize += Util.getDefaultBufferSize(renderers[i].getTrackType());
|
: targetBufferBytesOverwrite;
|
||||||
}
|
|
||||||
}
|
|
||||||
allocator.setTargetBufferSize(targetBufferSize);
|
allocator.setTargetBufferSize(targetBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,16 +206,28 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
@Override
|
@Override
|
||||||
public boolean shouldStartPlayback(long bufferedDurationUs, boolean rebuffering) {
|
public boolean shouldStartPlayback(long bufferedDurationUs, boolean rebuffering) {
|
||||||
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
|
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
|
||||||
return minBufferDurationUs <= 0 || bufferedDurationUs >= minBufferDurationUs;
|
return minBufferDurationUs <= 0
|
||||||
|
|| bufferedDurationUs >= minBufferDurationUs
|
||||||
|
|| (!prioritizeTimeOverSizeThresholds
|
||||||
|
&& allocator.getTotalBytesAllocated() >= targetBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldContinueLoading(long bufferedDurationUs) {
|
public boolean shouldContinueLoading(long bufferedDurationUs) {
|
||||||
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
||||||
boolean wasBuffering = isBuffering;
|
boolean wasBuffering = isBuffering;
|
||||||
isBuffering = bufferedDurationUs < minBufferUs // below low watermark
|
if (prioritizeTimeOverSizeThresholds) {
|
||||||
|| (bufferedDurationUs <= maxBufferUs // between watermarks
|
isBuffering =
|
||||||
&& isBuffering && !targetBufferSizeReached);
|
bufferedDurationUs < minBufferUs // below low watermark
|
||||||
|
|| (bufferedDurationUs <= maxBufferUs // between watermarks
|
||||||
|
&& isBuffering
|
||||||
|
&& !targetBufferSizeReached);
|
||||||
|
} else {
|
||||||
|
isBuffering =
|
||||||
|
!targetBufferSizeReached
|
||||||
|
&& (bufferedDurationUs < minBufferUs // below low watermark
|
||||||
|
|| (bufferedDurationUs <= maxBufferUs && isBuffering)); // between watermarks
|
||||||
|
}
|
||||||
if (priorityTaskManager != null && isBuffering != wasBuffering) {
|
if (priorityTaskManager != null && isBuffering != wasBuffering) {
|
||||||
if (isBuffering) {
|
if (isBuffering) {
|
||||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
||||||
@ -182,6 +238,25 @@ public final class DefaultLoadControl implements LoadControl {
|
|||||||
return isBuffering;
|
return isBuffering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate target buffer size in bytes based on the selected tracks. The player will try not to
|
||||||
|
* exceed this target buffer. Only used when {@code targetBufferBytes} is {@link C#LENGTH_UNSET}.
|
||||||
|
*
|
||||||
|
* @param renderers The renderers for which the track were selected.
|
||||||
|
* @param trackSelectionArray The selected tracks.
|
||||||
|
* @return The target buffer size in bytes.
|
||||||
|
*/
|
||||||
|
protected int calculateTargetBufferSize(
|
||||||
|
Renderer[] renderers, TrackSelectionArray trackSelectionArray) {
|
||||||
|
int targetBufferSize = 0;
|
||||||
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
|
if (trackSelectionArray.get(i) != null) {
|
||||||
|
targetBufferSize += Util.getDefaultBufferSize(renderers[i].getTrackType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targetBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
private void reset(boolean resetAllocator) {
|
private void reset(boolean resetAllocator) {
|
||||||
targetBufferSize = 0;
|
targetBufferSize = 0;
|
||||||
if (priorityTaskManager != null && isBuffering) {
|
if (priorityTaskManager != null && isBuffering) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user