From 5364962dca36136d0765aefb885af61015fb503e Mon Sep 17 00:00:00 2001 From: hoangtc Date: Fri, 5 Jan 2018 07:35:28 -0800 Subject: [PATCH] Automatically apply rotation for TextureView in SimpleExoPlayer. If SimpleExoPlayer is using TextView as output, we can handle video rotation by automatically applying a matrix transformation to the TextureView when we have this information available from the video (from video's metadata). GitHub: #91 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=180925571 --- RELEASENOTES.md | 3 + .../exoplayer2/ui/SimpleExoPlayerView.java | 74 ++++++++++++++++++- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e167fe94b6..997c3047c4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,6 +2,9 @@ ### dev-v2 (not yet released) ### +* SimpleExoPlayerView: Automatically apply video rotation if + `SimpleExoPlayerView` is configured to use `TextureView` + ([#91](https://github.com/google/ExoPlayer/issues/91)). * Player interface: * Add optional parameter to `stop` to reset the player when stopping. * Add a reason to `EventListener.onTimelineChanged` to distinguish between diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index def8925ec3..6e69a31fd9 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -22,6 +22,8 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.RectF; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; @@ -224,6 +226,7 @@ public final class SimpleExoPlayerView extends FrameLayout { private boolean controllerAutoShow; private boolean controllerHideDuringAds; private boolean controllerHideOnTouch; + private int textureViewRotation; public SimpleExoPlayerView(Context context) { this(context, null); @@ -920,6 +923,31 @@ public final class SimpleExoPlayerView extends FrameLayout { aspectRatioFrame.setResizeMode(resizeMode); } + /** Applies a texture rotation to a {@link TextureView}. */ + private static void applyTextureViewRotation(TextureView textureView, int textureViewRotation) { + float textureViewWidth = textureView.getWidth(); + float textureViewHeight = textureView.getHeight(); + if (textureViewWidth == 0 || textureViewHeight == 0 || textureViewRotation == 0) { + textureView.setTransform(null); + } else { + Matrix transformMatrix = new Matrix(); + float pivotX = textureViewWidth / 2; + float pivotY = textureViewHeight / 2; + transformMatrix.postRotate(textureViewRotation, pivotX, pivotY); + + // After rotation, scale the rotated texture to fit the TextureView size. + RectF originalTextureRect = new RectF(0, 0, textureViewWidth, textureViewHeight); + RectF rotatedTextureRect = new RectF(); + transformMatrix.mapRect(rotatedTextureRect, originalTextureRect); + transformMatrix.postScale( + textureViewWidth / rotatedTextureRect.width(), + textureViewHeight / rotatedTextureRect.height(), + pivotX, + pivotY); + textureView.setTransform(transformMatrix); + } + } + @SuppressLint("InlinedApi") private boolean isDpadKey(int keyCode) { return keyCode == KeyEvent.KEYCODE_DPAD_UP @@ -934,7 +962,7 @@ public final class SimpleExoPlayerView extends FrameLayout { } private final class ComponentListener extends Player.DefaultEventListener - implements TextOutput, SimpleExoPlayer.VideoListener { + implements TextOutput, SimpleExoPlayer.VideoListener, OnLayoutChangeListener { // TextOutput implementation @@ -950,10 +978,32 @@ public final class SimpleExoPlayerView extends FrameLayout { @Override public void onVideoSizeChanged( int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - if (contentFrame != null) { - float aspectRatio = height == 0 ? 1 : (width * pixelWidthHeightRatio) / height; - contentFrame.setAspectRatio(aspectRatio); + if (contentFrame == null) { + return; } + float videoAspectRatio = + (height == 0 || width == 0) ? 1 : (width * pixelWidthHeightRatio) / height; + + if (surfaceView instanceof TextureView) { + // Try to apply rotation transformation when our surface is a TextureView. + if (unappliedRotationDegrees == 90 || unappliedRotationDegrees == 270) { + // We will apply a rotation 90/270 degree to the output texture of the TextureView. + // In this case, the output video's width and height will be swapped. + videoAspectRatio = 1 / videoAspectRatio; + } + if (textureViewRotation != 0) { + surfaceView.removeOnLayoutChangeListener(this); + } + textureViewRotation = unappliedRotationDegrees; + if (textureViewRotation != 0) { + // The texture view's dimensions might be changed after layout step. + // So add an OnLayoutChangeListener to apply rotation after layout step. + surfaceView.addOnLayoutChangeListener(this); + } + applyTextureViewRotation((TextureView) surfaceView, textureViewRotation); + } + + contentFrame.setAspectRatio(videoAspectRatio); } @Override @@ -985,5 +1035,21 @@ public final class SimpleExoPlayerView extends FrameLayout { hideController(); } } + + // OnLayoutChangeListener implementation + + @Override + public void onLayoutChange( + View view, + int left, + int top, + int right, + int bottom, + int oldLeft, + int oldTop, + int oldRight, + int oldBottom) { + applyTextureViewRotation((TextureView) view, textureViewRotation); + } } }