From 922529fd1d80ea51dc7bf0938a4960eb2708068c Mon Sep 17 00:00:00 2001 From: WeiChungChang Date: Tue, 21 Feb 2017 12:53:56 +0800 Subject: [PATCH] 'locakl_high_reverse_playback' --- .../google/android/exoplayer2/ExoPlayer.java | 3 + .../android/exoplayer2/ExoPlayerImpl.java | 22 ++++++ .../exoplayer2/ExoPlayerImplInternal.java | 62 ++++++++++------- .../android/exoplayer2/SimpleExoPlayer.java | 69 +++++++++++++++++++ .../google/android/exoplayer2/util/Util.java | 11 +++ 5 files changed, 144 insertions(+), 23 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 91217cd62c6..351b71210fd 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -344,6 +344,9 @@ public ExoPlayerMessage(ExoPlayerComponent target, int messageType, Object messa */ void seekTo(int windowIndex, long positionMs); + /*TODO: add commmets later*/ + void seekWithDelay(long positionMs, long delayMs); + /** * Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention * is to pause playback. diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index ddb4337f3ef..47817e4f8c8 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -195,6 +195,28 @@ public void seekTo(int windowIndex, long positionMs) { } } } + @Override + public void seekWithDelay(long positionMs, long delayMs) { + seekToWithDelay(getCurrentWindowIndex(), positionMs, delayMs); + } + + public void seekToWithDelay(int windowIndex, long positionMs, long delayMs) { + if (windowIndex < 0 || (!timeline.isEmpty() && windowIndex >= timeline.getWindowCount())) { + throw new IllegalSeekPositionException(timeline, windowIndex, positionMs); + } + pendingSeekAcks++; + maskingWindowIndex = windowIndex; + if (positionMs == C.TIME_UNSET) { + maskingWindowPositionMs = 0; + internalPlayer.seekToWithDelay(timeline, windowIndex, C.TIME_UNSET, delayMs); + } else { + maskingWindowPositionMs = positionMs; + internalPlayer.seekToWithDelay(timeline, windowIndex, C.msToUs(positionMs), delayMs); + for (EventListener listener : listeners) { + listener.onPositionDiscontinuity(); + } + } + } @Override public void stop() { diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 933c13e3e4e..b4300ba6d6a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -39,7 +39,7 @@ import android.os.Build; import android.media.PlaybackParams; - +import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroup; @@ -218,10 +218,23 @@ public void setPlayWhenReady(boolean playWhenReady) { } public void seekTo(Timeline timeline, int windowIndex, long positionUs) { + if (Util.isHighSpeed(speed)) { + handler.removeMessages(MSG_SEEK_TO); + } handler.obtainMessage(MSG_SEEK_TO, new SeekPosition(timeline, windowIndex, positionUs)) .sendToTarget(); } + public void seekToWithDelay(Timeline timeline, int windowIndex, long positionUs, long delay) { + if (delay == 0) { + handler.obtainMessage(MSG_SEEK_TO, new SeekPosition(timeline, windowIndex, positionUs)) + .sendToTarget(); + return; + } + Message message = handler.obtainMessage(MSG_SEEK_TO, new SeekPosition(timeline, windowIndex, positionUs)); + handler.sendMessageDelayed(message, (delay)); + } + public void stop() { handler.sendEmptyMessage(MSG_STOP); } @@ -1420,30 +1433,33 @@ public float getPlaybackSpeed() { public void setPlaybackSpeed(float speed) { this.speed = speed; - - if ((Build.VERSION.SDK_INT >= 23) && (rendererMediaClockSource != null)) { - PlaybackParams params = new PlaybackParams(); - params.setSpeed(speed); - ExoPlayerMessage[] messages = new ExoPlayerMessage[renderers.length]; - for (int i = 0; i < renderers.length; i++) { - messages[i] = new ExoPlayerMessage(renderers[i], C.MSG_SET_PLAYBACK_PARAMS, params); - } - try { - sendMessagesInternal(messages); - } catch (ExoPlaybackException e) { - e.printStackTrace(); - } + if (Util.isHighSpeed(speed)/*in this mode, we operate by seek*/) { + return; } else { - this.speed = speed; - standaloneMediaClock.setPlaybackSpeed(speed); - if (rendererMediaClock != null) { - rendererMediaClock.setPlaybackSpeed(speed); + if ((Build.VERSION.SDK_INT >= 23) && (rendererMediaClockSource != null)) { + PlaybackParams params = new PlaybackParams(); + params.setSpeed(speed); + ExoPlayerMessage[] messages = new ExoPlayerMessage[renderers.length]; + for (int i = 0; i < renderers.length; i++) { + messages[i] = new ExoPlayerMessage(renderers[i], C.MSG_SET_PLAYBACK_PARAMS, params); + } + try { + sendMessagesInternal(messages); + } catch (ExoPlaybackException e) { + e.printStackTrace(); + } + } else { + this.speed = speed; + standaloneMediaClock.setPlaybackSpeed(speed); + if (rendererMediaClock != null) { + rendererMediaClock.setPlaybackSpeed(speed); + } + } + if (playingPeriodHolder != null) { + setFormatSpeed(speed); + } else { + pendingFormatSpeed = true; } - } - if (playingPeriodHolder != null) { - setFormatSpeed(speed); - } else { - pendingFormatSpeed = true; } } diff --git a/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 8aad5520368..47325882598 100644 --- a/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -51,6 +51,9 @@ import java.util.ArrayList; import java.util.List; +import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.util.StandaloneMediaClock; + /** * An {@link ExoPlayer} implementation that uses default {@link Renderer} components. Instances can * be obtained from {@link ExoPlayerFactory}. @@ -147,6 +150,9 @@ void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, private float audioVolume; private PlaybackParamsHolder playbackParamsHolder; + boolean trickPlayBySeek; + private final StandaloneMediaClock standaloneMediaClock; + private float speed; protected SimpleExoPlayer(Context context, TrackSelector trackSelector, LoadControl loadControl, DrmSessionManager drmSessionManager, @ExtensionRendererMode int extensionRendererMode, long allowedVideoJoiningTimeMs) { @@ -183,6 +189,9 @@ protected SimpleExoPlayer(Context context, TrackSelector trackSelector, LoadCont // Build the player and associated objects. player = new ExoPlayerImpl(renderers, trackSelector, loadControl); + standaloneMediaClock = new StandaloneMediaClock(); + this.speed = 1; + trickPlayBySeek = false; } /** @@ -486,6 +495,9 @@ public void prepare(MediaSource mediaSource, boolean resetPosition, boolean rese @Override public void setPlayWhenReady(boolean playWhenReady) { + if (!getPlayWhenReady() && speed != 1 && playWhenReady) { + setPlaybackSpeed(1); + } player.setPlayWhenReady(playWhenReady); } @@ -499,6 +511,12 @@ public boolean isLoading() { return player.isLoading(); } + @Override + public void seekWithDelay(long positionMs, long delayMs) { + + player.seekWithDelay(positionMs, delayMs); + } + @Override public void seekToDefaultPosition() { player.seekToDefaultPosition(); @@ -511,11 +529,21 @@ public void seekToDefaultPosition(int windowIndex) { @Override public void seekTo(long positionMs) { + + if (Util.isHighSpeed(speed)) { + standaloneMediaClock.setPositionUs(positionMs * 1000); + } player.seekTo(positionMs); } @Override public void seekTo(int windowIndex, long positionMs) { + + if (Util.isHighSpeed(speed)) { + standaloneMediaClock.stop(); + standaloneMediaClock.setPositionUs(positionMs * 1000); + standaloneMediaClock.start(); + } player.seekTo(windowIndex, positionMs); } @@ -893,6 +921,25 @@ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegre } } + private long getNextPositionMs() { + long currentPositionUs = standaloneMediaClock.getPositionUs(); + long nextPositionUs = ((currentPositionUs / 1000) + ((long)speed * Util.TRICK_PLAY_DISPLAY_TIME_MS)); /*in ms*/ + if (speed > 0) { + if (nextPositionUs > (getDuration())) { + trickPlayBySeek = false; + seekWithDelay(getDuration()/*in ms*/, 0); + return C.TIME_END_OF_SOURCE; + } + } else { + if (nextPositionUs < 0) { + trickPlayBySeek = false; + seekWithDelay(0, 0); + return C.TIME_END_OF_SOURCE; + } + } + return nextPositionUs; /*in ms*/ + } + @Override public void onRenderedFirstFrame(Surface surface) { if (videoListener != null && SimpleExoPlayer.this.surface == surface) { @@ -901,6 +948,13 @@ public void onRenderedFirstFrame(Surface surface) { if (videoDebugListener != null) { videoDebugListener.onRenderedFirstFrame(surface); } + if (trickPlayBySeek) { + /*issue next seek*/ + long nextPosition = getNextPositionMs(); + if (nextPosition != C.TIME_END_OF_SOURCE) { + seekWithDelay(nextPosition, Util.TRICK_PLAY_DISPLAY_TIME_MS); + } + } } @Override @@ -1043,6 +1097,21 @@ public float getPlaybackSpeed() { @Override public void setPlaybackSpeed(float speed) { + this.speed = speed; + + if (videoDecoderCounters != null && Util.isHighSpeed(speed)) { + standaloneMediaClock.start(); + long currentPositionMs = getCurrentPosition(); + standaloneMediaClock.setPositionUs(currentPositionMs * 1000); + standaloneMediaClock.setPlaybackSpeed(speed); + + setPlayWhenReady(false); + seekWithDelay(currentPositionMs, 0); + trickPlayBySeek = true; + } else { + trickPlayBySeek = false; + setPlayWhenReady(true); + } player.setPlaybackSpeed(speed); } diff --git a/library/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/src/main/java/com/google/android/exoplayer2/util/Util.java index e854c051654..2c706a9367f 100644 --- a/library/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -59,6 +59,10 @@ */ public final class Util { + public static final boolean TRICK_PLAY_TEST_HACK = false; + public static final boolean TRICK_PLAY_HIGH_SPEED = true; + public static final long TRICK_PLAY_DISPLAY_TIME_MS = 500; /*ms*/ + public static final long MAX_NATIVE_SUPPORT_SPEED = 4; /** * Like {@link android.os.Build.VERSION#SDK_INT}, but in a place where it can be conveniently * overridden for local testing. @@ -103,6 +107,13 @@ public final class Util { private Util() {} + public static boolean isHighSpeed(float speed) { + if (((speed > MAX_NATIVE_SUPPORT_SPEED) || (speed < 0))) { + return true; + } + return false; + } + /** * Converts the entirety of an {@link InputStream} to a byte array. *