15

I have a RelativeLayout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_gravity="center"
    android:foregroundGravity="center"
    android:gravity="center"
    android:orientation="horizontal" >

    <VideoView
        android:id="@+id/videoViewPanel"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center" 
        android:layout_centerInParent="true"/>

</RelativeLayout>

And what I need is to show video fullscreen cropped. If I could compare to ImageView, I need to show it as crop_center.

How can I make VideoView not to auto-resize video to fit center, but crop center?

Vladyslav Matviienko
  • 10,610
  • 4
  • 33
  • 52
  • This solution for a VideoView scales Center Crop or Center Inside keeping the aspect ratio of the video like an ImageView does. Hope it helps someone! https://stackoverflow.com/a/53641686/6082973 – Carlitos Dec 06 '18 at 02:57
  • @Carlitos it won't center crop the video, as it changes the VideoVIew size. – Vladyslav Matviienko Dec 06 '18 at 05:46

6 Answers6

30

In Android's VideoView, here is a simple and easy way to achieve the same effect as ImageView.ScaleType.CENTER_CROP

xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="@dimen/dimen_0dp"
        android:layout_height="@dimen/dimen_0dp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

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 / scaleX);
         }
      }
});

In Kotlin:

videoView.setOnPreparedListener { mediaPlayer ->
    val videoRatio = mediaPlayer.videoWidth / mediaPlayer.videoHeight.toFloat()
    val screenRatio = videoView.width / videoView.height.toFloat()
    val scaleX = videoRatio / screenRatio
    if (scaleX >= 1f) {
        videoView.scaleX = scaleX
    } else {
        videoView.scaleY = 1f / scaleX
    }
}

And this worked for me. Hope this will help someone.

Alfonso
  • 8,386
  • 1
  • 43
  • 63
Nabin
  • 1,451
  • 3
  • 19
  • 26
11

The solution is to use TextureView instead of VideoView(SurfaceView).
TextureView does not make any manipulations with the content to fit it ti the screen.
Here is the code sample for the solution:

//store the SurfaceTexture to set surface for MediaPlayer
mTextureView.setSurfaceTextureListener(new SurfaceTextureListener() {
@Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface,
            int width, int height) {
        FullScreenActivity.this.mSurface = surface;

    }

....

Surface s = new Surface(mSurface);
mPlayer = mp;
mp.setSurface(s);

scaleVideo(mp);//<-- this function scales video to run cropped

....

private void scaleVideo(MediaPlayer mPlayer) {

        LayoutParams videoParams = (LayoutParams) mTextureView
                .getLayoutParams();
        DisplayMetrics dm = new DisplayMetrics();
        FullScreenActivity.this.getWindowManager().getDefaultDisplay()
                .getMetrics(dm);

        final int height = dm.heightPixels;
        final int width = dm.widthPixels;
        int videoHeight = mPlayer.getVideoHeight();
        int videoWidth = mPlayer.getVideoWidth();
        double hRatio = 1;

        hRatio = (height * 1.0 / videoHeight) / (width * 1.0 / videoWidth);
        videoParams.x = (int) (hRatio <= 1 ? 0 : Math.round((-(hRatio - 1) / 2)
                * width));
        videoParams.y = (int) (hRatio >= 1 ? 0 : Math
                .round((((-1 / hRatio) + 1) / 2) * height));
        videoParams.width = width - videoParams.x - videoParams.x;
        videoParams.height = height - videoParams.y - videoParams.y;
        Log.e(TAG, "x:" + videoParams.x + " y:" + videoParams.y);
        mTextureView.setScaleX(1.00001f);//<-- this line enables smoothing of the picture in TextureView.
        mTextureView.requestLayout();
        mTextureView.invalidate();

    }
Vladyslav Matviienko
  • 10,610
  • 4
  • 33
  • 52
  • 4
    Here's a library that Uses a textureView and has centerCrop added: https://github.com/dmytrodanylyk/android-video-crop – Jordy Apr 11 '14 at 11:42
3

I just put video inside ConstraintLayout with such parameters. This helped stretch video and achieve android:scaleType="centerCrop" effect.

<VideoView
    android:id="@+id/video_view"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:layout_gravity="center_horizontal"
    android:layout_width="0dp"
    android:layout_height="0dp" />
soshial
  • 5,906
  • 6
  • 32
  • 40
2

To crop center in fullscreen you can still use a VideoView. Set the VideoView width and height to match the parent inside a RelativeLayout and adjust it to be bigger than the screen and set his position.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rootLayout"
tools:context="com.example.Activity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_height="match_parent">

        <VideoView
            android:id="@+id/video_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:layout_centerVertical="true" />

    </RelativeLayout>
</RelativeLayout>

And then in onCreate:

   RelativeLayout rootView=(RelativeLayout) findViewById(R.id.rootLayout);
    Display display=getWindowManager().getDefaultDisplay();
    Point size=new Point();
    display.getSize(size);

    FrameLayout.LayoutParams rootViewParams = (FrameLayout.LayoutParams) rootView.getLayoutParams();
    int videoWidth=864;
    int videoHeight=1280;

    if ((float)videoWidth/(float)videoHeight<(float)size.x/(float)size.y) {
        rootViewParams.width=size.x;
        rootViewParams.height=videoHeight*size.x/videoWidth;
        rootView.setX(0);
        rootView.setY((rootViewParams.height-size.y)/2*-1);
    } else {
        rootViewParams.width=videoWidth*size.y/videoHeight;
        rootViewParams.height=size.y;
        rootView.setX((rootViewParams.width-size.x)/2*-1);
        rootView.setY(0);
    }
    rootView.setLayoutParams(rootViewParams);


    final VideoView mVideoView=(VideoView)findViewById(R.id.video_view);
    mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.splash));
    mVideoView.requestFocus();

    mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            mVideoView.start();
        }
    });
MazarD
  • 2,759
  • 2
  • 22
  • 33
  • I've tried similar solution, as it themed obvious to me when asked a question 4 years ago, and that time VideoView was force fitting video inside itself, which prohibited cropping. Don't know how it works now, since 4 years passed, and something has to be changed in the SDK. – Vladyslav Matviienko Jul 06 '17 at 05:34
  • Ok, I imagined that, but I spent some time looking for the solution and this question is clear and shows up in the first positions of google, so I decided to answer. This works for me in api level 25. – MazarD Jul 06 '17 at 05:50
  • are you sure that it is supposed to **crop**, not to **fit center**? – Vladyslav Matviienko Jul 06 '17 at 06:09
  • You are totally right, it was stretching. I changed the video and it cheated on me. I've just edited the answer with a correct solution using VideoView in a RelativeLayout and adjusting the size and position to be outside the screen. This finally works. Can't believe how such a simple task could be so difficult. – MazarD Jul 06 '17 at 09:32
  • Hi, Thank you for providing this answer. I am trying to make a login screen like the one Spotify has , but using this solution I am not able to position other elements on the screen well, because the rootview does no longer match the screen. Are there any way to do this on *not* the root view? and rather just resize a child of the root view? I tried to do this, but with no luck. – Simon Olsen Jan 13 '18 at 20:02
  • I don't think so. It has to be the root view, because the childs can't overflow their parent, only the rootview can do that. Maybe you can then set a child view inside the rootview matching the screen size and position everything there. – MazarD Jan 15 '18 at 14:29
  • No upvotes after all this time? It works perfectly! – spacer GIF Aug 15 '19 at 21:15
  • This is the only solution that worked. Thank you so much. – Bucky Jan 30 '22 at 17:02
0

I have found a solution: The default behavior is just like fitCenter , so I compute the video ratio(width/height) and screen ratio, and then scale the VideoView to full screen. The result is just like centerCrop .

hanswim
  • 1,182
  • 8
  • 20
0

Adding an addition to answer by @Nabin. If you are experiencing problem on pause. If video pause causes the video view height to change and show a black screen below. use this.

public class CustomVideoView extends VideoView {
private int originalWidth = 0;
private int originalHeight = 0;

public CustomVideoView(Context context) {
    super(context);
}

public CustomVideoView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (originalWidth == 0 || originalHeight == 0) {
        originalWidth = MeasureSpec.getSize(widthMeasureSpec);
        originalHeight = MeasureSpec.getSize(heightMeasureSpec);
    }

    setMeasuredDimension(originalWidth, originalHeight);
}

}

Rohaitas Tanoli
  • 624
  • 4
  • 16