diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ed1eff0233..97f3b29c3e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -112,6 +112,8 @@ ([#4791](https://github.com/google/ExoPlayer/issues/4791)). * MPEG-TS: Support CEA-608/708 in H262 ([#2565](https://github.com/google/ExoPlayer/issues/2565)). +* Allow configuration of the back buffer in `DefaultLoadControl.Builder` + ([#4857](https://github.com/google/ExoPlayer/issues/4857)). * Allow apps to pass a `CacheKeyFactory` for setting custom cache keys when creating a `CacheDataSource`. * Provide additional information for adaptive track selection. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java index c466815c79..97a56b844c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java @@ -52,14 +52,20 @@ public class DefaultLoadControl implements LoadControl { 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. + * The default target buffer size in bytes. The value ({@link C#LENGTH_UNSET}) means that the load + * control will calculate the target buffer size based on the selected tracks. */ 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; + /** The default back buffer duration in milliseconds. */ + public static final int DEFAULT_BACK_BUFFER_DURATION_MS = 0; + + /** The default for whether the back buffer is retained from the previous keyframe. */ + public static final boolean DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME = false; + /** Builder for {@link DefaultLoadControl}. */ public static final class Builder { @@ -71,6 +77,8 @@ public class DefaultLoadControl implements LoadControl { private int targetBufferBytes; private boolean prioritizeTimeOverSizeThresholds; private PriorityTaskManager priorityTaskManager; + private int backBufferDurationMs; + private boolean retainBackBufferFromKeyframe; /** Constructs a new instance. */ public Builder() { @@ -82,6 +90,8 @@ public class DefaultLoadControl implements LoadControl { targetBufferBytes = DEFAULT_TARGET_BUFFER_BYTES; prioritizeTimeOverSizeThresholds = DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS; priorityTaskManager = null; + backBufferDurationMs = DEFAULT_BACK_BUFFER_DURATION_MS; + retainBackBufferFromKeyframe = DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME; } /** @@ -123,8 +133,7 @@ public class DefaultLoadControl implements LoadControl { /** * Sets 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)}. + * size will be calculated based on the selected tracks. * * @param targetBufferBytes The target buffer size in bytes. * @return This builder, for convenience. @@ -147,14 +156,33 @@ public class DefaultLoadControl implements LoadControl { return this; } - /** Sets the {@link PriorityTaskManager} to use. */ + /** + * Sets the {@link PriorityTaskManager} to use. + * + * @param priorityTaskManager The {@link PriorityTaskManager} to use. + * @return This builder, for convenience. + */ public Builder setPriorityTaskManager(PriorityTaskManager priorityTaskManager) { this.priorityTaskManager = priorityTaskManager; return this; } + /** + * Sets the back buffer duration, and whether the back buffer is retained from the previous + * keyframe. + * + * @param backBufferDurationMs The back buffer duration in milliseconds. + * @param retainBackBufferFromKeyframe Whether the back buffer is retained from the previous + * keyframe. + * @return This builder, for convenience. + */ + public Builder setBackBuffer(int backBufferDurationMs, boolean retainBackBufferFromKeyframe) { + this.backBufferDurationMs = backBufferDurationMs; + this.retainBackBufferFromKeyframe = retainBackBufferFromKeyframe; + return this; + } + /** Creates a {@link DefaultLoadControl}. */ - @SuppressWarnings("deprecation") public DefaultLoadControl createDefaultLoadControl() { if (allocator == null) { allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE); @@ -167,7 +195,9 @@ public class DefaultLoadControl implements LoadControl { bufferForPlaybackAfterRebufferMs, targetBufferBytes, prioritizeTimeOverSizeThresholds, - priorityTaskManager); + priorityTaskManager, + backBufferDurationMs, + retainBackBufferFromKeyframe); } } @@ -180,6 +210,8 @@ public class DefaultLoadControl implements LoadControl { private final int targetBufferBytesOverwrite; private final boolean prioritizeTimeOverSizeThresholds; private final PriorityTaskManager priorityTaskManager; + private final long backBufferDurationUs; + private final boolean retainBackBufferFromKeyframe; private int targetBufferSize; private boolean isBuffering; @@ -223,7 +255,7 @@ public class DefaultLoadControl implements LoadControl { bufferForPlaybackAfterRebufferMs, targetBufferBytes, prioritizeTimeOverSizeThresholds, - null); + /* priorityTaskManager= */ null); } /** @deprecated Use {@link Builder} instead. */ @@ -237,6 +269,30 @@ public class DefaultLoadControl implements LoadControl { int targetBufferBytes, boolean prioritizeTimeOverSizeThresholds, PriorityTaskManager priorityTaskManager) { + this( + allocator, + minBufferMs, + maxBufferMs, + bufferForPlaybackMs, + bufferForPlaybackAfterRebufferMs, + targetBufferBytes, + prioritizeTimeOverSizeThresholds, + priorityTaskManager, + DEFAULT_BACK_BUFFER_DURATION_MS, + DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME); + } + + protected DefaultLoadControl( + DefaultAllocator allocator, + int minBufferMs, + int maxBufferMs, + int bufferForPlaybackMs, + int bufferForPlaybackAfterRebufferMs, + int targetBufferBytes, + boolean prioritizeTimeOverSizeThresholds, + PriorityTaskManager priorityTaskManager, + int backBufferDurationMs, + boolean retainBackBufferFromKeyframe) { assertGreaterOrEqual(bufferForPlaybackMs, 0, "bufferForPlaybackMs", "0"); assertGreaterOrEqual( bufferForPlaybackAfterRebufferMs, 0, "bufferForPlaybackAfterRebufferMs", "0"); @@ -247,15 +303,18 @@ public class DefaultLoadControl implements LoadControl { "minBufferMs", "bufferForPlaybackAfterRebufferMs"); assertGreaterOrEqual(maxBufferMs, minBufferMs, "maxBufferMs", "minBufferMs"); + assertGreaterOrEqual(backBufferDurationMs, 0, "backBufferDurationMs", "0"); this.allocator = allocator; - minBufferUs = minBufferMs * 1000L; - maxBufferUs = maxBufferMs * 1000L; - bufferForPlaybackUs = bufferForPlaybackMs * 1000L; - bufferForPlaybackAfterRebufferUs = bufferForPlaybackAfterRebufferMs * 1000L; - targetBufferBytesOverwrite = targetBufferBytes; + this.minBufferUs = C.msToUs(minBufferMs); + this.maxBufferUs = C.msToUs(maxBufferMs); + this.bufferForPlaybackUs = C.msToUs(bufferForPlaybackMs); + this.bufferForPlaybackAfterRebufferUs = C.msToUs(bufferForPlaybackAfterRebufferMs); + this.targetBufferBytesOverwrite = targetBufferBytes; this.prioritizeTimeOverSizeThresholds = prioritizeTimeOverSizeThresholds; this.priorityTaskManager = priorityTaskManager; + this.backBufferDurationUs = C.msToUs(backBufferDurationMs); + this.retainBackBufferFromKeyframe = retainBackBufferFromKeyframe; } @Override @@ -290,12 +349,12 @@ public class DefaultLoadControl implements LoadControl { @Override public long getBackBufferDurationUs() { - return 0; + return backBufferDurationUs; } @Override public boolean retainBackBufferFromKeyframe() { - return false; + return retainBackBufferFromKeyframe; } @Override