Center Crop Exoplayer with SurfaceView
Asked Answered
S

2

9

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!

Shotton answered 27/2, 2017 at 20:0 Comment(6)
do you have to use SurfaceView? TextureView has a nice feature of setTransform(Matrix) that gives you a full control for scaling/translating/rotatingStrode
@Strode I probably could use texttureview. But ive read that it drains battery significantly faster than the surface view.Shotton
and you want to kill two birds with one stone...Strode
@Strode Well given the nature of where this video is I would prefer to not drain the users battery and would come up with alternate UX. The thing is that ExoPlayer with surface view clearly has some sort of support for this scaling, but it is not clear how to implement this as little information exists on this. There are some Github issues talking about this but the solution is never really clearly explained.Shotton
agreed, also VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING description is somehow misleading as it does not say how the content is cropped to fit the surfaceStrode
@Strode Yeah I agree, also no indication when the best time to call this is. Hopefully someone with more knowledge can help although no luck just yet.Shotton
P
30

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.

Penninite answered 26/9, 2018 at 7:32 Comment(2)
In fact, in the GitHub thread regarding this issue ( github.com/brianwernick/ExoMedia/issues/80), the same conclusion is reached at the end (use only RESIZE_MODE_ZOOM), and the author says they will probably offer support for scaling types by version 3.x.Holdfast
This works. I think this should be added to the Exoplayer docs.Cowage
J
2

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

Joust answered 31/7 at 8:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.