diff --git a/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java b/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java index 62eaa49b9ea..654ea544093 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java @@ -60,16 +60,16 @@ public interface RendererCapabilities { @interface AdaptiveSupport {} /** A mask to apply to {@link Capabilities} to obtain the {@link AdaptiveSupport} only. */ - int ADAPTIVE_SUPPORT_MASK = 0b11000; + int ADAPTIVE_SUPPORT_MASK = 0b11 << 3; /** The {@link Renderer} can seamlessly adapt between formats. */ - int ADAPTIVE_SEAMLESS = 0b10000; + int ADAPTIVE_SEAMLESS = 0b10 << 3; /** * The {@link Renderer} can adapt between formats, but may suffer a brief discontinuity * (~50-100ms) when adaptation occurs. */ - int ADAPTIVE_NOT_SEAMLESS = 0b01000; + int ADAPTIVE_NOT_SEAMLESS = 0b01 << 3; /** The {@link Renderer} does not support adaptation between formats. */ - int ADAPTIVE_NOT_SUPPORTED = 0b00000; + int ADAPTIVE_NOT_SUPPORTED = 0; /** * Level of renderer support for tunneling. One of {@link #TUNNELING_SUPPORTED} or {@link @@ -80,20 +80,62 @@ public interface RendererCapabilities { @IntDef({TUNNELING_SUPPORTED, TUNNELING_NOT_SUPPORTED}) @interface TunnelingSupport {} - /** A mask to apply to {@link Capabilities} to obtain the {@link TunnelingSupport} only. */ - int TUNNELING_SUPPORT_MASK = 0b100000; + /** A mask to apply to {@link Capabilities} to obtain {@link TunnelingSupport} only. */ + int TUNNELING_SUPPORT_MASK = 0b1 << 5; /** The {@link Renderer} supports tunneled output. */ - int TUNNELING_SUPPORTED = 0b100000; + int TUNNELING_SUPPORTED = 0b1 << 5; /** The {@link Renderer} does not support tunneled output. */ - int TUNNELING_NOT_SUPPORTED = 0b000000; + int TUNNELING_NOT_SUPPORTED = 0; + + /** + * Level of renderer support for hardware acceleration. One of {@link + * #HARDWARE_ACCELERATION_SUPPORTED} and {@link #HARDWARE_ACCELERATION_NOT_SUPPORTED}. + * + *

For video renderers, the level of support is indicated for non-tunneled output. + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + HARDWARE_ACCELERATION_SUPPORTED, + HARDWARE_ACCELERATION_NOT_SUPPORTED, + }) + @interface HardwareAccelerationSupport {} + /** A mask to apply to {@link Capabilities} to obtain {@link HardwareAccelerationSupport} only. */ + int HARDWARE_ACCELERATION_SUPPORT_MASK = 0b1 << 6; + /** The renderer is able to use hardware acceleration. */ + int HARDWARE_ACCELERATION_SUPPORTED = 0b1 << 6; + /** The renderer is not able to use hardware acceleration. */ + int HARDWARE_ACCELERATION_NOT_SUPPORTED = 0; + + /** + * Level of decoder support. One of {@link #DECODER_SUPPORT_PRIMARY} and {@link + * #DECODER_SUPPORT_FALLBACK}. + * + *

For video renderers, the level of support is indicated for non-tunneled output. + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + DECODER_SUPPORT_PRIMARY, + DECODER_SUPPORT_FALLBACK, + }) + @interface DecoderSupport {} + /** A mask to apply to {@link Capabilities} to obtain {@link DecoderSupport} only. */ + int MODE_SUPPORT_MASK = 0b1 << 7; + /** The renderer is able to use the primary decoder for the format's MIME type. */ + int DECODER_SUPPORT_PRIMARY = 0b1 << 7; + /** The renderer will use a fallback decoder. */ + int DECODER_SUPPORT_FALLBACK = 0; /** * Combined renderer capabilities. * - *

This is a bitwise OR of {@link C.FormatSupport}, {@link AdaptiveSupport} and {@link - * TunnelingSupport}. Use {@link #getFormatSupport(int)}, {@link #getAdaptiveSupport(int)} or - * {@link #getTunnelingSupport(int)} to obtain the individual flags. And use {@link #create(int)} - * or {@link #create(int, int, int)} to create the combined capabilities. + *

This is a bitwise OR of {@link C.FormatSupport}, {@link AdaptiveSupport}, {@link + * TunnelingSupport}, {@link HardwareAccelerationSupport} and {@link DecoderSupport}. Use {@link + * #getFormatSupport}, {@link #getAdaptiveSupport}, {@link #getTunnelingSupport}, {@link + * #getHardwareAccelerationSupport} and {@link #getDecoderSupport} to obtain individual + * components. Use {@link #create(int)}, {@link #create(int, int, int)} or {@link #create(int, + * int, int, int, int)} to create combined capabilities from individual components. * *

Possible values: * @@ -111,6 +153,11 @@ public interface RendererCapabilities { * #TUNNELING_SUPPORTED} and {@link #TUNNELING_NOT_SUPPORTED}. Only set if the level of * support for the format itself is {@link C#FORMAT_HANDLED} or {@link * C#FORMAT_EXCEEDS_CAPABILITIES}. + *

  • {@link HardwareAccelerationSupport}: The level of support for hardware acceleration. One + * of {@link #HARDWARE_ACCELERATION_SUPPORTED} and {@link + * #HARDWARE_ACCELERATION_NOT_SUPPORTED}. + *
  • {@link DecoderSupport}: The level of decoder support. One of {@link + * #DECODER_SUPPORT_PRIMARY} and {@link #DECODER_SUPPORT_FALLBACK}. * */ @Documented @@ -122,8 +169,10 @@ public interface RendererCapabilities { /** * Returns {@link Capabilities} for the given {@link C.FormatSupport}. * - *

    The {@link AdaptiveSupport} is set to {@link #ADAPTIVE_NOT_SUPPORTED} and {{@link - * TunnelingSupport} is set to {@link #TUNNELING_NOT_SUPPORTED}. + *

    {@link AdaptiveSupport} is set to {@link #ADAPTIVE_NOT_SUPPORTED}, {@link TunnelingSupport} + * is set to {@link #TUNNELING_NOT_SUPPORTED}, {@link HardwareAccelerationSupport} is set to + * {@link #HARDWARE_ACCELERATION_NOT_SUPPORTED} and {@link DecoderSupport} is set to {@link + * #DECODER_SUPPORT_PRIMARY}. * * @param formatSupport The {@link C.FormatSupport}. * @return The combined {@link Capabilities} of the given {@link C.FormatSupport}, {@link @@ -138,19 +187,53 @@ static int create(@C.FormatSupport int formatSupport) { * Returns {@link Capabilities} combining the given {@link C.FormatSupport}, {@link * AdaptiveSupport} and {@link TunnelingSupport}. * + *

    {@link HardwareAccelerationSupport} is set to {@link #HARDWARE_ACCELERATION_NOT_SUPPORTED} + * and {@link DecoderSupport} is set to {@link #DECODER_SUPPORT_PRIMARY}. + * * @param formatSupport The {@link C.FormatSupport}. * @param adaptiveSupport The {@link AdaptiveSupport}. * @param tunnelingSupport The {@link TunnelingSupport}. * @return The combined {@link Capabilities}. */ + @Capabilities + static int create( + @C.FormatSupport int formatSupport, + @AdaptiveSupport int adaptiveSupport, + @TunnelingSupport int tunnelingSupport) { + return create( + formatSupport, + adaptiveSupport, + tunnelingSupport, + HARDWARE_ACCELERATION_NOT_SUPPORTED, + DECODER_SUPPORT_PRIMARY); + } + + /** + * Returns {@link Capabilities} combining the given {@link C.FormatSupport}, {@link + * AdaptiveSupport}, {@link TunnelingSupport}, {@link HardwareAccelerationSupport} and {@link + * DecoderSupport}. + * + * @param formatSupport The {@link C.FormatSupport}. + * @param adaptiveSupport The {@link AdaptiveSupport}. + * @param tunnelingSupport The {@link TunnelingSupport}. + * @param hardwareAccelerationSupport The {@link HardwareAccelerationSupport}. + * @param decoderSupport The {@link DecoderSupport}. + * @return The combined {@link Capabilities}. + */ // Suppression needed for IntDef casting. @SuppressLint("WrongConstant") @Capabilities static int create( @C.FormatSupport int formatSupport, @AdaptiveSupport int adaptiveSupport, - @TunnelingSupport int tunnelingSupport) { - return formatSupport | adaptiveSupport | tunnelingSupport; + @TunnelingSupport int tunnelingSupport, + @HardwareAccelerationSupport int hardwareAccelerationSupport, + @DecoderSupport int decoderSupport) { + return formatSupport + | adaptiveSupport + | tunnelingSupport + | hardwareAccelerationSupport + | decoderSupport; } /** @@ -192,6 +275,32 @@ static int getTunnelingSupport(@Capabilities int supportFlags) { return supportFlags & TUNNELING_SUPPORT_MASK; } + /** + * Returns the {@link HardwareAccelerationSupport} from the combined {@link Capabilities}. + * + * @param supportFlags The combined {@link Capabilities}. + * @return The {@link HardwareAccelerationSupport} only. + */ + // Suppression needed for IntDef casting. + @SuppressLint("WrongConstant") + @HardwareAccelerationSupport + static int getHardwareAccelerationSupport(@Capabilities int supportFlags) { + return supportFlags & HARDWARE_ACCELERATION_SUPPORT_MASK; + } + + /** + * Returns the {@link DecoderSupport} from the combined {@link Capabilities}. + * + * @param supportFlags The combined {@link Capabilities}. + * @return The {@link DecoderSupport} only. + */ + // Suppression needed for IntDef casting. + @SuppressLint("WrongConstant") + @DecoderSupport + static int getDecoderSupport(@Capabilities int supportFlags) { + return supportFlags & MODE_SUPPORT_MASK; + } + /** Returns the name of the {@link Renderer}. */ String getName(); 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 fc9a1024063..41234fa8286 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 @@ -314,6 +314,7 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format forma // format's MIME type, according to the MediaCodecSelector. MediaCodecInfo decoderInfo = decoderInfos.get(0); boolean isFormatSupported = decoderInfo.isFormatSupported(format); + boolean isPreferredDecoder = true; if (!isFormatSupported) { // Check whether any of the other decoders support the format. for (int i = 1; i < decoderInfos.size(); i++) { @@ -321,18 +322,31 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format forma if (otherDecoderInfo.isFormatSupported(format)) { decoderInfo = otherDecoderInfo; isFormatSupported = true; + isPreferredDecoder = false; break; } } } + @C.FormatSupport + int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES; @AdaptiveSupport int adaptiveSupport = isFormatSupported && decoderInfo.isSeamlessAdaptationSupported(format) ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS; - @C.FormatSupport - int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES; - return RendererCapabilities.create(formatSupport, adaptiveSupport, tunnelingSupport); + @HardwareAccelerationSupport + int hardwareAccelerationSupport = + decoderInfo.hardwareAccelerated + ? HARDWARE_ACCELERATION_SUPPORTED + : HARDWARE_ACCELERATION_NOT_SUPPORTED; + @DecoderSupport + int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK; + return RendererCapabilities.create( + formatSupport, + adaptiveSupport, + tunnelingSupport, + hardwareAccelerationSupport, + decoderSupport); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java index 226e7b24ee6..37040c944f9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java @@ -216,6 +216,19 @@ public int getTypeSupport(@C.TrackType int trackType) { return bestRendererSupport; } + /** + * Returns the {@link Capabilities} of the renderer for an individual track. + * + * @param rendererIndex The renderer index. + * @param groupIndex The index of the track group to which the track belongs. + * @param trackIndex The index of the track within the track group. + * @return The {@link Capabilities}. + */ + @Capabilities + public int getCapabilities(int rendererIndex, int groupIndex, int trackIndex) { + return rendererFormatSupports[rendererIndex][groupIndex][trackIndex]; + } + /** * Returns the extent to which an individual track is supported by the renderer. * @@ -227,7 +240,7 @@ public int getTypeSupport(@C.TrackType int trackType) { @FormatSupport public int getTrackSupport(int rendererIndex, int groupIndex, int trackIndex) { return RendererCapabilities.getFormatSupport( - rendererFormatSupports[rendererIndex][groupIndex][trackIndex]); + getCapabilities(rendererIndex, groupIndex, trackIndex)); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java index 565f3eb8809..00eb88cb80a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java @@ -15,6 +15,12 @@ */ package com.google.android.exoplayer2.util; +import static com.google.android.exoplayer2.RendererCapabilities.DECODER_SUPPORT_FALLBACK; +import static com.google.android.exoplayer2.RendererCapabilities.HARDWARE_ACCELERATION_SUPPORTED; +import static com.google.android.exoplayer2.RendererCapabilities.getDecoderSupport; +import static com.google.android.exoplayer2.RendererCapabilities.getFormatSupport; +import static com.google.android.exoplayer2.RendererCapabilities.getHardwareAccelerationSupport; +import static com.google.android.exoplayer2.util.Util.getFormatSupportString; import static java.lang.Math.min; import android.os.SystemClock; @@ -29,6 +35,7 @@ import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport; +import com.google.android.exoplayer2.RendererCapabilities.Capabilities; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.audio.AudioAttributes; @@ -276,9 +283,16 @@ public void onTracksChanged( logd(" Group:" + trackGroup.id + ", adaptive_supported=" + adaptiveSupport + " ["); for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { String status = getTrackStatusString(trackSelection, trackGroup, trackIndex); - String formatSupport = - Util.getFormatSupportString( - mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex)); + @Capabilities + int capabilities = + mappedTrackInfo.getCapabilities(rendererIndex, groupIndex, trackIndex); + String formatSupport = getFormatSupportString(getFormatSupport(capabilities)); + String hardwareAccelerationSupport = + getHardwareAccelerationSupport(capabilities) == HARDWARE_ACCELERATION_SUPPORTED + ? ", accelerated=YES" + : ""; + String decoderSupport = + getDecoderSupport(capabilities) == DECODER_SUPPORT_FALLBACK ? ", fallback=YES" : ""; logd( " " + status @@ -287,7 +301,9 @@ public void onTracksChanged( + ", " + Format.toLogString(trackGroup.getFormat(trackIndex)) + ", supported=" - + formatSupport); + + formatSupport + + hardwareAccelerationSupport + + decoderSupport); } logd(" ]"); } @@ -315,7 +331,7 @@ public void onTracksChanged( TrackGroup trackGroup = unassociatedTrackGroups.get(groupIndex); for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { String status = getTrackStatusString(false); - String formatSupport = Util.getFormatSupportString(C.FORMAT_UNSUPPORTED_TYPE); + String formatSupport = getFormatSupportString(C.FORMAT_UNSUPPORTED_TYPE); logd( " " + status 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 ca15b69ce54..c25d915b26d 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 @@ -375,6 +375,7 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format forma // format's MIME type, according to the MediaCodecSelector. MediaCodecInfo decoderInfo = decoderInfos.get(0); boolean isFormatSupported = decoderInfo.isFormatSupported(format); + boolean isPreferredDecoder = true; if (!isFormatSupported) { // Check whether any of the other decoders support the format. for (int i = 1; i < decoderInfos.size(); i++) { @@ -382,15 +383,26 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format forma if (otherDecoderInfo.isFormatSupported(format)) { decoderInfo = otherDecoderInfo; isFormatSupported = true; + isPreferredDecoder = false; break; } } } + @C.FormatSupport + int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES; @AdaptiveSupport int adaptiveSupport = decoderInfo.isSeamlessAdaptationSupported(format) ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS; + @HardwareAccelerationSupport + int hardwareAccelerationSupport = + decoderInfo.hardwareAccelerated + ? HARDWARE_ACCELERATION_SUPPORTED + : HARDWARE_ACCELERATION_NOT_SUPPORTED; + @DecoderSupport + int decoderSupport = isPreferredDecoder ? DECODER_SUPPORT_PRIMARY : DECODER_SUPPORT_FALLBACK; + @TunnelingSupport int tunnelingSupport = TUNNELING_NOT_SUPPORTED; if (isFormatSupported) { List tunnelingDecoderInfos = @@ -409,9 +421,13 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format forma } } } - @C.FormatSupport - int formatSupport = isFormatSupported ? C.FORMAT_HANDLED : C.FORMAT_EXCEEDS_CAPABILITIES; - return RendererCapabilities.create(formatSupport, adaptiveSupport, tunnelingSupport); + + return RendererCapabilities.create( + formatSupport, + adaptiveSupport, + tunnelingSupport, + hardwareAccelerationSupport, + decoderSupport); } @Override diff --git a/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java b/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java index 850a9c8db0c..5b0a858678e 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/audio/DecoderAudioRendererTest.java @@ -17,6 +17,7 @@ import static com.google.android.exoplayer2.C.FORMAT_HANDLED; import static com.google.android.exoplayer2.RendererCapabilities.ADAPTIVE_NOT_SEAMLESS; +import static com.google.android.exoplayer2.RendererCapabilities.DECODER_SUPPORT_PRIMARY; import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_NOT_SUPPORTED; import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_SUPPORTED; import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM; @@ -92,7 +93,11 @@ protected Format getOutputFormat(FakeDecoder decoder) { @Test public void supportsFormatAtApi19() { assertThat(audioRenderer.supportsFormat(FORMAT)) - .isEqualTo(ADAPTIVE_NOT_SEAMLESS | TUNNELING_NOT_SUPPORTED | FORMAT_HANDLED); + .isEqualTo( + ADAPTIVE_NOT_SEAMLESS + | TUNNELING_NOT_SUPPORTED + | FORMAT_HANDLED + | DECODER_SUPPORT_PRIMARY); } @Config(sdk = 21) @@ -100,7 +105,8 @@ public void supportsFormatAtApi19() { public void supportsFormatAtApi21() { // From API 21, tunneling is supported. assertThat(audioRenderer.supportsFormat(FORMAT)) - .isEqualTo(ADAPTIVE_NOT_SEAMLESS | TUNNELING_SUPPORTED | FORMAT_HANDLED); + .isEqualTo( + ADAPTIVE_NOT_SEAMLESS | TUNNELING_SUPPORTED | FORMAT_HANDLED | DECODER_SUPPORT_PRIMARY); } @Test