From a75f902c810baf4068efb41225d4b12797e7d9d6 Mon Sep 17 00:00:00 2001 From: krocard Date: Thu, 16 Sep 2021 23:31:59 +0100 Subject: [PATCH] Add track type disabling to Track selection parameters This will allow to disable video/audio... through the player interface. PiperOrigin-RevId: 397183548 --- .../TrackSelectionParameters.java | 41 +++++++++++- .../trackselection/DefaultTrackSelector.java | 14 +++- .../DefaultTrackSelectorTest.java | 64 +++++++++++++++++-- 3 files changed, 111 insertions(+), 8 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java index 53b52af133..68e5b3c54f 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java @@ -31,10 +31,13 @@ import com.google.android.exoplayer2.Bundleable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.primitives.Ints; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Locale; +import java.util.Set; import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; @@ -90,6 +93,7 @@ public class TrackSelectionParameters implements Bundleable { // General private boolean forceLowestBitrate; private boolean forceHighestSupportedBitrate; + private ImmutableSet<@C.TrackType Integer> disabledTrackTypes; /** * @deprecated {@link Context} constraints will not be set using this constructor. Use {@link @@ -119,6 +123,7 @@ public class TrackSelectionParameters implements Bundleable { // General forceLowestBitrate = false; forceHighestSupportedBitrate = false; + disabledTrackTypes = ImmutableSet.of(); } /** @@ -219,6 +224,12 @@ public class TrackSelectionParameters implements Bundleable { bundle.getBoolean( keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate); + + disabledTrackTypes = + ImmutableSet.copyOf( + Ints.asList( + firstNonNull( + bundle.getIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE)), new int[0]))); } /** Overrides the value of the builder with the value of {@link TrackSelectionParameters}. */ @@ -226,7 +237,8 @@ public class TrackSelectionParameters implements Bundleable { "preferredVideoMimeTypes", "preferredAudioLanguages", "preferredAudioMimeTypes", - "preferredTextLanguages" + "preferredTextLanguages", + "disabledTrackTypes", }) private void init(@UnknownInitialization Builder this, TrackSelectionParameters parameters) { // Video @@ -255,6 +267,7 @@ public class TrackSelectionParameters implements Bundleable { // General forceLowestBitrate = parameters.forceLowestBitrate; forceHighestSupportedBitrate = parameters.forceHighestSupportedBitrate; + disabledTrackTypes = parameters.disabledTrackTypes; } /** Overrides the value of the builder with the value of {@link TrackSelectionParameters}. */ @@ -602,6 +615,18 @@ public class TrackSelectionParameters implements Bundleable { return this; } + /** + * Sets the disabled track types, preventing all tracks of those types from being selected for + * playback. + * + * @param disabledTrackTypes The track types to disable. + * @return This builder. + */ + public Builder setDisabledTrackTypes(Set<@C.TrackType Integer> disabledTrackTypes) { + this.disabledTrackTypes = ImmutableSet.copyOf(disabledTrackTypes); + return this; + } + /** Builds a {@link TrackSelectionParameters} instance with the selected values. */ public TrackSelectionParameters build() { return new TrackSelectionParameters(this); @@ -785,6 +810,12 @@ public class TrackSelectionParameters implements Bundleable { * other constraints. The default value is {@code false}. */ public final boolean forceHighestSupportedBitrate; + /** + * The track types that are disabled. No track of a disabled type will be selected, thus no track + * type contained in the set will be played. The default value is that no track type is disabled + * (empty set). + */ + public final ImmutableSet<@C.TrackType Integer> disabledTrackTypes; protected TrackSelectionParameters(Builder builder) { // Video @@ -813,6 +844,7 @@ public class TrackSelectionParameters implements Bundleable { // General this.forceLowestBitrate = builder.forceLowestBitrate; this.forceHighestSupportedBitrate = builder.forceHighestSupportedBitrate; + this.disabledTrackTypes = builder.disabledTrackTypes; } /** Creates a new {@link Builder}, copying the initial values from this instance. */ @@ -854,7 +886,8 @@ public class TrackSelectionParameters implements Bundleable { && selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage // General && forceLowestBitrate == other.forceLowestBitrate - && forceHighestSupportedBitrate == other.forceHighestSupportedBitrate; + && forceHighestSupportedBitrate == other.forceHighestSupportedBitrate + && disabledTrackTypes.equals(other.disabledTrackTypes); } @Override @@ -886,6 +919,7 @@ public class TrackSelectionParameters implements Bundleable { // General result = 31 * result + (forceLowestBitrate ? 1 : 0); result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0); + result = 31 * result + disabledTrackTypes.hashCode(); return result; } @@ -916,6 +950,7 @@ public class TrackSelectionParameters implements Bundleable { FIELD_PREFERRED_AUDIO_MIME_TYPES, FIELD_FORCE_LOWEST_BITRATE, FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE, + FIELD_DISABLED_TRACK_TYPE, }) private @interface FieldNumber {} @@ -941,6 +976,7 @@ public class TrackSelectionParameters implements Bundleable { private static final int FIELD_PREFERRED_AUDIO_MIME_TYPES = 20; private static final int FIELD_FORCE_LOWEST_BITRATE = 21; private static final int FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE = 22; + private static final int FIELD_DISABLED_TRACK_TYPE = 23; @Override @CallSuper @@ -983,6 +1019,7 @@ public class TrackSelectionParameters implements Bundleable { bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate); bundle.putBoolean( keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate); + bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes)); return bundle; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index fc9e188e16..0572e89a0e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -55,6 +55,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.compatqual.NullableType; @@ -607,6 +608,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { return this; } + @Override + public ParametersBuilder setDisabledTrackTypes(Set<@C.TrackType Integer> trackTypes) { + super.setDisabledTrackTypes(trackTypes); + return this; + } + /** * Sets whether to exceed renderer capabilities when no selection can be made otherwise. * @@ -1484,7 +1491,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Apply track disabling and overriding. for (int i = 0; i < rendererCount; i++) { - if (params.getRendererDisabled(i)) { + @C.TrackType int rendererType = mappedTrackInfo.getRendererType(i); + if (params.getRendererDisabled(i) || params.disabledTrackTypes.contains(rendererType)) { definitions[i] = null; continue; } @@ -1509,7 +1517,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { @NullableType RendererConfiguration[] rendererConfigurations = new RendererConfiguration[rendererCount]; for (int i = 0; i < rendererCount; i++) { - boolean forceRendererDisabled = params.getRendererDisabled(i); + @C.TrackType int rendererType = mappedTrackInfo.getRendererType(i); + boolean forceRendererDisabled = + params.getRendererDisabled(i) || params.disabledTrackTypes.contains(rendererType); boolean rendererEnabled = !forceRendererDisabled && (mappedTrackInfo.getRendererType(i) == C.TRACK_TYPE_NONE diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java index eb2a052d87..5630d5d832 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java @@ -49,6 +49,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationLi import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; +import com.google.common.collect.ImmutableSet; import java.util.HashMap; import java.util.Map; import org.junit.Before; @@ -101,12 +102,14 @@ public final class DefaultTrackSelectorTest { private static final TrackGroup AUDIO_TRACK_GROUP = new TrackGroup(AUDIO_FORMAT); private static final TrackGroupArray TRACK_GROUPS = new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP); + private static final TrackSelection VIDEO_TRACK_SELECTION = + new FixedTrackSelection(VIDEO_TRACK_GROUP, 0); + private static final TrackSelection AUDIO_TRACK_SELECTION = + new FixedTrackSelection(AUDIO_TRACK_GROUP, 0); private static final TrackSelection[] TRACK_SELECTIONS = - new TrackSelection[] { - new FixedTrackSelection(VIDEO_TRACK_GROUP, 0), new FixedTrackSelection(AUDIO_TRACK_GROUP, 0) - }; + new TrackSelection[] {VIDEO_TRACK_SELECTION, AUDIO_TRACK_SELECTION}; private static final TrackSelection[] TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER = - new TrackSelection[] {new FixedTrackSelection(VIDEO_TRACK_GROUP, 0), null}; + new TrackSelection[] {VIDEO_TRACK_SELECTION, null}; private static final Timeline TIMELINE = new FakeTimeline(); @@ -208,6 +211,58 @@ public final class DefaultTrackSelectorTest { .isEqualTo(new RendererConfiguration[] {DEFAULT, DEFAULT}); } + /** Tests disabling a track type. */ + @Test + public void selectVideoAudioTracks_withDisabledAudioType_onlyVideoIsSelected() + throws ExoPlaybackException { + trackSelector.setParameters( + defaultParameters.buildUpon().setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO))); + + TrackSelectorResult result = + trackSelector.selectTracks( + RENDERER_CAPABILITIES, + new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP), + periodId, + TIMELINE); + + assertThat(result.selections).asList().containsExactly(VIDEO_TRACK_SELECTION, null).inOrder(); + assertThat(result.rendererConfigurations).asList().containsExactly(DEFAULT, null); + } + + /** Tests that a disabled track type can be enabled again. */ + @Test + public void selectTracks_withClearedDisabledTrackType_selectsAll() throws ExoPlaybackException { + trackSelector.setParameters( + trackSelector + .buildUponParameters() + .setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO)) + .setDisabledTrackTypes(ImmutableSet.of())); + + TrackSelectorResult result = + trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS, periodId, TIMELINE); + + assertThat(result.selections).asList().containsExactlyElementsIn(TRACK_SELECTIONS).inOrder(); + assertThat(result.rendererConfigurations).asList().containsExactly(DEFAULT, DEFAULT).inOrder(); + } + + /** Tests disabling NONE track type rendering. */ + @Test + public void selectTracks_withDisabledNoneTracksAndNoSampleRenderer_disablesNoSampleRenderer() + throws ExoPlaybackException { + trackSelector.setParameters( + defaultParameters.buildUpon().setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_NONE))); + + TrackSelectorResult result = + trackSelector.selectTracks( + new RendererCapabilities[] {VIDEO_CAPABILITIES, NO_SAMPLE_CAPABILITIES}, + TRACK_GROUPS, + periodId, + TIMELINE); + + assertThat(result.selections).asList().containsExactly(VIDEO_TRACK_SELECTION, null).inOrder(); + assertThat(result.rendererConfigurations).asList().containsExactly(DEFAULT, null).inOrder(); + } + /** Tests disabling a renderer. */ @Test public void selectTracksWithDisabledRenderer() throws ExoPlaybackException { @@ -1760,6 +1815,7 @@ public final class DefaultTrackSelectorTest { .setRendererDisabled(1, true) .setRendererDisabled(3, true) .setRendererDisabled(5, false) + .setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO)) .build(); }