Commit d5ef11aa by krocard Committed by bachinger

Add track selection override to the player API

This moves `SelectionOverride` from `DefaultTrackSelector`
to `TrackSelectionParameters`.

It is then use to allow track selection override per
track selection array.

Note that contrary to
`DefaultTrackSelector.Parameters.selectionOverride`, the renderer
concept is not exposed.

This cl is a part of the bigger track selection change,
splitted for ease of review.
Find all cls with the tag:
#player-track-selection

PiperOrigin-RevId: 399933612
parent ece0cfc9
...@@ -24,6 +24,7 @@ import androidx.annotation.Nullable; ...@@ -24,6 +24,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Bundleable; import com.google.android.exoplayer2.Bundleable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
/** Utilities for {@link Bundleable}. */ /** Utilities for {@link Bundleable}. */
...@@ -108,14 +109,15 @@ public final class BundleableUtil { ...@@ -108,14 +109,15 @@ public final class BundleableUtil {
} }
/** /**
* Converts a list of {@link Bundleable} to an {@link ArrayList} of {@link Bundle} so that the * Converts a collection of {@link Bundleable} to an {@link ArrayList} of {@link Bundle} so that
* returned list can be put to {@link Bundle} using {@link Bundle#putParcelableArrayList} * the returned list can be put to {@link Bundle} using {@link Bundle#putParcelableArrayList}
* conveniently. * conveniently.
*/ */
public static <T extends Bundleable> ArrayList<Bundle> toBundleArrayList(List<T> bundleableList) { public static <T extends Bundleable> ArrayList<Bundle> toBundleArrayList(
ArrayList<Bundle> arrayList = new ArrayList<>(bundleableList.size()); Collection<T> bundleables) {
for (int i = 0; i < bundleableList.size(); i++) { ArrayList<Bundle> arrayList = new ArrayList<>(bundleables.size());
arrayList.add(bundleableList.get(i).toBundle()); for (T element : bundleables) {
arrayList.add(element.toBundle());
} }
return arrayList; return arrayList;
} }
......
...@@ -19,8 +19,14 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext; ...@@ -19,8 +19,14 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -58,10 +64,16 @@ public class TrackSelectionParametersTest { ...@@ -58,10 +64,16 @@ public class TrackSelectionParametersTest {
// General // General
assertThat(parameters.forceLowestBitrate).isFalse(); assertThat(parameters.forceLowestBitrate).isFalse();
assertThat(parameters.forceHighestSupportedBitrate).isFalse(); assertThat(parameters.forceHighestSupportedBitrate).isFalse();
assertThat(parameters.trackSelectionOverrides).isEmpty();
assertThat(parameters.disabledTrackTypes).isEmpty();
} }
@Test @Test
public void parametersSet_fromDefault_isAsExpected() { public void parametersSet_fromDefault_isAsExpected() {
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides =
ImmutableMap.of(
new TrackGroup(new Format.Builder().build()),
new TrackSelectionOverride(/* tracks= */ ImmutableSet.of(2, 3)));
TrackSelectionParameters parameters = TrackSelectionParameters parameters =
TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT
.buildUpon() .buildUpon()
...@@ -90,6 +102,8 @@ public class TrackSelectionParametersTest { ...@@ -90,6 +102,8 @@ public class TrackSelectionParametersTest {
// General // General
.setForceLowestBitrate(false) .setForceLowestBitrate(false)
.setForceHighestSupportedBitrate(true) .setForceHighestSupportedBitrate(true)
.setTrackSelectionOverrides(trackSelectionOverrides)
.setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_TEXT))
.build(); .build();
// Video // Video
...@@ -122,6 +136,9 @@ public class TrackSelectionParametersTest { ...@@ -122,6 +136,9 @@ public class TrackSelectionParametersTest {
// General // General
assertThat(parameters.forceLowestBitrate).isFalse(); assertThat(parameters.forceLowestBitrate).isFalse();
assertThat(parameters.forceHighestSupportedBitrate).isTrue(); assertThat(parameters.forceHighestSupportedBitrate).isTrue();
assertThat(parameters.trackSelectionOverrides).isEqualTo(trackSelectionOverrides);
assertThat(parameters.disabledTrackTypes)
.containsExactly(C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_TEXT);
} }
@Test @Test
...@@ -160,4 +177,17 @@ public class TrackSelectionParametersTest { ...@@ -160,4 +177,17 @@ public class TrackSelectionParametersTest {
assertThat(parameters.viewportHeight).isEqualTo(Integer.MAX_VALUE); assertThat(parameters.viewportHeight).isEqualTo(Integer.MAX_VALUE);
assertThat(parameters.viewportOrientationMayChange).isTrue(); assertThat(parameters.viewportOrientationMayChange).isTrue();
} }
/** Tests {@link SelectionOverride}'s {@link Bundleable} implementation. */
@Test
public void roundTripViaBundle_ofSelectionOverride_yieldsEqualInstance() {
SelectionOverride selectionOverrideToBundle =
new SelectionOverride(/* groupIndex= */ 1, /* tracks...= */ 2, 3);
SelectionOverride selectionOverrideFromBundle =
DefaultTrackSelector.SelectionOverride.CREATOR.fromBundle(
selectionOverrideToBundle.toBundle());
assertThat(selectionOverrideFromBundle).isEqualTo(selectionOverrideToBundle);
}
} }
...@@ -39,6 +39,7 @@ import com.google.android.exoplayer2.Timeline; ...@@ -39,6 +39,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.BundleableUtil; import com.google.android.exoplayer2.util.BundleableUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -609,6 +610,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -609,6 +610,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
@Override @Override
public ParametersBuilder setTrackSelectionOverrides(
Map<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) {
super.setTrackSelectionOverrides(trackSelectionOverrides);
return this;
}
@Override
public ParametersBuilder setDisabledTrackTypes(Set<@C.TrackType Integer> disabledTrackTypes) { public ParametersBuilder setDisabledTrackTypes(Set<@C.TrackType Integer> disabledTrackTypes) {
super.setDisabledTrackTypes(disabledTrackTypes); super.setDisabledTrackTypes(disabledTrackTypes);
return this; return this;
...@@ -1490,19 +1498,33 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1490,19 +1498,33 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Apply track disabling and overriding. // Apply track disabling and overriding.
for (int i = 0; i < rendererCount; i++) { for (int i = 0; i < rendererCount; i++) {
// Per renderer and per track type disabling
@C.TrackType int rendererType = mappedTrackInfo.getRendererType(i); @C.TrackType int rendererType = mappedTrackInfo.getRendererType(i);
if (params.getRendererDisabled(i) || params.disabledTrackTypes.contains(rendererType)) { if (params.getRendererDisabled(i) || params.disabledTrackTypes.contains(rendererType)) {
definitions[i] = null; definitions[i] = null;
continue; continue;
} }
// Per TrackGroupArray override
TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(i); TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(i);
if (params.hasSelectionOverride(i, rendererTrackGroups)) { if (params.hasSelectionOverride(i, rendererTrackGroups)) {
SelectionOverride override = params.getSelectionOverride(i, rendererTrackGroups); @Nullable SelectionOverride override = params.getSelectionOverride(i, rendererTrackGroups);
definitions[i] = definitions[i] =
override == null override == null
? null ? null
: new ExoTrackSelection.Definition( : new ExoTrackSelection.Definition(
rendererTrackGroups.get(override.groupIndex), override.tracks, override.type); rendererTrackGroups.get(override.groupIndex), override.tracks, override.type);
continue;
}
// Per TrackGroup override
for (int j = 0; j < rendererTrackGroups.length; j++) {
TrackGroup trackGroup = rendererTrackGroups.get(j);
@Nullable
TrackSelectionOverride overrideTracks = params.trackSelectionOverrides.get(trackGroup);
if (overrideTracks != null) {
definitions[i] =
new ExoTrackSelection.Definition(trackGroup, Ints.toArray(overrideTracks.tracks));
break;
}
} }
} }
......
...@@ -45,10 +45,12 @@ import com.google.android.exoplayer2.testutil.FakeTimeline; ...@@ -45,10 +45,12 @@ import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener; import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -152,16 +154,21 @@ public final class DefaultTrackSelectorTest { ...@@ -152,16 +154,21 @@ public final class DefaultTrackSelectorTest {
assertThat(parametersFromBundle).isEqualTo(parametersToBundle); assertThat(parametersFromBundle).isEqualTo(parametersToBundle);
} }
/** Tests {@link SelectionOverride}'s {@link Bundleable} implementation. */ /** Tests that an empty override clears a track selection. */
@Test @Test
public void roundTripViaBundle_ofSelectionOverride_yieldsEqualInstance() { public void selectTracks_withNullOverride_clearsTrackSelection() throws ExoPlaybackException {
SelectionOverride selectionOverrideToBundle = trackSelector.setParameters(
new SelectionOverride(/* groupIndex= */ 1, /* tracks...= */ 2, 3); trackSelector
.buildUponParameters()
.setTrackSelectionOverrides(
ImmutableMap.of(VIDEO_TRACK_GROUP, new TrackSelectionOverride(ImmutableSet.of()))));
SelectionOverride selectionOverrideFromBundle = TrackSelectorResult result =
SelectionOverride.CREATOR.fromBundle(selectionOverrideToBundle.toBundle()); trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS, periodId, TIMELINE);
assertThat(selectionOverrideFromBundle).isEqualTo(selectionOverrideToBundle); assertSelections(result, new TrackSelection[] {null, TRACK_SELECTIONS[1]});
assertThat(result.rendererConfigurations)
.isEqualTo(new RendererConfiguration[] {null, DEFAULT});
} }
/** Tests that a null override clears a track selection. */ /** Tests that a null override clears a track selection. */
...@@ -193,6 +200,29 @@ public final class DefaultTrackSelectorTest { ...@@ -193,6 +200,29 @@ public final class DefaultTrackSelectorTest {
.isEqualTo(new RendererConfiguration[] {DEFAULT, DEFAULT}); .isEqualTo(new RendererConfiguration[] {DEFAULT, DEFAULT});
} }
/** Tests that an empty override is not applied for a different set of available track groups. */
@Test
public void selectTracks_withEmptyTrackOverrideForDifferentTracks_hasNoEffect()
throws ExoPlaybackException {
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setTrackSelectionOverrides(
ImmutableMap.of(
new TrackGroup(VIDEO_FORMAT, VIDEO_FORMAT), TrackSelectionOverride.DISABLE)));
TrackSelectorResult result =
trackSelector.selectTracks(
RENDERER_CAPABILITIES,
new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP, VIDEO_TRACK_GROUP),
periodId,
TIMELINE);
assertThat(result.selections).asList().containsExactlyElementsIn(TRACK_SELECTIONS).inOrder();
assertThat(result.rendererConfigurations)
.isEqualTo(new RendererConfiguration[] {DEFAULT, DEFAULT});
}
/** Tests that an override is not applied for a different set of available track groups. */ /** Tests that an override is not applied for a different set of available track groups. */
@Test @Test
public void selectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException { public void selectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException {
...@@ -1815,6 +1845,10 @@ public final class DefaultTrackSelectorTest { ...@@ -1815,6 +1845,10 @@ public final class DefaultTrackSelectorTest {
.setRendererDisabled(1, true) .setRendererDisabled(1, true)
.setRendererDisabled(3, true) .setRendererDisabled(3, true)
.setRendererDisabled(5, false) .setRendererDisabled(5, false)
.setTrackSelectionOverrides(
ImmutableMap.of(
AUDIO_TRACK_GROUP,
new TrackSelectionOverride(/* tracks= */ ImmutableSet.of(3, 4, 5))))
.setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO)) .setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO))
.build(); .build();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment