Add flag to force synchronization in async queueing

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

PiperOrigin-RevId: 341431481
This commit is contained in:
christosts 2020-11-09 18:12:39 +00:00 committed by kim-vde
parent 9473fda056
commit 9e98a680da
6 changed files with 71 additions and 8 deletions

View file

@ -92,6 +92,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
private boolean enableDecoderFallback;
private MediaCodecSelector mediaCodecSelector;
private boolean enableAsyncQueueing;
private boolean forceAsyncQueueingSynchronizationWorkaround;
private boolean enableSynchronizeCodecInteractionsWithQueueing;
private boolean enableFloatOutput;
private boolean enableAudioTrackPlaybackParams;
@ -161,6 +162,24 @@ public class DefaultRenderersFactory implements RenderersFactory {
return this;
}
/**
* 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.
*
@ -353,6 +372,8 @@ public class DefaultRenderersFactory implements RenderersFactory {
eventListener,
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
videoRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing);
videoRenderer.experimentalSetForceAsyncQueueingSynchronizationWorkaround(
forceAsyncQueueingSynchronizationWorkaround);
videoRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(
enableSynchronizeCodecInteractionsWithQueueing);
out.add(videoRenderer);
@ -480,6 +501,8 @@ public class DefaultRenderersFactory implements RenderersFactory {
eventListener,
audioSink);
audioRenderer.experimentalSetAsynchronousBufferQueueingEnabled(enableAsyncQueueing);
audioRenderer.experimentalSetForceAsyncQueueingSynchronizationWorkaround(
forceAsyncQueueingSynchronizationWorkaround);
audioRenderer.experimentalSetSynchronizeCodecInteractionsWithQueueingEnabled(
enableSynchronizeCodecInteractionsWithQueueing);
out.add(audioRenderer);

View file

@ -72,11 +72,15 @@ import java.nio.ByteBuffer;
* {@link MediaCodec}.
*/
/* package */ AsynchronousMediaCodecAdapter(
MediaCodec codec, int trackType, boolean synchronizeCodecInteractionsWithQueueing) {
MediaCodec codec,
int trackType,
boolean forceQueueingSynchronizationWorkaround,
boolean synchronizeCodecInteractionsWithQueueing) {
this(
codec,
new HandlerThread(createCallbackThreadLabel(trackType)),
new HandlerThread(createQueueingThreadLabel(trackType)),
forceQueueingSynchronizationWorkaround,
synchronizeCodecInteractionsWithQueueing);
}
@ -85,10 +89,13 @@ 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);
this.bufferEnqueuer =
new AsynchronousMediaCodecBufferEnqueuer(
codec, enqueueingThread, forceQueueingSynchronizationWorkaround);
this.synchronizeCodecInteractionsWithQueueing = synchronizeCodecInteractionsWithQueueing;
this.state = STATE_CREATED;
}

View file

@ -68,18 +68,29 @@ 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) {
this(codec, queueingThread, /* conditionVariable= */ new ConditionVariable());
public AsynchronousMediaCodecBufferEnqueuer(
MediaCodec codec,
HandlerThread queueingThread,
boolean forceQueueingSynchronizationWorkaround) {
this(
codec,
queueingThread,
forceQueueingSynchronizationWorkaround,
/* conditionVariable= */ new ConditionVariable());
}
@VisibleForTesting
/* package */ AsynchronousMediaCodecBufferEnqueuer(
MediaCodec codec, HandlerThread handlerThread, ConditionVariable conditionVariable) {
MediaCodec codec,
HandlerThread handlerThread,
boolean forceQueueingSynchronizationWorkaround,
ConditionVariable conditionVariable) {
this.codec = codec;
this.handlerThread = handlerThread;
this.conditionVariable = conditionVariable;
pendingRuntimeException = new AtomicReference<>();
needsSynchronizationWorkaround = needsSynchronizationWorkaround();
needsSynchronizationWorkaround =
forceQueueingSynchronizationWorkaround || needsSynchronizationWorkaround();
}
/**

View file

@ -348,6 +348,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean waitingForFirstSampleInFormat;
private boolean pendingOutputEndOfStream;
private boolean enableAsynchronousBufferQueueing;
private boolean forceAsyncQueueingSynchronizationWorkaround;
private boolean enableSynchronizeCodecInteractionsWithQueueing;
@Nullable private ExoPlaybackException pendingPlaybackException;
protected DecoderCounters decoderCounters;
@ -417,6 +418,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
enableAsynchronousBufferQueueing = enabled;
}
/**
* 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.
*
@ -1068,7 +1082,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (enableAsynchronousBufferQueueing && Util.SDK_INT >= 23) {
codecAdapter =
new AsynchronousMediaCodecAdapter(
codec, getTrackType(), enableSynchronizeCodecInteractionsWithQueueing);
codec,
getTrackType(),
forceAsyncQueueingSynchronizationWorkaround,
enableSynchronizeCodecInteractionsWithQueueing);
} else {
codecAdapter = new SynchronousMediaCodecAdapter(codec);
}

View file

@ -51,6 +51,7 @@ public class AsynchronousMediaCodecAdapterTest {
codec,
callbackThread,
queueingThread,
/* forceQueueingSynchronizationWorkaround= */ false,
/* synchronizeCodecInteractionsWithQueueing= */ false);
bufferInfo = new MediaCodec.BufferInfo();
}

View file

@ -56,7 +56,11 @@ public class AsynchronousMediaCodecBufferEnqueuerTest {
codec.start();
handlerThread = new TestHandlerThread("TestHandlerThread");
enqueuer =
new AsynchronousMediaCodecBufferEnqueuer(codec, handlerThread, mockConditionVariable);
new AsynchronousMediaCodecBufferEnqueuer(
codec,
handlerThread,
/* forceQueueingSynchronizationWorkaround= */ false,
mockConditionVariable);
}
@After