Question

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?

Was it helpful?

Solution 2

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

    }

OTHER TIPS

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.

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" />

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();
        }
    });

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 .

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top