59

So I have extended VideoView's onMeasure to scale up the video to fit inside a fullscreen view.

here is how:

public void setVideoAspect(int w,int h){
    wVideo=w;
    hVideo=h;
    onMeasure(w, h);
}
 @Override
 protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
 {
     super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     if(wVideo!=0 && hVideo!=0)
     setMeasuredDimension(wVideo,hVideo);
 }

I call setVideoAspect() with the display metrics (width, hight) of the screen. The problem is that this method stretches the video to fit inside the screen. I want to be able to keep the aspect ratio. (I have 4:3 video and 3:2 screen size.) I used the folowing code to give the retained ratio measurements to the view:

int height =  (int) (metrics.widthPixels*3/(float)4);
                        int width=  metrics.widthPixels;   
                        mVideoView.setVideoAspect(width,height);

So this does the job but there is an issue: it gives me a 4:3 video with the width of the screen and scales the height correctly, but it doesn't center the video. (It just crops the bottom part of the video instead of the top and the bottom equally.) I have a relative layout containing the VideoView with the gravity of the VideoView set to center.

Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
DArkO
  • 15,880
  • 12
  • 60
  • 88

5 Answers5

136

Try using a FrameLayout instead. I'm not sure why, but if I use a Linear or Relative in my code it won't center, but FrameLayout does. Here is the XML that fit my video to the screen, preserving the ratio and centering it:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/bg">
    <!-- Video player -->
    <VideoView
        android:id="@+id/surface_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"/>
</FrameLayout>
MashukKhan
  • 1,946
  • 1
  • 27
  • 46
Cameron
  • 3,098
  • 1
  • 22
  • 40
  • 1
    If you are fine with Android automatically resizing the video for you (if in landscape, most likely will fill the screen vertically and will then size horizontal to keep the ratio) I don't think you will need any of that code. It should work with that code though, if you still need it for whatever reason – Cameron Feb 01 '11 at 13:40
  • 2
    I don't know why, but this doesn't show up on Google when searching for aligning a video within a VideoView. I had to start writing the question, before I got this related answer suggested to me. Thanks! :) – jlindenbaum May 17 '11 at 21:18
  • @CameronW I'm fine with Android automatically resizing the video for me. but accordingto this: http://stackoverflow.com/questions/4434027/android-videoview-orientation-change-with-buffered-video/4452597#4452597 resizing can be done via code only. no? – Elad Benda Oct 13 '13 at 14:13
  • Works. This is one of the things that irk me about Android - this shouldn't make a difference! – kaay Apr 25 '16 at 17:50
  • Nice catch! Thank you very much – Vlad Aug 06 '18 at 18:47
14

In order to center the video in the RelativeLayout I added both layout_gravity="center" ad layout_centerInParent="true". It works on my Android 4.3 phone.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <VideoView android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_centerInParent="true" />
</RelativeLayout>
duggu
  • 37,851
  • 12
  • 116
  • 113
frognosis
  • 1,576
  • 2
  • 11
  • 10
  • 1
    if you have VideoView to match_parent, ten it's taking full space of RelativeLayout thus android:layout_gravity="center" and android:layout_centerInParent="true" shouldn't have any effect. – Malachiasz Nov 27 '14 at 14:25
  • @Malachiasz In RelativeLayout if I give match_parent only video shows left side, after apply the android:layout_centerInParent --> video shows in center. Don't confuse others. This ans working. – Ranjithkumar Apr 18 '18 at 11:22
10

This works for any video keeping the video's aspect ratio. It positions the video inside the VideoView and performs a Center Crop or a Center Inside just like an ImageView.

I am using a VideoView to cover the whole ConstraintLayout. You can use any other layout probably with match_parent as width and height.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <VideoView
        android:id="@+id/videoView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

In onCreate:

Uri uri = //The uri of your video.
VideoView videoView = findViewById(R.id.videoView);
videoView.setVideoURI(uri);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {

        //Get your video's width and height
        int videoWidth = mp.getVideoWidth();
        int videoHeight = mp.getVideoHeight();

        //Get VideoView's current width and height
        int videoViewWidth = videoView.getWidth();
        int videoViewHeight = videoView.getHeight();

        float xScale = (float) videoViewWidth / videoWidth;
        float yScale = (float) videoViewHeight / videoHeight;

        //For Center Crop use the Math.max to calculate the scale
        //float scale = Math.max(xScale, yScale);
        //For Center Inside use the Math.min scale. 
        //I prefer Center Inside so I am using Math.min
        float scale = Math.min(xScale, yScale);

        float scaledWidth = scale * videoWidth;
        float scaledHeight = scale * videoHeight;

        //Set the new size for the VideoView based on the dimensions of the video
        ViewGroup.LayoutParams layoutParams = videoView.getLayoutParams();
        layoutParams.width = (int)scaledWidth;
        layoutParams.height = (int)scaledHeight;
        videoView.setLayoutParams(layoutParams);               
    }
 });

Hope it helps someone!

Carlitos
  • 343
  • 5
  • 7
9

Cameron's Answer in a programmatic way(in case someone like me needs it) This code is inside onCreate of an activity in my code( 'this' below refers to the activity)

    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

    FrameLayout fl = new FrameLayout(this);

    fl.setLayoutParams(lp);

    VideoView vv = new VideoView(this);

    FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);

    lp2.gravity = Gravity.CENTER;

    vv.setLayoutParams(lp2);

    fl.addView(vv);

    setContentView(fl);
Hoven
  • 393
  • 4
  • 8
4

If you are looking for the same effect as ImageView.ScaleType.CENTER_CROP feature in VideoView then

Here is a simple and easy solution

See my XML and Kotlin version answer here: https://stackoverflow.com/a/59069292/6255841

In JAVA:

videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        float videoRatio = mp.getVideoWidth() / (float) mp.getVideoHeight();
        float screenRatio = videoView.getWidth() / (float) 
        videoView.getHeight();
        float scaleX = videoRatio / screenRatio;
        if (scaleX >= 1f) {
            videoView.setScaleX(scaleX);
        } else {
            videoView.setScaleY(1f / scale);
        }
     }
});
Nabin
  • 1,451
  • 3
  • 19
  • 26