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 d8bc042ad7..4cbcc00886 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 @@ -25,7 +25,7 @@ import com.google.android.exoplayer2.util.Util; /** * The default {@link LoadControl} implementation. */ -public final class DefaultLoadControl implements LoadControl { +public class DefaultLoadControl implements LoadControl { /** * The default minimum duration of media that the player will attempt to ensure is buffered at all @@ -163,6 +163,16 @@ public final class DefaultLoadControl implements LoadControl { return allocator; } + @Override + public long getBackBufferDurationUs() { + return 0; + } + + @Override + public boolean retainBackBufferFromKeyframe() { + return false; + } + @Override public boolean shouldStartPlayback(long bufferedDurationUs, boolean rebuffering) { long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index caf64d4e90..6acab54ba0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -107,6 +107,8 @@ import java.io.IOException; private final Timeline.Window window; private final Timeline.Period period; private final MediaPeriodInfoSequence mediaPeriodInfoSequence; + private final long backBufferDurationUs; + private final boolean retainBackBufferFromKeyframe; private PlaybackInfo playbackInfo; private PlaybackParameters playbackParameters; @@ -147,6 +149,9 @@ import java.io.IOException; this.state = Player.STATE_IDLE; this.player = player; + backBufferDurationUs = loadControl.getBackBufferDurationUs(); + retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe(); + playbackInfo = new PlaybackInfo(null, null, 0, C.TIME_UNSET); rendererCapabilities = new RendererCapabilities[renderers.length]; for (int i = 0; i < renderers.length; i++) { @@ -541,7 +546,8 @@ import java.io.IOException; TraceUtil.beginSection("doSomeWork"); updatePlaybackPositions(); - playingPeriodHolder.mediaPeriod.discardBuffer(playbackInfo.positionUs, false); + playingPeriodHolder.mediaPeriod.discardBuffer(playbackInfo.positionUs - backBufferDurationUs, + retainBackBufferFromKeyframe); boolean allRenderersEnded = true; boolean allRenderersReadyOrEnded = true; @@ -732,7 +738,8 @@ import java.io.IOException; setPlayingPeriodHolder(newPlayingPeriodHolder); if (playingPeriodHolder.hasEnabledTracks) { periodPositionUs = playingPeriodHolder.mediaPeriod.seekToUs(periodPositionUs); - playingPeriodHolder.mediaPeriod.discardBuffer(periodPositionUs, false); + playingPeriodHolder.mediaPeriod.discardBuffer(periodPositionUs - backBufferDurationUs, + retainBackBufferFromKeyframe); } resetRendererPosition(periodPositionUs); maybeContinueLoading(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/LoadControl.java b/library/core/src/main/java/com/google/android/exoplayer2/LoadControl.java index c092480222..44b16b0cf6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/LoadControl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/LoadControl.java @@ -55,6 +55,38 @@ public interface LoadControl { */ Allocator getAllocator(); + /** + * Returns the duration of media to retain in the buffer prior to the current playback position, + * for fast backward seeking. + *
+ * Note: If {@link #retainBackBufferFromKeyframe()} is false then seeking in the back-buffer will + * only be fast if the back-buffer contains a keyframe prior to the seek position. + *
+ * Note: Implementations should return a single value. Dynamic changes to the back-buffer are not + * currently supported. + * + * @return The duration of media to retain in the buffer prior to the current playback position, + * in microseconds. + */ + long getBackBufferDurationUs(); + + /** + * Returns whether media should be retained from the keyframe before the current playback position + * minus {@link #getBackBufferDurationUs()}, rather than any sample before or at that position. + *
+ * Warning: Returning true will cause the back-buffer size to depend on the spacing of keyframes + * in the media being played. Returning true is not recommended unless you control the media and + * are comfortable with the back-buffer size exceeding {@link #getBackBufferDurationUs()} by as + * much as the maximum duration between adjacent keyframes in the media. + *
+ * Note: Implementations should return a single value. Dynamic changes to the back-buffer are not + * currently supported. + * + * @return Whether media should be retained from the keyframe before the current playback position + * minus {@link #getBackBufferDurationUs()}, rather than any sample before or at that position. + */ + boolean retainBackBufferFromKeyframe(); + /** * Called by the player to determine whether sufficient media is buffered for playback to be * started or resumed.