From 97fbbad6a756ae51336e62e572a416a29f100092 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 3 Feb 2020 11:04:33 +0000 Subject: [PATCH] Avoid unnecessary decoder instantiations on key rotation Issue: #6903 PiperOrigin-RevId: 292884280 --- .../mediacodec/MediaCodecRenderer.java | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) 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 14890b84dd6..41bae90a0f5 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 @@ -1337,7 +1337,9 @@ protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybac if ((sourceDrmSession == null && codecDrmSession != null) || (sourceDrmSession != null && codecDrmSession == null) - || (sourceDrmSession != null && !codecInfo.secure) + || (sourceDrmSession != null + && !codecInfo.secure + && maybeRequiresSecureDecoder(sourceDrmSession, newFormat)) || (Util.SDK_INT < 23 && sourceDrmSession != codecDrmSession)) { // We might need to switch between the clear and protected output paths, or we're using DRM // prior to API level 23 where the codec needs to be re-initialized to switch to the new DRM @@ -1794,9 +1796,22 @@ private void reinitializeCodec() throws ExoPlaybackException { maybeInitCodec(); } + private boolean isDecodeOnlyBuffer(long presentationTimeUs) { + // We avoid using decodeOnlyPresentationTimestamps.remove(presentationTimeUs) because it would + // box presentationTimeUs, creating a Long object that would need to be garbage collected. + int size = decodeOnlyPresentationTimestamps.size(); + for (int i = 0; i < size; i++) { + if (decodeOnlyPresentationTimestamps.get(i) == presentationTimeUs) { + decodeOnlyPresentationTimestamps.remove(i); + return true; + } + } + return false; + } + @RequiresApi(23) private void updateDrmSessionOrReinitializeCodecV23() throws ExoPlaybackException { - FrameworkMediaCrypto sessionMediaCrypto = sourceDrmSession.getMediaCrypto(); + @Nullable FrameworkMediaCrypto sessionMediaCrypto = sourceDrmSession.getMediaCrypto(); if (sessionMediaCrypto == null) { // We'd only expect this to happen if the CDM from which the pending session is obtained needs // provisioning. This is unlikely to happen (it probably requires a switch from one DRM scheme @@ -1830,17 +1845,38 @@ private void updateDrmSessionOrReinitializeCodecV23() throws ExoPlaybackExceptio codecDrainAction = DRAIN_ACTION_NONE; } - private boolean isDecodeOnlyBuffer(long presentationTimeUs) { - // We avoid using decodeOnlyPresentationTimestamps.remove(presentationTimeUs) because it would - // box presentationTimeUs, creating a Long object that would need to be garbage collected. - int size = decodeOnlyPresentationTimestamps.size(); - for (int i = 0; i < size; i++) { - if (decodeOnlyPresentationTimestamps.get(i) == presentationTimeUs) { - decodeOnlyPresentationTimestamps.remove(i); - return true; - } + /** + * Returns whether a {@link DrmSession} may require a secure decoder for a given {@link Format}. + * + * @param drmSession The {@link DrmSession}. + * @param format The {@link Format}. + * @return Whether a secure decoder may be required. + */ + private static boolean maybeRequiresSecureDecoder( + DrmSession drmSession, Format format) { + @Nullable FrameworkMediaCrypto sessionMediaCrypto = drmSession.getMediaCrypto(); + if (sessionMediaCrypto == null) { + // We'd only expect this to happen if the CDM from which the pending session is obtained needs + // provisioning. This is unlikely to happen (it probably requires a switch from one DRM scheme + // to another, where the new CDM hasn't been used before and needs provisioning). Assume that + // a secure decoder may be required. + return true; + } + if (sessionMediaCrypto.forceAllowInsecureDecoderComponents) { + return false; + } + MediaCrypto mediaCrypto; + try { + mediaCrypto = new MediaCrypto(sessionMediaCrypto.uuid, sessionMediaCrypto.sessionId); + } catch (MediaCryptoException e) { + // This shouldn't happen, but if it does then assume that a secure decoder may be required. + return true; + } + try { + return mediaCrypto.requiresSecureDecoderComponent(format.sampleMimeType); + } finally { + mediaCrypto.release(); } - return false; } private static MediaCodec.CryptoInfo getFrameworkCryptoInfo(