Commit 9e98a680 by christosts Committed by kim-vde

Add flag to force synchronization in async queueing

Add experiment flag to force synchronization between
queueing threads in AsynchronousMediaCodecAdapter.

PiperOrigin-RevId: 341431481
parent 9473fda0
...@@ -92,6 +92,7 @@ public class DefaultRenderersFactory implements RenderersFactory { ...@@ -92,6 +92,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
private boolean enableDecoderFallback; private boolean enableDecoderFallback;
private MediaCodecSelector mediaCodecSelector; private MediaCodecSelector mediaCodecSelector;
private boolean enableAsyncQueueing; private boolean enableAsyncQueueing;
private boolean forceAsyncQueueingSynchronizationWorkaround;
private boolean enableSynchronizeCodecInteractionsWithQueueing; private boolean enableSynchronizeCodecInteractionsWithQueueing;
private boolean enableFloatOutput; private boolean enableFloatOutput;
private boolean enableAudioTrackPlaybackParams; private boolean enableAudioTrackPlaybackParams;
...@@ -162,6 +163,24 @@ public class DefaultRenderersFactory implements RenderersFactory { ...@@ -162,6 +163,24 @@ public class DefaultRenderersFactory implements RenderersFactory {
} }
/** /**
* Enable the asynchronous queueing synchronization workaround.
*
* <p>When enabled, the queueing threads for {@link MediaCodec} instances will synchronize on a
* shared lock when submitting buffers to the respective {@link MediaCodec}.
*
* <p>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;
return this;
}
/**
* Enable synchronizing codec interactions with asynchronous buffer queueing. * Enable synchronizing codec interactions with asynchronous buffer queueing.
* *
* <p>This method is experimental, and will be renamed or removed in a future release. * <p>This method is experimental, and will be renamed or removed in a future release.
...@@ -353,6 +372,8 @@ public class DefaultRenderersFactory implements RenderersFactory { ...@@ -353,6 +372,8 @@ public class DefaultRenderersFactory implements RenderersFactory {
eventListener, eventListener,
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
videoRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing); videoRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing);
videoRenderer.experimentalSetForceAsyncQueueingSynchronizationWorkaround(
forceAsyncQueueingSynchronizationWorkaround);
videoRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled( videoRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(
enableSynchronizeCodecInteractionsWithQueueing); enableSynchronizeCodecInteractionsWithQueueing);
out.add(videoRenderer); out.add(videoRenderer);
...@@ -480,6 +501,8 @@ public class DefaultRenderersFactory implements RenderersFactory { ...@@ -480,6 +501,8 @@ public class DefaultRenderersFactory implements RenderersFactory {
eventListener, eventListener,
audioSink); audioSink);
audioRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing); audioRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing);
audioRenderer.experimentalSetForceAsyncQueueingSynchronizationWorkaround(
forceAsyncQueueingSynchronizationWorkaround);
audioRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled( audioRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(
enableSynchronizeCodecInteractionsWithQueueing); enableSynchronizeCodecInteractionsWithQueueing);
out.add(audioRenderer); out.add(audioRenderer);
......
...@@ -72,11 +72,15 @@ import java.nio.ByteBuffer; ...@@ -72,11 +72,15 @@ import java.nio.ByteBuffer;
* {@link MediaCodec}. * {@link MediaCodec}.
*/ */
/* package */ AsynchronousMediaCodecAdapter( /* package */ AsynchronousMediaCodecAdapter(
MediaCodec codec, int trackType, boolean synchronizeCodecInteractionsWithQueueing) { MediaCodec codec,
int trackType,
boolean forceQueueingSynchronizationWorkaround,
boolean synchronizeCodecInteractionsWithQueueing) {
this( this(
codec, codec,
new HandlerThread(createCallbackThreadLabel(trackType)), new HandlerThread(createCallbackThreadLabel(trackType)),
new HandlerThread(createQueueingThreadLabel(trackType)), new HandlerThread(createQueueingThreadLabel(trackType)),
forceQueueingSynchronizationWorkaround,
synchronizeCodecInteractionsWithQueueing); synchronizeCodecInteractionsWithQueueing);
} }
...@@ -85,10 +89,13 @@ import java.nio.ByteBuffer; ...@@ -85,10 +89,13 @@ import java.nio.ByteBuffer;
MediaCodec codec, MediaCodec codec,
HandlerThread callbackThread, HandlerThread callbackThread,
HandlerThread enqueueingThread, HandlerThread enqueueingThread,
boolean forceQueueingSynchronizationWorkaround,
boolean synchronizeCodecInteractionsWithQueueing) { boolean synchronizeCodecInteractionsWithQueueing) {
this.codec = codec; this.codec = codec;
this.asynchronousMediaCodecCallback = new AsynchronousMediaCodecCallback(callbackThread); this.asynchronousMediaCodecCallback = new AsynchronousMediaCodecCallback(callbackThread);
this.bufferEnqueuer = new AsynchronousMediaCodecBufferEnqueuer(codec, enqueueingThread); this.bufferEnqueuer =
new AsynchronousMediaCodecBufferEnqueuer(
codec, enqueueingThread, forceQueueingSynchronizationWorkaround);
this.synchronizeCodecInteractionsWithQueueing = synchronizeCodecInteractionsWithQueueing; this.synchronizeCodecInteractionsWithQueueing = synchronizeCodecInteractionsWithQueueing;
this.state = STATE_CREATED; this.state = STATE_CREATED;
} }
......
...@@ -68,18 +68,29 @@ class AsynchronousMediaCodecBufferEnqueuer { ...@@ -68,18 +68,29 @@ class AsynchronousMediaCodecBufferEnqueuer {
* @param codec The {@link MediaCodec} to submit input buffers to. * @param codec The {@link MediaCodec} to submit input buffers to.
* @param queueingThread The {@link HandlerThread} to use for queueing buffers. * @param queueingThread The {@link HandlerThread} to use for queueing buffers.
*/ */
public AsynchronousMediaCodecBufferEnqueuer(MediaCodec codec, HandlerThread queueingThread) { public AsynchronousMediaCodecBufferEnqueuer(
this(codec, queueingThread, /* conditionVariable= */ new ConditionVariable()); MediaCodec codec,
HandlerThread queueingThread,
boolean forceQueueingSynchronizationWorkaround) {
this(
codec,
queueingThread,
forceQueueingSynchronizationWorkaround,
/* conditionVariable= */ new ConditionVariable());
} }
@VisibleForTesting @VisibleForTesting
/* package */ AsynchronousMediaCodecBufferEnqueuer( /* package */ AsynchronousMediaCodecBufferEnqueuer(
MediaCodec codec, HandlerThread handlerThread, ConditionVariable conditionVariable) { MediaCodec codec,
HandlerThread handlerThread,
boolean forceQueueingSynchronizationWorkaround,
ConditionVariable conditionVariable) {
this.codec = codec; this.codec = codec;
this.handlerThread = handlerThread; this.handlerThread = handlerThread;
this.conditionVariable = conditionVariable; this.conditionVariable = conditionVariable;
pendingRuntimeException = new AtomicReference<>(); pendingRuntimeException = new AtomicReference<>();
needsSynchronizationWorkaround = needsSynchronizationWorkaround(); needsSynchronizationWorkaround =
forceQueueingSynchronizationWorkaround || needsSynchronizationWorkaround();
} }
/** /**
......
...@@ -348,6 +348,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -348,6 +348,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean waitingForFirstSampleInFormat; private boolean waitingForFirstSampleInFormat;
private boolean pendingOutputEndOfStream; private boolean pendingOutputEndOfStream;
private boolean enableAsynchronousBufferQueueing; private boolean enableAsynchronousBufferQueueing;
private boolean forceAsyncQueueingSynchronizationWorkaround;
private boolean enableSynchronizeCodecInteractionsWithQueueing; private boolean enableSynchronizeCodecInteractionsWithQueueing;
@Nullable private ExoPlaybackException pendingPlaybackException; @Nullable private ExoPlaybackException pendingPlaybackException;
protected DecoderCounters decoderCounters; protected DecoderCounters decoderCounters;
...@@ -418,6 +419,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -418,6 +419,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Enable the asynchronous queueing synchronization workaround.
*
* <p>When enabled, the queueing threads for {@link MediaCodec} instance will synchronize on a
* shared lock when submitting buffers to the respective {@link MediaCodec}.
*
* <p>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;
}
/**
* Enable synchronizing codec interactions with asynchronous buffer queueing. * Enable synchronizing codec interactions with asynchronous buffer queueing.
* *
* <p>When enabled, codec interactions will wait until all input buffers pending for asynchronous * <p>When enabled, codec interactions will wait until all input buffers pending for asynchronous
...@@ -1068,7 +1082,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1068,7 +1082,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) { if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) {
codecAdapter = codecAdapter =
new AsynchronousMediaCodecAdapter( new AsynchronousMediaCodecAdapter(
codec, getTrackType(), enableSynchronizeCodecInteractionsWithQueueing); codec,
getTrackType(),
forceAsyncQueueingSynchronizationWorkaround,
enableSynchronizeCodecInteractionsWithQueueing);
} else { } else {
codecAdapter = new SynchronousMediaCodecAdapter(codec); codecAdapter = new SynchronousMediaCodecAdapter(codec);
} }
......
...@@ -51,6 +51,7 @@ public class AsynchronousMediaCodecAdapterTest { ...@@ -51,6 +51,7 @@ public class AsynchronousMediaCodecAdapterTest {
codec, codec,
callbackThread, callbackThread,
queueingThread, queueingThread,
/* forceQueueingSynchronizationWorkaround= */ false,
/* synchronizeCodecInteractionsWithQueueing= */ false); /* synchronizeCodecInteractionsWithQueueing= */ false);
bufferInfo = new MediaCodec.BufferInfo(); bufferInfo = new MediaCodec.BufferInfo();
} }
......
...@@ -56,7 +56,11 @@ public class AsynchronousMediaCodecBufferEnqueuerTest { ...@@ -56,7 +56,11 @@ public class AsynchronousMediaCodecBufferEnqueuerTest {
codec.start(); codec.start();
handlerThread = new TestHandlerThread("TestHandlerThread"); handlerThread = new TestHandlerThread("TestHandlerThread");
enqueuer = enqueuer =
new AsynchronousMediaCodecBufferEnqueuer(codec, handlerThread, mockConditionVariable); new AsynchronousMediaCodecBufferEnqueuer(
codec,
handlerThread,
/* forceQueueingSynchronizationWorkaround= */ false,
mockConditionVariable);
} }
@After @After
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment