Video is cut on the edge when using Compose and uses RESIZE_MODE_ZOOM - Only Android 14
Version
Media3 1.2.1
More version details
Reproduced also in latest version of Exoplayer, and Media3 1.3.0-beta01
Devices that reproduce the issue
Any device or emulator running Android 14
Devices that do not reproduce the issue
Any device or emulator running Android 13 or lower
Reproducible in the demo app?
No
Reproduction steps
Reproduced in Demo Project: Demo project
Just open the app and check the video dimensions
The bug happens in the following conditions:
- PlayerView is inside an
AndroidViewin Compose - The Composable function is inside a component with
fillMaxSize()modifier - The video is using UnstableApi
RESIZE_MODE_ZOOM
(It also happens in RESIZE_MODE_FIXED_HEIGHT, RESIZE_MODE_FIXED_WIDTH and RESIZE_MODE_FIT, but does not happen with RESIZE_MODE_FILL)
Expected result
The video is not cut on the edge.
Actual result
The video is cut:
You can check closer to the status bar to identify the issue
Just change the resizeMode in the demo app to check the issue with other resize modes: https://github.com/jdelga/Media3ComposeDemo/blob/main/app/src/main/java/com/javierdelgado/media3composedemo/VideoScreen.kt#L21
Media
Not applicable, but a media item is already added to the demo project
Bug Report
- [X] You will email the zip file produced by
adb bugreportto [email protected] after filing this issue.
Comments
It would be very useful to add full support to resizeMode (currently as UnstableApi) and add a proper Compose player.
In the bugreport there is an AspectRatioFrameLayout that doesn't fit with its parent PlayerView:
androidx.compose.ui.platform.ComposeView{56f1745 V.E...... ........ 0,0-1080,2270}
androidx.compose.ui.platform.AndroidComposeView{6ba67ab VFED..... ........ 0,0-1080,2270}
androidx.compose.ui.platform.AndroidViewsHandler{745e9fd V.E...... ......ID 0,0-1080,2270}
androidx.compose.ui.viewinterop.ViewFactoryHolder{5747a8 V.E...... ......I. 0,0-1080,2270}
androidx.media3.ui.PlayerView{84a4c6d V.E...... ........ 0,0-1080,2270}
androidx.media3.ui.AspectRatioFrameLayout{439f0a2 V.E...... ........ -58,0-1139,2270 #7f07003d app:id/exo_content_frame}
According to: https://github.com/androidx/media/blob/d13a0f4ec62ca092b79746a5725b62a3244cc5b4/libraries/ui/src/main/java/androidx/media3/ui/AspectRatioFrameLayout.java#L174-L209
RESIZE_MODE_FILL is actually not doing any resizing ("Ignore target aspect ratio" branch)
RESIZE_MODE_ZOOM in the case of your media will increase the width (since AspectDeformation>0)
And you are right, AspectRatioFrameLayout will be bigger than PlayerView, but that's ok, because the parent will end up cropping it.
| Pixel5 API34 | Pixel5 API30 | |
|---|---|---|
| Android | 14 | 11 |
| View | ||
| width | 1080 | 1080 |
| height | 2138 | 2072 |
| View aspect ratio | 0.505145 | 0.5212355 |
| Video aspect ratio | 0.52734375 | 0.52734375 |
| AspectDeformation | 0.043945312 | 0.01171875 |
| New view width | 1127 | 1092 |
| AspectRatioFrameLayout | ||
| x | -8dp | -2dp |
| y | 49dp | 49p |
| width | 1127/2.75=409 | 1092/2.75=397 |
| heigth | 2138/2.75=777 | 2072/2.75=753 |
Given that the screen width is only 392dp, Android tries to position the ARFL in the centre by:
- leaving 8dp and 9dp on each side (8+392+9 = 409)
- leaving 2dp and 3dp on each side (2+392+3 = 397)
My guess is that since the stretch in Android14 is bigger, there is some delay in stretching the view?
I managed to reproduce your issue, but it disappears so quickly that I cannot catch the setup in the state where the width:
https://github.com/androidx/media/assets/19333204/80e6befd-e8d0-43f8-bfd4-e211bc630d75
Thank you very much for testing it. Have you tried the uploaded Demo Project? I am using useController = false and the video is not adjusted to its correct location. The controller may be interacting somehow and after it appears, the video is adjusted.
useController = false
https://github.com/androidx/media/assets/36664452/9c0087cb-4a9e-4b1b-a871-39a81c11d379
useController = true
https://github.com/androidx/media/assets/36664452/8f8b6d7c-0dcf-4fca-8b5c-5b0b001b5eee
I'm +1 - ing this issue. I ran into this earlier this week where my video would be rendered stretched and it seems to be related. Setting 'controllerAutoShow' to true triggers a re-layout of the PlayerView, thus correcting its size.
Below is a sample project which is essentially this box in an activity;
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black),
contentAlignment = Alignment.Center
) {
AndroidView(
factory = { ctx ->
PlayerView(ctx).apply {
useController = true
// Setting controllerAutoShow to true fill show the controller automatically
// Having it auto-show triggers a re-layout of the PlayerView
// which causes the layout to be corrected
controllerAutoShow = false
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
}
},
update = {
it.player = exoPlayer
exoPlayer.setMediaItem(
MediaItem.fromUri("https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")
)
exoPlayer.playWhenReady = true
exoPlayer.prepare()
},
)
}
I'm also seeing this issue on my app.
it seems 100% linked to having a parent with fillMaxSize().
In my case, I have a single activity with a NavHost() that handles the whole navigation. Therefore, this issue is a big problem as the only solution I've found is to create a second activity to host the PlayerView
Also, please note that it happens a lot on Android 14 devices, but ALSO on Android 13 and lower, when playing HLS and when a track change occurs (linked to available bandwidth).
I'm also facing this issue. resizeMode is set to AspectRatioFrameLayout.RESIZE_MODE_ZOOM. parent view is set to fillMaxSize(). Is there a workaround for now to make the PlayerView fill the entire screen on all devices without changing the aspect ratio?
I'm also facing this issue.
resizeModeis set toAspectRatioFrameLayout.RESIZE_MODE_ZOOM. parent view is set tofillMaxSize(). Is there a workaround for now to make thePlayerViewfill the entire screen on all devices without changing the aspect ratio?
This one might work https://github.com/androidx/media/issues/1237#issuecomment-2049992538
@jdelga Could you try setting app:surface_type="texture_view" to see if we can isolate this issue as a SurfaceView in Compose issue instead?
As you can see in the Demo project, the issue happens when using a full Compose implementation. The only AndroidView is added to work with PlayerView inside compose. Where should I place the attribute surfaceType for the PlayerView in code ?
My current solution is use fillXXX in the specific case. For example. if i want RESIZE_MODE_FIXED_WIDTH i use the container with fillMaxWith() and not fillMaxSize(). that works to solve my use cases.
I'm also facing this issue.
resizeModeis set toAspectRatioFrameLayout.RESIZE_MODE_ZOOM. parent view is set tofillMaxSize(). Is there a workaround for now to make thePlayerViewfill the entire screen on all devices without changing the aspect ratio?This one might work #1237 (comment)
I used this solution in my compose project, it works perfectly.
First, i created a new layout called video_player.xml in the layout directory of my project:
<?xml version="1.0" encoding="utf-8"?>
<androidx.media3.ui.PlayerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/custom_video_player"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:surface_type="texture_view"
app:use_controller="false" />
As mentioned by @promanowicz, the property app:surface_type="texture_view" is the key to solve the issue.
Then i inflated that file in compose:
@Composable
fun VideoComponent() {
val context = LocalContext.current
val exoplayer = remember {
ExoPlayer.Builder(context)
.setTrackSelector(trackSelector)
.build()
.apply {
setMediaItem(MediaItem.fromUri("your_video_url"l))
prepare()
play()
playWhenReady = true
}
}
var exoPlayerView = remember {
val view = View.inflate(context, R.layout.video_player, null)
val playerView = view.findViewById<PlayerView>(R.id.custom_video_player)
playerView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
playerView.player = exoplayer
playerView
}
AndroidView(
modifier = Modifier.fillMaxSize()
factory = { exoPlayerView }
)
}
This is almost certainly a duplicate of https://github.com/androidx/media/issues/1237, which is fixed in Android 15 and a workaround for Android 14 is in https://github.com/androidx/media/commit/968f72fec6d5452a34976824ac822782eeeb8f45 which will be released in media3 1.4.0-rc01.