From 7a2c7c3297ea7dbe265cab215974178648c7d009 Mon Sep 17 00:00:00 2001 From: christosts Date: Mon, 4 Oct 2021 16:57:12 +0100 Subject: [PATCH] Make asynchronous queueing non-experimental This change makes asynchronous queueing non-experimental, it enables the feature by default on devices with API level >= 31 (Android 12+) and exposes APIs for apps to either fully opt-in or opt-out from the feature. The choice to use or not asynchronous queueing is moved out of MediaCodecRenderer to a new MediaCodecAdapter factory, the DefaultMediaCodecAdapterFactory. This is because, at the moment, if an app passes a custom adapter factory to a MediaCodecRenderer and then enables asynchronous queueing on it, the custom adapter factory is not used but this is not visible to the user. The default behavior of DefaultMediaCodecAdapterFactory is to create asynchronous MediaCodec adapters for devices with API level >= 31 (Android 12+), and synchronous MediaCodec adapters on devices with older API versions. DefaultMediaCodecAdapterFactory exposes methods to force enable or force disable the use of asynchronous adapters so that applications can enable asynchronous queueing on devices with API versions before 31 (but not before 23), or fully disable the feature. For applications that build MediaCodecRenderers directly, they will need to create a DefaultMediaCodecAdapterFactory and pass it to the renderer constructor. For applications that rely on the DefaultRenderersFactory, additional methods have been added on the DefaultRenderersFactory to control enabling/disabling asynchronous queueing. Issue: #6348 PiperOrigin-RevId: 400733506 --- RELEASENOTES.md | 8 +- .../exoplayer2/DefaultRenderersFactory.java | 49 +++----- .../AsynchronousMediaCodecAdapter.java | 22 +--- .../AsynchronousMediaCodecBufferEnqueuer.java | 38 ++----- .../DefaultMediaCodecAdapterFactory.java | 105 ++++++++++++++++++ .../mediacodec/MediaCodecAdapter.java | 3 +- .../mediacodec/MediaCodecRenderer.java | 59 +--------- .../AsynchronousMediaCodecAdapterTest.java | 1 - ...nchronousMediaCodecBufferEnqueuerTest.java | 6 +- 9 files changed, 143 insertions(+), 148 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/mediacodec/DefaultMediaCodecAdapterFactory.java diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 793a5bacef..c880d831e8 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -3,6 +3,10 @@ ### dev-v2 (not yet released) * Core Library: + * Enable MediaCodec asynchronous queueing by default on devices with API + level >= 31. Add methods in `DefaultMediaCodecRendererFactory` and + `DefaultRenderersFactory` to force enable or force disable asynchronous + queueing ([6348](https://github.com/google/ExoPlayer/issues/6348)). * Move `com.google.android.exoplayer2.device.DeviceInfo` to `com.google.android.exoplayer2.DeviceInfo`. * Move `com.google.android.exoplayer2.drm.DecryptionException` to @@ -13,8 +17,8 @@ `GlUtil.glAssertionsEnabled` instead. * Move `Player.addListener(EventListener)` and `Player.removeListener(EventListener)` out of `Player` into subclasses. - * Fix `mediaMetadata` being reset when media is - repeated ([#9458](https://github.com/google/ExoPlayer/issues/9458)). + * Fix `mediaMetadata` being reset when media is repeated + ([#9458](https://github.com/google/ExoPlayer/issues/9458)). * Video: * Fix bug in `MediaCodecVideoRenderer` that resulted in re-using a released `Surface` when playing without an app-provided `Surface` diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java index d4284842df..03ccc297a8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java @@ -28,6 +28,7 @@ import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink.DefaultAudioProcessorChain; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; +import com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.MetadataRenderer; @@ -87,13 +88,11 @@ public class DefaultRenderersFactory implements RenderersFactory { private static final String TAG = "DefaultRenderersFactory"; private final Context context; + private final DefaultMediaCodecAdapterFactory codecAdapterFactory; @ExtensionRendererMode private int extensionRendererMode; private long allowedVideoJoiningTimeMs; private boolean enableDecoderFallback; private MediaCodecSelector mediaCodecSelector; - private boolean enableAsyncQueueing; - private boolean forceAsyncQueueingSynchronizationWorkaround; - private boolean enableSynchronizeCodecInteractionsWithQueueing; private boolean enableFloatOutput; private boolean enableAudioTrackPlaybackParams; private boolean enableOffload; @@ -101,6 +100,7 @@ public class DefaultRenderersFactory implements RenderersFactory { /** @param context A {@link Context}. */ public DefaultRenderersFactory(Context context) { this.context = context; + codecAdapterFactory = new DefaultMediaCodecAdapterFactory(); extensionRendererMode = EXTENSION_RENDERER_MODE_OFF; allowedVideoJoiningTimeMs = DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS; mediaCodecSelector = MediaCodecSelector.DEFAULT; @@ -130,6 +130,7 @@ public class DefaultRenderersFactory implements RenderersFactory { this.extensionRendererMode = extensionRendererMode; this.allowedVideoJoiningTimeMs = allowedVideoJoiningTimeMs; mediaCodecSelector = MediaCodecSelector.DEFAULT; + codecAdapterFactory = new DefaultMediaCodecAdapterFactory(); } /** @@ -149,34 +150,28 @@ public class DefaultRenderersFactory implements RenderersFactory { } /** - * Enable asynchronous buffer queueing for both {@link MediaCodecAudioRenderer} and {@link - * MediaCodecVideoRenderer} instances. + * Enables {@link com.google.android.exoplayer2.mediacodec.MediaCodecRenderer} instances to + * operate their {@link MediaCodec} in asynchronous mode and perform asynchronous queueing. * - *

This method is experimental, and will be renamed or removed in a future release. + *

This feature can be enabled only on devices with API versions >= 23. For devices with + * older API versions, this method is a no-op. * - * @param enabled Whether asynchronous queueing is enabled. * @return This factory, for convenience. */ - public DefaultRenderersFactory experimentalSetAsynchronousBufferQueueingEnabled(boolean enabled) { - enableAsyncQueueing = enabled; + public DefaultRenderersFactory forceEnableMediaCodecAsynchronousQueueing() { + codecAdapterFactory.forceEnableAsynchronous(); return this; } /** - * Enable the asynchronous queueing synchronization workaround. + * Disables {@link com.google.android.exoplayer2.mediacodec.MediaCodecRenderer} instances from + * operating their {@link MediaCodec} in asynchronous mode and perform asynchronous queueing. + * {@link MediaCodec} instances will be operated synchronous mode. * - *

When enabled, the queueing threads for {@link MediaCodec} instances will synchronize on a - * shared lock when submitting buffers to the respective {@link MediaCodec}. - * - *

This method is experimental, and will be renamed or removed in a future release. - * - * @param enabled Whether the asynchronous queueing synchronization workaround is enabled by - * default. * @return This factory, for convenience. */ - public DefaultRenderersFactory experimentalSetForceAsyncQueueingSynchronizationWorkaround( - boolean enabled) { - this.forceAsyncQueueingSynchronizationWorkaround = enabled; + public DefaultRenderersFactory forceDisableMediaCodecAsynchronousQueueing() { + codecAdapterFactory.forceDisableAsynchronous(); return this; } @@ -191,7 +186,7 @@ public class DefaultRenderersFactory implements RenderersFactory { */ public DefaultRenderersFactory experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled( boolean enabled) { - enableSynchronizeCodecInteractionsWithQueueing = enabled; + codecAdapterFactory.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(enabled); return this; } @@ -373,17 +368,13 @@ public class DefaultRenderersFactory implements RenderersFactory { MediaCodecVideoRenderer videoRenderer = new MediaCodecVideoRenderer( context, + codecAdapterFactory, mediaCodecSelector, allowedVideoJoiningTimeMs, enableDecoderFallback, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); - videoRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing); - videoRenderer.experimentalSetForceAsyncQueueingSynchronizationWorkaround( - forceAsyncQueueingSynchronizationWorkaround); - videoRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled( - enableSynchronizeCodecInteractionsWithQueueing); out.add(videoRenderer); if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) { @@ -497,16 +488,12 @@ public class DefaultRenderersFactory implements RenderersFactory { MediaCodecAudioRenderer audioRenderer = new MediaCodecAudioRenderer( context, + codecAdapterFactory, mediaCodecSelector, enableDecoderFallback, eventHandler, eventListener, audioSink); - audioRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing); - audioRenderer.experimentalSetForceAsyncQueueingSynchronizationWorkaround( - forceAsyncQueueingSynchronizationWorkaround); - audioRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled( - enableSynchronizeCodecInteractionsWithQueueing); out.add(audioRenderer); if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapter.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapter.java index 5832144f5a..8302bd2903 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapter.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapter.java @@ -49,15 +49,11 @@ import java.nio.ByteBuffer; public static final class Factory implements MediaCodecAdapter.Factory { private final Supplier callbackThreadSupplier; private final Supplier queueingThreadSupplier; - private final boolean forceQueueingSynchronizationWorkaround; private final boolean synchronizeCodecInteractionsWithQueueing; /** Creates a factory for codecs handling the specified {@link C.TrackType track type}. */ public Factory(@C.TrackType int trackType) { - this( - trackType, - /* forceQueueingSynchronizationWorkaround= */ false, - /* synchronizeCodecInteractionsWithQueueing= */ false); + this(trackType, /* synchronizeCodecInteractionsWithQueueing= */ false); } /** @@ -65,23 +61,17 @@ import java.nio.ByteBuffer; * * @param trackType One of {@link C#TRACK_TYPE_AUDIO} or {@link C#TRACK_TYPE_VIDEO}. Used for * labelling the internal thread accordingly. - * @param forceQueueingSynchronizationWorkaround Whether the queueing synchronization workaround - * will be enabled by default or only for the predefined devices. * @param synchronizeCodecInteractionsWithQueueing Whether the adapter should synchronize {@link * MediaCodec} interactions with asynchronous buffer queueing. When {@code true}, codec * interactions will wait until all input buffers pending queueing wil be submitted to the * {@link MediaCodec}. */ - public Factory( - @C.TrackType int trackType, - boolean forceQueueingSynchronizationWorkaround, - boolean synchronizeCodecInteractionsWithQueueing) { + public Factory(@C.TrackType int trackType, boolean synchronizeCodecInteractionsWithQueueing) { this( /* callbackThreadSupplier= */ () -> new HandlerThread(createCallbackThreadLabel(trackType)), /* queueingThreadSupplier= */ () -> new HandlerThread(createQueueingThreadLabel(trackType)), - forceQueueingSynchronizationWorkaround, synchronizeCodecInteractionsWithQueueing); } @@ -89,11 +79,9 @@ import java.nio.ByteBuffer; /* package */ Factory( Supplier callbackThreadSupplier, Supplier queueingThreadSupplier, - boolean forceQueueingSynchronizationWorkaround, boolean synchronizeCodecInteractionsWithQueueing) { this.callbackThreadSupplier = callbackThreadSupplier; this.queueingThreadSupplier = queueingThreadSupplier; - this.forceQueueingSynchronizationWorkaround = forceQueueingSynchronizationWorkaround; this.synchronizeCodecInteractionsWithQueueing = synchronizeCodecInteractionsWithQueueing; } @@ -111,7 +99,6 @@ import java.nio.ByteBuffer; codec, callbackThreadSupplier.get(), queueingThreadSupplier.get(), - forceQueueingSynchronizationWorkaround, synchronizeCodecInteractionsWithQueueing); TraceUtil.endSection(); codecAdapter.initialize( @@ -153,13 +140,10 @@ import java.nio.ByteBuffer; MediaCodec codec, HandlerThread callbackThread, HandlerThread enqueueingThread, - boolean forceQueueingSynchronizationWorkaround, boolean synchronizeCodecInteractionsWithQueueing) { this.codec = codec; this.asynchronousMediaCodecCallback = new AsynchronousMediaCodecCallback(callbackThread); - this.bufferEnqueuer = - new AsynchronousMediaCodecBufferEnqueuer( - codec, enqueueingThread, forceQueueingSynchronizationWorkaround); + this.bufferEnqueuer = new AsynchronousMediaCodecBufferEnqueuer(codec, enqueueingThread); this.synchronizeCodecInteractionsWithQueueing = synchronizeCodecInteractionsWithQueueing; this.state = STATE_CREATED; } 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 8a2bb9a9bc..1605c669e7 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 @@ -30,7 +30,6 @@ import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.decoder.CryptoInfo; import com.google.android.exoplayer2.util.ConditionVariable; import com.google.android.exoplayer2.util.Util; -import com.google.common.base.Ascii; import java.util.ArrayDeque; import java.util.Arrays; import java.util.concurrent.atomic.AtomicReference; @@ -60,7 +59,6 @@ class AsynchronousMediaCodecBufferEnqueuer { private @MonotonicNonNull Handler handler; private final AtomicReference<@NullableType RuntimeException> pendingRuntimeException; private final ConditionVariable conditionVariable; - private final boolean needsSynchronizationWorkaround; private boolean started; /** @@ -69,29 +67,17 @@ class AsynchronousMediaCodecBufferEnqueuer { * @param codec The {@link MediaCodec} to submit input buffers to. * @param queueingThread The {@link HandlerThread} to use for queueing buffers. */ - public AsynchronousMediaCodecBufferEnqueuer( - MediaCodec codec, - HandlerThread queueingThread, - boolean forceQueueingSynchronizationWorkaround) { - this( - codec, - queueingThread, - forceQueueingSynchronizationWorkaround, - /* conditionVariable= */ new ConditionVariable()); + public AsynchronousMediaCodecBufferEnqueuer(MediaCodec codec, HandlerThread queueingThread) { + this(codec, queueingThread, /* conditionVariable= */ new ConditionVariable()); } @VisibleForTesting /* package */ AsynchronousMediaCodecBufferEnqueuer( - MediaCodec codec, - HandlerThread handlerThread, - boolean forceQueueingSynchronizationWorkaround, - ConditionVariable conditionVariable) { + MediaCodec codec, HandlerThread handlerThread, ConditionVariable conditionVariable) { this.codec = codec; this.handlerThread = handlerThread; this.conditionVariable = conditionVariable; pendingRuntimeException = new AtomicReference<>(); - needsSynchronizationWorkaround = - forceQueueingSynchronizationWorkaround || needsSynchronizationWorkaround(); } /** @@ -247,11 +233,10 @@ class AsynchronousMediaCodecBufferEnqueuer { private void doQueueSecureInputBuffer( int index, int offset, MediaCodec.CryptoInfo info, long presentationTimeUs, int flags) { try { - if (needsSynchronizationWorkaround) { - synchronized (QUEUE_SECURE_LOCK) { - codec.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags); - } - } else { + // Synchronize calls to MediaCodec.queueSecureInputBuffer() to avoid race conditions inside + // the crypto module when audio and video are sharing the same DRM session + // (see [Internal: b/149908061]). + synchronized (QUEUE_SECURE_LOCK) { codec.queueSecureInputBuffer(index, offset, info, presentationTimeUs, flags); } } catch (RuntimeException e) { @@ -299,15 +284,6 @@ class AsynchronousMediaCodecBufferEnqueuer { } } - /** - * Returns whether this device needs the synchronization workaround when queueing secure input - * buffers (see [Internal: b/149908061]). - */ - private static boolean needsSynchronizationWorkaround() { - String manufacturer = Ascii.toLowerCase(Util.MANUFACTURER); - return manufacturer.contains("samsung") || manufacturer.contains("motorola"); - } - /** Performs a deep copy of {@code cryptoInfo} to {@code frameworkCryptoInfo}. */ private static void copy( CryptoInfo cryptoInfo, android.media.MediaCodec.CryptoInfo frameworkCryptoInfo) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/DefaultMediaCodecAdapterFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/DefaultMediaCodecAdapterFactory.java new file mode 100644 index 0000000000..f371d92598 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/DefaultMediaCodecAdapterFactory.java @@ -0,0 +1,105 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.mediacodec; + +import androidx.annotation.IntDef; +import com.google.android.exoplayer2.util.Log; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The default {@link MediaCodecAdapter.Factory}. + * + *

By default, this factory {@link #createAdapter creates} {@link AsynchronousMediaCodecAdapter} + * instances on devices with API level >= 31 (Android 12+). For devices with older API versions, + * the default behavior is to create {@link SynchronousMediaCodecAdapter} instances. The factory + * offers APIs to force the creation of {@link AsynchronousMediaCodecAdapter} (applicable for + * devices with API >= 23) or {@link SynchronousMediaCodecAdapter} instances. + */ +public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.Factory { + + @Retention(RetentionPolicy.SOURCE) + @IntDef({MODE_DEFAULT, MODE_ENABLED, MODE_DISABLED}) + private @interface Mode {} + + private static final int MODE_DEFAULT = 0; + private static final int MODE_ENABLED = 1; + private static final int MODE_DISABLED = 2; + + private static final String TAG = "DefaultMediaCodecAdapterFactory"; + + @Mode private int asynchronousMode; + private boolean enableSynchronizeCodecInteractionsWithQueueing; + + public DefaultMediaCodecAdapterFactory() { + asynchronousMode = MODE_DEFAULT; + } + + /** + * Forces this factory to always create {@link AsynchronousMediaCodecAdapter} instances, provided + * the device API level is >= 23. For devices with API level < 23, the factory will create + * {@link SynchronousMediaCodecAdapter SynchronousMediaCodecAdapters}. + * + * @return This factory, for convenience. + */ + public DefaultMediaCodecAdapterFactory forceEnableAsynchronous() { + asynchronousMode = MODE_ENABLED; + return this; + } + + /** + * Forces the factory to always create {@link SynchronousMediaCodecAdapter} instances. + * + * @return This factory, for convenience. + */ + public DefaultMediaCodecAdapterFactory forceDisableAsynchronous() { + asynchronousMode = MODE_DISABLED; + return this; + } + + /** + * Enable synchronizing codec interactions with asynchronous buffer queueing. + * + *

This method is experimental, and will be renamed or removed in a future release. + * + * @param enabled Whether codec interactions will be synchronized with asynchronous buffer + * queueing. + */ + public void experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(boolean enabled) { + enableSynchronizeCodecInteractionsWithQueueing = enabled; + } + + @Override + public MediaCodecAdapter createAdapter(MediaCodecAdapter.Configuration configuration) + throws IOException { + if ((asynchronousMode == MODE_ENABLED && Util.SDK_INT >= 23) + || (asynchronousMode == MODE_DEFAULT && Util.SDK_INT >= 31)) { + int trackType = MimeTypes.getTrackType(configuration.format.sampleMimeType); + Log.i( + TAG, + "Creating an asynchronous MediaCodec adapter for track type " + + Util.getTrackTypeString(trackType)); + AsynchronousMediaCodecAdapter.Factory factory = + new AsynchronousMediaCodecAdapter.Factory( + trackType, enableSynchronizeCodecInteractionsWithQueueing); + return factory.createAdapter(configuration); + } + return new SynchronousMediaCodecAdapter.Factory().createAdapter(configuration); + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.java index 2353baf516..ffd7758680 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecAdapter.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.google.android.exoplayer2.mediacodec; import android.media.MediaCodec; @@ -179,7 +178,7 @@ public interface MediaCodecAdapter { interface Factory { /** Default factory used in most cases. */ - Factory DEFAULT = new SynchronousMediaCodecAdapter.Factory(); + Factory DEFAULT = new DefaultMediaCodecAdapterFactory(); /** Creates a {@link MediaCodecAdapter} instance. */ MediaCodecAdapter createAdapter(Configuration configuration) throws IOException; 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 0836102ae6..389e675c59 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 @@ -350,9 +350,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private boolean outputStreamEnded; private boolean waitingForFirstSampleInFormat; private boolean pendingOutputEndOfStream; - private boolean enableAsynchronousBufferQueueing; - private boolean forceAsyncQueueingSynchronizationWorkaround; - private boolean enableSynchronizeCodecInteractionsWithQueueing; @Nullable private ExoPlaybackException pendingPlaybackException; protected DecoderCounters decoderCounters; private long outputStreamStartPositionUs; @@ -428,46 +425,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { this.renderTimeLimitMs = renderTimeLimitMs; } - /** - * Enables asynchronous input buffer queueing. - * - *

Operates the underlying {@link MediaCodec} in asynchronous mode and submits input buffers - * from a separate thread to unblock the playback thread. - * - *

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 experimentalSetAsynchronousBufferQueueingEnabled(boolean enabled) { - enableAsynchronousBufferQueueing = enabled; - } - - /** - * Enables the asynchronous queueing synchronization workaround. - * - *

When enabled, the queueing threads for {@link MediaCodec} instance will synchronize on a - * shared lock when submitting buffers to the respective {@link MediaCodec}. - * - *

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 experimentalSetForceAsyncQueueingSynchronizationWorkaround(boolean enabled) { - this.forceAsyncQueueingSynchronizationWorkaround = enabled; - } - - /** - * Enables synchronizing codec interactions with asynchronous buffer queueing. - * - *

When enabled, codec interactions will wait until all input buffers pending for asynchronous - * queueing are submitted to the {@link MediaCodec} first. This method is effective only if {@link - * #experimentalSetAsynchronousBufferQueueingEnabled asynchronous buffer queueing} is enabled. - * - *

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 experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(boolean enabled) { - enableSynchronizeCodecInteractionsWithQueueing = enabled; - } - @Override @AdaptiveSupport public final int supportsMixedMimeTypeAdaptation() { @@ -520,7 +477,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { * no codec operating rate should be set. * @return The parameters needed to call {@link MediaCodec#configure}. */ - @Nullable protected abstract MediaCodecAdapter.Configuration getMediaCodecConfiguration( MediaCodecInfo codecInfo, Format format, @@ -1092,7 +1048,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private void initCodec(MediaCodecInfo codecInfo, MediaCrypto crypto) throws Exception { long codecInitializingTimestamp; long codecInitializedTimestamp; - @Nullable MediaCodecAdapter codecAdapter = null; String codecName = codecInfo.name; float codecOperatingRate = Util.SDK_INT < 23 @@ -1105,19 +1060,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { TraceUtil.beginSection("createCodec:" + codecName); MediaCodecAdapter.Configuration configuration = getMediaCodecConfiguration(codecInfo, inputFormat, crypto, codecOperatingRate); - if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) { - codecAdapter = - new AsynchronousMediaCodecAdapter.Factory( - getTrackType(), - forceAsyncQueueingSynchronizationWorkaround, - enableSynchronizeCodecInteractionsWithQueueing) - .createAdapter(configuration); - } else { - codecAdapter = codecAdapterFactory.createAdapter(configuration); - } + codec = codecAdapterFactory.createAdapter(configuration); codecInitializedTimestamp = SystemClock.elapsedRealtime(); - this.codec = codecAdapter; this.codecInfo = codecInfo; this.codecOperatingRate = codecOperatingRate; codecInputFormat = inputFormat; @@ -1133,7 +1078,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecNeedsMonoChannelCountWorkaround(codecName, codecInputFormat); codecNeedsEosPropagation = codecNeedsEosPropagationWorkaround(codecInfo) || getCodecNeedsEosPropagation(); - if (codecAdapter.needsReconfiguration()) { + if (codec.needsReconfiguration()) { this.codecReconfigured = true; this.codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING; this.codecNeedsAdaptationWorkaroundBuffer = diff --git a/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapterTest.java b/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapterTest.java index 94410ab11f..9aa2b5f3ba 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapterTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapterTest.java @@ -54,7 +54,6 @@ public class AsynchronousMediaCodecAdapterTest { new AsynchronousMediaCodecAdapter.Factory( /* callbackThreadSupplier= */ () -> callbackThread, /* queueingThreadSupplier= */ () -> queueingThread, - /* forceQueueingSynchronizationWorkaround= */ false, /* synchronizeCodecInteractionsWithQueueing= */ false) .createAdapter(configuration); bufferInfo = new MediaCodec.BufferInfo(); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuerTest.java index e5fdd126f4..f3a08df819 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuerTest.java @@ -56,11 +56,7 @@ public class AsynchronousMediaCodecBufferEnqueuerTest { codec.start(); handlerThread = new TestHandlerThread("TestHandlerThread"); enqueuer = - new AsynchronousMediaCodecBufferEnqueuer( - codec, - handlerThread, - /* forceQueueingSynchronizationWorkaround= */ false, - mockConditionVariable); + new AsynchronousMediaCodecBufferEnqueuer(codec, handlerThread, mockConditionVariable); } @After