diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 1e4506c795..2c368ef6fa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -359,6 +359,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private boolean enableAsynchronousBufferQueueing; private boolean forceAsyncQueueingSynchronizationWorkaround; private boolean enableSynchronizeCodecInteractionsWithQueueing; + private boolean enableRecoverableCodecExceptionRetries; @Nullable private ExoPlaybackException pendingPlaybackException; protected DecoderCounters decoderCounters; private long outputStreamStartPositionUs; @@ -465,6 +466,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer { enableSynchronizeCodecInteractionsWithQueueing = enabled; } + /** + * Enable internal player retries for codec exceptions if the underlying platform indicates that + * they are recoverable. + * + *

This method is experimental, and will be renamed or removed in a future release. It should + * only be called before the renderer is used. + */ + public void experimentalSetRecoverableCodecExceptionRetriesEnabled(boolean enabled) { + enableRecoverableCodecExceptionRetries = enabled; + } + @Override @AdaptiveSupport public final int supportsMixedMimeTypeAdaptation() { @@ -836,7 +848,15 @@ public abstract class MediaCodecRenderer extends BaseRenderer { decoderCounters.ensureUpdated(); } catch (IllegalStateException e) { if (isMediaCodecException(e)) { - throw createRendererException(createDecoderException(e, getCodecInfo()), inputFormat); + boolean isRecoverable = + enableRecoverableCodecExceptionRetries + && Util.SDK_INT >= 21 + && isRecoverableMediaCodecExceptionV21(e); + if (isRecoverable) { + releaseCodec(); + } + throw createRendererException( + createDecoderException(e, getCodecInfo()), inputFormat, isRecoverable); } throw e; } @@ -2263,6 +2283,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return error instanceof MediaCodec.CodecException; } + @RequiresApi(21) + private static boolean isRecoverableMediaCodecExceptionV21(IllegalStateException error) { + if (error instanceof MediaCodec.CodecException) { + return ((MediaCodec.CodecException) error).isRecoverable(); + } + return false; + } + /** * Returns whether the decoder is known to fail when flushed. *