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() {