mirror of
https://github.com/samsonjs/media.git
synced 2026-04-03 10:55:48 +00:00
Add ability to disable Surface.setFrameRate calls
Adding a CHANGE_FRAME_RATE_STRATEGY_ALWAYS strategy is omitted from this commit, since adding it is more complicated than just plumbing it through and leaving everything else unchanged. Specifically, VideoFrameReleaseTimeHelper would need updating to behave differently when such a strategy is enabled. It currently calls setFrameRate in cases such as pausing, seeking and re-buffering, on the assumption that changes to the underlying display refresh rate will only be made if they can be done seamlessly. For a mode in which this will not be the case, it makes more sense to stick to the content frame-rate when these events occur. It may also make sense to only use explicit content frame-rate values, and not those inferred from individual frame timestamps. Finally, for adaptive content containing a mix of frame-rates, it makes sense to use the maximal frame-rate across all variants, and to avoid calling setFrameRate on switches from one variant to another. Applications that know the frame-rate of their content can set ExoPlayer's strategy to CHANGE_FRAME_RATE_STRATEGY_OFF and then use setFrameRate directly on the output surface. Note that this is likely to be a better option for apps than anything we could implement in ExoPlayer, because the application layer most likely knows the frame-rate of the content earlier than ExoPlayer does (e.g., to perform the disruptive mode switch at the same time as an activity transition). Adding CHANGE_FRAME_RATE_STRATEGY_ALWAYS will be deferred until there's clear demand for it. In the meantime, we'll recommend the alternative approach above. PiperOrigin-RevId: 389610965
This commit is contained in:
parent
eb74856c57
commit
0097a79c2d
7 changed files with 155 additions and 29 deletions
|
|
@ -50,11 +50,16 @@
|
|||
* Change interface of `LoadErrorHandlingPolicy` to support configuring the
|
||||
behavior of track and location fallback. Location fallback is currently
|
||||
only supported for DASH manifests with multiple base URLs.
|
||||
* Disable platform transcoding when playing content URIs on Android 12.
|
||||
* Restrict use of `AudioTrack.isDirectPlaybackSupported` to TVs, to avoid
|
||||
listing audio offload encodings as supported for passthrough mode on
|
||||
mobile devices
|
||||
([#9239](https://github.com/google/ExoPlayer/issues/9239)).
|
||||
* Android 12 compatibility:
|
||||
* Disable platform transcoding when playing content URIs on Android 12.
|
||||
* Add `ExoPlayer.setVideoChangeFrameRateStrategy` to allow disabling of
|
||||
calls from the player to `Surface.setFrameRate`. This is useful for
|
||||
applications wanting to call `Surface.setFrameRate` directly from
|
||||
application code with Android 12's `Surface.CHANGE_FRAME_RATE_ALWAYS`.
|
||||
* Remove deprecated symbols:
|
||||
* Remove `Player.getPlaybackError`. Use `Player.getPlayerError` instead.
|
||||
* Remove `Player.getCurrentTag`. Use `Player.getCurrentMediaItem` and
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import android.media.AudioFormat;
|
|||
import android.media.AudioManager;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
import android.view.Surface;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
|
@ -491,6 +492,23 @@ public final class C {
|
|||
/** A default video scaling mode for {@link MediaCodec}-based renderers. */
|
||||
public static final int VIDEO_SCALING_MODE_DEFAULT = VIDEO_SCALING_MODE_SCALE_TO_FIT;
|
||||
|
||||
/** Strategies for calling {@link Surface#setFrameRate}. */
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF, VIDEO_CHANGE_FRAME_RATE_STRATEGY_ONLY_IF_SEAMLESS})
|
||||
public @interface VideoChangeFrameRateStrategy {}
|
||||
/**
|
||||
* Strategy to never call {@link Surface#setFrameRate}. Use this strategy if you prefer to call
|
||||
* {@link Surface#setFrameRate} directly from application code.
|
||||
*/
|
||||
public static final int VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF = Integer.MIN_VALUE;
|
||||
/**
|
||||
* Strategy to call {@link Surface#setFrameRate} with {@link
|
||||
* Surface#CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS} when the output frame rate is known.
|
||||
*/
|
||||
public static final int VIDEO_CHANGE_FRAME_RATE_STRATEGY_ONLY_IF_SEAMLESS =
|
||||
Surface.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
|
||||
|
||||
/**
|
||||
* Track selection flags. Possible flag values are {@link #SELECTION_FLAG_DEFAULT}, {@link
|
||||
* #SELECTION_FLAG_FORCED} and {@link #SELECTION_FLAG_AUTOSELECT}.
|
||||
|
|
@ -982,7 +1000,7 @@ public final class C {
|
|||
FORMAT_UNSUPPORTED_SUBTYPE,
|
||||
FORMAT_UNSUPPORTED_TYPE
|
||||
})
|
||||
public static @interface FormatSupport {}
|
||||
public @interface FormatSupport {}
|
||||
// TODO(b/172315872) Renderer was a link. Link to equivalent concept or remove @code.
|
||||
/** The {@code Renderer} is capable of rendering the format. */
|
||||
public static final int FORMAT_HANDLED = 0b100;
|
||||
|
|
@ -1023,6 +1041,7 @@ public final class C {
|
|||
* audio MIME type.
|
||||
*/
|
||||
public static final int FORMAT_UNSUPPORTED_TYPE = 0b000;
|
||||
|
||||
/**
|
||||
* Converts a time in microseconds to the corresponding time in milliseconds, preserving {@link
|
||||
* #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2;
|
|||
|
||||
import android.content.Context;
|
||||
import android.media.AudioTrack;
|
||||
import android.media.MediaCodec;
|
||||
import android.os.Looper;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
|
|
@ -241,6 +242,9 @@ public interface ExoPlayer extends Player {
|
|||
/**
|
||||
* Sets the {@link C.VideoScalingMode}.
|
||||
*
|
||||
* <p>The scaling mode only applies if a {@link MediaCodec}-based video {@link Renderer} is
|
||||
* enabled and if the output surface is owned by a {@link SurfaceView}.
|
||||
*
|
||||
* @param videoScalingMode The {@link C.VideoScalingMode}.
|
||||
*/
|
||||
void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode);
|
||||
|
|
@ -249,6 +253,25 @@ public interface ExoPlayer extends Player {
|
|||
@C.VideoScalingMode
|
||||
int getVideoScalingMode();
|
||||
|
||||
/**
|
||||
* Sets a {@link C.VideoChangeFrameRateStrategy} that will be used by the player when provided
|
||||
* with a video output {@link Surface}.
|
||||
*
|
||||
* <p>The strategy only applies if a {@link MediaCodec}-based video {@link Renderer} is enabled.
|
||||
* Applications wishing to use {@link Surface#CHANGE_FRAME_RATE_ALWAYS} should set the mode to
|
||||
* {@link C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF} to disable calls to {@link
|
||||
* Surface#setFrameRate} from ExoPlayer, and should then call {@link Surface#setFrameRate}
|
||||
* directly from application code.
|
||||
*
|
||||
* @param videoChangeFrameRateStrategy A {@link C.VideoChangeFrameRateStrategy}.
|
||||
*/
|
||||
void setVideoChangeFrameRateStrategy(
|
||||
@C.VideoChangeFrameRateStrategy int videoChangeFrameRateStrategy);
|
||||
|
||||
/** Returns the {@link C.VideoChangeFrameRateStrategy}. */
|
||||
@C.VideoChangeFrameRateStrategy
|
||||
int getVideoChangeFrameRateStrategy();
|
||||
|
||||
/**
|
||||
* Adds a listener to receive video events.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -119,37 +119,43 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
* owned by a {@link android.view.SurfaceView}.
|
||||
*/
|
||||
int MSG_SET_SCALING_MODE = 4;
|
||||
/**
|
||||
* The type of a message that can be passed to a video renderer via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be one of the integer strategy
|
||||
* constants in {@link C.VideoChangeFrameRateStrategy}.
|
||||
*/
|
||||
int MSG_SET_CHANGE_FRAME_RATE_STRATEGY = 5;
|
||||
/**
|
||||
* A type of a message that can be passed to an audio renderer via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be an {@link AuxEffectInfo}
|
||||
* instance representing an auxiliary audio effect for the underlying audio track.
|
||||
*/
|
||||
int MSG_SET_AUX_EFFECT_INFO = 5;
|
||||
int MSG_SET_AUX_EFFECT_INFO = 6;
|
||||
/**
|
||||
* The type of a message that can be passed to a video renderer via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be a {@link
|
||||
* VideoFrameMetadataListener} instance, or null.
|
||||
*/
|
||||
int MSG_SET_VIDEO_FRAME_METADATA_LISTENER = 6;
|
||||
int MSG_SET_VIDEO_FRAME_METADATA_LISTENER = 7;
|
||||
/**
|
||||
* The type of a message that can be passed to a camera motion renderer via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be a {@link CameraMotionListener}
|
||||
* instance, or null.
|
||||
*/
|
||||
int MSG_SET_CAMERA_MOTION_LISTENER = 7;
|
||||
int MSG_SET_CAMERA_MOTION_LISTENER = 8;
|
||||
/**
|
||||
* The type of a message that can be passed to an audio renderer via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be a {@link Boolean} instance
|
||||
* telling whether to enable or disable skipping silences in the audio stream.
|
||||
*/
|
||||
int MSG_SET_SKIP_SILENCE_ENABLED = 8;
|
||||
int MSG_SET_SKIP_SILENCE_ENABLED = 9;
|
||||
/**
|
||||
* The type of a message that can be passed to audio and video renderers via {@link
|
||||
* ExoPlayer#createMessage(Target)}. The message payload should be an {@link Integer} instance
|
||||
* representing the audio session ID that will be attached to the underlying audio track. Video
|
||||
* renderers that support tunneling will use the audio session ID when tunneling is enabled.
|
||||
*/
|
||||
int MSG_SET_AUDIO_SESSION_ID = 9;
|
||||
int MSG_SET_AUDIO_SESSION_ID = 10;
|
||||
/**
|
||||
* The type of a message that can be passed to a {@link Renderer} via {@link
|
||||
* ExoPlayer#createMessage(Target)}, to inform the renderer that it can schedule waking up another
|
||||
|
|
@ -157,7 +163,7 @@ public interface Renderer extends PlayerMessage.Target {
|
|||
*
|
||||
* <p>The message payload must be a {@link WakeupListener} instance.
|
||||
*/
|
||||
int MSG_SET_WAKEUP_LISTENER = 10;
|
||||
int MSG_SET_WAKEUP_LISTENER = 11;
|
||||
/**
|
||||
* Applications or extensions may define custom {@code MSG_*} constants that can be passed to
|
||||
* renderers. These custom constants must be greater than or equal to this value.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import static com.google.android.exoplayer2.Renderer.MSG_SET_AUDIO_ATTRIBUTES;
|
|||
import static com.google.android.exoplayer2.Renderer.MSG_SET_AUDIO_SESSION_ID;
|
||||
import static com.google.android.exoplayer2.Renderer.MSG_SET_AUX_EFFECT_INFO;
|
||||
import static com.google.android.exoplayer2.Renderer.MSG_SET_CAMERA_MOTION_LISTENER;
|
||||
import static com.google.android.exoplayer2.Renderer.MSG_SET_CHANGE_FRAME_RATE_STRATEGY;
|
||||
import static com.google.android.exoplayer2.Renderer.MSG_SET_SCALING_MODE;
|
||||
import static com.google.android.exoplayer2.Renderer.MSG_SET_SKIP_SILENCE_ENABLED;
|
||||
import static com.google.android.exoplayer2.Renderer.MSG_SET_VIDEO_FRAME_METADATA_LISTENER;
|
||||
|
|
@ -130,6 +131,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
private boolean handleAudioBecomingNoisy;
|
||||
private boolean skipSilenceEnabled;
|
||||
@C.VideoScalingMode private int videoScalingMode;
|
||||
@C.VideoChangeFrameRateStrategy private int videoChangeFrameRateStrategy;
|
||||
private boolean useLazyPreparation;
|
||||
private SeekParameters seekParameters;
|
||||
private long seekBackIncrementMs;
|
||||
|
|
@ -168,6 +170,8 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
* <li>{@code handleAudioBecomingNoisy}: {@code false}
|
||||
* <li>{@code skipSilenceEnabled}: {@code false}
|
||||
* <li>{@link C.VideoScalingMode}: {@link C#VIDEO_SCALING_MODE_DEFAULT}
|
||||
* <li>{@link C.VideoChangeFrameRateStrategy}: {@link
|
||||
* C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_ONLY_IF_SEAMLESS}
|
||||
* <li>{@code useLazyPreparation}: {@code true}
|
||||
* <li>{@link SeekParameters}: {@link SeekParameters#DEFAULT}
|
||||
* <li>{@code seekBackIncrementMs}: {@link C#DEFAULT_SEEK_BACK_INCREMENT_MS}
|
||||
|
|
@ -267,6 +271,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
audioAttributes = AudioAttributes.DEFAULT;
|
||||
wakeMode = C.WAKE_MODE_NONE;
|
||||
videoScalingMode = C.VIDEO_SCALING_MODE_DEFAULT;
|
||||
videoChangeFrameRateStrategy = C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_ONLY_IF_SEAMLESS;
|
||||
useLazyPreparation = true;
|
||||
seekParameters = SeekParameters.DEFAULT;
|
||||
seekBackIncrementMs = C.DEFAULT_SEEK_BACK_INCREMENT_MS;
|
||||
|
|
@ -462,9 +467,8 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
/**
|
||||
* Sets the {@link C.VideoScalingMode} that will be used by the player.
|
||||
*
|
||||
* <p>Note that the scaling mode only applies if a {@link MediaCodec}-based video {@link
|
||||
* Renderer} is enabled and if the output surface is owned by a {@link
|
||||
* android.view.SurfaceView}.
|
||||
* <p>The scaling mode only applies if a {@link MediaCodec}-based video {@link Renderer} is
|
||||
* enabled and if the output surface is owned by a {@link SurfaceView}.
|
||||
*
|
||||
* @param videoScalingMode A {@link C.VideoScalingMode}.
|
||||
* @return This builder.
|
||||
|
|
@ -476,6 +480,27 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link C.VideoChangeFrameRateStrategy} that will be used by the player when provided
|
||||
* with a video output {@link Surface}.
|
||||
*
|
||||
* <p>The strategy only applies if a {@link MediaCodec}-based video {@link Renderer} is enabled.
|
||||
* Applications wishing to use {@link Surface#CHANGE_FRAME_RATE_ALWAYS} should set the mode to
|
||||
* {@link C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF} to disable calls to {@link
|
||||
* Surface#setFrameRate} from ExoPlayer, and should then call {@link Surface#setFrameRate}
|
||||
* directly from application code.
|
||||
*
|
||||
* @param videoChangeFrameRateStrategy A {@link C.VideoChangeFrameRateStrategy}.
|
||||
* @return This builder.
|
||||
* @throws IllegalStateException If {@link #build()} has already been called.
|
||||
*/
|
||||
public Builder setVideoChangeFrameRateStrategy(
|
||||
@C.VideoChangeFrameRateStrategy int videoChangeFrameRateStrategy) {
|
||||
Assertions.checkState(!buildCalled);
|
||||
this.videoChangeFrameRateStrategy = videoChangeFrameRateStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether media sources should be initialized lazily.
|
||||
*
|
||||
|
|
@ -661,6 +686,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
private boolean surfaceHolderSurfaceIsVideoOutput;
|
||||
@Nullable private TextureView textureView;
|
||||
@C.VideoScalingMode private int videoScalingMode;
|
||||
@C.VideoChangeFrameRateStrategy private int videoChangeFrameRateStrategy;
|
||||
private int surfaceWidth;
|
||||
private int surfaceHeight;
|
||||
@Nullable private DecoderCounters videoDecoderCounters;
|
||||
|
|
@ -714,6 +740,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
priorityTaskManager = builder.priorityTaskManager;
|
||||
audioAttributes = builder.audioAttributes;
|
||||
videoScalingMode = builder.videoScalingMode;
|
||||
videoChangeFrameRateStrategy = builder.videoChangeFrameRateStrategy;
|
||||
skipSilenceEnabled = builder.skipSilenceEnabled;
|
||||
detachSurfaceTimeoutMs = builder.detachSurfaceTimeoutMs;
|
||||
componentListener = new ComponentListener();
|
||||
|
|
@ -799,6 +826,8 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
sendRendererMessage(TRACK_TYPE_VIDEO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
|
||||
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUDIO_ATTRIBUTES, audioAttributes);
|
||||
sendRendererMessage(TRACK_TYPE_VIDEO, MSG_SET_SCALING_MODE, videoScalingMode);
|
||||
sendRendererMessage(
|
||||
TRACK_TYPE_VIDEO, MSG_SET_CHANGE_FRAME_RATE_STRATEGY, videoChangeFrameRateStrategy);
|
||||
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_SKIP_SILENCE_ENABLED, skipSilenceEnabled);
|
||||
sendRendererMessage(
|
||||
TRACK_TYPE_VIDEO, MSG_SET_VIDEO_FRAME_METADATA_LISTENER, frameMetadataListener);
|
||||
|
|
@ -851,14 +880,6 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the video scaling mode.
|
||||
*
|
||||
* <p>Note that the scaling mode only applies if a {@link MediaCodec}-based video {@link Renderer}
|
||||
* is enabled and if the output surface is owned by a {@link android.view.SurfaceView}.
|
||||
*
|
||||
* @param videoScalingMode The {@link C.VideoScalingMode}.
|
||||
*/
|
||||
@Override
|
||||
public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -872,6 +893,24 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
return videoScalingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVideoChangeFrameRateStrategy(
|
||||
@C.VideoChangeFrameRateStrategy int videoChangeFrameRateStrategy) {
|
||||
verifyApplicationThread();
|
||||
if (this.videoChangeFrameRateStrategy == videoChangeFrameRateStrategy) {
|
||||
return;
|
||||
}
|
||||
this.videoChangeFrameRateStrategy = videoChangeFrameRateStrategy;
|
||||
sendRendererMessage(
|
||||
TRACK_TYPE_VIDEO, MSG_SET_CHANGE_FRAME_RATE_STRATEGY, videoChangeFrameRateStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
@C.VideoChangeFrameRateStrategy
|
||||
public int getVideoChangeFrameRateStrategy() {
|
||||
return videoChangeFrameRateStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoSize getVideoSize() {
|
||||
return videoSize;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ import java.util.List;
|
|||
* payload should be one of the integer scaling modes in {@link C.VideoScalingMode}. Note that
|
||||
* the scaling mode only applies if the {@link Surface} targeted by this renderer is owned by
|
||||
* a {@link android.view.SurfaceView}.
|
||||
* <li>Message with type {@link #MSG_SET_CHANGE_FRAME_RATE_STRATEGY} to set the strategy used to
|
||||
* call {@link Surface#setFrameRate}.
|
||||
* <li>Message with type {@link #MSG_SET_VIDEO_FRAME_METADATA_LISTENER} to set a listener for
|
||||
* metadata associated with frames being rendered. The message payload should be the {@link
|
||||
* VideoFrameMetadataListener}, or null.
|
||||
|
|
@ -515,6 +517,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||
codec.setVideoScalingMode(scalingMode);
|
||||
}
|
||||
break;
|
||||
case MSG_SET_CHANGE_FRAME_RATE_STRATEGY:
|
||||
frameReleaseHelper.setChangeFrameRateStrategy((int) message);
|
||||
break;
|
||||
case MSG_SET_VIDEO_FRAME_METADATA_LISTENER:
|
||||
frameMetadataListener = (VideoFrameMetadataListener) message;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ public final class VideoFrameReleaseHelper {
|
|||
private float surfacePlaybackFrameRate;
|
||||
|
||||
private float playbackSpeed;
|
||||
@C.VideoChangeFrameRateStrategy private int changeFrameRateStrategy;
|
||||
|
||||
private long vsyncDurationNs;
|
||||
private long vsyncOffsetNs;
|
||||
|
|
@ -132,6 +133,20 @@ public final class VideoFrameReleaseHelper {
|
|||
vsyncOffsetNs = C.TIME_UNSET;
|
||||
formatFrameRate = Format.NO_VALUE;
|
||||
playbackSpeed = 1f;
|
||||
changeFrameRateStrategy = C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_ONLY_IF_SEAMLESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the {@link C.VideoChangeFrameRateStrategy} used when calling {@link
|
||||
* Surface#setFrameRate}.
|
||||
*/
|
||||
public void setChangeFrameRateStrategy(
|
||||
@C.VideoChangeFrameRateStrategy int changeFrameRateStrategy) {
|
||||
if (this.changeFrameRateStrategy == changeFrameRateStrategy) {
|
||||
return;
|
||||
}
|
||||
this.changeFrameRateStrategy = changeFrameRateStrategy;
|
||||
updateSurfacePlaybackFrameRate(/* forceUpdate= */ true);
|
||||
}
|
||||
|
||||
/** Called when the renderer is enabled. */
|
||||
|
|
@ -146,7 +161,7 @@ public final class VideoFrameReleaseHelper {
|
|||
public void onStarted() {
|
||||
started = true;
|
||||
resetAdjustment();
|
||||
updateSurfacePlaybackFrameRate(/* isNewSurface= */ false);
|
||||
updateSurfacePlaybackFrameRate(/* forceUpdate= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -164,7 +179,7 @@ public final class VideoFrameReleaseHelper {
|
|||
}
|
||||
clearSurfaceFrameRate();
|
||||
this.surface = surface;
|
||||
updateSurfacePlaybackFrameRate(/* isNewSurface= */ true);
|
||||
updateSurfacePlaybackFrameRate(/* forceUpdate= */ true);
|
||||
}
|
||||
|
||||
/** Called when the renderer's position is reset. */
|
||||
|
|
@ -180,7 +195,7 @@ public final class VideoFrameReleaseHelper {
|
|||
public void onPlaybackSpeed(float playbackSpeed) {
|
||||
this.playbackSpeed = playbackSpeed;
|
||||
resetAdjustment();
|
||||
updateSurfacePlaybackFrameRate(/* isNewSurface= */ false);
|
||||
updateSurfacePlaybackFrameRate(/* forceUpdate= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -322,7 +337,7 @@ public final class VideoFrameReleaseHelper {
|
|||
|
||||
if (shouldUpdate) {
|
||||
surfaceMediaFrameRate = candidateFrameRate;
|
||||
updateSurfacePlaybackFrameRate(/* isNewSurface= */ false);
|
||||
updateSurfacePlaybackFrameRate(/* forceUpdate= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,10 +345,16 @@ public final class VideoFrameReleaseHelper {
|
|||
* Updates the playback frame rate of the current {@link #surface} based on the playback speed,
|
||||
* frame rate of the content, and whether the renderer is started.
|
||||
*
|
||||
* @param isNewSurface Whether the current {@link #surface} is new.
|
||||
* <p>Does nothing if {@link #changeFrameRateStrategy} is {@link
|
||||
* C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF}.
|
||||
*
|
||||
* @param forceUpdate Whether to call {@link Surface#setFrameRate} even if the frame rate is
|
||||
* unchanged.
|
||||
*/
|
||||
private void updateSurfacePlaybackFrameRate(boolean isNewSurface) {
|
||||
if (Util.SDK_INT < 30 || surface == null) {
|
||||
private void updateSurfacePlaybackFrameRate(boolean forceUpdate) {
|
||||
if (Util.SDK_INT < 30
|
||||
|| surface == null
|
||||
|| changeFrameRateStrategy == C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -343,16 +364,24 @@ public final class VideoFrameReleaseHelper {
|
|||
}
|
||||
// We always set the frame-rate if we have a new surface, since we have no way of knowing what
|
||||
// it might have been set to previously.
|
||||
if (!isNewSurface && this.surfacePlaybackFrameRate == surfacePlaybackFrameRate) {
|
||||
if (!forceUpdate && this.surfacePlaybackFrameRate == surfacePlaybackFrameRate) {
|
||||
return;
|
||||
}
|
||||
this.surfacePlaybackFrameRate = surfacePlaybackFrameRate;
|
||||
Api30.setSurfaceFrameRate(surface, surfacePlaybackFrameRate);
|
||||
}
|
||||
|
||||
/** Clears the frame-rate of the current {@link #surface}. */
|
||||
/**
|
||||
* Clears the frame-rate of the current {@link #surface}.
|
||||
*
|
||||
* <p>Does nothing if {@link #changeFrameRateStrategy} is {@link
|
||||
* C#VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF}.
|
||||
*/
|
||||
private void clearSurfaceFrameRate() {
|
||||
if (Util.SDK_INT < 30 || surface == null || surfacePlaybackFrameRate == 0) {
|
||||
if (Util.SDK_INT < 30
|
||||
|| surface == null
|
||||
|| changeFrameRateStrategy == C.VIDEO_CHANGE_FRAME_RATE_STRATEGY_OFF
|
||||
|| surfacePlaybackFrameRate == 0) {
|
||||
return;
|
||||
}
|
||||
surfacePlaybackFrameRate = 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue