diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8ef7be083d..742b245699 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -61,6 +61,14 @@ present or newly absent. * Add support for reading AC-4 streams ([#5303](https://github.com/google/ExoPlayer/pull/5303)). +* Video: + * Remove `MediaCodecSelector.DEFAULT_WITH_FALLBACK`. Apps should instead + signal that fallback should be used by passing `true` as the + `enableDecoderFallback` parameter when instantiating the video renderer. + * Support video tunneling when the decoder is not listed first for the MIME + type ([#3100](https://github.com/google/ExoPlayer/issues/3100)). + * Query `MediaCodecList.ALL_CODECS` when selecting a tunneling decoder + ([#5547](https://github.com/google/ExoPlayer/issues/5547)). * Add support for SHOUTcast ICY metadata ([#3735](https://github.com/google/ExoPlayer/issues/3735)). * CEA-608: Improved conformance to the specification @@ -102,9 +110,6 @@ ([#5698](https://github.com/google/ExoPlayer/issues/5698), [#5694](https://github.com/google/ExoPlayer/issues/5694)). * Move `PriorityTaskManager` from `DefaultLoadControl` to `SimpleExoPlayer`. -* Remove `MediaCodecSelector.DEFAULT_WITH_FALLBACK`. Apps should instead signal - that fallback should be used by passing `true` as the `enableDecoderFallback` - parameter when instantiating the video renderer. ### 2.9.6 ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 0982bc8862..07769e7d85 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -289,11 +289,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } } List decoderInfos = - mediaCodecSelector.getDecoderInfos(format.sampleMimeType, requiresSecureDecryption); + mediaCodecSelector.getDecoderInfos( + format.sampleMimeType, requiresSecureDecryption, /* requiresTunnelingDecoder= */ false); if (decoderInfos.isEmpty()) { return requiresSecureDecryption && !mediaCodecSelector - .getDecoderInfos(format.sampleMimeType, /* requiresSecureDecoder= */ false) + .getDecoderInfos( + format.sampleMimeType, + /* requiresSecureDecoder= */ false, + /* requiresTunnelingDecoder= */ false) .isEmpty() ? FORMAT_UNSUPPORTED_DRM : FORMAT_UNSUPPORTED_SUBTYPE; @@ -322,7 +326,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media return Collections.singletonList(passthroughDecoderInfo); } } - return super.getDecoderInfos(mediaCodecSelector, format, requiresSecureDecoder); + return mediaCodecSelector.getDecoderInfos( + format.sampleMimeType, requiresSecureDecoder, /* requiresTunnelingDecoder= */ false); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index bbf1134b7f..f7855810d4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -441,11 +441,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { * @return A list of {@link MediaCodecInfo}s corresponding to decoders. May be empty. * @throws DecoderQueryException Thrown if there was an error querying decoders. */ - protected List getDecoderInfos( + protected abstract List getDecoderInfos( MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) - throws DecoderQueryException { - return mediaCodecSelector.getDecoderInfos(format.sampleMimeType, requiresSecureDecoder); - } + throws DecoderQueryException; /** * Configures a newly created {@link MediaCodec}. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java index a5cbb77342..41cb4ee04a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java @@ -32,9 +32,11 @@ public interface MediaCodecSelector { MediaCodecSelector DEFAULT = new MediaCodecSelector() { @Override - public List getDecoderInfos(String mimeType, boolean requiresSecureDecoder) + public List getDecoderInfos( + String mimeType, boolean requiresSecureDecoder, boolean requiresTunnelingDecoder) throws DecoderQueryException { - return MediaCodecUtil.getDecoderInfos(mimeType, requiresSecureDecoder); + return MediaCodecUtil.getDecoderInfos( + mimeType, requiresSecureDecoder, requiresTunnelingDecoder); } @Override @@ -48,10 +50,12 @@ public interface MediaCodecSelector { * * @param mimeType The MIME type for which a decoder is required. * @param requiresSecureDecoder Whether a secure decoder is required. + * @param requiresTunnelingDecoder Whether a tunneling decoder is required. * @return A list of {@link MediaCodecInfo}s corresponding to decoders. May be empty. * @throws DecoderQueryException Thrown if there was an error querying decoders. */ - List getDecoderInfos(String mimeType, boolean requiresSecureDecoder) + List getDecoderInfos( + String mimeType, boolean requiresSecureDecoder, boolean requiresTunnelingDecoder) throws DecoderQueryException; /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index 5a3179f110..3211f7ea8e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -87,17 +87,19 @@ public final class MediaCodecUtil { /** * Optional call to warm the codec cache for a given mime type. - *

- * Calling this method may speed up subsequent calls to {@link #getDecoderInfo(String, boolean)} - * and {@link #getDecoderInfos(String, boolean)}. + * + *

Calling this method may speed up subsequent calls to {@link #getDecoderInfo(String, boolean, + * boolean)} and {@link #getDecoderInfos(String, boolean, boolean)}. * * @param mimeType The mime type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. + * @param tunneling Whether the decoder is required to support tunneling. Always pass false unless + * tunneling really is required. */ - public static void warmDecoderInfoCache(String mimeType, boolean secure) { + public static void warmDecoderInfoCache(String mimeType, boolean secure, boolean tunneling) { try { - getDecoderInfos(mimeType, secure); + getDecoderInfos(mimeType, secure, tunneling); } catch (DecoderQueryException e) { // Codec warming is best effort, so we can swallow the exception. Log.e(TAG, "Codec warming failed", e); @@ -112,7 +114,8 @@ public final class MediaCodecUtil { */ @Nullable public static MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException { - MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.AUDIO_RAW, /* secure= */ false); + MediaCodecInfo decoderInfo = + getDecoderInfo(MimeTypes.AUDIO_RAW, /* secure= */ false, /* tunneling= */ false); return decoderInfo == null ? null : MediaCodecInfo.newPassthroughInstance(decoderInfo.name); } @@ -122,13 +125,15 @@ public final class MediaCodecUtil { * @param mimeType The MIME type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. + * @param tunneling Whether the decoder is required to support tunneling. Always pass false unless + * tunneling really is required. * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. * @throws DecoderQueryException If there was an error querying the available decoders. */ @Nullable - public static MediaCodecInfo getDecoderInfo(String mimeType, boolean secure) + public static MediaCodecInfo getDecoderInfo(String mimeType, boolean secure, boolean tunneling) throws DecoderQueryException { - List decoderInfos = getDecoderInfos(mimeType, secure); + List decoderInfos = getDecoderInfos(mimeType, secure, tunneling); return decoderInfos.isEmpty() ? null : decoderInfos.get(0); } @@ -139,19 +144,23 @@ public final class MediaCodecUtil { * @param mimeType The MIME type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. + * @param tunneling Whether the decoder is required to support tunneling. Always pass false unless + * tunneling really is required. * @return A list of all {@link MediaCodecInfo}s for the given mime type, in the order given by * {@link MediaCodecList}. * @throws DecoderQueryException If there was an error querying the available decoders. */ - public static synchronized List getDecoderInfos(String mimeType, boolean secure) - throws DecoderQueryException { - CodecKey key = new CodecKey(mimeType, secure); + public static synchronized List getDecoderInfos( + String mimeType, boolean secure, boolean tunneling) throws DecoderQueryException { + CodecKey key = new CodecKey(mimeType, secure, tunneling); List cachedDecoderInfos = decoderInfosCache.get(key); if (cachedDecoderInfos != null) { return cachedDecoderInfos; } - MediaCodecListCompat mediaCodecList = Util.SDK_INT >= 21 - ? new MediaCodecListCompatV21(secure) : new MediaCodecListCompatV16(); + MediaCodecListCompat mediaCodecList = + Util.SDK_INT >= 21 + ? new MediaCodecListCompatV21(secure, tunneling) + : new MediaCodecListCompatV16(); ArrayList decoderInfos = getDecoderInfosInternal(key, mediaCodecList, mimeType); if (secure && decoderInfos.isEmpty() && 21 <= Util.SDK_INT && Util.SDK_INT <= 23) { // Some devices don't list secure decoders on API level 21 [Internal: b/18678462]. Try the @@ -165,7 +174,7 @@ public final class MediaCodecUtil { } if (MimeTypes.AUDIO_E_AC3_JOC.equals(mimeType)) { // E-AC3 decoders can decode JOC streams, but in 2-D rather than 3-D. - CodecKey eac3Key = new CodecKey(MimeTypes.AUDIO_E_AC3, key.secure); + CodecKey eac3Key = new CodecKey(MimeTypes.AUDIO_E_AC3, key.secure, key.tunneling); ArrayList eac3DecoderInfos = getDecoderInfosInternal(eac3Key, mediaCodecList, mimeType); decoderInfos.addAll(eac3DecoderInfos); @@ -184,7 +193,8 @@ public final class MediaCodecUtil { public static int maxH264DecodableFrameSize() throws DecoderQueryException { if (maxH264DecodableFrameSize == -1) { int result = 0; - MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.VIDEO_H264, false); + MediaCodecInfo decoderInfo = + getDecoderInfo(MimeTypes.VIDEO_H264, /* secure= */ false, /* tunneling= */ false); if (decoderInfo != null) { for (CodecProfileLevel profileLevel : decoderInfo.getProfileLevels()) { result = Math.max(avcLevelToMaxFrameSize(profileLevel.level), result); @@ -202,12 +212,12 @@ public final class MediaCodecUtil { * Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the given * codec description string (as defined by RFC 6381). * - * @param codec A codec description string, as defined by RFC 6381. + * @param codec A codec description string, as defined by RFC 6381, or {@code null} if not known. * @return A pair (profile constant, level constant) if {@code codec} is well-formed and * recognized, or null otherwise */ @Nullable - public static Pair getCodecProfileAndLevel(String codec) { + public static Pair getCodecProfileAndLevel(@Nullable String codec) { if (codec == null) { return null; } @@ -254,36 +264,58 @@ public final class MediaCodecUtil { // Note: MediaCodecList is sorted by the framework such that the best decoders come first. for (int i = 0; i < numberOfCodecs; i++) { android.media.MediaCodecInfo codecInfo = mediaCodecList.getCodecInfoAt(i); - String codecName = codecInfo.getName(); - String codecSupportedType = - getCodecSupportedType(codecInfo, codecName, secureDecodersExplicit, requestedMimeType); - if (codecSupportedType != null) { - try { - CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(codecSupportedType); - boolean secure = mediaCodecList.isSecurePlaybackSupported(mimeType, capabilities); - boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(codecName); - if ((secureDecodersExplicit && key.secure == secure) - || (!secureDecodersExplicit && !key.secure)) { - decoderInfos.add( - MediaCodecInfo.newInstance( - codecName, mimeType, capabilities, forceDisableAdaptive, false)); - } else if (!secureDecodersExplicit && secure) { - decoderInfos.add( - MediaCodecInfo.newInstance( - codecName + ".secure", mimeType, capabilities, forceDisableAdaptive, true)); - // It only makes sense to have one synthesized secure decoder, return immediately. - return decoderInfos; - } - } catch (Exception e) { - if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) { - // Suppress error querying secondary codec capabilities up to API level 23. - Log.e(TAG, "Skipping codec " + codecName + " (failed to query capabilities)"); - } else { - // Rethrow error querying primary codec capabilities, or secondary codec - // capabilities if API level is greater than 23. - Log.e(TAG, "Failed to query codec " + codecName + " (" + codecSupportedType + ")"); - throw e; - } + String name = codecInfo.getName(); + String supportedType = + getCodecSupportedType(codecInfo, name, secureDecodersExplicit, requestedMimeType); + if (supportedType == null) { + continue; + } + try { + CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(supportedType); + boolean tunnelingSupported = + mediaCodecList.isFeatureSupported( + CodecCapabilities.FEATURE_TunneledPlayback, supportedType, capabilities); + boolean tunnelingRequired = + mediaCodecList.isFeatureRequired( + CodecCapabilities.FEATURE_TunneledPlayback, supportedType, capabilities); + if ((!key.tunneling && tunnelingRequired) || (key.tunneling && !tunnelingSupported)) { + continue; + } + boolean secureSupported = + mediaCodecList.isFeatureSupported( + CodecCapabilities.FEATURE_SecurePlayback, supportedType, capabilities); + boolean secureRequired = + mediaCodecList.isFeatureRequired( + CodecCapabilities.FEATURE_SecurePlayback, supportedType, capabilities); + if ((!key.secure && secureRequired) || (key.secure && !secureSupported)) { + continue; + } + boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(name); + if ((secureDecodersExplicit && key.secure == secureSupported) + || (!secureDecodersExplicit && !key.secure)) { + decoderInfos.add( + MediaCodecInfo.newInstance( + name, mimeType, capabilities, forceDisableAdaptive, /* forceSecure= */ false)); + } else if (!secureDecodersExplicit && secureSupported) { + decoderInfos.add( + MediaCodecInfo.newInstance( + name + ".secure", + mimeType, + capabilities, + forceDisableAdaptive, + /* forceSecure= */ true)); + // It only makes sense to have one synthesized secure decoder, return immediately. + return decoderInfos; + } + } catch (Exception e) { + if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) { + // Suppress error querying secondary codec capabilities up to API level 23. + Log.e(TAG, "Skipping codec " + name + " (failed to query capabilities)"); + } else { + // Rethrow error querying primary codec capabilities, or secondary codec + // capabilities if API level is greater than 23. + Log.e(TAG, "Failed to query codec " + name + " (" + supportedType + ")"); + throw e; } } } @@ -364,7 +396,8 @@ public final class MediaCodecUtil { // Work around https://github.com/google/ExoPlayer/issues/1528 and // https://github.com/google/ExoPlayer/issues/3171. - if (Util.SDK_INT < 18 && "OMX.MTK.AUDIO.DECODER.AAC".equals(name) + if (Util.SDK_INT < 18 + && "OMX.MTK.AUDIO.DECODER.AAC".equals(name) && ("a70".equals(Util.DEVICE) || ("Xiaomi".equals(Util.MANUFACTURER) && Util.DEVICE.startsWith("HM")))) { return false; @@ -417,9 +450,12 @@ public final class MediaCodecUtil { // Work around https://github.com/google/ExoPlayer/issues/548. // VP8 decoder on Samsung Galaxy S3/S4/S4 Mini/Tab 3/Note 2 does not render video. if (Util.SDK_INT <= 19 - && "OMX.SEC.vp8.dec".equals(name) && "samsung".equals(Util.MANUFACTURER) - && (Util.DEVICE.startsWith("d2") || Util.DEVICE.startsWith("serrano") - || Util.DEVICE.startsWith("jflte") || Util.DEVICE.startsWith("santos") + && "OMX.SEC.vp8.dec".equals(name) + && "samsung".equals(Util.MANUFACTURER) + && (Util.DEVICE.startsWith("d2") + || Util.DEVICE.startsWith("serrano") + || Util.DEVICE.startsWith("jflte") + || Util.DEVICE.startsWith("santos") || Util.DEVICE.startsWith("t0"))) { return false; } @@ -659,12 +695,11 @@ public final class MediaCodecUtil { */ boolean secureDecodersExplicit(); - /** - * Whether secure playback is supported for the given {@link CodecCapabilities}, which should - * have been obtained from a {@link android.media.MediaCodecInfo} obtained from this list. - */ - boolean isSecurePlaybackSupported(String mimeType, CodecCapabilities capabilities); + /** Whether the specified {@link CodecCapabilities} {@code feature} is supported. */ + boolean isFeatureSupported(String feature, String mimeType, CodecCapabilities capabilities); + /** Whether the specified {@link CodecCapabilities} {@code feature} is required. */ + boolean isFeatureRequired(String feature, String mimeType, CodecCapabilities capabilities); } @TargetApi(21) @@ -674,8 +709,11 @@ public final class MediaCodecUtil { private android.media.MediaCodecInfo[] mediaCodecInfos; - public MediaCodecListCompatV21(boolean includeSecure) { - codecKind = includeSecure ? MediaCodecList.ALL_CODECS : MediaCodecList.REGULAR_CODECS; + public MediaCodecListCompatV21(boolean includeSecure, boolean includeTunneling) { + codecKind = + includeSecure || includeTunneling + ? MediaCodecList.ALL_CODECS + : MediaCodecList.REGULAR_CODECS; } @Override @@ -696,8 +734,15 @@ public final class MediaCodecUtil { } @Override - public boolean isSecurePlaybackSupported(String mimeType, CodecCapabilities capabilities) { - return capabilities.isFeatureSupported(CodecCapabilities.FEATURE_SecurePlayback); + public boolean isFeatureSupported( + String feature, String mimeType, CodecCapabilities capabilities) { + return capabilities.isFeatureSupported(feature); + } + + @Override + public boolean isFeatureRequired( + String feature, String mimeType, CodecCapabilities capabilities) { + return capabilities.isFeatureRequired(feature); } private void ensureMediaCodecInfosInitialized() { @@ -727,10 +772,18 @@ public final class MediaCodecUtil { } @Override - public boolean isSecurePlaybackSupported(String mimeType, CodecCapabilities capabilities) { + public boolean isFeatureSupported( + String feature, String mimeType, CodecCapabilities capabilities) { // Secure decoders weren't explicitly listed prior to API level 21. We assume that a secure // H264 decoder exists. - return MimeTypes.VIDEO_H264.equals(mimeType); + return CodecCapabilities.FEATURE_SecurePlayback.equals(feature) + && MimeTypes.VIDEO_H264.equals(mimeType); + } + + @Override + public boolean isFeatureRequired( + String feature, String mimeType, CodecCapabilities capabilities) { + return false; } } @@ -739,10 +792,12 @@ public final class MediaCodecUtil { public final String mimeType; public final boolean secure; + public final boolean tunneling; - public CodecKey(String mimeType, boolean secure) { + public CodecKey(String mimeType, boolean secure, boolean tunneling) { this.mimeType = mimeType; this.secure = secure; + this.tunneling = tunneling; } @Override @@ -751,6 +806,7 @@ public final class MediaCodecUtil { int result = 1; result = prime * result + ((mimeType == null) ? 0 : mimeType.hashCode()); result = prime * result + (secure ? 1231 : 1237); + result = prime * result + (tunneling ? 1231 : 1237); return result; } @@ -763,7 +819,9 @@ public final class MediaCodecUtil { return false; } CodecKey other = (CodecKey) obj; - return TextUtils.equals(mimeType, other.mimeType) && secure == other.secure; + return TextUtils.equals(mimeType, other.mimeType) + && secure == other.secure + && tunneling == other.tunneling; } } @@ -901,5 +959,4 @@ public final class MediaCodecUtil { MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(39, CodecProfileLevel.AACObjectELD); MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(42, CodecProfileLevel.AACObjectXHE); } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index f26bc29aec..193fbddfec 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -52,6 +52,7 @@ import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher; import java.nio.ByteBuffer; +import java.util.Collections; import java.util.List; /** @@ -304,11 +305,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } } List decoderInfos = - mediaCodecSelector.getDecoderInfos(format.sampleMimeType, requiresSecureDecryption); + getDecoderInfos(mediaCodecSelector, format, requiresSecureDecryption); if (decoderInfos.isEmpty()) { return requiresSecureDecryption && !mediaCodecSelector - .getDecoderInfos(format.sampleMimeType, /* requiresSecureDecoder= */ false) + .getDecoderInfos( + format.sampleMimeType, + /* requiresSecureDecoder= */ false, + /* requiresTunnelingDecoder= */ false) .isEmpty() ? FORMAT_UNSUPPORTED_DRM : FORMAT_UNSUPPORTED_SUBTYPE; @@ -323,11 +327,34 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { decoderInfo.isSeamlessAdaptationSupported(format) ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS; - int tunnelingSupport = decoderInfo.tunneling ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED; + int tunnelingSupport = TUNNELING_NOT_SUPPORTED; + if (isFormatSupported) { + List tunnelingDecoderInfos = + mediaCodecSelector.getDecoderInfos( + format.sampleMimeType, + requiresSecureDecryption, + /* requiresTunnelingDecoder= */ true); + if (!tunnelingDecoderInfos.isEmpty()) { + MediaCodecInfo tunnelingDecoderInfo = tunnelingDecoderInfos.get(0); + if (tunnelingDecoderInfo.isFormatSupported(format) + && tunnelingDecoderInfo.isSeamlessAdaptationSupported(format)) { + tunnelingSupport = TUNNELING_SUPPORTED; + } + } + } int formatSupport = isFormatSupported ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES; return adaptiveSupport | tunnelingSupport | formatSupport; } + @Override + protected List getDecoderInfos( + MediaCodecSelector mediaCodecSelector, Format format, boolean requiresSecureDecoder) + throws DecoderQueryException { + List decoderInfos = + mediaCodecSelector.getDecoderInfos(format.sampleMimeType, requiresSecureDecoder, tunneling); + return Collections.unmodifiableList(decoderInfos); + } + @Override protected void onEnabled(boolean joining) throws ExoPlaybackException { super.onEnabled(joining); diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java index e2988b88b6..598138126b 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java @@ -628,7 +628,9 @@ public final class DashStreamingTest { @Test public void testDecoderInfoH264() throws DecoderQueryException { - MediaCodecInfo decoderInfo = MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H264, false); + MediaCodecInfo decoderInfo = + MediaCodecUtil.getDecoderInfo( + MimeTypes.VIDEO_H264, /* secure= */ false, /* tunneling= */ false); assertThat(decoderInfo).isNotNull(); assertThat(Util.SDK_INT < 21 || decoderInfo.adaptive).isTrue(); } @@ -639,7 +641,11 @@ public final class DashStreamingTest { // Pass. return; } - assertThat(MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H265, false).adaptive).isTrue(); + assertThat( + MediaCodecUtil.getDecoderInfo( + MimeTypes.VIDEO_H265, /* secure= */ false, /* tunneling= */ false) + .adaptive) + .isTrue(); } @Test @@ -648,13 +654,18 @@ public final class DashStreamingTest { // Pass. return; } - assertThat(MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_VP9, false).adaptive).isTrue(); + assertThat( + MediaCodecUtil.getDecoderInfo( + MimeTypes.VIDEO_VP9, /* secure= */ false, /* tunneling= */ false) + .adaptive) + .isTrue(); } // Internal. private static boolean shouldSkipAdaptiveTest(String mimeType) throws DecoderQueryException { - MediaCodecInfo decoderInfo = MediaCodecUtil.getDecoderInfo(mimeType, false); + MediaCodecInfo decoderInfo = + MediaCodecUtil.getDecoderInfo(mimeType, /* secure= */ false, /* tunneling= */ false); return decoderInfo == null || !decoderInfo.adaptive; } diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java index a3d4a112b7..b2a49a31fe 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java @@ -106,7 +106,8 @@ public final class DashTestRunner { if (Util.SDK_INT >= 18) { try { // Force L3 if secure decoder is not available. - if (MediaCodecUtil.getDecoderInfo(mimeType, true) == null) { + if (MediaCodecUtil.getDecoderInfo(mimeType, /* secure= */ true, /* tunneling= */ false) + == null) { return false; } MediaDrm mediaDrm = MediaDrmBuilder.build(); diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/EnumerateDecodersTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/EnumerateDecodersTest.java index d40a705414..d256db8c30 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/EnumerateDecodersTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/EnumerateDecodersTest.java @@ -82,12 +82,16 @@ public class EnumerateDecodersTest { } private void enumerateDecoders(String mimeType) throws DecoderQueryException { - logDecoderInfos(mimeType, /* secure= */ false); - logDecoderInfos(mimeType, /* secure= */ true); + logDecoderInfos(mimeType, /* secure= */ false, /* tunneling= */ false); + logDecoderInfos(mimeType, /* secure= */ true, /* tunneling= */ false); + logDecoderInfos(mimeType, /* secure= */ false, /* tunneling= */ true); + logDecoderInfos(mimeType, /* secure= */ true, /* tunneling= */ true); } - private void logDecoderInfos(String mimeType, boolean secure) throws DecoderQueryException { - List mediaCodecInfos = MediaCodecUtil.getDecoderInfos(mimeType, secure); + private void logDecoderInfos(String mimeType, boolean secure, boolean tunneling) + throws DecoderQueryException { + List mediaCodecInfos = + MediaCodecUtil.getDecoderInfos(mimeType, secure, tunneling); for (MediaCodecInfo mediaCodecInfo : mediaCodecInfos) { CodecCapabilities capabilities = Assertions.checkNotNull(mediaCodecInfo.capabilities); metricsLogger.logMetric(