-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Secure decoder is re-initialized if renderer is disabled during a transition (e.g. due to seeking or a discontinuity) #8842
Comments
Do you see the black screen on all devices, or just specific ones? Are you switching between two pieces of differently encrypted DRM content, or from encrypted to/from clear? If the latter, you should try using a placeholder DRM session for the clear content: https://google.github.io/ExoPlayer/drm.html#drm-sessions-for-clear-content If this reproduces consistently across devices would you be able to provide a stream we can use to reproduce the issue? Please either upload it here or send to [email protected] using a subject in the format "Issue #1234" (where "#1234" should be replaced with this issue number.) Please also update this issue to indicate you’ve done this. |
|
Not sure I understand this - you only see the issue when switching from encrypted to clear content? In that case, try the placeholder DRM session approach I linked. |
Hi @icbaker , Rigth now, without using the placeholder DRM Session, i see a black screen when switching from DRM Protected Content -> Clear Content. I've tried the approach you've suggested, by by passing Am i missing something to implement the approach you suggested? Thank you |
@jrocharodrigues This doesn't answer your question, but you shouldn't need to both configure the DRM fields of
There isn't really enough info here to say I'm afraid. I suggest you file a new issue with clear repro steps and preferably a minimal reproducible example that demonstrates the problem in a way that we can build locally. This could be an Android Studio project on GitHub, or zipped up and sent to [email protected] using a subject in the format "Issue #1234", where "#1234" should be replaced with your issue number. Please also update this issue to indicate you’ve done this. It's quite likely this is device specific (that's generally been our experience with these black-screen-during-DRM-transitions issues) - so if you have access to a device from a different manufacturer to experiment with that would also be worth a try (and let us know in the issue what devices you've tried and what you've seen). |
@icbaker Thank you for your answer.
Ok, that explains why the behavior didn't change until i changed the configuration on the
I'll do some more tests in different devices to check if it's a device specific issue, and if needed i'll open a new issue. Best regards |
Hi @icbaker i've done some more testing in different devices, with the sample app, playing the playlist "Clear -> Enc -> Clear -> Enc -> Enc", from the provided samples. The devices i tested were: Is this behaviour correct or should i open a issue for this? |
@jrocharodrigues I can reproduce what you're seeing on Chromecast with Google TV (and not on a Pixel 3a XL). I crafted the following JSON with clipping to make the transitions more obvious (because tears of steel starts/ends with a black screen, so seeing black flashes was really hard):
I found the following:
Fixing the bug highlighted in (2) and (5) means possibly changing The bug highlighted in (3) and (6) looks similar to me to #8568 (comment), where a secure decoder gets re-initialised while 'playing' an empty mid-roll ad. I'll confess that was languishing on my TODO list - I'll aim to take a look at it/this soon (though it likely won't be in the next week). If I conclude the root cause is the same then I'll dupe them together, but I'll keep them separate for now. |
@icbaker Thank you for answer. BRs |
I did some more testing. I removed the clipping (which I'd added to make the black flashes more obvious) and observed that the secure decoder is no longer re-initialized during transitions. This is because the clipping caused the second period to start at a discontinuity (since I clipped to arbitrary point, and didn't hit a key frame), and so we went into this code here: ExoPlayer/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java Lines 1992 to 1999 in 92e05bc
When the clipping is removed, the second piece of content starts with a keyframe, and the renderer is never disabled so the video decoder is kept during the transition. This should mean there's no black flash - but I can't actually confirm that with this content, because it starts & ends with black... I assume both reporters on this issue are only seeing the black flash when the second piece of content starts with a discontinuity? As highlighted in the original content, secure decoders are treated differently to clear ones when being the renderer is disabled. Clear ones are kept while the renderer is disabled, while secure ones are immediately released: Lines 761 to 764 in 92e05bc
I discussed with the team about why this is, and the story behind the TODO there. It turns out it's related to
The TODO is related to the 'foreground mode' case, and a concern about DRM license refreshes continuing to (arguably pointlessly) happen while the player is stopped. The license refresh period is out of ExoPlayer's control (it's defined by the license policy) and these refreshes could be a considered a waste of precious network resources. So the decision was taken to simply release secure codecs in this case (and their associate DRM sessions) to prevent spurious license refreshes. The (somewhat unintended) side-effect of this is that when transitioning into a period that starts with a discontinuity the secure codecs are also released (of course the time the renderer spends 'disabled' in this case is very small, so the DRM license refresh issue isn't a concern). The intention to fix the TODO was to create a new DRM 'mode' where license refreshes are blocked - and this could be used while in this disabled state. I'm not convinced that's necessary - I think it's possible to argue the network resources used by the license refreshes are included in the 'limited resources' referred to in the Having understood what's going on here, I retract my statement above that this is a bug in ExoPlayer. I think it's more like a limitation that only arises in a specific situation (transitioning into a period that starts with a discontinuity). I'm going to experiment with removing the TODO and associated branch, so that secure decoders will always be kept while a renderer is disabled. If that seems to work in a range of different cases I'll submit the change. The I will also look into possibly making |
I tested with live and on demand streams and i see the black screen in both (when switching from enc -> clear). I think that at least the on demand ones should both start with an key frame and the shouldn't have a discontinuity. Right now i'm little confused and with what is expected and what needs to be fixed :) I made some more tests with this samples that don't start with black, and still see the same behavior i reported:
|
@jrocharodrigues Thanks for providing some content to reproduce the problem. However when I play that I don't see the video decoder being re-initialized - it keeps a secure decoder throughout the transition, so it doesn't reproduce the problem. I'm using a version of ExoPlayer built from dev-v2 (but I would expect it to be very similar to 2.14.0). What version of ExoPlayer are you using? There have been some recent fixes in this area.
I guess firstly you can confirm the 'cause' of the black flash is a decoder release/re-acquire. If you're using the demo app, or have the
In the 'good' case (no black flash) I'd expect to see a single In the 'bad' case (black flash) I'd also expect to see Then working out why the decoder is being released is trickier, there's no simple recipe I can give you, just some patience and a debugger (or give me reproducible media and I'll try and work it out).
Yeah, fair enough - there are a lot of branches to this problem and we've also made some recent improvements so there's different behaviour on different versions of the library... I'll try a brief summary (apologies if any of this is re-hashing basic info) :) Root causeSome devices show a black screen when detaching a surface from a secure decoder. The surface gets detached when the decoder is released. The secure decoder is (obviously, unavoidably) released when transitioning from using a secure decoder to an insecure one. That means the simplest 'repro case' for this problem (as you've seen) is playing encrypted content followed by clear content. However as detailed below, the problem can still occur when transitioning between two pieces of content that should both use a secure decoder (in certain circumstances). ExoPlayer's general workaroundTo avoid the secure codec being released when transitioning from encrypted to clear content, ExoPlayer provides the Caveats with the workaround (API design)The flag is specified per I've opened a separate issue to track the silent-dropping behaviour, so we can keep this one focussed: #8957 Cases not solved by the workaroundHowever there are some cases where the decoder is still released during the transition. This means the problem can still occur between two secure periods, or a secure period & a clear period using
(1) is fixed by removing the TODO, but that change breaks when resuming stopped media using foreground mode - so it's not an easy fix. I think it's still worth pursuing, but it may take some time to come up with the right solution. I'm going to repurpose this issue to track it. As I mentioned, (2) isn't really solvable by ExoPlayer in the general case. There may be other cases where the decoder is released during the transition - as we discover them I'll track them as separate issues if it seems like there's an ExoPlayer change we can make to resolve it. Other approaches/related workLooking into the future, I think we should also be asking device manufacturers/SoC vendors if the 'black flash' can be avoided. This obviously doesn't help for all the devices already out in the wild with this behaviour, but it would help reduce the frequency of the problem, and mean that we can detach the surface without triggering a flash. |
Hi @icbaker , thanks for your answer, it's pretty clear for me now.
I was testing with 2.13.3, but now i tested with both 2.14.0 and dev-v2
Maybe i'm missing some change in my tests, because i see the logs:
When transitioning between tracks, even when on the pixel 4, where i don't see the black screen (maybe it's to fast?)... Besides the items in the playlist and setting the shutter color to transparent do i have to change anything else? |
I would expect the video decoder re-initialization (or lack of) to be consistent across all devices (which is what you're seeing) - the difference between devices is about how they behave when the surface is detached from the secure decoder as part of this re-initialization. That's where it seems some devices (like the Pixel 4 and 3a XL that I've tested with) don't show a black screen, while other devices (like Chromecast with Google TV) do. In other words:
I wasn't testing with a shutter color change, I just copied your JSON into the demo app and played it. Thanks for the patch, I just tried with the shutter color change too and still didn't see the decoder re-initialize at the transition though. Would you be able to provide the zip file produced by |
@icbaker I think i might have found the difference.
I was testing the transition by using the nextTrack/previousTrack controls to skip to the next/previous item, because it is closer to the real use case of my app (tune next/previous live channel). Is this the expected behaviour? Do you also see video decoder being release when using the next track button? |
Ah! I was only ever letting the transition happen during normal playback rather than using next/previous track :) Using the next/previous track buttons I see the secure decoder released/re-initialized at the transition point (and this doesn't happen with an insecure decoder). I think this is because when seeking to a different period we always disabled & re-enable the decoder. I'm not 100% sure this is discontinuity related though - I'll tweak the issue title to reflect that. Removing the TODO and associated logic, so secure & insecure decoders are treated the same (as mentioned at the bottom of #8842 (comment)) avoids this re-initialization, so should fix the 'black flash' too. Unfortunately as I said above, that breaks other things - so there's more work needed here before we can make that change. |
@icbaker Ok, thank you. |
This change introduces a third 'state' for `DefaultDrmSessionManager`: It's been fully released (prepareCount == 0) but at least one of its sessions is still active. In this state new acquisitions are rejected (`(pre)acquireSession()` calls will fail) but the machinery to support the existing sessions (ExoMediaDrm and MediaDrmHandler) is kept until they're all released. This change will allow us to remove the TODO in MediaCodecRenderer that resolves Issue: #8842. PiperOrigin-RevId: 376193952
A renderer is disabled (without being reset) in two situations: * When transitioning into a period that starts with a discontinuity * When stopping the player with setForegroundMode(true) Before this change the behaviour of `MediaCodecRenderer` when disabled (but not reset) depended on whether the content being decoded had an associated `DrmSession`: * For content without an associated DRM session the MediaCodec instance was kept alive. * For content with an associated DRM session, the MediaCodec instance was released. This was to prevent the DRM session from staying alive and continuing to make license refresh network requests while the player was stopped in 'foreground mode'. This change removes the second bullet, and keeps MediaCodec instances alive in both the secure and insecure case. This will result in the DRM machinery making occasional license refresh network requests (at a frequency defined by the license policy) while the player is stopped and in 'foreground mode'. This network usage is considered to be a 'limited resource' as described by the `ExoPlayer#setForegroundMode` javadoc. This means that switches between secure content (or between secure and clear content when `MediaItem.drmConfiguration.sessionForClearTypes` indicates a secure decoder should be used for clear content) should keep the same video decoder, thus avoiding the 'black flash' that occurs on some devices when switching the surface away from a secure decoder. Issue: #8842 #minor-release PiperOrigin-RevId: 376825501
This is fixed by the commits referenced above - i'm hoping to include them in the 2.14.1 release. |
This change introduces a third 'state' for `DefaultDrmSessionManager`: It's been fully released (prepareCount == 0) but at least one of its sessions is still active. In this state new acquisitions are rejected (`(pre)acquireSession()` calls will fail) but the machinery to support the existing sessions (ExoMediaDrm and MediaDrmHandler) is kept until they're all released. This change will allow us to remove the TODO in MediaCodecRenderer that resolves Issue: #8842. PiperOrigin-RevId: 376193952
A renderer is disabled (without being reset) in two situations: * When transitioning into a period that starts with a discontinuity * When stopping the player with setForegroundMode(true) Before this change the behaviour of `MediaCodecRenderer` when disabled (but not reset) depended on whether the content being decoded had an associated `DrmSession`: * For content without an associated DRM session the MediaCodec instance was kept alive. * For content with an associated DRM session, the MediaCodec instance was released. This was to prevent the DRM session from staying alive and continuing to make license refresh network requests while the player was stopped in 'foreground mode'. This change removes the second bullet, and keeps MediaCodec instances alive in both the secure and insecure case. This will result in the DRM machinery making occasional license refresh network requests (at a frequency defined by the license policy) while the player is stopped and in 'foreground mode'. This network usage is considered to be a 'limited resource' as described by the `ExoPlayer#setForegroundMode` javadoc. This means that switches between secure content (or between secure and clear content when `MediaItem.drmConfiguration.sessionForClearTypes` indicates a secure decoder should be used for clear content) should keep the same video decoder, thus avoiding the 'black flash' that occurs on some devices when switching the surface away from a secure decoder. Issue: #8842 #minor-release PiperOrigin-RevId: 376825501
Just tested it and it works very well :) Thank you |
Hi.
I am searching way to change stream without black screen.
I made shutter surface transparent with
setShutterBackgroundColor(Color.TRANSPARENT);
and now don't have a problem with HLS clear content, but still have with DASH DRM content
After some investigation figured out black screen happens due to decoder reset with this condition
if (sourceDrmSession != null || codecDrmSession != null) {
// TODO: Do something better with this case.
onReset();
}
So may be exists way to avoid resetting. Or may be exist other way to avoid black screen.
Actually the streams have the same url, but different parameters. So no need to change codec and so on
The text was updated successfully, but these errors were encountered: