Rich Luick
Rich Luick

Reputation: 2364

Center Crop Exoplayer with SurfaceView

I am currently using Exoplayer in a project and am looking to achieve a "CenterCrop" type attribute similar on the video to what you might see in an imageview. Basically it will fit to the height of the surfaceview, keep the same aspect ratio, and crop the edges on the side that go off the screen. My layout looks something like this:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/videoPlayerContainer"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="404dp">

    <com.google.android.exoplayer2.ui.SimpleExoPlayerView
        android:id="@+id/videoPlayer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        app:controller_layout_id="@layout/empty_controls">

        <SurfaceView
            android:id="@+id/surfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </com.google.android.exoplayer2.ui.SimpleExoPlayerView>

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text"
        android:background="@android:color/white"/>

</FrameLayout>

Most of the code to create and start the player was already set up by a colleague in a wrapper and basically looks like the following:

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

LoadControl loadControl = new DefaultLoadControl();
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector, loadControl);

simpleExoplayer.setSurfaceView(surfaceView);

DataSource.Factory mediaDataSourceFactory = new DefaultDataSourceFactory(context, "Agent");

MediaSource videoSource = new HlsMediaSource(uri, mediaDataSourceFactory, new Handler(), null);

simpleExoplayer.addListener(this);
simpleExoplayer.prepare(videoSource);

simpleExoplayer.setPlayWhenReady(true);

//this is supposedly used to set the scaling mode
simpleExoplayer.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);

This code takes in a uri does some setup and plays the video, which is all working fine. After doing some research on cropping, I found the "setVideoScalingMode" which I added as the last line in the code above. This unfortunately does nothing. Does anyone have any idea on how this is supposed to be done and what I can adjust to get it to work? Thanks!

Upvotes: 10

Views: 9701

Answers (2)

Danylo Oliinyk
Danylo Oliinyk

Reputation: 91

To have ExoPlayer related answers in one place (also i didn't find any answer that did work for me) so posting here:

I'm using kotlin + compose, so it looks like:

val exoPlayer = remember {
    ExoPlayer.Builder(context).build()
        .apply {
            ...
            videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
            ...
        }
}

Notice the clipToBounds():

AndroidView(
    modifier = Modifier
        .fillMaxSize()
        .clipToBounds(),
    factory = { _ ->
        PlayerView(context).apply {
            player = exoPlayer
            ...
            resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
        }
    }
)

So in addition to mentioned C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING and AspectRatioFrameLayout.RESIZE_MODE_ZOOM i needed to add clipToBounds() that was the key.

Upd. 11/September/2024:

There's a known issue on API 34 when video flickers with shrink/extend (i have a video on login screen which sometimes is shown with black bar, then extended to fill max size).

Here's issue's thread with a workaround: https://github.com/androidx/media/issues/1237

If you don't want to read the thread, here's demo repository with a workaround: https://github.com/phcannesson/AspectFrameLayoutDemo/blob/3f2582bfe8a221c27a64422df7cd60a346b5f9b5/app/src/main/java/com/phcannesson/aspectframelayoutdemo/ui/PlayerFixTextureViewScreen.kt#L40

Upvotes: 2

Arsal Imam
Arsal Imam

Reputation: 2982

I know this very late to answer. After did a lot of brainstorming, studying EXOPlayer source to achieve this feature, I have figured it out by myself, what I did is just add the below line and it worked like a charm:

mVideoView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM); //This will increase video's height or width to fit with maintaining aspect ratios of video.

And remove the other two options which are mentioned below:

mExoplayer.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
mVideoView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL)

May this helps others.

Upvotes: 31

Related Questions