From 4c0ba12c40d7ac5c5944fe95bd9b832f4c9149bd Mon Sep 17 00:00:00 2001 From: christosts Date: Thu, 27 Feb 2020 16:17:27 +0000 Subject: [PATCH] Synchronize calls to queueSecureInpuffer() Parallel asynchronous calls to MediaCodec.queueSecureInputBuffer() may produce garbled video on some platforms. This workaround synchronizes calls to MediaCodec.queueSecureInputBuffer() so that only one call is in flight. PiperOrigin-RevId: 297601037 --- .../AsynchronousMediaCodecBufferEnqueuer.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java index 94a606f133..bd03663a4b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java @@ -49,11 +49,14 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque @GuardedBy("MESSAGE_PARAMS_INSTANCE_POOL") private static final ArrayDeque MESSAGE_PARAMS_INSTANCE_POOL = new ArrayDeque<>(); + private static final Object QUEUE_SECURE_LOCK = new Object(); + private final MediaCodec codec; private final HandlerThread handlerThread; private @MonotonicNonNull Handler handler; private final AtomicReference<@NullableType RuntimeException> pendingRuntimeException; private final ConditionVariable conditionVariable; + private final boolean needsSynchronizationWorkaround; private boolean started; /** @@ -76,6 +79,7 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque this.handlerThread = handlerThread; this.conditionVariable = conditionVariable; pendingRuntimeException = new AtomicReference<>(); + needsSynchronizationWorkaround = needsSynchronizationWorkaround(); } @Override @@ -207,7 +211,13 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque private void doQueueSecureInputBuffer( int index, int offset, MediaCodec.CryptoInfo info, long presentationTimeUs, int flags) { try { - codec.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags); + if (needsSynchronizationWorkaround) { + synchronized (QUEUE_SECURE_LOCK) { + codec.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags); + } + } else { + codec.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags); + } } catch (RuntimeException e) { setPendingRuntimeException(e); } @@ -260,6 +270,15 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque } } + /** + * Returns whether this device needs the synchronization workaround when queueing secure input + * buffers (see [Internal: b/149908061]). + */ + private static boolean needsSynchronizationWorkaround() { + String manufacturer = Util.toLowerInvariant(Util.MANUFACTURER); + return manufacturer.contains("samsung") || manufacturer.contains("motorola"); + } + private static String createThreadLabel(int trackType) { StringBuilder labelBuilder = new StringBuilder("MediaCodecInputBufferEnqueuer:"); if (trackType == C.TRACK_TYPE_AUDIO) {