mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Reduce flakiness for MediaCodecVideoRendererTests past SDK 30
PiperOrigin-RevId: 715761006
This commit is contained in:
parent
a2016f03c6
commit
62341f31f9
@ -74,8 +74,15 @@ import java.nio.ByteBuffer;
|
|||||||
new HandlerThread(createQueueingThreadLabel(trackType)));
|
new HandlerThread(createQueueingThreadLabel(trackType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
/**
|
||||||
/* package */ Factory(
|
* Creates an factory for {@link AsynchronousMediaCodecAdapter} instances.
|
||||||
|
*
|
||||||
|
* @param callbackThreadSupplier A supplier of {@link HandlerThread} used for {@link MediaCodec}
|
||||||
|
* callbacks invoked when buffers are available.
|
||||||
|
* @param queueingThreadSupplier A supplier of {@link HandlerThread} to use for queueing
|
||||||
|
* buffers.
|
||||||
|
*/
|
||||||
|
public Factory(
|
||||||
Supplier<HandlerThread> callbackThreadSupplier,
|
Supplier<HandlerThread> callbackThreadSupplier,
|
||||||
Supplier<HandlerThread> queueingThreadSupplier) {
|
Supplier<HandlerThread> queueingThreadSupplier) {
|
||||||
this.callbackThreadSupplier = callbackThreadSupplier;
|
this.callbackThreadSupplier = callbackThreadSupplier;
|
||||||
|
@ -19,12 +19,14 @@ import static java.lang.annotation.ElementType.TYPE_USE;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
@ -57,6 +59,8 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
|||||||
private static final String TAG = "DMCodecAdapterFactory";
|
private static final String TAG = "DMCodecAdapterFactory";
|
||||||
|
|
||||||
@Nullable private final Context context;
|
@Nullable private final Context context;
|
||||||
|
@Nullable private final Supplier<HandlerThread> callbackThreadSupplier;
|
||||||
|
@Nullable private final Supplier<HandlerThread> queueingThreadSupplier;
|
||||||
|
|
||||||
private @Mode int asynchronousMode;
|
private @Mode int asynchronousMode;
|
||||||
private boolean asyncCryptoFlagEnabled;
|
private boolean asyncCryptoFlagEnabled;
|
||||||
@ -69,6 +73,8 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
|||||||
asynchronousMode = MODE_DEFAULT;
|
asynchronousMode = MODE_DEFAULT;
|
||||||
asyncCryptoFlagEnabled = false;
|
asyncCryptoFlagEnabled = false;
|
||||||
context = null;
|
context = null;
|
||||||
|
callbackThreadSupplier = null;
|
||||||
|
queueingThreadSupplier = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,9 +83,26 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
|||||||
* @param context A {@link Context}.
|
* @param context A {@link Context}.
|
||||||
*/
|
*/
|
||||||
public DefaultMediaCodecAdapterFactory(Context context) {
|
public DefaultMediaCodecAdapterFactory(Context context) {
|
||||||
|
this(context, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the default media codec adapter factory.
|
||||||
|
*
|
||||||
|
* @param context A {@link Context}.
|
||||||
|
* @param callbackThreadSupplier A supplier of {@link HandlerThread} used for {@link MediaCodec}
|
||||||
|
* callbacks invoked when buffers are available.
|
||||||
|
* @param queueingThreadSupplier A supplier of {@link HandlerThread} to use for queueing buffers.
|
||||||
|
*/
|
||||||
|
public DefaultMediaCodecAdapterFactory(
|
||||||
|
Context context,
|
||||||
|
@Nullable Supplier<HandlerThread> callbackThreadSupplier,
|
||||||
|
@Nullable Supplier<HandlerThread> queueingThreadSupplier) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
asynchronousMode = MODE_DEFAULT;
|
asynchronousMode = MODE_DEFAULT;
|
||||||
asyncCryptoFlagEnabled = false;
|
asyncCryptoFlagEnabled = false;
|
||||||
|
this.callbackThreadSupplier = callbackThreadSupplier;
|
||||||
|
this.queueingThreadSupplier = queueingThreadSupplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,7 +155,10 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
|||||||
"Creating an asynchronous MediaCodec adapter for track type "
|
"Creating an asynchronous MediaCodec adapter for track type "
|
||||||
+ Util.getTrackTypeString(trackType));
|
+ Util.getTrackTypeString(trackType));
|
||||||
AsynchronousMediaCodecAdapter.Factory factory =
|
AsynchronousMediaCodecAdapter.Factory factory =
|
||||||
new AsynchronousMediaCodecAdapter.Factory(trackType);
|
callbackThreadSupplier != null && queueingThreadSupplier != null
|
||||||
|
? new AsynchronousMediaCodecAdapter.Factory(
|
||||||
|
callbackThreadSupplier, queueingThreadSupplier)
|
||||||
|
: new AsynchronousMediaCodecAdapter.Factory(trackType);
|
||||||
factory.experimentalSetAsyncCryptoFlagEnabled(asyncCryptoFlagEnabled);
|
factory.experimentalSetAsyncCryptoFlagEnabled(asyncCryptoFlagEnabled);
|
||||||
return factory.createAdapter(configuration);
|
return factory.createAdapter(configuration);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ import android.media.MediaCodecInfo.CodecProfileLevel;
|
|||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@ -61,6 +62,7 @@ import androidx.media3.exoplayer.RendererConfiguration;
|
|||||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||||
|
import androidx.media3.exoplayer.mediacodec.DefaultMediaCodecAdapterFactory;
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecAdapter;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecAdapter;
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecInfo;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecInfo;
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
|
||||||
@ -89,6 +91,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -106,7 +109,6 @@ import org.robolectric.shadows.ShadowLooper;
|
|||||||
import org.robolectric.shadows.ShadowSystemClock;
|
import org.robolectric.shadows.ShadowSystemClock;
|
||||||
|
|
||||||
/** Unit test for {@link MediaCodecVideoRenderer}. */
|
/** Unit test for {@link MediaCodecVideoRenderer}. */
|
||||||
@Config(sdk = 30) // TODO: b/382017156 - Remove this when the tests pass on API 31+.
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class MediaCodecVideoRendererTest {
|
public class MediaCodecVideoRendererTest {
|
||||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||||
@ -146,6 +148,9 @@ public class MediaCodecVideoRendererTest {
|
|||||||
/* forceDisableAdaptive= */ false,
|
/* forceDisableAdaptive= */ false,
|
||||||
/* forceSecure= */ false);
|
/* forceSecure= */ false);
|
||||||
|
|
||||||
|
private final AtomicReference<HandlerThread> callbackThread = new AtomicReference<>();
|
||||||
|
private final AtomicReference<HandlerThread> queueingThread = new AtomicReference<>();
|
||||||
|
|
||||||
private Looper testMainLooper;
|
private Looper testMainLooper;
|
||||||
private Surface surface;
|
private Surface surface;
|
||||||
private MediaCodecVideoRenderer mediaCodecVideoRenderer;
|
private MediaCodecVideoRenderer mediaCodecVideoRenderer;
|
||||||
@ -170,12 +175,22 @@ public class MediaCodecVideoRendererTest {
|
|||||||
/* vendor= */ false,
|
/* vendor= */ false,
|
||||||
/* forceDisableAdaptive= */ false,
|
/* forceDisableAdaptive= */ false,
|
||||||
/* forceSecure= */ false));
|
/* forceSecure= */ false));
|
||||||
|
|
||||||
mediaCodecVideoRenderer =
|
mediaCodecVideoRenderer =
|
||||||
new MediaCodecVideoRenderer(
|
new MediaCodecVideoRenderer(
|
||||||
ApplicationProvider.getApplicationContext(),
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
new DefaultMediaCodecAdapterFactory(
|
||||||
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
() -> {
|
||||||
|
callbackThread.set(new HandlerThread("MCVRTest:MediaCodecAsyncAdapter"));
|
||||||
|
return callbackThread.get();
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
queueingThread.set(new HandlerThread("MCVRTest:MediaCodecQueueingThread"));
|
||||||
|
return queueingThread.get();
|
||||||
|
}),
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
/* allowedJoiningTimeMs= */ 0,
|
/* allowedJoiningTimeMs= */ 0,
|
||||||
|
/* enableDecoderFallback= */ false,
|
||||||
/* eventHandler= */ new Handler(testMainLooper),
|
/* eventHandler= */ new Handler(testMainLooper),
|
||||||
/* eventListener= */ eventListener,
|
/* eventListener= */ eventListener,
|
||||||
/* maxDroppedFramesToNotify= */ 1) {
|
/* maxDroppedFramesToNotify= */ 1) {
|
||||||
@ -230,11 +245,15 @@ public class MediaCodecVideoRendererTest {
|
|||||||
|
|
||||||
mediaCodecVideoRenderer.start();
|
mediaCodecVideoRenderer.start();
|
||||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
mediaCodecVideoRenderer.render(40_000, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(40_000, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
|
}
|
||||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||||
int posUs = 80_001; // Ensures buffer will be 30_001us late.
|
int posUs = 80_001; // Ensures buffer will be 30_001us late.
|
||||||
while (!mediaCodecVideoRenderer.isEnded()) {
|
while (!mediaCodecVideoRenderer.isEnded()) {
|
||||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
posUs += 40_000;
|
posUs += 40_000;
|
||||||
}
|
}
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
@ -273,7 +292,9 @@ public class MediaCodecVideoRendererTest {
|
|||||||
|
|
||||||
mediaCodecVideoRenderer.start();
|
mediaCodecVideoRenderer.start();
|
||||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
while (decoderCounters.renderedOutputBufferCount == 0) {
|
||||||
mediaCodecVideoRenderer.render(10_000, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(10_000, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
}
|
||||||
// Ensure existing buffer will be 1 second late and new (not yet read) buffers are available
|
// Ensure existing buffer will be 1 second late and new (not yet read) buffers are available
|
||||||
// to be skipped and to skip to in the input stream.
|
// to be skipped and to skip to in the input stream.
|
||||||
int posUs = 1_020_000;
|
int posUs = 1_020_000;
|
||||||
@ -322,13 +343,16 @@ public class MediaCodecVideoRendererTest {
|
|||||||
/* positionUs= */ 0,
|
/* positionUs= */ 0,
|
||||||
/* joining= */ true,
|
/* joining= */ true,
|
||||||
/* mayRenderStartOfStream= */ false,
|
/* mayRenderStartOfStream= */ false,
|
||||||
/* startPositionUs= */ 50_000,
|
/* startPositionUs= */ 0,
|
||||||
/* offsetUs= */ 0,
|
/* offsetUs= */ 0,
|
||||||
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
||||||
|
|
||||||
mediaCodecVideoRenderer.start();
|
mediaCodecVideoRenderer.start();
|
||||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
|
}
|
||||||
int posUs = 20_001; // Ensures buffer will be 29_999us early.
|
int posUs = 20_001; // Ensures buffer will be 29_999us early.
|
||||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
@ -360,12 +384,15 @@ public class MediaCodecVideoRendererTest {
|
|||||||
/* positionUs= */ 0,
|
/* positionUs= */ 0,
|
||||||
/* joining= */ true,
|
/* joining= */ true,
|
||||||
/* mayRenderStartOfStream= */ false,
|
/* mayRenderStartOfStream= */ false,
|
||||||
/* startPositionUs= */ 50_000,
|
/* startPositionUs= */ 0,
|
||||||
/* offsetUs= */ 0,
|
/* offsetUs= */ 0,
|
||||||
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
/* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object()));
|
||||||
|
|
||||||
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
mediaCodecVideoRenderer.setCurrentStreamFinal();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
|
}
|
||||||
int posUs = 20_001; // Ensures buffer will be 29_999us early.
|
int posUs = 20_001; // Ensures buffer will be 29_999us early.
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(posUs, SystemClock.elapsedRealtime() * 1000);
|
||||||
@ -876,9 +903,10 @@ public class MediaCodecVideoRendererTest {
|
|||||||
|
|
||||||
int positionUs = 20_000;
|
int positionUs = 20_000;
|
||||||
do {
|
do {
|
||||||
ShadowSystemClock.advanceBy(10, TimeUnit.MILLISECONDS);
|
ShadowSystemClock.advanceBy(2, TimeUnit.MILLISECONDS);
|
||||||
mediaCodecVideoRenderer.render(positionUs, msToUs(SystemClock.elapsedRealtime()));
|
mediaCodecVideoRenderer.render(positionUs, msToUs(SystemClock.elapsedRealtime()));
|
||||||
positionUs += 10_000;
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
|
positionUs += 2_000;
|
||||||
} while (!mediaCodecVideoRenderer.isEnded());
|
} while (!mediaCodecVideoRenderer.isEnded());
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
|
|
||||||
@ -956,12 +984,15 @@ public class MediaCodecVideoRendererTest {
|
|||||||
new MediaSource.MediaPeriodId(new Object()));
|
new MediaSource.MediaPeriodId(new Object()));
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
|
|
||||||
verify(eventListener).onRenderedFirstFrame(eq(surface), /* renderTimeMs= */ anyLong());
|
verify(eventListener).onRenderedFirstFrame(eq(surface), /* renderTimeMs= */ anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Config(minSdk = 30)
|
||||||
@Test
|
@Test
|
||||||
public void enable_withoutMayRenderStartOfStream_doesNotRenderFirstFrameBeforeStart()
|
public void enable_withoutMayRenderStartOfStream_doesNotRenderFirstFrameBeforeStart()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@ -987,6 +1018,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
new MediaSource.MediaPeriodId(new Object()));
|
new MediaSource.MediaPeriodId(new Object()));
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
}
|
}
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
|
|
||||||
@ -1018,6 +1050,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
mediaCodecVideoRenderer.start();
|
mediaCodecVideoRenderer.start();
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
}
|
}
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
|
|
||||||
@ -1051,6 +1084,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
new MediaSource.MediaPeriodId(new Object()));
|
new MediaSource.MediaPeriodId(new Object()));
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
}
|
}
|
||||||
shadowOf(testMainLooper).idle();
|
shadowOf(testMainLooper).idle();
|
||||||
|
|
||||||
@ -1100,6 +1134,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(
|
mediaCodecVideoRenderer.render(
|
||||||
/* positionUs= */ i * 10, SystemClock.elapsedRealtime() * 1000);
|
/* positionUs= */ i * 10, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
if (!replacedStream && mediaCodecVideoRenderer.hasReadStreamToEnd()) {
|
if (!replacedStream && mediaCodecVideoRenderer.hasReadStreamToEnd()) {
|
||||||
mediaCodecVideoRenderer.replaceStream(
|
mediaCodecVideoRenderer.replaceStream(
|
||||||
new Format[] {VIDEO_H264},
|
new Format[] {VIDEO_H264},
|
||||||
@ -1164,6 +1199,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(
|
mediaCodecVideoRenderer.render(
|
||||||
/* positionUs= */ i * 10, SystemClock.elapsedRealtime() * 1000);
|
/* positionUs= */ i * 10, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
if (!replacedStream && mediaCodecVideoRenderer.hasReadStreamToEnd()) {
|
if (!replacedStream && mediaCodecVideoRenderer.hasReadStreamToEnd()) {
|
||||||
mediaCodecVideoRenderer.replaceStream(
|
mediaCodecVideoRenderer.replaceStream(
|
||||||
new Format[] {VIDEO_H264},
|
new Format[] {VIDEO_H264},
|
||||||
@ -1212,6 +1248,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
// Render at the original start position.
|
// Render at the original start position.
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(/* positionUs= */ 1000, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(/* positionUs= */ 1000, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the position to before the original start position and render at this position.
|
// Reset the position to before the original start position and render at this position.
|
||||||
@ -1221,6 +1258,7 @@ public class MediaCodecVideoRendererTest {
|
|||||||
fakeSampleStream.writeData(/* startPositionUs= */ 500);
|
fakeSampleStream.writeData(/* startPositionUs= */ 500);
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
mediaCodecVideoRenderer.render(/* positionUs= */ 500, SystemClock.elapsedRealtime() * 1000);
|
mediaCodecVideoRenderer.render(/* positionUs= */ 500, SystemClock.elapsedRealtime() * 1000);
|
||||||
|
maybeIdleAsynchronousMediaCodecAdapterThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert that we rendered the first frame after the reset.
|
// Assert that we rendered the first frame after the reset.
|
||||||
@ -1573,6 +1611,15 @@ public class MediaCodecVideoRendererTest {
|
|||||||
assertThat(surfacesSet).containsExactly(newSurface);
|
assertThat(surfacesSet).containsExactly(newSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeIdleAsynchronousMediaCodecAdapterThreads() {
|
||||||
|
if (queueingThread.get() != null) {
|
||||||
|
shadowOf(queueingThread.get().getLooper()).idle();
|
||||||
|
}
|
||||||
|
if (callbackThread.get() != null) {
|
||||||
|
shadowOf(callbackThread.get().getLooper()).idle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static CodecCapabilities createCodecCapabilities(int profile, int level) {
|
private static CodecCapabilities createCodecCapabilities(int profile, int level) {
|
||||||
CodecCapabilities capabilities = new CodecCapabilities();
|
CodecCapabilities capabilities = new CodecCapabilities();
|
||||||
capabilities.profileLevels = new CodecProfileLevel[] {new CodecProfileLevel()};
|
capabilities.profileLevels = new CodecProfileLevel[] {new CodecProfileLevel()};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user