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 d39af2adca..f1fbad4c61 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 @@ -447,7 +447,9 @@ import java.util.concurrent.atomic.AtomicBoolean; @Override public void onPlaybackParametersChanged(PlaybackParameters newPlaybackParameters) { - sendPlaybackParametersChangedInternal(newPlaybackParameters, /* acknowledgeCommand= */ false); + handler + .obtainMessage(MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, newPlaybackParameters) + .sendToTarget(); } // Handler.Callback implementation. @@ -501,8 +503,7 @@ import java.util.concurrent.atomic.AtomicBoolean; reselectTracksInternal(); break; case MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL: - handlePlaybackParameters( - (PlaybackParameters) msg.obj, /* acknowledgeCommand= */ msg.arg1 != 0); + handlePlaybackParameters((PlaybackParameters) msg.obj, /* acknowledgeCommand= */ false); break; case MSG_SEND_MESSAGE: sendMessageInternal((PlayerMessage) msg.obj); @@ -888,6 +889,11 @@ import java.util.concurrent.atomic.AtomicBoolean; getCurrentLiveOffsetUs(), getTotalBufferedDurationUs()); if (mediaClock.getPlaybackParameters().speed != adjustedSpeed) { mediaClock.setPlaybackParameters(playbackInfo.playbackParameters.withSpeed(adjustedSpeed)); + handlePlaybackParameters( + playbackInfo.playbackParameters, + /* currentPlaybackSpeed= */ mediaClock.getPlaybackParameters().speed, + /* updatePlaybackInfo= */ false, + /* acknowledgeCommand= */ false); } } } @@ -1279,10 +1285,10 @@ import java.util.concurrent.atomic.AtomicBoolean; notifyTrackSelectionDiscontinuity(); } - private void setPlaybackParametersInternal(PlaybackParameters playbackParameters) { + private void setPlaybackParametersInternal(PlaybackParameters playbackParameters) + throws ExoPlaybackException { mediaClock.setPlaybackParameters(playbackParameters); - sendPlaybackParametersChangedInternal( - mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true); + handlePlaybackParameters(mediaClock.getPlaybackParameters(), /* acknowledgeCommand= */ true); } private void setSeekParametersInternal(SeekParameters seekParameters) { @@ -2141,12 +2147,30 @@ import java.util.concurrent.atomic.AtomicBoolean; private void handlePlaybackParameters( PlaybackParameters playbackParameters, boolean acknowledgeCommand) throws ExoPlaybackException { - playbackInfoUpdate.incrementPendingOperationAcks(acknowledgeCommand ? 1 : 0); - playbackInfo = playbackInfo.copyWithPlaybackParameters(playbackParameters); + handlePlaybackParameters( + playbackParameters, + playbackParameters.speed, + /* updatePlaybackInfo= */ true, + acknowledgeCommand); + } + + private void handlePlaybackParameters( + PlaybackParameters playbackParameters, + float currentPlaybackSpeed, + boolean updatePlaybackInfo, + boolean acknowledgeCommand) + throws ExoPlaybackException { + if (updatePlaybackInfo) { + if (acknowledgeCommand) { + playbackInfoUpdate.incrementPendingOperationAcks(1); + } + playbackInfo = playbackInfo.copyWithPlaybackParameters(playbackParameters); + } updateTrackSelectionPlaybackSpeed(playbackParameters.speed); for (Renderer renderer : renderers) { if (renderer != null) { - renderer.setPlaybackSpeed(playbackParameters.speed); + renderer.setPlaybackSpeed( + currentPlaybackSpeed, /* targetPlaybackSpeed= */ playbackParameters.speed); } } } @@ -2372,17 +2396,6 @@ import java.util.concurrent.atomic.AtomicBoolean; loadControl.onTracksSelected(renderers, trackGroups, trackSelectorResult.selections); } - private void sendPlaybackParametersChangedInternal( - PlaybackParameters playbackParameters, boolean acknowledgeCommand) { - handler - .obtainMessage( - MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, - acknowledgeCommand ? 1 : 0, - 0, - playbackParameters) - .sendToTarget(); - } - private boolean shouldPlayWhenReady() { return playbackInfo.playWhenReady && playbackInfo.playbackSuppressionReason == Player.PLAYBACK_SUPPRESSION_REASON_NONE; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java b/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java index 515f723cb9..8578a23929 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java @@ -403,10 +403,14 @@ public interface Renderer extends PlayerMessage.Target { * *

The default implementation is a no-op. * - * @param playbackSpeed The factor by which playback is sped up. + * @param currentPlaybackSpeed The factor by which playback is currently sped up. + * @param targetPlaybackSpeed The target factor by which playback should be sped up. This may be + * different from {@code currentPlaybackSpeed}, for example, if the speed is temporarily + * adjusted for live playback. * @throws ExoPlaybackException If an error occurs handling the playback speed. */ - default void setPlaybackSpeed(float playbackSpeed) throws ExoPlaybackException {} + default void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpeed) + throws ExoPlaybackException {} /** * Incrementally renders the {@link SampleStream}. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 7580202852..990369c783 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -390,7 +390,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media @Override protected float getCodecOperatingRateV23( - float playbackSpeed, Format format, Format[] streamFormats) { + float targetPlaybackSpeed, Format format, Format[] streamFormats) { // Use the highest known stream sample-rate up front, to avoid having to reconfigure the codec // should an adaptive switch to that stream occur. int maxSampleRate = -1; @@ -400,7 +400,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media maxSampleRate = max(maxSampleRate, streamSampleRate); } } - return maxSampleRate == -1 ? CODEC_OPERATING_RATE_UNSET : (maxSampleRate * playbackSpeed); + return maxSampleRate == -1 ? CODEC_OPERATING_RATE_UNSET : (maxSampleRate * targetPlaybackSpeed); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 61e121d6b7..6ca35003d9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -312,7 +312,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @Nullable private MediaCrypto mediaCrypto; private boolean mediaCryptoRequiresSecureDecoder; private long renderTimeLimitMs; - private float playbackSpeed; + private float currentPlaybackSpeed; + private float targetPlaybackSpeed; @Nullable private MediaCodecAdapter codec; @Nullable private Format codecInputFormat; @Nullable private MediaFormat codecOutputMediaFormat; @@ -393,7 +394,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { formatQueue = new TimedValueQueue<>(); decodeOnlyPresentationTimestamps = new ArrayList<>(); outputBufferInfo = new MediaCodec.BufferInfo(); - playbackSpeed = 1f; + currentPlaybackSpeed = 1f; + targetPlaybackSpeed = 1f; renderTimeLimitMs = C.TIME_UNSET; pendingOutputStreamStartPositionsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; @@ -715,8 +717,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } @Override - public void setPlaybackSpeed(float playbackSpeed) throws ExoPlaybackException { - this.playbackSpeed = playbackSpeed; + public void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpeed) + throws ExoPlaybackException { + this.currentPlaybackSpeed = currentPlaybackSpeed; + this.targetPlaybackSpeed = targetPlaybackSpeed; if (codec != null && codecDrainAction != DRAIN_ACTION_REINITIALIZE && getState() != STATE_DISABLED) { @@ -1082,7 +1086,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { float codecOperatingRate = Util.SDK_INT < 23 ? CODEC_OPERATING_RATE_UNSET - : getCodecOperatingRateV23(playbackSpeed, inputFormat, getStreamFormats()); + : getCodecOperatingRateV23(targetPlaybackSpeed, inputFormat, getStreamFormats()); if (codecOperatingRate <= assumedMinimumCodecOperatingRate) { codecOperatingRate = CODEC_OPERATING_RATE_UNSET; } @@ -1624,9 +1628,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { && SystemClock.elapsedRealtime() < codecHotswapDeadlineMs)); } - /** Returns the playback speed, as set by {@link #setPlaybackSpeed}. */ + /** Returns the current playback speed, as set by {@link #setPlaybackSpeed}. */ protected float getPlaybackSpeed() { - return playbackSpeed; + return currentPlaybackSpeed; } /** Returns the operating rate used by the current codec */ @@ -1640,14 +1644,16 @@ public abstract class MediaCodecRenderer extends BaseRenderer { * *

The default implementation returns {@link #CODEC_OPERATING_RATE_UNSET}. * - * @param playbackSpeed The factor by which playback is sped up. + * @param targetPlaybackSpeed The target factor by which playback should be sped up. This may be + * different from the current playback speed, for example, if the speed is temporarily + * adjusted for live playback. * @param format The {@link Format} for which the codec is being configured. * @param streamFormats The possible stream formats. * @return The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if no codec operating * rate should be set. */ protected float getCodecOperatingRateV23( - float playbackSpeed, Format format, Format[] streamFormats) { + float targetPlaybackSpeed, Format format, Format[] streamFormats) { return CODEC_OPERATING_RATE_UNSET; } @@ -1665,7 +1671,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } float newCodecOperatingRate = - getCodecOperatingRateV23(playbackSpeed, format, getStreamFormats()); + getCodecOperatingRateV23(targetPlaybackSpeed, format, getStreamFormats()); if (codecOperatingRate == newCodecOperatingRate) { // No change. return true; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index c52e7063e5..9e3ccbf570 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -645,14 +645,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } @Override - public void setPlaybackSpeed(float playbackSpeed) throws ExoPlaybackException { - super.setPlaybackSpeed(playbackSpeed); - frameReleaseHelper.onPlaybackSpeed(playbackSpeed); + public void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpeed) + throws ExoPlaybackException { + super.setPlaybackSpeed(currentPlaybackSpeed, targetPlaybackSpeed); + frameReleaseHelper.onPlaybackSpeed(currentPlaybackSpeed); } @Override protected float getCodecOperatingRateV23( - float playbackSpeed, Format format, Format[] streamFormats) { + float targetPlaybackSpeed, Format format, Format[] streamFormats) { // Use the highest known stream frame-rate up front, to avoid having to reconfigure the codec // should an adaptive switch to that stream occur. float maxFrameRate = -1; @@ -662,7 +663,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { maxFrameRate = max(maxFrameRate, streamFrameRate); } } - return maxFrameRate == -1 ? CODEC_OPERATING_RATE_UNSET : (maxFrameRate * playbackSpeed); + return maxFrameRate == -1 ? CODEC_OPERATING_RATE_UNSET : (maxFrameRate * targetPlaybackSpeed); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java index c646a2323f..1778ed6976 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java @@ -190,10 +190,9 @@ public final class VideoFrameReleaseHelper { } /** - * Called when the renderer's playback speed changes, where 1 is the default rate, 2 is twice the - * default rate, 0.5 is half the default rate and so on. + * Called when the renderer's playback speed changes. * - * @param playbackSpeed The player's speed. + * @param playbackSpeed The factor by which playback is sped up. */ public void onPlaybackSpeed(float playbackSpeed) { this.playbackSpeed = playbackSpeed;