diff --git a/library/src/main/java/com/google/android/exoplayer2/C.java b/library/src/main/java/com/google/android/exoplayer2/C.java index 3392aa64c6..3e6fac4a5e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/src/main/java/com/google/android/exoplayer2/C.java @@ -222,6 +222,29 @@ public final class C { */ public static final int BUFFER_FLAG_DECODE_ONLY = 0x80000000; + /** + * Video scaling modes for {@link MediaCodec}-based {@link Renderer}s. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {VIDEO_SCALING_MODE_SCALE_TO_FIT, VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}) + public @interface VideoScalingMode {} + /** + * @see MediaCodec#VIDEO_SCALING_MODE_SCALE_TO_FIT + */ + @SuppressWarnings("InlinedApi") + public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = + MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT; + /** + * @see MediaCodec#VIDEO_SCALING_MODE_SCALE_TO_FIT + */ + @SuppressWarnings("InlinedApi") + public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = + MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING; + /** + * A default video scaling mode for {@link MediaCodec}-based {@link Renderer}s. + */ + public static final int VIDEO_SCALING_MODE_DEFAULT = VIDEO_SCALING_MODE_SCALE_TO_FIT; + /** * Track selection flags. */ @@ -463,6 +486,16 @@ public final class C { */ public static final int MSG_SET_STREAM_TYPE = 4; + /** + * The type of a message that can be passed to a {@link MediaCodec}-based video {@link Renderer} + * via {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message + * object 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 the renderer is + * owned by a {@link android.view.SurfaceView}. + */ + public static final int MSG_SET_SCALING_MODE = 5; + /** * Applications or extensions may define custom {@code MSG_*} constants greater than or equal to * this value. 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 bb5f3d42ed..ca193c576b 100644 --- a/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -103,6 +103,8 @@ public final class SimpleExoPlayer implements ExoPlayer { private Surface surface; private boolean ownsSurface; + @C.VideoScalingMode + private int videoScalingMode; private SurfaceHolder surfaceHolder; private TextureView textureView; private TextRenderer.Output textOutput; @@ -115,7 +117,7 @@ public final class SimpleExoPlayer implements ExoPlayer { private int audioSessionId; @C.StreamType private int audioStreamType; - private float volume; + private float audioVolume; private PlaybackParamsHolder playbackParamsHolder; /* package */ SimpleExoPlayer(Context context, TrackSelector trackSelector, @@ -152,14 +154,43 @@ public final class SimpleExoPlayer implements ExoPlayer { this.audioRendererCount = audioRendererCount; // Set initial values. + audioVolume = 1; audioSessionId = AudioTrack.SESSION_ID_NOT_SET; audioStreamType = C.STREAM_TYPE_DEFAULT; - volume = 1; + videoScalingMode = C.VIDEO_SCALING_MODE_DEFAULT; // Build the player and associated objects. player = new ExoPlayerImpl(renderers, trackSelector, loadControl); } + /** + * Sets the video scaling mode. + *

+ * 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 video scaling mode. + */ + public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) { + this.videoScalingMode = videoScalingMode; + ExoPlayerMessage[] messages = new ExoPlayerMessage[videoRendererCount]; + int count = 0; + for (Renderer renderer : renderers) { + if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) { + messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_SCALING_MODE, + videoScalingMode); + } + } + player.sendMessages(messages); + } + + /** + * Returns the video scaling mode. + */ + public @C.VideoScalingMode int getVideoScalingMode() { + return videoScalingMode; + } + /** * Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView} * currently set on the player. @@ -267,15 +298,15 @@ public final class SimpleExoPlayer implements ExoPlayer { /** * Sets the audio volume, with 0 being silence and 1 being unity gain. * - * @param volume The volume. + * @param audioVolume The audio volume. */ - public void setVolume(float volume) { - this.volume = volume; + public void setVolume(float audioVolume) { + this.audioVolume = audioVolume; ExoPlayerMessage[] messages = new ExoPlayerMessage[audioRendererCount]; int count = 0; for (Renderer renderer : renderers) { if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { - messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_VOLUME, volume); + messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_VOLUME, audioVolume); } } player.sendMessages(messages); @@ -285,7 +316,7 @@ public final class SimpleExoPlayer implements ExoPlayer { * Returns the audio volume, with 0 being silence and 1 being unity gain. */ public float getVolume() { - return volume; + return audioVolume; } /** @@ -568,9 +599,8 @@ public final class SimpleExoPlayer implements ExoPlayer { DrmSessionManager drmSessionManager, ArrayList renderersList, long allowedVideoJoiningTimeMs) { MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer(context, - MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, - allowedVideoJoiningTimeMs, drmSessionManager, false, mainHandler, componentListener, - MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); + MediaCodecSelector.DEFAULT, allowedVideoJoiningTimeMs, drmSessionManager, false, + mainHandler, componentListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); renderersList.add(videoRenderer); Renderer audioRenderer = new MediaCodecAudioRenderer(MediaCodecSelector.DEFAULT, diff --git a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 63a77e2215..ca06a00619 100644 --- a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -375,6 +375,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return codec == null && format != null; } + protected final MediaCodec getCodec() { + return codec; + } + @Override protected void onEnabled(boolean joining) throws ExoPlaybackException { decoderCounters = new DecoderCounters(); diff --git a/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index b94beb10f6..c2d5558225 100644 --- a/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -57,7 +57,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper; private final EventDispatcher eventDispatcher; private final long allowedJoiningTimeMs; - private final int videoScalingMode; private final int maxDroppedFramesToNotify; private final boolean deviceNeedsAutoFrcWorkaround; @@ -65,6 +64,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private CodecMaxValues codecMaxValues; private Surface surface; + @C.VideoScalingMode + private int scalingMode; private boolean renderedFirstFrame; private long joiningDeadlineMs; private long droppedFrameAccumulationStartTimeMs; @@ -85,32 +86,25 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { /** * @param context A context. * @param mediaCodecSelector A decoder selector. - * @param videoScalingMode The scaling mode to pass to - * {@link MediaCodec#setVideoScalingMode(int)}. */ - public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, - int videoScalingMode) { - this(context, mediaCodecSelector, videoScalingMode, 0); + public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) { + this(context, mediaCodecSelector, 0); } /** * @param context A context. * @param mediaCodecSelector A decoder selector. - * @param videoScalingMode The scaling mode to pass to - * {@link MediaCodec#setVideoScalingMode(int)}. * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * can attempt to seamlessly join an ongoing playback. */ public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, - int videoScalingMode, long allowedJoiningTimeMs) { - this(context, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, null, -1); + long allowedJoiningTimeMs) { + this(context, mediaCodecSelector, allowedJoiningTimeMs, null, null, -1); } /** * @param context A context. * @param mediaCodecSelector A decoder selector. - * @param videoScalingMode The scaling mode to pass to - * {@link MediaCodec#setVideoScalingMode(int)}. * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * can attempt to seamlessly join an ongoing playback. * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be @@ -120,17 +114,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { * invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}. */ public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, - int videoScalingMode, long allowedJoiningTimeMs, Handler eventHandler, - VideoRendererEventListener eventListener, int maxDroppedFrameCountToNotify) { - this(context, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, false, - eventHandler, eventListener, maxDroppedFrameCountToNotify); + long allowedJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener, + int maxDroppedFrameCountToNotify) { + this(context, mediaCodecSelector, allowedJoiningTimeMs, null, false, eventHandler, + eventListener, maxDroppedFrameCountToNotify); } /** * @param context A context. * @param mediaCodecSelector A decoder selector. - * @param videoScalingMode The scaling mode to pass to - * {@link MediaCodec#setVideoScalingMode(int)}. * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * can attempt to seamlessly join an ongoing playback. * @param drmSessionManager For use with encrypted content. May be null if support for encrypted @@ -147,12 +139,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { * invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}. */ public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, - int videoScalingMode, long allowedJoiningTimeMs, - DrmSessionManager drmSessionManager, + long allowedJoiningTimeMs, DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, Handler eventHandler, VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) { super(C.TRACK_TYPE_VIDEO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys); - this.videoScalingMode = videoScalingMode; this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); @@ -163,6 +153,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { currentHeight = Format.NO_VALUE; currentPixelWidthHeightRatio = Format.NO_VALUE; pendingPixelWidthHeightRatio = Format.NO_VALUE; + scalingMode = C.VIDEO_SCALING_MODE_DEFAULT; clearLastReportedVideoSize(); } @@ -284,6 +275,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { public void handleMessage(int messageType, Object message) throws ExoPlaybackException { if (messageType == C.MSG_SET_SURFACE) { setSurface((Surface) message); + } else if (messageType == C.MSG_SET_SCALING_MODE) { + scalingMode = (Integer) message; + MediaCodec codec = getCodec(); + if (codec != null) { + setVideoScalingMode(codec, scalingMode); + } } else { super.handleMessage(messageType, message); } @@ -358,7 +355,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { currentUnappliedRotationDegrees = pendingRotationDegrees; } // Must be applied each time the output format changes. - codec.setVideoScalingMode(videoScalingMode); + setVideoScalingMode(codec, scalingMode); } @Override @@ -488,6 +485,36 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } } + private void clearLastReportedVideoSize() { + lastReportedWidth = Format.NO_VALUE; + lastReportedHeight = Format.NO_VALUE; + lastReportedPixelWidthHeightRatio = Format.NO_VALUE; + lastReportedUnappliedRotationDegrees = Format.NO_VALUE; + } + + private void maybeNotifyVideoSizeChanged() { + if (lastReportedWidth != currentWidth || lastReportedHeight != currentHeight + || lastReportedUnappliedRotationDegrees != currentUnappliedRotationDegrees + || lastReportedPixelWidthHeightRatio != currentPixelWidthHeightRatio) { + eventDispatcher.videoSizeChanged(currentWidth, currentHeight, currentUnappliedRotationDegrees, + currentPixelWidthHeightRatio); + lastReportedWidth = currentWidth; + lastReportedHeight = currentHeight; + lastReportedUnappliedRotationDegrees = currentUnappliedRotationDegrees; + lastReportedPixelWidthHeightRatio = currentPixelWidthHeightRatio; + } + } + + private void maybeNotifyDroppedFrames() { + if (droppedFrames > 0) { + long now = SystemClock.elapsedRealtime(); + long elapsedMs = now - droppedFrameAccumulationStartTimeMs; + eventDispatcher.droppedFrames(droppedFrames, elapsedMs); + droppedFrames = 0; + droppedFrameAccumulationStartTimeMs = now; + } + } + @SuppressLint("InlinedApi") private static MediaFormat getMediaFormat(Format format, CodecMaxValues codecMaxValues, boolean deviceNeedsAutoFrcWorkaround) { @@ -583,34 +610,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { return (maxPixels * 3) / (2 * minCompressionRatio); } - private void clearLastReportedVideoSize() { - lastReportedWidth = Format.NO_VALUE; - lastReportedHeight = Format.NO_VALUE; - lastReportedPixelWidthHeightRatio = Format.NO_VALUE; - lastReportedUnappliedRotationDegrees = Format.NO_VALUE; - } - - private void maybeNotifyVideoSizeChanged() { - if (lastReportedWidth != currentWidth || lastReportedHeight != currentHeight - || lastReportedUnappliedRotationDegrees != currentUnappliedRotationDegrees - || lastReportedPixelWidthHeightRatio != currentPixelWidthHeightRatio) { - eventDispatcher.videoSizeChanged(currentWidth, currentHeight, currentUnappliedRotationDegrees, - currentPixelWidthHeightRatio); - lastReportedWidth = currentWidth; - lastReportedHeight = currentHeight; - lastReportedUnappliedRotationDegrees = currentUnappliedRotationDegrees; - lastReportedPixelWidthHeightRatio = currentPixelWidthHeightRatio; - } - } - - private void maybeNotifyDroppedFrames() { - if (droppedFrames > 0) { - long now = SystemClock.elapsedRealtime(); - long elapsedMs = now - droppedFrameAccumulationStartTimeMs; - eventDispatcher.droppedFrames(droppedFrames, elapsedMs); - droppedFrames = 0; - droppedFrameAccumulationStartTimeMs = now; - } + private static void setVideoScalingMode(MediaCodec codec, int scalingMode) { + codec.setVideoScalingMode(scalingMode); } /** diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugMediaCodecVideoRenderer.java b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugMediaCodecVideoRenderer.java index cbc5f35e94..e38dea948a 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugMediaCodecVideoRenderer.java +++ b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugMediaCodecVideoRenderer.java @@ -40,10 +40,10 @@ public class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer { private int bufferCount; public DebugMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, - int videoScalingMode, long allowedJoiningTimeMs, Handler eventHandler, - VideoRendererEventListener eventListener, int maxDroppedFrameCountToNotify) { - super(context, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, false, - eventHandler, eventListener, maxDroppedFrameCountToNotify); + long allowedJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener, + int maxDroppedFrameCountToNotify) { + super(context, mediaCodecSelector, allowedJoiningTimeMs, null, false, eventHandler, + eventListener, maxDroppedFrameCountToNotify); startIndex = 0; queueSize = 0; }