Retry creating a MediaCodec instance in MediaCodecRenderer
It's been observed that some devices fail when releasing a secure codec attached to a surface and immediately trying to create a new codec (secure or insecure) attached to the same surface. This change catches all exceptions thrown during codec creation, sleeps for a short time, and then retries the codec creation. This is observed to fix the problem (we believe this is because it allows enough time for some background part of the previous codec release operation to complete). This change should have no effect on the control flow when codec creation succeeds first time. It will introduce a slight delay when creating the preferred codec fails (while we sleep and retry), which will either delay propagating a permanent error or attempting to initialize a fallback decoder. We can't avoid the extra delay to instantiating the fallback decoder because we can't know whether we expect the second attempt to create the preferred decoder to succeed or fail. The benefit to always retrying the preferred decoder creation (fixing playback failures) outweighs the unfortunate additional delay to instantiating fallback decoders. Issue: google/ExoPlayer#8696 #minor-release PiperOrigin-RevId: 414671743
This commit is contained in:
parent
fcdb96f0f1
commit
07352a4585
@ -14,6 +14,10 @@
|
|||||||
`TrackGroup` constructor. This fixes a crash when resuming playback
|
`TrackGroup` constructor. This fixes a crash when resuming playback
|
||||||
after backgrounding the app with an active track override
|
after backgrounding the app with an active track override
|
||||||
((#9718)[https://github.com/google/ExoPlayer/issues/9718]).
|
((#9718)[https://github.com/google/ExoPlayer/issues/9718]).
|
||||||
|
* Sleep and retry when creating a `MediaCodec` instance fails. This works
|
||||||
|
around an issue that occurs on some devices when switching a surface
|
||||||
|
from a secure codec to another codec
|
||||||
|
(#8696)[https://github.com/google/ExoPlayer/issues/8696].
|
||||||
* Android 12 compatibility:
|
* Android 12 compatibility:
|
||||||
* Upgrade the Cast extension to depend on
|
* Upgrade the Cast extension to depend on
|
||||||
`com.google.android.gms:play-services-cast-framework:20.1.0`. Earlier
|
`com.google.android.gms:play-services-cast-framework:20.1.0`. Earlier
|
||||||
|
@ -976,13 +976,27 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
|
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaCodecInfo preferredCodecInfo = availableCodecInfos.peekFirst();
|
||||||
while (codec == null) {
|
while (codec == null) {
|
||||||
MediaCodecInfo codecInfo = availableCodecInfos.peekFirst();
|
MediaCodecInfo codecInfo = availableCodecInfos.peekFirst();
|
||||||
if (!shouldInitCodec(codecInfo)) {
|
if (!shouldInitCodec(codecInfo)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
initCodec(codecInfo, crypto);
|
try {
|
||||||
|
initCodec(codecInfo, crypto);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (codecInfo == preferredCodecInfo) {
|
||||||
|
// If creating the preferred decoder failed then sleep briefly before retrying.
|
||||||
|
// Workaround for [internal b/191966399].
|
||||||
|
// See also https://github.com/google/ExoPlayer/issues/8696.
|
||||||
|
Log.w(TAG, "Preferred decoder instantiation failed. Sleeping for 50ms then retrying.");
|
||||||
|
Thread.sleep(/* millis= */ 50);
|
||||||
|
initCodec(codecInfo, crypto);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, "Failed to initialize decoder: " + codecInfo, e);
|
Log.w(TAG, "Failed to initialize decoder: " + codecInfo, e);
|
||||||
// This codec failed to initialize, so fall back to the next codec in the list (if any). We
|
// This codec failed to initialize, so fall back to the next codec in the list (if any). We
|
||||||
@ -1060,13 +1074,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
codecOperatingRate = CODEC_OPERATING_RATE_UNSET;
|
codecOperatingRate = CODEC_OPERATING_RATE_UNSET;
|
||||||
}
|
}
|
||||||
codecInitializingTimestamp = SystemClock.elapsedRealtime();
|
codecInitializingTimestamp = SystemClock.elapsedRealtime();
|
||||||
TraceUtil.beginSection("createCodec:" + codecName);
|
|
||||||
MediaCodecAdapter.Configuration configuration =
|
MediaCodecAdapter.Configuration configuration =
|
||||||
getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate);
|
getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate);
|
||||||
if (Util.SDK_INT >= 31) {
|
if (Util.SDK_INT >= 31) {
|
||||||
Api31.setLogSessionIdToMediaCodecFormat(configuration, getPlayerId());
|
Api31.setLogSessionIdToMediaCodecFormat(configuration, getPlayerId());
|
||||||
}
|
}
|
||||||
codec = codecAdapterFactory.createAdapter(configuration);
|
try {
|
||||||
|
TraceUtil.beginSection("createCodec:" + codecName);
|
||||||
|
codec = codecAdapterFactory.createAdapter(configuration);
|
||||||
|
} finally {
|
||||||
|
TraceUtil.endSection();
|
||||||
|
}
|
||||||
codecInitializedTimestamp = SystemClock.elapsedRealtime();
|
codecInitializedTimestamp = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
this.codecInfo = codecInfo;
|
this.codecInfo = codecInfo;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user