Commit 9d7d8adc by olly Committed by Oliver Woodman

Allow changing of video scaling mode

Issue #2016

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=139803888
parent 48461468
...@@ -223,6 +223,29 @@ public final class C { ...@@ -223,6 +223,29 @@ public final class C {
public static final int BUFFER_FLAG_DECODE_ONLY = 0x80000000; 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. * Track selection flags.
*/ */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
...@@ -464,6 +487,16 @@ public final class C { ...@@ -464,6 +487,16 @@ public final class C {
public static final int MSG_SET_STREAM_TYPE = 4; 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}.
* <p>
* 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 * Applications or extensions may define custom {@code MSG_*} constants greater than or equal to
* this value. * this value.
*/ */
......
...@@ -103,6 +103,8 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -103,6 +103,8 @@ public final class SimpleExoPlayer implements ExoPlayer {
private Surface surface; private Surface surface;
private boolean ownsSurface; private boolean ownsSurface;
@C.VideoScalingMode
private int videoScalingMode;
private SurfaceHolder surfaceHolder; private SurfaceHolder surfaceHolder;
private TextureView textureView; private TextureView textureView;
private TextRenderer.Output textOutput; private TextRenderer.Output textOutput;
...@@ -115,7 +117,7 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -115,7 +117,7 @@ public final class SimpleExoPlayer implements ExoPlayer {
private int audioSessionId; private int audioSessionId;
@C.StreamType @C.StreamType
private int audioStreamType; private int audioStreamType;
private float volume; private float audioVolume;
private PlaybackParamsHolder playbackParamsHolder; private PlaybackParamsHolder playbackParamsHolder;
/* package */ SimpleExoPlayer(Context context, TrackSelector trackSelector, /* package */ SimpleExoPlayer(Context context, TrackSelector trackSelector,
...@@ -152,15 +154,44 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -152,15 +154,44 @@ public final class SimpleExoPlayer implements ExoPlayer {
this.audioRendererCount = audioRendererCount; this.audioRendererCount = audioRendererCount;
// Set initial values. // Set initial values.
audioVolume = 1;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET; audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioStreamType = C.STREAM_TYPE_DEFAULT; audioStreamType = C.STREAM_TYPE_DEFAULT;
volume = 1; videoScalingMode = C.VIDEO_SCALING_MODE_DEFAULT;
// Build the player and associated objects. // Build the player and associated objects.
player = new ExoPlayerImpl(renderers, trackSelector, loadControl); player = new ExoPlayerImpl(renderers, trackSelector, loadControl);
} }
/** /**
* 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 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} * Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView}
* currently set on the player. * currently set on the player.
*/ */
...@@ -267,15 +298,15 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -267,15 +298,15 @@ public final class SimpleExoPlayer implements ExoPlayer {
/** /**
* Sets the audio volume, with 0 being silence and 1 being unity gain. * 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) { public void setVolume(float audioVolume) {
this.volume = volume; this.audioVolume = audioVolume;
ExoPlayerMessage[] messages = new ExoPlayerMessage[audioRendererCount]; ExoPlayerMessage[] messages = new ExoPlayerMessage[audioRendererCount];
int count = 0; int count = 0;
for (Renderer renderer : renderers) { for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { 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); player.sendMessages(messages);
...@@ -285,7 +316,7 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -285,7 +316,7 @@ public final class SimpleExoPlayer implements ExoPlayer {
* Returns the audio volume, with 0 being silence and 1 being unity gain. * Returns the audio volume, with 0 being silence and 1 being unity gain.
*/ */
public float getVolume() { public float getVolume() {
return volume; return audioVolume;
} }
/** /**
...@@ -568,9 +599,8 @@ public final class SimpleExoPlayer implements ExoPlayer { ...@@ -568,9 +599,8 @@ public final class SimpleExoPlayer implements ExoPlayer {
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, ArrayList<Renderer> renderersList, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, ArrayList<Renderer> renderersList,
long allowedVideoJoiningTimeMs) { long allowedVideoJoiningTimeMs) {
MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer(context, MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer(context,
MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, MediaCodecSelector.DEFAULT, allowedVideoJoiningTimeMs, drmSessionManager, false,
allowedVideoJoiningTimeMs, drmSessionManager, false, mainHandler, componentListener, mainHandler, componentListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
renderersList.add(videoRenderer); renderersList.add(videoRenderer);
Renderer audioRenderer = new MediaCodecAudioRenderer(MediaCodecSelector.DEFAULT, Renderer audioRenderer = new MediaCodecAudioRenderer(MediaCodecSelector.DEFAULT,
......
...@@ -375,6 +375,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -375,6 +375,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return codec == null && format != null; return codec == null && format != null;
} }
protected final MediaCodec getCodec() {
return codec;
}
@Override @Override
protected void onEnabled(boolean joining) throws ExoPlaybackException { protected void onEnabled(boolean joining) throws ExoPlaybackException {
decoderCounters = new DecoderCounters(); decoderCounters = new DecoderCounters();
......
...@@ -57,7 +57,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -57,7 +57,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper; private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final long allowedJoiningTimeMs; private final long allowedJoiningTimeMs;
private final int videoScalingMode;
private final int maxDroppedFramesToNotify; private final int maxDroppedFramesToNotify;
private final boolean deviceNeedsAutoFrcWorkaround; private final boolean deviceNeedsAutoFrcWorkaround;
...@@ -65,6 +64,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -65,6 +64,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private CodecMaxValues codecMaxValues; private CodecMaxValues codecMaxValues;
private Surface surface; private Surface surface;
@C.VideoScalingMode
private int scalingMode;
private boolean renderedFirstFrame; private boolean renderedFirstFrame;
private long joiningDeadlineMs; private long joiningDeadlineMs;
private long droppedFrameAccumulationStartTimeMs; private long droppedFrameAccumulationStartTimeMs;
...@@ -85,32 +86,25 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -85,32 +86,25 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
/** /**
* @param context A context. * @param context A context.
* @param mediaCodecSelector A decoder selector. * @param mediaCodecSelector A decoder selector.
* @param videoScalingMode The scaling mode to pass to
* {@link MediaCodec#setVideoScalingMode(int)}.
*/ */
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) {
int videoScalingMode) { this(context, mediaCodecSelector, 0);
this(context, mediaCodecSelector, videoScalingMode, 0);
} }
/** /**
* @param context A context. * @param context A context.
* @param mediaCodecSelector A decoder selector. * @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 * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback. * can attempt to seamlessly join an ongoing playback.
*/ */
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
int videoScalingMode, long allowedJoiningTimeMs) { long allowedJoiningTimeMs) {
this(context, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, null, -1); this(context, mediaCodecSelector, allowedJoiningTimeMs, null, null, -1);
} }
/** /**
* @param context A context. * @param context A context.
* @param mediaCodecSelector A decoder selector. * @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 * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback. * can attempt to seamlessly join an ongoing playback.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
...@@ -120,17 +114,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -120,17 +114,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}. * invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
*/ */
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
int videoScalingMode, long allowedJoiningTimeMs, Handler eventHandler, long allowedJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener,
VideoRendererEventListener eventListener, int maxDroppedFrameCountToNotify) { int maxDroppedFrameCountToNotify) {
this(context, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, false, this(context, mediaCodecSelector, allowedJoiningTimeMs, null, false, eventHandler,
eventHandler, eventListener, maxDroppedFrameCountToNotify); eventListener, maxDroppedFrameCountToNotify);
} }
/** /**
* @param context A context. * @param context A context.
* @param mediaCodecSelector A decoder selector. * @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 * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback. * can attempt to seamlessly join an ongoing playback.
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted * @param drmSessionManager For use with encrypted content. May be null if support for encrypted
...@@ -147,12 +139,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -147,12 +139,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}. * invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
*/ */
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
int videoScalingMode, long allowedJoiningTimeMs, long allowedJoiningTimeMs, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
boolean playClearSamplesWithoutKeys, Handler eventHandler, boolean playClearSamplesWithoutKeys, Handler eventHandler,
VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) { VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) {
super(C.TRACK_TYPE_VIDEO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys); super(C.TRACK_TYPE_VIDEO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys);
this.videoScalingMode = videoScalingMode;
this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.allowedJoiningTimeMs = allowedJoiningTimeMs;
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context);
...@@ -163,6 +153,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -163,6 +153,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
currentHeight = Format.NO_VALUE; currentHeight = Format.NO_VALUE;
currentPixelWidthHeightRatio = Format.NO_VALUE; currentPixelWidthHeightRatio = Format.NO_VALUE;
pendingPixelWidthHeightRatio = Format.NO_VALUE; pendingPixelWidthHeightRatio = Format.NO_VALUE;
scalingMode = C.VIDEO_SCALING_MODE_DEFAULT;
clearLastReportedVideoSize(); clearLastReportedVideoSize();
} }
...@@ -284,6 +275,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -284,6 +275,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
public void handleMessage(int messageType, Object message) throws ExoPlaybackException { public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
if (messageType == C.MSG_SET_SURFACE) { if (messageType == C.MSG_SET_SURFACE) {
setSurface((Surface) message); setSurface((Surface) message);
} else if (messageType == C.MSG_SET_SCALING_MODE) {
scalingMode = (Integer) message;
MediaCodec codec = getCodec();
if (codec != null) {
setVideoScalingMode(codec, scalingMode);
}
} else { } else {
super.handleMessage(messageType, message); super.handleMessage(messageType, message);
} }
...@@ -358,7 +355,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -358,7 +355,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
currentUnappliedRotationDegrees = pendingRotationDegrees; currentUnappliedRotationDegrees = pendingRotationDegrees;
} }
// Must be applied each time the output format changes. // Must be applied each time the output format changes.
codec.setVideoScalingMode(videoScalingMode); setVideoScalingMode(codec, scalingMode);
} }
@Override @Override
...@@ -488,6 +485,36 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -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") @SuppressLint("InlinedApi")
private static MediaFormat getMediaFormat(Format format, CodecMaxValues codecMaxValues, private static MediaFormat getMediaFormat(Format format, CodecMaxValues codecMaxValues,
boolean deviceNeedsAutoFrcWorkaround) { boolean deviceNeedsAutoFrcWorkaround) {
...@@ -583,34 +610,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -583,34 +610,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
return (maxPixels * 3) / (2 * minCompressionRatio); return (maxPixels * 3) / (2 * minCompressionRatio);
} }
private void clearLastReportedVideoSize() { private static void setVideoScalingMode(MediaCodec codec, int scalingMode) {
lastReportedWidth = Format.NO_VALUE; codec.setVideoScalingMode(scalingMode);
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;
}
} }
/** /**
......
...@@ -40,10 +40,10 @@ public class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer { ...@@ -40,10 +40,10 @@ public class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer {
private int bufferCount; private int bufferCount;
public DebugMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector, public DebugMediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector,
int videoScalingMode, long allowedJoiningTimeMs, Handler eventHandler, long allowedJoiningTimeMs, Handler eventHandler, VideoRendererEventListener eventListener,
VideoRendererEventListener eventListener, int maxDroppedFrameCountToNotify) { int maxDroppedFrameCountToNotify) {
super(context, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, false, super(context, mediaCodecSelector, allowedJoiningTimeMs, null, false, eventHandler,
eventHandler, eventListener, maxDroppedFrameCountToNotify); eventListener, maxDroppedFrameCountToNotify);
startIndex = 0; startIndex = 0;
queueSize = 0; queueSize = 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment