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;
}