Failure on some Android 11 devices when switching from secure decoder to a different decoder
See original GitHub issueReproduction Steps
Set SimpleExoPlayer to play a MediaItem configured to play using Widevine, with M3U8 mimetype.
Email coming with replacements for <snip>
values.
Exoplayer version: 2.13.2 Android Version: 11
Devices
- Samsung S20 FE 5G (Qualcomm and Exynos chipsets both repro)
- Samsung Notes - (tablet)
- Samsung Galaxy Note - (phone)
- Samsung Galaxy Note Ultra OS
Basic Reproduction Case:
val player = SimpleExoPlayer.Builder(applicationContext).build()
val mediaItem = MediaItem.Builder()
.setUri(<snip>)
.setMimeType(MimeTypes.APPLICATION_M3U8)
.setDrmUuid(C.WIDEVINE_UUID)
.setDrmLicenseUri(<snip>)
.setDrmLicenseRequestHeaders(mutableMapOf(
<snip>
))
.build()
player.addMediaItem(mediaItem)
player.prepare()
player.play()
The content piece is a 45-second snippet of a live playlist setup as VOD. It is 30 seconds of the content which is Widevine CTR encrypted content with a 15-second ad. On the switch to the ad, there is a discontinuity and switch to unencrypted content.
On the failure case:
I/ACodec: [OMX.Exynos.avc.dec] Now Loaded
D/SurfaceUtils: connecting to surface 0x71e621ca70, reason connectToSurface
E/SurfaceUtils: Failed to connect to surface 0x71e621ca70, err -22
E/MediaCodec: nativeWindowConnect returned an error: Invalid argument (-22)
When it does not fail, there is no failure to connect the surface with the code -22
.
This does not occur on all Android 11 devices. And even on the Samsung devices we have seen it occur on, not all of them have a 100% reproduction rate. On a device with a high reproduction rate, we’ve also discovered that setting a logging breakpoint in SynchronousMediaCodecAdapter on the codec.configure
line eliminates the issue.
Additionally, calling setDrmSessionForClearPeriods(true)
on the MediaItem does resolve the error. But raises the question of what other issues this will potentially cause.
Content to follow in email, along with complete Logcat output from both successful and failure cases.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:14 (10 by maintainers)
Top GitHub Comments
The commit above works around this issue by retrying a failed decoder creation after a short delay.
Adding some more info from some brief investigations, and responding to @cdongieux’s request for additional workaround suggestions in https://github.com/google/ExoPlayer/issues/9250#issuecomment-892462112:
I experimented with a couple of hacks in
MediaCodecVideoRenderer
and found they both resolve this issue. We’d like to understand exactly what’s going wrong inside the framework before submitting any workaround like this to the library, but you’re free to make the changes to a local copy of the library (or subclassMediaCodecVideoRenderer
). In both cases I overrodeMediaCodecRenderer#releaseCodec
inMediaCodecVideoRenderer
:Thread.sleep()
calls afterMediaCodec#release()
and before we try and set the surface onto the new codec. In my overriding implementation ofMediaCodecVideoRenderer#releaseCodec()
I calledsuper.releaseCodec()
and thenThread.sleep(60)
. For the content I was using I found that 60ms was long enough, but 45ms wasn’t. Obviously this is really hacky, and hard-coding sleep times like this isn’t really a reliable or production-ready approach. I include it here mainly for completeness.MediaCodecVideoRenderer
already has adummySurface
field we can use (it might be null and need initializing). CallinggetCodec().setOutputSurface(dummySurface)
beforesuper.releaseCodec()
resolved the issue for me.