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) {
|
public DefaultRenderersFactory(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
codecAdapterFactory = new DefaultMediaCodecAdapterFactory();
|
codecAdapterFactory = new DefaultMediaCodecAdapterFactory(context);
|
||||||
extensionRendererMode = EXTENSION_RENDERER_MODE_OFF;
|
extensionRendererMode = EXTENSION_RENDERER_MODE_OFF;
|
||||||
allowedVideoJoiningTimeMs = DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS;
|
allowedVideoJoiningTimeMs = DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS;
|
||||||
mediaCodecSelector = MediaCodecSelector.DEFAULT;
|
mediaCodecSelector = MediaCodecSelector.DEFAULT;
|
||||||
|
@ -191,7 +191,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||||||
AudioSink audioSink) {
|
AudioSink audioSink) {
|
||||||
this(
|
this(
|
||||||
context,
|
context,
|
||||||
MediaCodecAdapter.Factory.DEFAULT,
|
MediaCodecAdapter.Factory.getDefault(context),
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
/* enableDecoderFallback= */ false,
|
/* enableDecoderFallback= */ false,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
@ -219,7 +219,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||||||
AudioSink audioSink) {
|
AudioSink audioSink) {
|
||||||
this(
|
this(
|
||||||
context,
|
context,
|
||||||
MediaCodecAdapter.Factory.DEFAULT,
|
MediaCodecAdapter.Factory.getDefault(context),
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
enableDecoderFallback,
|
enableDecoderFallback,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
|
@ -17,8 +17,10 @@ package androidx.media3.exoplayer.mediacodec;
|
|||||||
|
|
||||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
|
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;
|
||||||
@ -54,12 +56,30 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
|||||||
|
|
||||||
private static final String TAG = "DMCodecAdapterFactory";
|
private static final String TAG = "DMCodecAdapterFactory";
|
||||||
|
|
||||||
|
@Nullable private final Context context;
|
||||||
|
|
||||||
private @Mode int asynchronousMode;
|
private @Mode int asynchronousMode;
|
||||||
private boolean asyncCryptoFlagEnabled;
|
private boolean asyncCryptoFlagEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #DefaultMediaCodecAdapterFactory(Context)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public DefaultMediaCodecAdapterFactory() {
|
public DefaultMediaCodecAdapterFactory() {
|
||||||
asynchronousMode = MODE_DEFAULT;
|
asynchronousMode = MODE_DEFAULT;
|
||||||
asyncCryptoFlagEnabled = true;
|
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 {
|
throws IOException {
|
||||||
if (Util.SDK_INT >= 23
|
if (Util.SDK_INT >= 23
|
||||||
&& (asynchronousMode == MODE_ENABLED
|
&& (asynchronousMode == MODE_ENABLED
|
||||||
|| (asynchronousMode == MODE_DEFAULT && Util.SDK_INT >= 31))) {
|
|| (asynchronousMode == MODE_DEFAULT && shouldUseAsynchronousAdapterInDefaultMode()))) {
|
||||||
int trackType = MimeTypes.getTrackType(configuration.format.sampleMimeType);
|
int trackType = MimeTypes.getTrackType(configuration.format.sampleMimeType);
|
||||||
Log.i(
|
Log.i(
|
||||||
TAG,
|
TAG,
|
||||||
@ -118,4 +138,19 @@ public final class DefaultMediaCodecAdapterFactory implements MediaCodecAdapter.
|
|||||||
}
|
}
|
||||||
return new SynchronousMediaCodecAdapter.Factory().createAdapter(configuration);
|
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;
|
package androidx.media3.exoplayer.mediacodec;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.media.MediaCrypto;
|
import android.media.MediaCrypto;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
@ -120,9 +121,23 @@ public interface MediaCodecAdapter {
|
|||||||
/** A factory for {@link MediaCodecAdapter} instances. */
|
/** A factory for {@link MediaCodecAdapter} instances. */
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
|
||||||
/** Default factory used in most cases. */
|
/**
|
||||||
|
* @deprecated Use {@link #getDefault} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@SuppressWarnings("deprecation") // Forwarding to deprecated method.
|
||||||
Factory DEFAULT = new DefaultMediaCodecAdapterFactory();
|
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. */
|
/** Creates a {@link MediaCodecAdapter} instance. */
|
||||||
MediaCodecAdapter createAdapter(Configuration configuration) throws IOException;
|
MediaCodecAdapter createAdapter(Configuration configuration) throws IOException;
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
int maxDroppedFramesToNotify) {
|
int maxDroppedFramesToNotify) {
|
||||||
this(
|
this(
|
||||||
context,
|
context,
|
||||||
MediaCodecAdapter.Factory.DEFAULT,
|
MediaCodecAdapter.Factory.getDefault(context),
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
allowedJoiningTimeMs,
|
allowedJoiningTimeMs,
|
||||||
/* enableDecoderFallback= */ false,
|
/* enableDecoderFallback= */ false,
|
||||||
@ -256,7 +256,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
int maxDroppedFramesToNotify) {
|
int maxDroppedFramesToNotify) {
|
||||||
this(
|
this(
|
||||||
context,
|
context,
|
||||||
MediaCodecAdapter.Factory.DEFAULT,
|
MediaCodecAdapter.Factory.getDefault(context),
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
allowedJoiningTimeMs,
|
allowedJoiningTimeMs,
|
||||||
enableDecoderFallback,
|
enableDecoderFallback,
|
||||||
|
@ -44,6 +44,7 @@ import androidx.media3.exoplayer.drm.DrmSessionManager;
|
|||||||
import androidx.media3.exoplayer.source.MediaSource;
|
import androidx.media3.exoplayer.source.MediaSource;
|
||||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||||
import androidx.media3.test.utils.FakeSampleStream;
|
import androidx.media3.test.utils.FakeSampleStream;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -480,7 +481,7 @@ public class MediaCodecRendererTest {
|
|||||||
public TestRenderer() {
|
public TestRenderer() {
|
||||||
super(
|
super(
|
||||||
C.TRACK_TYPE_AUDIO,
|
C.TRACK_TYPE_AUDIO,
|
||||||
MediaCodecAdapter.Factory.DEFAULT,
|
MediaCodecAdapter.Factory.getDefault(ApplicationProvider.getApplicationContext()),
|
||||||
/* mediaCodecSelector= */ (mimeType, requiresSecureDecoder, requiresTunnelingDecoder) ->
|
/* mediaCodecSelector= */ (mimeType, requiresSecureDecoder, requiresTunnelingDecoder) ->
|
||||||
Collections.singletonList(
|
Collections.singletonList(
|
||||||
MediaCodecInfo.newInstance(
|
MediaCodecInfo.newInstance(
|
||||||
|
@ -81,7 +81,7 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
|
|||||||
*/
|
*/
|
||||||
public CapturingRenderersFactory(Context context) {
|
public CapturingRenderersFactory(Context context) {
|
||||||
this.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.audioSink = new CapturingAudioSink(new DefaultAudioSink.Builder(context).build());
|
||||||
this.imageOutput = new CapturingImageOutput();
|
this.imageOutput = new CapturingImageOutput();
|
||||||
this.imageDecoderFactory = ImageDecoder.Factory.DEFAULT;
|
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 static class Factory implements MediaCodecAdapter.Factory, Dumper.Dumpable {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
private final List<CapturingMediaCodecAdapter> constructedAdapters;
|
private final List<CapturingMediaCodecAdapter> constructedAdapters;
|
||||||
|
|
||||||
private Factory() {
|
private Factory(Context context) {
|
||||||
|
this.context = context;
|
||||||
constructedAdapters = new ArrayList<>();
|
constructedAdapters = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +180,7 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
|
|||||||
public MediaCodecAdapter createAdapter(Configuration configuration) throws IOException {
|
public MediaCodecAdapter createAdapter(Configuration configuration) throws IOException {
|
||||||
CapturingMediaCodecAdapter adapter =
|
CapturingMediaCodecAdapter adapter =
|
||||||
new CapturingMediaCodecAdapter(
|
new CapturingMediaCodecAdapter(
|
||||||
MediaCodecAdapter.Factory.DEFAULT.createAdapter(configuration),
|
MediaCodecAdapter.Factory.getDefault(context).createAdapter(configuration),
|
||||||
configuration.codecInfo.name);
|
configuration.codecInfo.name);
|
||||||
constructedAdapters.add(adapter);
|
constructedAdapters.add(adapter);
|
||||||
return adapter;
|
return adapter;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user