mirror of
https://github.com/androidx/media.git
synced 2025-05-09 16:40:55 +08:00
Add start() method in MediaCodecAdapter
PiperOrigin-RevId: 288476415
This commit is contained in:
parent
c5535e825e
commit
fb42f818ec
@ -38,7 +38,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
private final MediaCodec codec;
|
||||
@Nullable private IllegalStateException internalException;
|
||||
private boolean flushing;
|
||||
private Runnable onCodecStart;
|
||||
private Runnable codecStartRunnable;
|
||||
|
||||
/**
|
||||
* Create a new {@code AsynchronousMediaCodecAdapter}.
|
||||
@ -55,7 +55,12 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
handler = new Handler(looper);
|
||||
this.codec = codec;
|
||||
this.codec.setCallback(mediaCodecAsyncCallback);
|
||||
onCodecStart = () -> codec.start();
|
||||
codecStartRunnable = codec::start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
codecStartRunnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -105,7 +110,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
flushing = false;
|
||||
mediaCodecAsyncCallback.flush();
|
||||
try {
|
||||
onCodecStart.run();
|
||||
codecStartRunnable.run();
|
||||
} catch (IllegalStateException e) {
|
||||
// Catch IllegalStateException directly so that we don't have to wrap it.
|
||||
internalException = e;
|
||||
@ -115,8 +120,8 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
/* package */ void setOnCodecStart(Runnable onCodecStart) {
|
||||
this.onCodecStart = onCodecStart;
|
||||
/* package */ void setCodecStartRunnable(Runnable codecStartRunnable) {
|
||||
this.codecStartRunnable = codecStartRunnable;
|
||||
}
|
||||
|
||||
private void maybeThrowException() throws IllegalStateException {
|
||||
|
@ -26,7 +26,6 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@ -54,7 +53,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@MonotonicNonNull private Handler handler;
|
||||
private long pendingFlushCount;
|
||||
private @State int state;
|
||||
private Runnable onCodecStart;
|
||||
private Runnable codecStartRunnable;
|
||||
@Nullable private IllegalStateException internalException;
|
||||
|
||||
/**
|
||||
@ -77,31 +76,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
this.codec = codec;
|
||||
this.handlerThread = handlerThread;
|
||||
state = STATE_CREATED;
|
||||
onCodecStart = codec::start;
|
||||
codecStartRunnable = codec::start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the operation of the instance.
|
||||
*
|
||||
* <p>After a call to this method, make sure to call {@link #shutdown()} to terminate the internal
|
||||
* Thread. You can only call this method once during the lifetime of this instance; calling this
|
||||
* method again will throw an {@link IllegalStateException}.
|
||||
*
|
||||
* @throws IllegalStateException If this method has been called already.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
Assertions.checkState(state == STATE_CREATED);
|
||||
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
codec.setCallback(this, handler);
|
||||
codecStartRunnable.run();
|
||||
state = STATE_STARTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int dequeueInputBufferIndex() {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
if (isFlushing()) {
|
||||
return MediaCodec.INFO_TRY_AGAIN_LATER;
|
||||
} else {
|
||||
@ -112,8 +100,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
public synchronized int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
if (isFlushing()) {
|
||||
return MediaCodec.INFO_TRY_AGAIN_LATER;
|
||||
} else {
|
||||
@ -124,15 +110,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
public synchronized MediaFormat getOutputFormat() {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
return mediaCodecAsyncCallback.getOutputFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
codec.flush();
|
||||
++pendingFlushCount;
|
||||
Util.castNonNull(handler).post(this::onFlushCompleted);
|
||||
@ -177,8 +159,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
/* package */ void setOnCodecStart(Runnable onCodecStart) {
|
||||
this.onCodecStart = onCodecStart;
|
||||
/* package */ void setCodecStartRunnable(Runnable codecStartRunnable) {
|
||||
this.codecStartRunnable = codecStartRunnable;
|
||||
}
|
||||
|
||||
private synchronized void onFlushCompleted() {
|
||||
@ -199,7 +181,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
mediaCodecAsyncCallback.flush();
|
||||
try {
|
||||
onCodecStart.run();
|
||||
codecStartRunnable.run();
|
||||
} catch (IllegalStateException e) {
|
||||
internalException = e;
|
||||
} catch (Exception e) {
|
||||
|
@ -31,6 +31,13 @@ import android.media.MediaFormat;
|
||||
*/
|
||||
/* package */ interface MediaCodecAdapter {
|
||||
|
||||
/**
|
||||
* Starts this instance.
|
||||
*
|
||||
* @see MediaCodec#start().
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Returns the next available input buffer index from the underlying {@link MediaCodec} or {@link
|
||||
* MediaCodec#INFO_TRY_AGAIN_LATER} if no such buffer exists.
|
||||
|
@ -995,11 +995,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
} else if (mediaCodecOperationMode == OPERATION_MODE_ASYNCHRONOUS_DEDICATED_THREAD
|
||||
&& Util.SDK_INT >= 23) {
|
||||
codecAdapter = new DedicatedThreadAsyncMediaCodecAdapter(codec, getTrackType());
|
||||
((DedicatedThreadAsyncMediaCodecAdapter) codecAdapter).start();
|
||||
} else if (mediaCodecOperationMode == OPERATION_MODE_ASYNCHRONOUS_DEDICATED_THREAD_MULTI_LOCK
|
||||
&& Util.SDK_INT >= 23) {
|
||||
codecAdapter = new MultiLockAsyncMediaCodecAdapter(codec, getTrackType());
|
||||
((MultiLockAsyncMediaCodecAdapter) codecAdapter).start();
|
||||
} else {
|
||||
codecAdapter = new SynchronousMediaCodecAdapter(codec);
|
||||
}
|
||||
@ -1009,7 +1007,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||
configureCodec(codecInfo, codec, inputFormat, crypto, codecOperatingRate);
|
||||
TraceUtil.endSection();
|
||||
TraceUtil.beginSection("startCodec");
|
||||
codec.start();
|
||||
codecAdapter.start();
|
||||
TraceUtil.endSection();
|
||||
codecInitializedTimestamp = SystemClock.elapsedRealtime();
|
||||
getCodecBuffers(codec);
|
||||
|
@ -27,7 +27,6 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.IntArrayQueue;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayDeque;
|
||||
@ -94,7 +93,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
private final HandlerThread handlerThread;
|
||||
@MonotonicNonNull private Handler handler;
|
||||
private Runnable onCodecStart;
|
||||
private Runnable codecStartRunnable;
|
||||
|
||||
/** Creates a new instance that wraps the specified {@link MediaCodec}. */
|
||||
/* package */ MultiLockAsyncMediaCodecAdapter(MediaCodec codec, int trackType) {
|
||||
@ -114,25 +113,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
codecException = null;
|
||||
state = STATE_CREATED;
|
||||
this.handlerThread = handlerThread;
|
||||
onCodecStart = codec::start;
|
||||
codecStartRunnable = codec::start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the operation of this instance.
|
||||
*
|
||||
* <p>After a call to this method, make sure to call {@link #shutdown()} to terminate the internal
|
||||
* Thread. You can only call this method once during the lifetime of an instance; calling this
|
||||
* method again will throw an {@link IllegalStateException}.
|
||||
*
|
||||
* @throws IllegalStateException If this method has been called already.
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
synchronized (objectStateLock) {
|
||||
Assertions.checkState(state == STATE_CREATED);
|
||||
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
codec.setCallback(this, handler);
|
||||
codecStartRunnable.run();
|
||||
state = STATE_STARTED;
|
||||
}
|
||||
}
|
||||
@ -140,8 +130,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
public int dequeueInputBufferIndex() {
|
||||
synchronized (objectStateLock) {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
if (isFlushing()) {
|
||||
return MediaCodec.INFO_TRY_AGAIN_LATER;
|
||||
} else {
|
||||
@ -154,8 +142,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
public int dequeueOutputBufferIndex(MediaCodec.BufferInfo bufferInfo) {
|
||||
synchronized (objectStateLock) {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
if (isFlushing()) {
|
||||
return MediaCodec.INFO_TRY_AGAIN_LATER;
|
||||
} else {
|
||||
@ -168,8 +154,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
public MediaFormat getOutputFormat() {
|
||||
synchronized (objectStateLock) {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
if (currentFormat == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -181,8 +165,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
public void flush() {
|
||||
synchronized (objectStateLock) {
|
||||
Assertions.checkState(state == STATE_STARTED);
|
||||
|
||||
codec.flush();
|
||||
pendingFlush++;
|
||||
Util.castNonNull(handler).post(this::onFlushComplete);
|
||||
@ -200,8 +182,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
/* package */ void setOnCodecStart(Runnable onCodecStart) {
|
||||
this.onCodecStart = onCodecStart;
|
||||
/* package */ void setCodecStartRunnable(Runnable codecStartRunnable) {
|
||||
this.codecStartRunnable = codecStartRunnable;
|
||||
}
|
||||
|
||||
private int dequeueAvailableInputBufferIndex() {
|
||||
@ -307,7 +289,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
clearAvailableOutput();
|
||||
codecException = null;
|
||||
try {
|
||||
onCodecStart.run();
|
||||
codecStartRunnable.run();
|
||||
} catch (IllegalStateException e) {
|
||||
codecException = e;
|
||||
} catch (Exception e) {
|
||||
|
@ -23,12 +23,18 @@ import android.media.MediaFormat;
|
||||
* A {@link MediaCodecAdapter} that operates the underlying {@link MediaCodec} in synchronous mode.
|
||||
*/
|
||||
/* package */ final class SynchronousMediaCodecAdapter implements MediaCodecAdapter {
|
||||
|
||||
private final MediaCodec codec;
|
||||
|
||||
public SynchronousMediaCodecAdapter(MediaCodec mediaCodec) {
|
||||
this.codec = mediaCodec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
codec.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dequeueInputBufferIndex() {
|
||||
return codec.dequeueInputBuffer(0);
|
||||
|
@ -19,7 +19,7 @@ package com.google.android.exoplayer2.mediacodec;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
@ -29,7 +29,7 @@ import android.os.Looper;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -45,27 +45,32 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
private MediaCodec.BufferInfo bufferInfo;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
public void setUp() throws IOException {
|
||||
handlerThread = new HandlerThread("TestHandlerThread");
|
||||
handlerThread.start();
|
||||
looper = handlerThread.getLooper();
|
||||
codec = MediaCodec.createByCodecName("h264");
|
||||
adapter = new AsynchronousMediaCodecAdapter(codec, looper);
|
||||
adapter.setCodecStartRunnable(() -> {});
|
||||
bufferInfo = new MediaCodec.BufferInfo();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
adapter.shutdown();
|
||||
handlerThread.quit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withoutInputBuffer_returnsTryAgainLater() {
|
||||
adapter.start();
|
||||
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(MediaCodec.INFO_TRY_AGAIN_LATER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withInputBuffer_returnsInputBuffer() {
|
||||
adapter.start();
|
||||
adapter.getMediaCodecCallback().onInputBufferAvailable(codec, /* index=*/ 0);
|
||||
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(0);
|
||||
@ -73,6 +78,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_whileFlushing_returnsTryAgainLater() {
|
||||
adapter.start();
|
||||
adapter.getMediaCodecCallback().onInputBufferAvailable(codec, /* index=*/ 0);
|
||||
adapter.flush();
|
||||
adapter.getMediaCodecCallback().onInputBufferAvailable(codec, /* index=*/ 1);
|
||||
@ -83,9 +89,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_afterFlushCompletes_returnsNextInputBuffer()
|
||||
throws InterruptedException {
|
||||
// Disable calling codec.start() after flush() completes to avoid receiving buffers from the
|
||||
// shadow codec impl
|
||||
adapter.setOnCodecStart(() -> {});
|
||||
adapter.start();
|
||||
Handler handler = new Handler(looper);
|
||||
handler.post(
|
||||
() -> adapter.getMediaCodecCallback().onInputBufferAvailable(codec, /* index=*/ 0));
|
||||
@ -100,28 +104,35 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_afterFlushCompletesWithError_throwsException()
|
||||
throws InterruptedException {
|
||||
adapter.setOnCodecStart(
|
||||
AtomicInteger calls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
throw new IllegalStateException("codec#start() exception");
|
||||
if (calls.incrementAndGet() == 2) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
});
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withoutOutputBuffer_returnsTryAgainLater() {
|
||||
adapter.start();
|
||||
|
||||
assertThat(adapter.dequeueOutputBufferIndex(bufferInfo))
|
||||
.isEqualTo(MediaCodec.INFO_TRY_AGAIN_LATER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withOutputBuffer_returnsOutputBuffer() {
|
||||
adapter.start();
|
||||
MediaCodec.BufferInfo outBufferInfo = new MediaCodec.BufferInfo();
|
||||
outBufferInfo.presentationTimeUs = 10;
|
||||
adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 0, outBufferInfo);
|
||||
@ -132,6 +143,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_whileFlushing_returnsTryAgainLater() {
|
||||
adapter.start();
|
||||
adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 0, bufferInfo);
|
||||
adapter.flush();
|
||||
adapter.getMediaCodecCallback().onOutputBufferAvailable(codec, /* index=*/ 1, bufferInfo);
|
||||
@ -143,9 +155,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_afterFlushCompletes_returnsNextOutputBuffer()
|
||||
throws InterruptedException {
|
||||
// Disable calling codec.start() after flush() completes to avoid receiving buffers from the
|
||||
// shadow codec impl
|
||||
adapter.setOnCodecStart(() -> {});
|
||||
adapter.start();
|
||||
Handler handler = new Handler(looper);
|
||||
MediaCodec.BufferInfo info0 = new MediaCodec.BufferInfo();
|
||||
handler.post(
|
||||
@ -164,31 +174,23 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_afterFlushCompletesWithError_throwsException()
|
||||
throws InterruptedException {
|
||||
adapter.setOnCodecStart(
|
||||
AtomicInteger calls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
throw new RuntimeException("codec#start() exception");
|
||||
if (calls.incrementAndGet() == 2) {
|
||||
throw new RuntimeException("codec#start() exception");
|
||||
}
|
||||
});
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_withoutFormat_throwsException() {
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_withMultipleFormats_returnsFormatsInCorrectOrder() {
|
||||
adapter.start();
|
||||
MediaFormat[] formats = new MediaFormat[10];
|
||||
MediaCodec.Callback mediaCodecCallback = adapter.getMediaCodecCallback();
|
||||
for (int i = 0; i < formats.length; i++) {
|
||||
@ -212,6 +214,7 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_afterFlush_returnsPreviousFormat() throws InterruptedException {
|
||||
adapter.start();
|
||||
MediaFormat format = new MediaFormat();
|
||||
adapter.getMediaCodecCallback().onOutputFormatChanged(codec, format);
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
@ -223,13 +226,13 @@ public class AsynchronousMediaCodecAdapterTest {
|
||||
|
||||
@Test
|
||||
public void shutdown_withPendingFlush_cancelsFlush() throws InterruptedException {
|
||||
AtomicBoolean onCodecStartCalled = new AtomicBoolean(false);
|
||||
Runnable onCodecStart = () -> onCodecStartCalled.set(true);
|
||||
adapter.setOnCodecStart(onCodecStart);
|
||||
AtomicInteger onCodecStartCalled = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> onCodecStartCalled.incrementAndGet());
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(onCodecStartCalled.get()).isFalse();
|
||||
assertThat(onCodecStartCalled.get()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package com.google.android.exoplayer2.mediacodec;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
@ -47,16 +47,18 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
private MediaCodec.BufferInfo bufferInfo = null;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
public void setUp() throws IOException {
|
||||
codec = MediaCodec.createByCodecName("h264");
|
||||
handlerThread = new TestHandlerThread("TestHandlerThread");
|
||||
adapter = new DedicatedThreadAsyncMediaCodecAdapter(codec, handlerThread);
|
||||
adapter.setCodecStartRunnable(() -> {});
|
||||
bufferInfo = new MediaCodec.BufferInfo();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(TestHandlerThread.INSTANCES_STARTED.get()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@ -66,42 +68,15 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_calledTwice_throwsException() {
|
||||
adapter.start();
|
||||
try {
|
||||
adapter.start();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withoutStart_throwsException() {
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withAfterFlushFailed_throwsException()
|
||||
throws InterruptedException {
|
||||
adapter.setOnCodecStart(
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
throw new IllegalStateException("codec#start() exception");
|
||||
if (codecStartCalls.incrementAndGet() == 2) {
|
||||
throw new IllegalStateException("codec#start() exception");
|
||||
}
|
||||
});
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
@ -110,11 +85,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -144,9 +116,6 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withFlushCompletedAndInputBuffer_returnsInputBuffer()
|
||||
throws InterruptedException {
|
||||
// Disable calling codec.start() after flush to avoid receiving buffers from the
|
||||
// shadow codec impl
|
||||
adapter.setOnCodecStart(() -> {});
|
||||
adapter.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
Handler handler = new Handler(looper);
|
||||
@ -169,39 +138,18 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.onMediaCodecError(new IllegalStateException("error from codec"));
|
||||
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withoutStart_throwsException() {
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withInternalException_throwsException()
|
||||
throws InterruptedException {
|
||||
adapter.setOnCodecStart(
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
throw new RuntimeException("codec#start() exception");
|
||||
if (codecStartCalls.incrementAndGet() == 2) {
|
||||
throw new RuntimeException("codec#start() exception");
|
||||
}
|
||||
});
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
@ -210,11 +158,7 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -275,42 +219,14 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.onMediaCodecError(new IllegalStateException("error from codec"));
|
||||
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_withoutStart_throwsException() {
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_withoutFormatReceived_throwsException() {
|
||||
adapter.start();
|
||||
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.getOutputFormat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -351,28 +267,10 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_withoutStarted_throwsException() {
|
||||
try {
|
||||
adapter.flush();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.flush();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_multipleTimes_onlyLastFlushExecutes() throws InterruptedException {
|
||||
AtomicInteger onCodecStartCount = new AtomicInteger(0);
|
||||
adapter.setOnCodecStart(() -> onCodecStartCount.incrementAndGet());
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
|
||||
adapter.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
Handler handler = new Handler(looper);
|
||||
@ -384,23 +282,23 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.flush(); // Enqueues a second flush event
|
||||
handler.post(() -> adapter.onInputBufferAvailable(codec, 3));
|
||||
|
||||
// Progress the looper until the milestoneCount is increased - first flush event
|
||||
// should have been a no-op
|
||||
// Progress the looper until the milestoneCount is increased.
|
||||
// adapter.start() will call codec.start(). First flush event should not call codec.start().
|
||||
ShadowLooper shadowLooper = shadowOf(looper);
|
||||
while (milestoneCount.get() < 1) {
|
||||
shadowLooper.runOneTask();
|
||||
}
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(0);
|
||||
assertThat(codecStartCalls.get()).isEqualTo(1);
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(3);
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(1);
|
||||
assertThat(codecStartCalls.get()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_andImmediatelyShutdown_flushIsNoOp() throws InterruptedException {
|
||||
AtomicInteger onCodecStartCount = new AtomicInteger(0);
|
||||
adapter.setOnCodecStart(() -> onCodecStartCount.incrementAndGet());
|
||||
adapter.setCodecStartRunnable(() -> onCodecStartCount.incrementAndGet());
|
||||
adapter.start();
|
||||
// Obtain looper when adapter is started
|
||||
Looper looper = handlerThread.getLooper();
|
||||
@ -408,8 +306,8 @@ public class DedicatedThreadAsyncMediaCodecAdapterTest {
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, 5, TimeUnit.SECONDS)).isTrue();
|
||||
// only shutdown flushes the MediaCodecAsync handler
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(0);
|
||||
// Only adapter.start() calls onCodecStart.
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(1);
|
||||
}
|
||||
|
||||
private static class TestHandlerThread extends HandlerThread {
|
||||
|
@ -19,7 +19,7 @@ package com.google.android.exoplayer2.mediacodec;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.areEqual;
|
||||
import static com.google.android.exoplayer2.mediacodec.MediaCodecTestUtils.waitUntilAllEventsAreExecuted;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
@ -44,20 +44,21 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
private MultiLockAsyncMediaCodecAdapter adapter;
|
||||
private MediaCodec codec;
|
||||
private MediaCodec.BufferInfo bufferInfo = null;
|
||||
private MediaCodecAsyncCallback mediaCodecAsyncCallbackSpy;
|
||||
private TestHandlerThread handlerThread;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
public void setUp() throws IOException {
|
||||
codec = MediaCodec.createByCodecName("h264");
|
||||
handlerThread = new TestHandlerThread("TestHandlerThread");
|
||||
adapter = new MultiLockAsyncMediaCodecAdapter(codec, handlerThread);
|
||||
adapter.setCodecStartRunnable(() -> {});
|
||||
bufferInfo = new MediaCodec.BufferInfo();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(TestHandlerThread.INSTANCES_STARTED.get()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@ -67,42 +68,15 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_calledTwice_throwsException() {
|
||||
adapter.start();
|
||||
try {
|
||||
adapter.start();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withoutStart_throwsException() {
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withAfterFlushFailed_throwsException()
|
||||
throws InterruptedException {
|
||||
adapter.setOnCodecStart(
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
throw new IllegalStateException("codec#start() exception");
|
||||
if (codecStartCalls.incrementAndGet() == 2) {
|
||||
throw new IllegalStateException("codec#start() exception");
|
||||
}
|
||||
});
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
@ -111,11 +85,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -145,9 +115,6 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
@Test
|
||||
public void dequeueInputBufferIndex_withFlushCompletedAndInputBuffer_returnsInputBuffer()
|
||||
throws InterruptedException {
|
||||
// Disable calling codec.start() after flush to avoid receiving buffers from the
|
||||
// shadow codec impl
|
||||
adapter.setOnCodecStart(() -> {});
|
||||
adapter.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
Handler handler = new Handler(looper);
|
||||
@ -170,39 +137,19 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.onMediaCodecError(new IllegalStateException("error from codec"));
|
||||
|
||||
try {
|
||||
adapter.dequeueInputBufferIndex();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueInputBufferIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withoutStart_throwsException() {
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dequeueOutputBufferIndex_withInternalException_throwsException()
|
||||
throws InterruptedException {
|
||||
adapter.setOnCodecStart(
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(
|
||||
() -> {
|
||||
throw new RuntimeException("codec#start() exception");
|
||||
if (codecStartCalls.incrementAndGet() == 2) {
|
||||
throw new RuntimeException("codec#start() exception");
|
||||
}
|
||||
});
|
||||
adapter.start();
|
||||
adapter.flush();
|
||||
@ -211,11 +158,7 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
waitUntilAllEventsAreExecuted(
|
||||
handlerThread.getLooper(), /* time= */ 5, TimeUnit.SECONDS))
|
||||
.isTrue();
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -276,42 +219,14 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.start();
|
||||
adapter.onMediaCodecError(new IllegalStateException("error from codec"));
|
||||
|
||||
try {
|
||||
adapter.dequeueOutputBufferIndex(bufferInfo);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_withoutStart_throwsException() {
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.dequeueOutputBufferIndex(bufferInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOutputFormat_withoutFormatReceived_throwsException() {
|
||||
adapter.start();
|
||||
|
||||
try {
|
||||
adapter.getOutputFormat();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertThrows(IllegalStateException.class, () -> adapter.getOutputFormat());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -352,28 +267,10 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
assertThat(adapter.getOutputFormat()).isEqualTo(format);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_withoutStarted_throwsException() {
|
||||
try {
|
||||
adapter.flush();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_afterShutdown_throwsException() {
|
||||
adapter.start();
|
||||
adapter.shutdown();
|
||||
try {
|
||||
adapter.flush();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_multipleTimes_onlyLastFlushExecutes() throws InterruptedException {
|
||||
AtomicInteger onCodecStartCount = new AtomicInteger(0);
|
||||
adapter.setOnCodecStart(() -> onCodecStartCount.incrementAndGet());
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
|
||||
adapter.start();
|
||||
Looper looper = handlerThread.getLooper();
|
||||
Handler handler = new Handler(looper);
|
||||
@ -385,23 +282,23 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.flush(); // Enqueues a second flush event
|
||||
handler.post(() -> adapter.onInputBufferAvailable(codec, 3));
|
||||
|
||||
// Progress the looper until the milestoneCount is increased - first flush event
|
||||
// should have been a no-op
|
||||
// Progress the looper until the milestoneCount is increased:
|
||||
// adapter.start() called codec.start() but first flush event should have been a no-op
|
||||
ShadowLooper shadowLooper = shadowOf(looper);
|
||||
while (milestoneCount.get() < 1) {
|
||||
shadowLooper.runOneTask();
|
||||
}
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(0);
|
||||
assertThat(codecStartCalls.get()).isEqualTo(1);
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, /* time= */ 5, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(adapter.dequeueInputBufferIndex()).isEqualTo(3);
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(1);
|
||||
assertThat(codecStartCalls.get()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flush_andImmediatelyShutdown_flushIsNoOp() throws InterruptedException {
|
||||
AtomicInteger onCodecStartCount = new AtomicInteger(0);
|
||||
adapter.setOnCodecStart(() -> onCodecStartCount.incrementAndGet());
|
||||
AtomicInteger codecStartCalls = new AtomicInteger(0);
|
||||
adapter.setCodecStartRunnable(() -> codecStartCalls.incrementAndGet());
|
||||
adapter.start();
|
||||
// Obtain looper when adapter is started.
|
||||
Looper looper = handlerThread.getLooper();
|
||||
@ -409,8 +306,8 @@ public class MultiLockAsyncMediaCodecAdapterTest {
|
||||
adapter.shutdown();
|
||||
|
||||
assertThat(waitUntilAllEventsAreExecuted(looper, 5, TimeUnit.SECONDS)).isTrue();
|
||||
// Only shutdown flushes the MediaCodecAsync handler.
|
||||
assertThat(onCodecStartCount.get()).isEqualTo(0);
|
||||
// Only adapter.start() called codec#start()
|
||||
assertThat(codecStartCalls.get()).isEqualTo(1);
|
||||
}
|
||||
|
||||
private static class TestHandlerThread extends HandlerThread {
|
||||
|
Loading…
x
Reference in New Issue
Block a user