Giter Site home page Giter Site logo

Comments (39)

icbaker avatar icbaker commented on August 21, 2024 12

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.

icbaker avatar icbaker commented on August 21, 2024 9

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.

phcannesson avatar phcannesson commented on August 21, 2024 5

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?

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.

jreck avatar jreck commented on August 21, 2024 5

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.

phcannesson avatar phcannesson commented on August 21, 2024 4

+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.

icbaker avatar icbaker commented on August 21, 2024 4

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:

  1. The problematic cases both have an additional surfaceSize [eventTime=0.06, mediaPos=0.00, window=0, 0, 0] before surfaceSize [eventTime=0.07, mediaPos=0.00, window=0, 1080, 1080]
  2. The problematic cases both see renderedFirstFrame before surfaceSize [eventTime=1.52, mediaPos=0.00, window=0, period=0, 1080, 607], whereas in the working case the surfaceSize arrives before renderedFirstFrame.

from media.

MGaetan89 avatar MGaetan89 commented on August 21, 2024 3

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.

icbaker avatar icbaker commented on August 21, 2024 3

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) and UQ1A.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.

harry248 avatar harry248 commented on August 21, 2024 2

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.

harry248 avatar harry248 commented on August 21, 2024 1

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.

MykolaKosianchuk avatar MykolaKosianchuk commented on August 21, 2024 1

@icbaker It is not reproducible in the demo app
Looks like it is related to the compose

from media.

fpitterstv2 avatar fpitterstv2 commented on August 21, 2024 1

We are seeing this now when migrating to compose :(
Using RESIZE_MODE_FIT inside a fillMaxSize composable

from media.

rbugajewski avatar rbugajewski commented on August 21, 2024 1

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.

rbugajewski avatar rbugajewski commented on August 21, 2024 1

@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.

kotya341 avatar kotya341 commented on August 21, 2024 1

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.

icbaker avatar icbaker commented on August 21, 2024 1

@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.

MykolaKosianchuk avatar MykolaKosianchuk commented on August 21, 2024

@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.

icbaker avatar icbaker commented on August 21, 2024

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.

phcannesson avatar phcannesson commented on August 21, 2024

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.

promanowicz avatar promanowicz commented on August 21, 2024

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.

speedclaud avatar speedclaud commented on August 21, 2024

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):

compose-media.zip

This is what it looks like:

Screenshot_20240411_121959

from media.

phcannesson avatar phcannesson commented on August 21, 2024

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.

speedclaud avatar speedclaud commented on August 21, 2024

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.

speedclaud avatar speedclaud commented on August 21, 2024

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.

phcannesson avatar phcannesson commented on August 21, 2024

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.

icbaker avatar icbaker commented on August 21, 2024

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.

jdelga avatar jdelga commented on August 21, 2024

This seems a duplicate of #1123

from media.

fpitterstv2 avatar fpitterstv2 commented on August 21, 2024

Also reproducible on an emulator using VanillaIceCream

from media.

jreck avatar jreck commented on August 21, 2024

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.

jreck avatar jreck commented on August 21, 2024

I can confirm that the clipping change is not the cause of this issue.

from media.

devno44 avatar devno44 commented on August 21, 2024

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.

icbaker avatar icbaker commented on August 21, 2024

@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.

kotya341 avatar kotya341 commented on August 21, 2024

@oceanjules
could you please reopen our thread, I can't reply on it
This conversation has been locked and limited to collaborators.

from media.

phcannesson avatar phcannesson commented on August 21, 2024

Should we also reopen this one or does 1.4.0 contain a valid fix ?

from media.

icbaker avatar icbaker commented on August 21, 2024

@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.

Omkar-Amberkar avatar Omkar-Amberkar commented on August 21, 2024

@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.

icbaker avatar icbaker commented on August 21, 2024

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.

Omkar-Amberkar avatar Omkar-Amberkar commented on August 21, 2024

@icbaker yes it does but wanted to check in with you guys to see if that seems correct when using compose.

from media.

efemoney avatar efemoney commented on August 21, 2024

@Omkar-Amberkar it is correct. It does the exact same thing. I have the same workaround in my code.

from media.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.