Skip to content

Commit aeff51c

Browse files
christoststonihei
authored andcommitted
AsynchronousMediaCodecAdapter: surface queueing errors sooner
The AsynchronousMediaCodecAdapter's queuing thread stores any exceptions raised by MediaCodec and re-throws them on the next call to queueInputBuffer()/queueSecureInputBuffer(). However, if MediaCodec raises and error while queueing, it goes into a failed state and does not announce available input buffers. If there is no input available input buffer, the MediaCodecRenderer will never call queueInputBuffer()/queueSecureInputBuffer(), hence playback is stalled. This change surfaces the queueing error through the adapter's dequeueing methods. PiperOrigin-RevId: 508637346 (cherry picked from commit a5f4651)
1 parent 2794992 commit aeff51c

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,13 @@ public void releaseOutputBuffer(int index, long renderTimeStampNs) {
191191

192192
@Override
193193
public int dequeueInputBufferIndex() {
194+
bufferEnqueuer.maybeThrowException();
194195
return asynchronousMediaCodecCallback.dequeueInputBufferIndex();
195196
}
196197

197198
@Override
198199
public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
200+
bufferEnqueuer.maybeThrowException();
199201
return asynchronousMediaCodecCallback.dequeueOutputBufferIndex(bufferInfo);
200202
}
201203

library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ public void waitUntilQueueingComplete() throws InterruptedException {
162162
blockUntilHandlerThreadIsIdle();
163163
}
164164

165-
private void maybeThrowException() {
165+
/** Throw any exception that occurred on the enqueuer's background queueing thread. */
166+
public void maybeThrowException() {
166167
@Nullable RuntimeException exception = pendingRuntimeException.getAndSet(null);
167168
if (exception != null) {
168169
throw exception;

library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecCallback.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,12 @@ private void flushInternal() {
263263
// else, pendingOutputFormat may already be non-null following a previous flush, and remains
264264
// set in this case.
265265

266+
// mediaCodecException is not reset to null. If the codec has raised an error, then it remains
267+
// in FAILED_STATE even after flushing.
266268
availableInputBuffers.clear();
267269
availableOutputBuffers.clear();
268270
bufferInfos.clear();
269271
formats.clear();
270-
mediaCodecException = null;
271272
}
272273

273274
@GuardedBy("lock")

library/core/src/test/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecAdapterTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ public void dequeueInputBufferIndex_withMediaCodecError_throwsException() throws
8080
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
8181
}
8282

83+
@Test
84+
public void dequeueInputBufferIndex_withPendingQueueingError_throwsException() {
85+
// Force MediaCodec to throw an error by attempting to queue input buffer -1.
86+
adapter.queueInputBuffer(
87+
/* index= */ -1,
88+
/* offset= */ 0,
89+
/* size= */ 0,
90+
/* presentationTimeUs= */ 0,
91+
/* flags= */ 0);
92+
shadowOf(queueingThread.getLooper()).idle();
93+
94+
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
95+
}
96+
8397
@Test
8498
public void dequeueInputBufferIndex_afterShutdown_returnsTryAgainLater() {
8599
adapter.release();
@@ -123,6 +137,20 @@ public void dequeueOutputBufferIndex_withMediaCodecError_throwsException() throw
123137
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
124138
}
125139

140+
@Test
141+
public void dequeueOutputBufferIndex_withPendingQueueingError_throwsException() {
142+
// Force MediaCodec to throw an error by attempting to queue input buffer -1.
143+
adapter.queueInputBuffer(
144+
/* index= */ -1,
145+
/* offset= */ 0,
146+
/* size= */ 0,
147+
/* presentationTimeUs= */ 0,
148+
/* flags= */ 0);
149+
shadowOf(queueingThread.getLooper()).idle();
150+
151+
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
152+
}
153+
126154
@Test
127155
public void dequeueOutputBufferIndex_afterShutdown_returnsTryAgainLater() {
128156
int index = adapter.dequeueInputBufferIndex();

0 commit comments

Comments
 (0)