Comments (39)
I've updated the title of this issue to reflect that this isn't specific to AspectRatioFrameLayout
, and it's more related to SurfaceView
inside a Compose AndroidView
on Android 14.
With the support of the graphics team, I've also submitted a workaround (linked above) to PlayerView
, which resolves this issue for users of this class. This will be included in 1.4.0-rc01
. I'm going to close this issue, since that should resolve the issue for users of media3's UI components. Those who have written their own UI components may be able to adopt a similar workaround.
from media.
I have filed an issue internally to ask for assistance from the Window Manager team (who own SurfaceView) and Compose folks: b/334901521
from media.
I found a "fix", the stretch is gone when using
app:surface_type="texture_view"
. So I assume there's something wrong withapp:surface_type="surface_view"
insideAndroidView
on the latest android?Is it true that
texture_view
drains more battery?
I can confirm that it seems to fix.
I've created a public repo to reproduce and play with the configuration :
https://github.com/phcannesson/AspectFrameLayoutDemo
The player with app:surface_type="texture_view"
works well.
from media.
The issue is that somehow this transaction isn't happening: https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/view/SurfaceView.java;drc=a7ba109ec6c7c1ca82f96651863b3d2c10c6bc34;l=2113
In the repro app the transaction that updates the bounds of the SurfaceView is just getting dropped on the floor, so the compositor still thinks it's the original square dimensions thus the stretching. But it's not clear yet why or why Compose specifically seems to trigger this. We have a platform workaround, though, but no guidance yet on a Compose workaround since the root cause isn't understood yet.
from media.
+1 this
We've spent days trying to understand issues we have with Android 14 devices recently.
Going back to our previous app versions doesn't fix anything, so we came up with the same conclusion as @MykolaKosianchuk , it's probably related to a recent Android patch.
from media.
Thanks for the repro app in #1237 (comment). I ran this on a Pixel 7a running lynx-userdebug AP1A.240405.002
and observed the problematic behaviour shown in your screenshot nearly every time (the first time i launched the app it seemed to work OK, but the subsequent ~10 times it shows the problem - even after swiping the app away from recents, and clearing app data).
I added an EventLogger
(https://developer.android.com/media/media3/exoplayer/debug-logging) and grabbed the logcat filtered to EventLogger
of a problematic repro.
I then flashed my device back to before the March feature release, to lynx-userdebug UQ1A.240205.002
and installed the app. The first time I launched the video it played fine. I grabbed the same filtered logcat, and diffed it against the problematic behaviour. Then subsequent launches of the video (without dismissing the app) showed the problem (and I grabbed the logcat). Swiping the app away and re-launching it seems to allow the playback to work correctly once, then subsequent launches are problematic.
I observed the following in logcat right at the start of playback in the problematic case on AP1A.240405.002
:
timeline [eventTime=0.02, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
mediaItem [eventTime=0.02, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
state [eventTime=0.02, mediaPos=0.00, window=0, BUFFERING]
surfaceSize [eventTime=0.06, mediaPos=0.00, window=0, 0, 0]
surfaceSize [eventTime=0.08, mediaPos=0.00, window=0, 1080, 1080]
timeline [eventTime=0.09, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
positionDiscontinuity [eventTime=0.10, mediaPos=0.00, window=0, reason=REMOVE, PositionInfo:old [mediaItem=0, period=0, pos=0], PositionInfo:new [mediaItem=0, period=0, pos=0]]
mediaItem [eventTime=0.10, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
loading [eventTime=0.11, mediaPos=0.00, window=0, true]
timeline [eventTime=0.11, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [?]
window [?, seekable=false, dynamic=false]
]
timeline [eventTime=1.15, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [634.40]
window [634.40, seekable=true, dynamic=false]
]
videoEnabled [eventTime=1.16, mediaPos=0.00, window=0, period=0]
tracks [eventTime=1.16, mediaPos=0.00, window=0, period=0
group [
[X] Track:0, id=1, mimeType=video/av01, res=854x480, fps=29.999998, supported=YES
]
]
downstreamFormat [eventTime=1.16, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, fps=29.999998]
videoDecoderInitialized [eventTime=1.20, mediaPos=0.00, window=0, period=0, c2.google.av1.decoder]
videoInputFormat [eventTime=1.21, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, fps=29.999998]
videoSize [eventTime=1.33, mediaPos=0.00, window=0, period=0, 854, 480]
renderedFirstFrame [eventTime=1.34, mediaPos=0.00, window=0, period=0, Surface(name=null)/@0xe4d0ed2]
surfaceSize [eventTime=1.35, mediaPos=0.00, window=0, period=0, 1080, 607]
state [eventTime=1.36, mediaPos=0.02, window=0, period=0, READY]
isPlaying [eventTime=1.36, mediaPos=0.02, window=0, period=0, true]
loading [eventTime=1.91, mediaPos=0.56, window=0, period=0, false]
loading [eventTime=3.42, mediaPos=2.08, window=0, period=0, true]
loading [eventTime=3.48, mediaPos=2.14, window=0, period=0, false]
The same part of logcat in the working case on UQ1A.240205.002
:
timeline [eventTime=0.03, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
mediaItem [eventTime=0.03, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
state [eventTime=0.03, mediaPos=0.00, window=0, BUFFERING]
surfaceSize [eventTime=0.07, mediaPos=0.00, window=0, 1080, 1080]
timeline [eventTime=0.09, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
positionDiscontinuity [eventTime=0.09, mediaPos=0.00, window=0, reason=REMOVE, PositionInfo:old [mediaItem=0, period=0, pos=0], PositionInfo:new [mediaItem=0, period=0, pos=0]]
mediaItem [eventTime=0.09, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
loading [eventTime=0.11, mediaPos=0.00, window=0, true]
timeline [eventTime=0.11, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [?]
window [?, seekable=false, dynamic=false]
]
timeline [eventTime=1.26, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [634.40]
window [634.40, seekable=true, dynamic=false]
]
videoEnabled [eventTime=1.45, mediaPos=0.00, window=0, period=0]
tracks [eventTime=1.46, mediaPos=0.00, window=0, period=0
group [
[X] Track:0, id=1, mimeType=video/av01, res=854x480, fps=29.999998, supported=YES
]
]
downstreamFormat [eventTime=1.46, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, fps=29.999998]
videoDecoderInitialized [eventTime=1.49, mediaPos=0.00, window=0, period=0, c2.google.av1.decoder]
videoInputFormat [eventTime=1.49, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, fps=29.999998]
videoSize [eventTime=1.52, mediaPos=0.00, window=0, period=0, 854, 480]
surfaceSize [eventTime=1.52, mediaPos=0.00, window=0, period=0, 1080, 607]
renderedFirstFrame [eventTime=1.53, mediaPos=0.00, window=0, period=0, Surface(name=null)/@0xb940abd]
state [eventTime=1.53, mediaPos=0.00, window=0, period=0, READY]
isPlaying [eventTime=1.53, mediaPos=0.00, window=0, period=0, true]
loading [eventTime=2.29, mediaPos=0.76, window=0, period=0, false]
loading [eventTime=3.61, mediaPos=2.08, window=0, period=0, true]
loading [eventTime=3.67, mediaPos=2.15, window=0, period=0, false]
And finally, the problematic case on UQ1A.240205.002
:
timeline [eventTime=0.02, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
mediaItem [eventTime=0.02, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
state [eventTime=0.02, mediaPos=0.00, window=0, BUFFERING]
surfaceSize [eventTime=0.06, mediaPos=0.00, window=0, 0, 0]
surfaceSize [eventTime=0.07, mediaPos=0.00, window=0, 1080, 1080]
loading [eventTime=0.08, mediaPos=0.00, window=0, period=0, true]
timeline [eventTime=0.08, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [?]
window [?, seekable=false, dynamic=false]
]
timeline [eventTime=0.08, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
positionDiscontinuity [eventTime=0.08, mediaPos=0.00, window=0, reason=REMOVE, PositionInfo:old [mediaItem=0, period=0, pos=0], PositionInfo:new [mediaItem=0, period=0, pos=0]]
mediaItem [eventTime=0.08, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
timeline [eventTime=0.09, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [?]
window [?, seekable=false, dynamic=false]
]
timeline [eventTime=1.30, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [634.40]
window [634.40, seekable=true, dynamic=false]
]
videoEnabled [eventTime=1.31, mediaPos=0.00, window=0, period=0]
tracks [eventTime=1.31, mediaPos=0.00, window=0, period=0
group [
[X] Track:0, id=1, mimeType=video/av01, res=854x480, fps=29.999998, supported=YES
]
]
downstreamFormat [eventTime=1.31, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, fps=29.999998]
videoDecoderInitialized [eventTime=1.36, mediaPos=0.00, window=0, period=0, c2.google.av1.decoder]
videoInputFormat [eventTime=1.36, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, fps=29.999998]
videoSize [eventTime=1.51, mediaPos=0.00, window=0, period=0, 854, 480]
renderedFirstFrame [eventTime=1.51, mediaPos=0.00, window=0, period=0, Surface(name=null)/@0x4a7b0d3]
surfaceSize [eventTime=1.53, mediaPos=0.00, window=0, period=0, 1080, 607]
state [eventTime=1.53, mediaPos=0.02, window=0, period=0, READY]
isPlaying [eventTime=1.54, mediaPos=0.02, window=0, period=0, true]
loading [eventTime=2.21, mediaPos=0.70, window=0, period=0, false]
loading [eventTime=3.60, mediaPos=2.08, window=0, period=0, true]
loading [eventTime=3.67, mediaPos=2.15, window=0, period=0, false]
There are two key differences between the working and problematic cases:
- The problematic cases both have an additional
surfaceSize [eventTime=0.06, mediaPos=0.00, window=0, 0, 0]
beforesurfaceSize [eventTime=0.07, mediaPos=0.00, window=0, 1080, 1080]
- The problematic cases both see
renderedFirstFrame
beforesurfaceSize [eventTime=1.52, mediaPos=0.00, window=0, period=0, 1080, 607]
, whereas in the working case thesurfaceSize
arrives beforerenderedFirstFrame
.
from media.
I have filed an issue internally to ask for assistance from the Window Manager team (who own SurfaceView) and Compose folks: b/334901521
Any chance to make the issue public to follow the discussion? Or it (may) contains confidential information?
from media.
I've done a bit more testing on different Android versions. This is on Pixel 7a and Pixel Fold (folded). My observations:
- I haven't managed to repro on Android 13
- On Android 14 before the March 2024 update (specifically I tested
UP1A.231005.007
(the first stable Android 14 build) andUQ1A.240205.002.B1
(just before the March release))- I observe the issue at a high repro rate (~90%)
- As soon as you tap on the playback to make the controls appear, the issue is resolved
- On Android 14 after the March 2024 update (specifically I tested
AP1A.240305.019.A1
)- The repro rate appears to be about the same
- Tapping the playback to make the controls appear doesn't resolve the issue
I suspect this may be why the issue has become more obvious since the March 2024 release. Before this point it was quickly resolved as soon as something else changed (in this case the controls appearing), but after this the problem persists.
from media.
While digging in AOSP code, I've noticed this change : https://cs.android.com/android/_/android/platform/frameworks/base/+/1b152e712159c0b82831a7567ce2f3c49cdc11bf It apparently modified how
SurfaceView
is clipped.It seemed to have been released in Android 14 QPR2.
It's a wild guess, but I thought it was worth mentioning.
With QPR2 our QA also started to report the issue, so very likely related.
from media.
We have the same problem. We had already observed this in the QPR but unfortunately did not create an issue. Interestingly, we "only" have the problem if we use the AndroidView (which creates the PlayerView) in an if block, i.e. the composable is not called immediately.
from media.
@icbaker It is not reproducible in the demo app
Looks like it is related to the compose
from media.
We are seeing this now when migrating to compose :(
Using RESIZE_MODE_FIT
inside a fillMaxSize composable
from media.
I want to report that at our company we face the same issue on some Google Pixel 8 Pro devices. We’ve identified the regression back to the clipping calculation of the SurfaceView
on 5th, March 2024. We also tried the mentioned workarounds, but switching to a TextureView
is not possible for us due to DRM, and disabling hardware acceleration (which would bypass the check) is also not possible as this would heavily degrade the user experience.
We would greatly appreciate if the vendor could keep us updated on the issue if we do not have any chances to follow the discussion on b/334901521.
from media.
@jreck This is very interesting, thanks for your investigation. So there seems to be another cause of the issue that was introduced on the 5th, March 2024, that is somehow correlated to hardware acceleration, Jetpack Compose, and Google Pixel phones.
from media.
Hello folks,
just want to share with you some updates.
after updating to the stable version of 1.4.0 I can still reproduce my problem from this ticket
from media.
@kotya341 Looks like @tonihei has unlocked the thread and you should be able to reply - apologies for missing that when I re-opened it.
from media.
@phcannesson Yes, we found this issue and tried to reproduce it on the device without the last patch but we can't. However, once we updated the phone, the issue appeared.
from media.
Reproducible in the demo app?
Not tested
Please can you test this? It would help us to debug if we know whether it can be reproduced in the demo app.
Interestingly, we "only" have the problem if we use the AndroidView (which creates the PlayerView) in an if block, i.e. the composable is not called immediately.
Is this true for everyone else that has commented on this bug? Is everyone else experiencing this only in Compose contexts, or also in conventional views? This looks like it might be a duplicate of #1123 but it's interesting to hear that the behaviour changes between Android 14 before the March 5th update and after it.
from media.
Reproducible in the demo app?
Not tested
Please can you test this? It would help us to debug if we know whether it can be reproduced in the demo app.
Interestingly, we "only" have the problem if we use the AndroidView (which creates the PlayerView) in an if block, i.e. the composable is not called immediately.
Is this true for everyone else that has commented on this bug? Is everyone else experiencing this only in Compose contexts, or also in conventional views? This looks like it might be a duplicate of #1123 but it's interesting to hear that the behaviour changes between Android 14 before the March 5th update and after it.
On our side we're using Compose.
We did not test with conventional views.
from media.
I have faced exact same issue, except I was using resizeMode with fixed height.
I addition I have noticed that the video gets right aspect ratio after I switched orientation to landscape and then back to portrait.
from media.
Hi @icbaker , I was also not able to reproduce the issue on your demo app on Pixel 7, Android 14, march 5th update, but we have the issue in our compose app using AndroidView. The issue is present in this sample app that uses compose, (press on the "Exo PlayerView" button):
This is what it looks like:
from media.
On our side, after some testing, we've detected that it seems to be related to the way the frame layout gets notified of changes in the player.
We've successfully "fixed" the issue by adding some delay before displaying the AndroidView
.
That apparently allows the player to be fully ready when the view is loaded.
from media.
On our side, after some testing, we've detected that it seems to be related to the way the frame layout gets notified of changes in the player. We've successfully "fixed" the issue by adding some delay before displaying the
AndroidView
. That apparently allows the player to be fully ready when the view is loaded.
I've tried adding a delay to the sample app above (with a boolean mutable state and a LaunchedEffect), but the stretch is still present when It shows.
from media.
I found a "fix", the stretch is gone when using app:surface_type="texture_view"
. So I assume there's something wrong with app:surface_type="surface_view"
inside AndroidView
on the latest android?
Is it true that texture_view
drains more battery?
from media.
While digging in AOSP code, I've noticed this change :
https://cs.android.com/android/_/android/platform/frameworks/base/+/1b152e712159c0b82831a7567ce2f3c49cdc11bf
It apparently modified how SurfaceView
is clipped.
It seemed to have been released in Android 14 QPR2.
It's a wild guess, but I thought it was worth mentioning.
from media.
Trying the same video in the main ExoPlayer demo app on the same device + build (lynx-userdebug UQ1A.240205.002
), I see the 'problematic sequence' in logcat (surfaceSize(0,0)
near the start, and then renderedFirstFrame
before surfaceSize
), but not the problematic symptoms.
This is perhaps obvious, but it adds more weight to the theory that the problem is related to how AspectRatioFrameLayout
(or perhaps SurfaceView
) behaves specifically in a Compose context.
Full logcat:
playWhenReady [eventTime=0.00, mediaPos=0.00, window=0, true, USER_REQUEST]
surfaceSize [eventTime=0.00, mediaPos=0.00, window=0, 0, 0]
timeline [eventTime=0.00, mediaPos=0.00, window=0, periodCount=1, windowCount=1, reason=PLAYLIST_CHANGED
period [?]
window [?, seekable=false, dynamic=true]
]
mediaItem [eventTime=0.01, mediaPos=0.00, window=0, reason=PLAYLIST_CHANGED]
state [eventTime=0.01, mediaPos=0.00, window=0, BUFFERING]
surfaceSize [eventTime=0.04, mediaPos=0.00, window=0, 1080, 2219]
loading [eventTime=0.04, mediaPos=0.00, window=0, period=0, true]
timeline [eventTime=0.04, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [?]
window [?, seekable=false, dynamic=false]
]
timeline [eventTime=0.77, mediaPos=0.00, window=0, period=0, periodCount=1, windowCount=1, reason=SOURCE_UPDATE
period [634.40]
window [634.40, seekable=true, dynamic=false]
]
videoEnabled [eventTime=0.79, mediaPos=0.00, window=0, period=0]
tracks [eventTime=0.79, mediaPos=0.00, window=0, period=0
group [
[X] Track:0, id=1, mimeType=video/av01, res=854x480, color=BT709/Limited range/SDR SMPTE 170M/8/8, fps=29.999998, supported=YES
]
Metadata [
TSSE: description=null: values=[Google]
Mp4Timestamp: creation time=0, modification time=0, timescale=1000
]
]
downstreamFormat [eventTime=0.81, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, color=BT709/Limited range/SDR SMPTE 170M/8/8, fps=29.999998]
videoDecoderInitialized [eventTime=0.84, mediaPos=0.00, window=0, period=0, c2.google.av1.decoder]
videoInputFormat [eventTime=0.84, mediaPos=0.00, window=0, period=0, id=1, mimeType=video/av01, res=854x480, color=BT709/Limited range/SDR SMPTE 170M/8/8, fps=29.999998]
videoSize [eventTime=1.07, mediaPos=0.00, window=0, period=0, 854, 480]
renderedFirstFrame [eventTime=1.07, mediaPos=0.00, window=0, period=0, Surface(name=null)/@0x12990bc]
surfaceSize [eventTime=1.09, mediaPos=0.00, window=0, period=0, 1080, 607]
state [eventTime=1.09, mediaPos=0.01, window=0, period=0, READY]
isPlaying [eventTime=1.10, mediaPos=0.02, window=0, period=0, true]
loading [eventTime=1.78, mediaPos=0.70, window=0, period=0, false]
loading [eventTime=3.17, mediaPos=2.09, window=0, period=0, true]
from media.
This seems a duplicate of #1123
from media.
Also reproducible on an emulator using VanillaIceCream
from media.
While digging in AOSP code, I've noticed this change : https://cs.android.com/android/_/android/platform/frameworks/base/+/1b152e712159c0b82831a7567ce2f3c49cdc11bf It apparently modified how
SurfaceView
is clipped.It seemed to have been released in Android 14 QPR2.
It's a wild guess, but I thought it was worth mentioning.
Very plausible but that behavior is still flag-disabled (note all the new paths are guarded by Flags.clipSurfaceviews() which is still false and never shipped as true). It's possible a path was missed there, but it's supposed to not be doing anything at the moment.
from media.
I can confirm that the clipping change is not the cause of this issue.
from media.
Is there any workaround for older versions ?
We can not change the ExoPlayer version right now, and can not use TextureView instead of SurfaceView.
from media.
@devno44 In order to backport the code change to an older version of the library you will need to build your chosen version locally (media3 instructions, ExoPlayer 2.19.0 instructions), and then apply the changes in 968f72f and 9980306 to your local copy of the code (note that in the exoplayer2
, the equivalent of media3's PlayerView
is StyledPlayerView
.
from media.
@oceanjules
could you please reopen our thread, I can't reply on it
This conversation has been locked and limited to collaborators.
from media.
Should we also reopen this one or does 1.4.0
contain a valid fix ?
from media.
@phcannesson This issue is fixed in 1.4.0-rc01
. If you're experiencing similar problems on that version or later, please open a new issue with details & repro steps.
from media.
@icbaker how would we be able to replicate your fix when we aren't using the PlayerView
directly but instead use the AspectRatioFrameLayout
and SurfaceView
inside the AndroidView
. I have created something similar in compose for our use case as below. let me know if this looks good
const val RESIZE_MODE_FIT = 0
const val RESIZE_MODE_FIXED_WIDTH = 1
const val RESIZE_MODE_FIXED_HEIGHT = 2
const val RESIZE_MODE_FILL = 3
const val RESIZE_MODE_ZOOM = 4
private const val MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f
@Composable
fun Surface(
modifier: Modifier = Modifier,
aspectRatio: Float = 16f / 9f,
resizeMode: Int = RESIZE_MODE_FIT,
onSurfaceCreated: (SurfaceView) -> Unit = {},
onSurfaceDestroyed: (SurfaceView) -> Unit = {},
) {
val mainLooperHandler = remember { Handler(Looper.getMainLooper()) }
val surfaceSyncGroupV34 = remember {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
SurfaceSyncGroupCompatV34()
} else {
null
}
}
AspectRatioLayout(
aspectRatio = aspectRatio,
resizeMode = resizeMode,
modifier = modifier
.drawWithContent {
// Draw the existing content
drawContent()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
surfaceSyncGroupV34?.maybeMarkSyncReadyAndClear()
}
},
) {
Box {
AndroidExternalSurface(
content = { context, state ->
SurfaceView(context).apply {
state.onSurface { surface, width, height ->
onSurfaceCreated(this@apply)
surface.onChanged { width, height ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
surfaceSyncGroupV34?.postRegister(
mainLooperHandler,
this@apply,
this@apply::invalidate
)
}
}
surface.onDestroyed {
onSurfaceDestroyed(this@apply)
}
}
holder.addCallback(state)
}
}
)
}
}
}
@Composable
private fun AspectRatioLayout(
modifier: Modifier,
aspectRatio: Float,
resizeMode: Int,
content: @Composable () -> Unit,
) {
if (aspectRatio <= 0) return
Layout(
content = content,
modifier = modifier
) { measurables, constraints ->
var width = constraints.maxWidth
var height = constraints.maxHeight
val viewAspectRatio = width.toFloat() / height
val aspectDeformation = aspectRatio / viewAspectRatio - 1
if (abs(aspectDeformation) > MAX_ASPECT_RATIO_DEFORMATION_FRACTION) {
when (resizeMode) {
RESIZE_MODE_FIXED_WIDTH -> height = (width / aspectRatio).toInt()
RESIZE_MODE_FIXED_HEIGHT -> width = (height * aspectRatio).toInt()
RESIZE_MODE_ZOOM -> if (aspectDeformation > 0) {
width = (height * aspectRatio).toInt()
} else {
height = (width / aspectRatio).toInt()
}
RESIZE_MODE_FIT -> if (aspectDeformation > 0) {
height = (width / aspectRatio).toInt()
} else {
width = (height * aspectRatio).toInt()
}
}
}
layout(width, height) {
val childConstraints = constraints.copy(
minWidth = 0,
minHeight = 0,
maxWidth = width,
maxHeight = height
)
measurables.forEach { measurable ->
val placeable = measurable.measure(childConstraints)
placeable.placeRelative(0, 0)
}
}
}
}
@RequiresApi(34)
private class SurfaceSyncGroupCompatV34 {
private var surfaceSyncGroup: SurfaceSyncGroup? = null
fun postRegister(
mainLooperHandler: Handler,
surfaceView: SurfaceView,
invalidate: Runnable
) {
mainLooperHandler.post {
val rootSurfaceControl = surfaceView.rootSurfaceControl ?: return@post
surfaceSyncGroup = SurfaceSyncGroup("exo-sync-b-334901521")
.apply { add(rootSurfaceControl) {} }
invalidate.run()
rootSurfaceControl.applyTransactionOnDraw(SurfaceControl.Transaction())
}
}
fun maybeMarkSyncReadyAndClear() {
surfaceSyncGroup?.markSyncReady()
}
}
from media.
Heads up for those subscribed to this thread: We have received a report (#1594) that the workaround we introduced in 30cb762 has introduced a regression in the behaviour of Shared Element Transitions. We are currently investigating this, and will update #1594 when we have more info.
@Omkar-Amberkar Does it work? That's probably the best/first test. In general we don't have the capacity for 1:1 code review, and we are also not the experts in these graphics APIs - so I'm afraid not best placed to debug your integration with them, if you're unable to adapt our published workaround to your needs.
from media.
@icbaker yes it does but wanted to check in with you guys to see if that seems correct when using compose.
from media.
@Omkar-Amberkar it is correct. It does the exact same thing. I have the same workaround in my code.
from media.
Related Issues (20)
- Identify MediaItem in TrackSelector's selectTracks Method HOT 1
- Media Session Service and IMA Ads (AdsLoader) HOT 3
- Clarification about the dependency injection from datasource factories HOT 1
- How to control audio playback with widgets? HOT 6
- androidx.media3.exoplayer.hls.SampleQueueMappingException on DRM Content specific on HiSense HiSmart 2K TV HOT 3
- Video freeze and audio continue playing when adapt from high bitrate to low on Pixel 6, Pixel 7, Pixel 7a with os 14 onwards HOT 3
- Issue with oldPosition and newPosition when changing audio using seekbar. HOT 1
- Reopen: Bug Resurfaces -> Low resolution on HD streams since v2.18.2 #693 HOT 2
- No video played when `setVideoEffects` called on NVIDIA Shield HOT 3
- TS stream pixelating when subtitles are parsed during extraction HOT 4
- How do I detect we're in a loading state while streaming HLS files? HOT 4
- CastPlayer how to support custom fields sent from receiver to sender? HOT 6
- Enhancing Media3's Robustness for IPTV: Improving Error Handling and Playlist Management HOT 2
- Bug between Flutter and ExoPlayer - URLs with included BasicAuth do not work HOT 5
- Nous avons une vidéo qui refuse d'être jouée HOT 1
- BehindLiveWindowException HOT 4
- Adding `player#setVideoEffect(emptyList())` workaround causes hevc video to be stuck HOT 7
- Avoid rebuffering when modifying TrackSelector parameters HOT 5
- Speaker info for WebVTT subtitles HOT 1
- transformer support soft decoding/encoding HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from media.