From c1e1497d1397a32e2c3d9476d9c87843451e6b1d Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Wed, 15 Jul 2015 11:09:20 +0100 Subject: [PATCH] Change how subtitles are laid out in the demo app. The SubtitleLayout is now properly aligned with the surface. This means the subtitles remain on top of the video in portrait mode, rather than being huge and below it. --- .../exoplayer/demo/PlayerActivity.java | 11 ++- demo/src/main/res/layout/player_activity.xml | 28 +++--- .../exoplayer/demo/webm/VideoPlayer.java | 21 +++-- .../main/res/layout/activity_video_player.xml | 23 +++-- .../ext/vp9/VpxVideoSurfaceView.java | 33 ------- .../exoplayer/AspectRatioFrameLayout.java | 86 +++++++++++++++++++ .../android/exoplayer/VideoSurfaceView.java | 77 ----------------- .../exoplayer/text/SubtitleLayout.java | 13 ++- 8 files changed, 144 insertions(+), 148 deletions(-) create mode 100644 library/src/main/java/com/google/android/exoplayer/AspectRatioFrameLayout.java delete mode 100644 library/src/main/java/com/google/android/exoplayer/VideoSurfaceView.java diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java index a27a80b783..f54dcfae58 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java @@ -15,8 +15,8 @@ */ package com.google.android.exoplayer.demo; +import com.google.android.exoplayer.AspectRatioFrameLayout; import com.google.android.exoplayer.ExoPlayer; -import com.google.android.exoplayer.VideoSurfaceView; import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver; import com.google.android.exoplayer.demo.player.DashRendererBuilder; @@ -55,6 +55,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.SurfaceHolder; +import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnKeyListener; @@ -109,7 +110,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, private MediaController mediaController; private View debugRootView; private View shutterView; - private VideoSurfaceView surfaceView; + private AspectRatioFrameLayout videoFrame; + private SurfaceView surfaceView; private TextView debugTextView; private TextView playerStateTextView; private SubtitleLayout subtitleLayout; @@ -170,7 +172,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, shutterView = findViewById(R.id.shutter); debugRootView = findViewById(R.id.controls_root); - surfaceView = (VideoSurfaceView) findViewById(R.id.surface_view); + videoFrame = (AspectRatioFrameLayout) findViewById(R.id.video_frame); + surfaceView = (SurfaceView) findViewById(R.id.surface_view); surfaceView.getHolder().addCallback(this); debugTextView = (TextView) findViewById(R.id.debug_text_view); @@ -364,7 +367,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, @Override public void onVideoSizeChanged(int width, int height, float pixelWidthAspectRatio) { shutterView.setVisibility(View.GONE); - surfaceView.setVideoWidthHeightRatio( + videoFrame.setAspectRatio( height == 0 ? 1 : (width * pixelWidthAspectRatio) / height); } diff --git a/demo/src/main/res/layout/player_activity.xml b/demo/src/main/res/layout/player_activity.xml index 2f0cce32a9..9b8925cce6 100644 --- a/demo/src/main/res/layout/player_activity.xml +++ b/demo/src/main/res/layout/player_activity.xml @@ -21,22 +21,26 @@ android:layout_height="match_parent" android:keepScreenOn="true"> - + android:layout_gravity="center"> - + - + + + + + - + android:layout_gravity="center"> - + + + + + MAX_ASPECT_RATIO_DEFORMATION_PERCENT) { - height = (int) (width / videoAspectRatio); - } else if (aspectDeformation < -MAX_ASPECT_RATIO_DEFORMATION_PERCENT) { - width = (int) (height * videoAspectRatio); - } - } - setMeasuredDimension(width, height); - } - } diff --git a/library/src/main/java/com/google/android/exoplayer/AspectRatioFrameLayout.java b/library/src/main/java/com/google/android/exoplayer/AspectRatioFrameLayout.java new file mode 100644 index 0000000000..92e9a1f798 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/AspectRatioFrameLayout.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +/** + * A {@link FrameLayout} that resizes itself to match a specified aspect ratio. + */ +public final class AspectRatioFrameLayout extends FrameLayout { + + /** + * The {@link FrameLayout} will not resize itself if the fractional difference between its natural + * aspect ratio and the requested aspect ratio falls below this threshold. + *

+ * This tolerance allows the view to occupy the whole of the screen when the requested aspect + * ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce + * the number of view layers that need to be composited by the underlying system, which can help + * to reduce power consumption. + */ + private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f; + + private float videoAspectRatio; + + public AspectRatioFrameLayout(Context context) { + super(context); + } + + public AspectRatioFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /** + * Set the aspect ratio that this view should satisfy. + * + * @param widthHeightRatio The width to height ratio. + */ + public void setAspectRatio(float widthHeightRatio) { + if (this.videoAspectRatio != widthHeightRatio) { + this.videoAspectRatio = widthHeightRatio; + requestLayout(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (videoAspectRatio == 0) { + // Aspect ratio not set. + return; + } + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + float viewAspectRatio = (float) width / height; + float aspectDeformation = videoAspectRatio / viewAspectRatio - 1; + if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) { + // We're within the allowed tolerance. + return; + } + + if (aspectDeformation > 0) { + height = (int) (width / videoAspectRatio); + } else { + width = (int) (height * videoAspectRatio); + } + super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer/VideoSurfaceView.java b/library/src/main/java/com/google/android/exoplayer/VideoSurfaceView.java deleted file mode 100644 index 9923e2ae5d..0000000000 --- a/library/src/main/java/com/google/android/exoplayer/VideoSurfaceView.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.SurfaceView; - -/** - * A SurfaceView that resizes itself to match a specified aspect ratio. - */ -public class VideoSurfaceView extends SurfaceView { - - /** - * The surface view will not resize itself if the fractional difference between its default - * aspect ratio and the aspect ratio of the video falls below this threshold. - *

- * This tolerance is useful for fullscreen playbacks, since it ensures that the surface will - * occupy the whole of the screen when playing content that has the same (or virtually the same) - * aspect ratio as the device. This typically reduces the number of view layers that need to be - * composited by the underlying system, which can help to reduce power consumption. - */ - private static final float MAX_ASPECT_RATIO_DEFORMATION_PERCENT = 0.01f; - - private float videoAspectRatio; - - public VideoSurfaceView(Context context) { - super(context); - } - - public VideoSurfaceView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Set the aspect ratio that this {@link VideoSurfaceView} should satisfy. - * - * @param widthHeightRatio The width to height ratio. - */ - public void setVideoWidthHeightRatio(float widthHeightRatio) { - if (this.videoAspectRatio != widthHeightRatio) { - this.videoAspectRatio = widthHeightRatio; - requestLayout(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int width = getMeasuredWidth(); - int height = getMeasuredHeight(); - if (videoAspectRatio != 0) { - float viewAspectRatio = (float) width / height; - float aspectDeformation = videoAspectRatio / viewAspectRatio - 1; - if (aspectDeformation > MAX_ASPECT_RATIO_DEFORMATION_PERCENT) { - height = (int) (width / videoAspectRatio); - } else if (aspectDeformation < -MAX_ASPECT_RATIO_DEFORMATION_PERCENT) { - width = (int) (height * videoAspectRatio); - } - } - setMeasuredDimension(width, height); - } - -} diff --git a/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java b/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java index 9c92f8821c..fc8f764ce4 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java +++ b/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java @@ -32,7 +32,13 @@ public final class SubtitleLayout extends ViewGroup { * Use the same line height ratio as WebVtt to match the display with the preview. * WebVtt specifies line height as 5.3% of the viewport height. */ - private static final float LINE_HEIGHT_RATIO = 0.0533f; + private static final float LINE_HEIGHT_FRACTION = 0.0533f; + + /** + * The default bottom padding to apply when {@link Cue#line} is {@link Cue#UNSET_VALUE}, as a + * fraction of the viewport height. + */ + private static final float DEFAULT_BOTTOM_PADDING_FRACTION = 0.08f; private final List subtitleViews; @@ -145,7 +151,8 @@ public final class SubtitleLayout extends ViewGroup { int viewLeft = (width - subtitleView.getMeasuredWidth()) / 2; int viewRight = viewLeft + subtitleView.getMeasuredWidth(); - int viewTop = bottom - subtitleView.getMeasuredHeight(); + int viewTop = bottom - subtitleView.getMeasuredHeight() + - (int) (height * DEFAULT_BOTTOM_PADDING_FRACTION); int viewBottom = bottom; if (subtitleCue.alignment != null) { @@ -176,7 +183,7 @@ public final class SubtitleLayout extends ViewGroup { } private void updateSubtitlesTextSize(int height) { - textSize = LINE_HEIGHT_RATIO * height * fontScale; + textSize = LINE_HEIGHT_FRACTION * height * fontScale; } private SubtitleView createSubtitleView() {