Allow changing of video scaling mode

Issue #2016

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=139803888
This commit is contained in:
olly 2016-11-21 10:45:25 -08:00 committed by Oliver Woodman
parent 4846146827
commit 9d7d8adc9c
5 changed files with 132 additions and 64 deletions

View file

@ -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}.
* <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
* this value.

View file

@ -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.
* <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}
* 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<FrameworkMediaCrypto> drmSessionManager, ArrayList<Renderer> 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,

View file

@ -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();

View file

@ -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<FrameworkMediaCrypto> drmSessionManager,
long allowedJoiningTimeMs, DrmSessionManager<FrameworkMediaCrypto> 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);
}
/**

View file

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