mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add device-specific opt-ins for async MediaCodecAdapter
Some devices just don't work very well with the synchronous
model, but are currently still excluded from our approximate
API 31 check. This change allows to include additional devices
or device groups by passing in the Context to the default
adapter.
It also adopts the workaround added in ebceee08c6
for Fire TV Smart devices that exhibit this issue.
PiperOrigin-RevId: 614642545
This commit is contained in:
parent
410c0492cc
commit
e4a55844d0
@ -112,7 +112,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||
*/
|
||||
public DefaultRenderersFactory(Context context) {
|
||||
this.context = context;
|
||||
codecAdapterFactory = new DefaultMediaCodecAdapterFactory();
|
||||
codecAdapterFactory = new DefaultMediaCodecAdapterFactory(context);
|
||||
extensionRendererMode = EXTENSION_RENDERER_MODE_OFF;
|
||||
allowedVideoJoiningTimeMs = DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS;
|
||||
mediaCodecSelector = MediaCodecSelector.DEFAULT;
|
||||
|
@ -191,7 +191,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
AudioSink audioSink) {
|
||||
this(
|
||||
context,
|
||||
MediaCodecAdapter.Factory.DEFAULT,
|
||||
MediaCodecAdapter.Factory.getDefault(context),
|
||||
mediaCodecSelector,
|
||||
/* enableDecoderFallback= */ false,
|
||||
eventHandler,
|
||||
@ -219,7 +219,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
AudioSink audioSink) {
|
||||
this(
|
||||
context,
|
||||
MediaCodecAdapter.Factory.DEFAULT,
|
||||
MediaCodecAdapter.Factory.getDefault(context),
|
||||
mediaCodecSelector,
|
||||
enableDecoderFallback,
|
||||
eventHandler,
|
||||
|
@ -17,8 +17,10 @@ package androidx.media3.exoplayer.mediacodec;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
@ -54,12 +56,30 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
||||
|
||||
private static final String TAG = "DMCodecAdapterFactory";
|
||||
|
||||
@Nullable private final Context context;
|
||||
|
||||
private @Mode int asynchronousMode;
|
||||
private boolean asyncCryptoFlagEnabled;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #DefaultMediaCodecAdapterFactory(Context)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultMediaCodecAdapterFactory() {
|
||||
asynchronousMode = MODE_DEFAULT;
|
||||
asyncCryptoFlagEnabled = true;
|
||||
context = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default media codec adapter factory.
|
||||
*
|
||||
* @param context A {@link Context}.
|
||||
*/
|
||||
public DefaultMediaCodecAdapterFactory(Context context) {
|
||||
this.context = context;
|
||||
asynchronousMode = MODE_DEFAULT;
|
||||
asyncCryptoFlagEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,7 +125,7 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
||||
throws IOException {
|
||||
if (Util.SDK_INT >= 23
|
||||
&& (asynchronousMode == MODE_ENABLED
|
||||
|| (asynchronousMode == MODE_DEFAULT && Util.SDK_INT >= 31))) {
|
||||
|| (asynchronousMode == MODE_DEFAULT && shouldUseAsynchronousAdapterInDefaultMode()))) {
|
||||
int trackType = MimeTypes.getTrackType(configuration.format.sampleMimeType);
|
||||
Log.i(
|
||||
TAG,
|
||||
@ -118,4 +138,19 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
||||
}
|
||||
return new SynchronousMediaCodecAdapter.Factory().createAdapter(configuration);
|
||||
}
|
||||
|
||||
private boolean shouldUseAsynchronousAdapterInDefaultMode() {
|
||||
if (Util.SDK_INT >= 31) {
|
||||
// Asynchronous codec interactions started to be reliable for all devices on API 31+.
|
||||
return true;
|
||||
}
|
||||
// Allow additional devices that work reliably with the asynchronous adapter and show
|
||||
// performance problems when not using it.
|
||||
if (context != null
|
||||
&& Util.SDK_INT >= 28
|
||||
&& context.getPackageManager().hasSystemFeature("com.amazon.hardware.tv_screen")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.mediacodec;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
@ -120,9 +121,23 @@ public interface MediaCodecAdapter {
|
||||
/** A factory for {@link MediaCodecAdapter} instances. */
|
||||
interface Factory {
|
||||
|
||||
/** Default factory used in most cases. */
|
||||
/**
|
||||
* @deprecated Use {@link #getDefault} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation") // Forwarding to deprecated method.
|
||||
Factory DEFAULT = new DefaultMediaCodecAdapterFactory();
|
||||
|
||||
/**
|
||||
* Returns the default factory that should be used in most cases.
|
||||
*
|
||||
* @param context A {@link Context}.
|
||||
* @return The default factory.
|
||||
*/
|
||||
static Factory getDefault(Context context) {
|
||||
return new DefaultMediaCodecAdapterFactory(context);
|
||||
}
|
||||
|
||||
/** Creates a {@link MediaCodecAdapter} instance. */
|
||||
MediaCodecAdapter createAdapter(Configuration configuration) throws IOException;
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
int maxDroppedFramesToNotify) {
|
||||
this(
|
||||
context,
|
||||
MediaCodecAdapter.Factory.DEFAULT,
|
||||
MediaCodecAdapter.Factory.getDefault(context),
|
||||
mediaCodecSelector,
|
||||
allowedJoiningTimeMs,
|
||||
/* enableDecoderFallback= */ false,
|
||||
@ -256,7 +256,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
int maxDroppedFramesToNotify) {
|
||||
this(
|
||||
context,
|
||||
MediaCodecAdapter.Factory.DEFAULT,
|
||||
MediaCodecAdapter.Factory.getDefault(context),
|
||||
mediaCodecSelector,
|
||||
allowedJoiningTimeMs,
|
||||
enableDecoderFallback,
|
||||
|
@ -44,6 +44,7 @@ import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.test.utils.FakeSampleStream;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -480,7 +481,7 @@ public class MediaCodecRendererTest {
|
||||
public TestRenderer() {
|
||||
super(
|
||||
C.TRACK_TYPE_AUDIO,
|
||||
MediaCodecAdapter.Factory.DEFAULT,
|
||||
MediaCodecAdapter.Factory.getDefault(ApplicationProvider.getApplicationContext()),
|
||||
/* mediaCodecSelector= */ (mimeType, requiresSecureDecoder, requiresTunnelingDecoder) ->
|
||||
Collections.singletonList(
|
||||
MediaCodecInfo.newInstance(
|
||||
|
@ -81,7 +81,7 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
|
||||
*/
|
||||
public CapturingRenderersFactory(Context context) {
|
||||
this.context = context;
|
||||
this.mediaCodecAdapterFactory = new CapturingMediaCodecAdapter.Factory();
|
||||
this.mediaCodecAdapterFactory = new CapturingMediaCodecAdapter.Factory(context);
|
||||
this.audioSink = new CapturingAudioSink(new DefaultAudioSink.Builder(context).build());
|
||||
this.imageOutput = new CapturingImageOutput();
|
||||
this.imageDecoderFactory = ImageDecoder.Factory.DEFAULT;
|
||||
@ -168,9 +168,11 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
|
||||
|
||||
private static class Factory implements MediaCodecAdapter.Factory, Dumper.Dumpable {
|
||||
|
||||
private final Context context;
|
||||
private final List<CapturingMediaCodecAdapter> constructedAdapters;
|
||||
|
||||
private Factory() {
|
||||
private Factory(Context context) {
|
||||
this.context = context;
|
||||
constructedAdapters = new ArrayList<>();
|
||||
}
|
||||
|
||||
@ -178,7 +180,7 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
|
||||
public MediaCodecAdapter createAdapter(Configuration configuration) throws IOException {
|
||||
CapturingMediaCodecAdapter adapter =
|
||||
new CapturingMediaCodecAdapter(
|
||||
MediaCodecAdapter.Factory.DEFAULT.createAdapter(configuration),
|
||||
MediaCodecAdapter.Factory.getDefault(context).createAdapter(configuration),
|
||||
configuration.codecInfo.name);
|
||||
constructedAdapters.add(adapter);
|
||||
return adapter;
|
||||
|
Loading…
x
Reference in New Issue
Block a user