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 8f59451c48..20d75ec1bd 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 @@ -660,10 +660,18 @@ import java.io.IOException; periodPositionUs = 0; } try { - if (periodId.equals(playbackInfo.periodId) - && ((periodPositionUs / 1000) == (playbackInfo.positionUs / 1000))) { - // Seek position equals the current position. Do nothing. - return; + if (periodId.equals(playbackInfo.periodId)) { + long adjustedPeriodPositionUs = periodPositionUs; + if (playingPeriodHolder != null) { + adjustedPeriodPositionUs = + playingPeriodHolder.mediaPeriod.getAdjustedSeekPositionUs( + adjustedPeriodPositionUs, SeekParameters.DEFAULT); + } + if ((adjustedPeriodPositionUs / 1000) == (playbackInfo.positionUs / 1000)) { + // Seek will be performed to the current position. Do nothing. + periodPositionUs = playbackInfo.positionUs; + return; + } } long newPeriodPositionUs = seekToPeriodPosition(periodId, periodPositionUs); seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index 539c4841e9..b1c12d6192 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.util.Assertions; @@ -170,6 +171,12 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb return seekUs - startUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return mediaPeriod.getAdjustedSeekPositionUs( + positionUs + startUs, adjustSeekParameters(positionUs + startUs, seekParameters)); + } + @Override public long getNextLoadPositionUs() { long nextLoadPositionUs = mediaPeriod.getNextLoadPositionUs(); @@ -202,6 +209,20 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb return pendingInitialDiscontinuityPositionUs != C.TIME_UNSET; } + private SeekParameters adjustSeekParameters(long positionUs, SeekParameters seekParameters) { + long toleranceBeforeMs = Math.min(positionUs - startUs, seekParameters.toleranceBeforeUs); + long toleranceAfterMs = + endUs == C.TIME_END_OF_SOURCE + ? seekParameters.toleranceAfterUs + : Math.min(endUs - positionUs, seekParameters.toleranceAfterUs); + if (toleranceBeforeMs == seekParameters.toleranceBeforeUs + && toleranceAfterMs == seekParameters.toleranceAfterUs) { + return seekParameters; + } else { + return new SeekParameters(toleranceBeforeMs, toleranceAfterMs); + } + } + private static boolean shouldKeepInitialDiscontinuity(long startUs, TrackSelection[] selections) { // If the clipping start position is non-zero, the clipping sample streams will adjust // timestamps on buffers they read from the unclipped sample streams. These adjusted buffer diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java index 32a180b956..1895f10d53 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.Allocator; @@ -114,6 +115,11 @@ public final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callb return mediaPeriod.seekToUs(positionUs); } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return mediaPeriod.getAdjustedSeekPositionUs(positionUs, seekParameters); + } + @Override public long getNextLoadPositionUs() { return mediaPeriod.getNextLoadPositionUs(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 6b9aeb39da..f8021c24df 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -21,6 +21,7 @@ import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.Extractor; @@ -369,6 +370,12 @@ import java.util.Arrays; return positionUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + // Treat all seeks into non-seekable media as being to t=0. + return seekMap.isSeekable() ? positionUs : 0; + } + // SampleStream methods. /* package */ boolean isReady(int track) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 54b34bc531..a5b2314d78 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.trackselection.TrackSelection; import java.io.IOException; @@ -149,6 +150,19 @@ public interface MediaPeriod extends SequenceableLoader { */ long seekToUs(long positionUs); + /** + * Returns the position to which a seek will be performed, given the specified seek position and + * {@link SeekParameters}. + * + *

This method should only be called after the period has been prepared. + * + * @param positionUs The seek position in microseconds. + * @param seekParameters Parameters that control how the seek is performed. Implementations may + * apply seek parameters on a best effort basis. + * @return The actual position to which a seek will be performed, in microseconds. + */ + long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters); + // SequenceableLoader interface. Overridden to provide more specific documentation. /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java index 5ac9fc8d97..cc0c63ef41 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; @@ -192,6 +193,11 @@ import java.util.IdentityHashMap; return positionUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return enabledPeriods[0].getAdjustedSeekPositionUs(positionUs, seekParameters); + } + // MediaPeriod.Callback implementation @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java index 7b8b54eedc..9fff3b4d85 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java @@ -20,6 +20,7 @@ import android.os.Handler; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.source.SingleSampleMediaSource.EventListener; import com.google.android.exoplayer2.trackselection.TrackSelection; @@ -153,11 +154,16 @@ import java.util.Arrays; @Override public long seekToUs(long positionUs) { for (int i = 0; i < sampleStreams.size(); i++) { - sampleStreams.get(i).seekToUs(positionUs); + sampleStreams.get(i).reset(); } return positionUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return positionUs; + } + // Loader.Callback implementation. @Override @@ -208,7 +214,7 @@ import java.util.Arrays; private int streamState; - public void seekToUs(long positionUs) { + public void reset() { if (streamState == STREAM_STATE_END_OF_STREAM) { streamState = STREAM_STATE_SEND_SAMPLE; } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index f320ad2844..2b7b16228e 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -20,6 +20,7 @@ import android.util.Pair; import android.util.SparseIntArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.EmptySampleStream; import com.google.android.exoplayer2.source.MediaPeriod; @@ -306,6 +307,11 @@ import java.util.Map; return positionUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return positionUs; + } + // SequenceableLoader.Callback implementation. @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 24acf0f84d..11602c722f 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.hls; import android.os.Handler; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; @@ -244,6 +245,11 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper return positionUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return positionUs; + } + // HlsSampleStreamWrapper.Callback implementation. @Override diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index 564993befe..5ee60bdeed 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.smoothstreaming; import android.util.Base64; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.MediaPeriod; @@ -182,6 +183,11 @@ import java.util.ArrayList; return positionUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return positionUs; + } + // SequenceableLoader.Callback implementation @Override diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java index d34c1d1c0c..0a5dcd5741 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil; import android.os.Handler; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.TrackGroup; @@ -176,6 +177,11 @@ public class FakeMediaPeriod implements MediaPeriod { return positionUs + seekOffsetUs; } + @Override + public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) { + return positionUs; + } + @Override public long getNextLoadPositionUs() { Assert.assertTrue(prepared); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSimpleExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSimpleExoPlayer.java index 1e7e0cd933..d568770219 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSimpleExoPlayer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSimpleExoPlayer.java @@ -422,8 +422,12 @@ public class FakeSimpleExoPlayer extends SimpleExoPlayer { SampleStream[] sampleStreams = new SampleStream[renderers.length]; boolean[] mayRetainStreamFlags = new boolean[renderers.length]; Arrays.fill(mayRetainStreamFlags, true); - mediaPeriod.selectTracks(selectorResult.selections.getAll(), mayRetainStreamFlags, - sampleStreams, new boolean[renderers.length], 0); + mediaPeriod.selectTracks( + selectorResult.selections.getAll(), + mayRetainStreamFlags, + sampleStreams, + new boolean[renderers.length], + /* positionUs = */ 0); eventListenerHandler.post(new Runnable() { @Override public void run() {