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
This commit is contained in:
parent
ece0cfc9f2
commit
d5ef11aaf3
@ -16,6 +16,8 @@
|
|||||||
package com.google.android.exoplayer2.trackselection;
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
|
import static com.google.android.exoplayer2.util.BundleableUtil.fromBundleNullableList;
|
||||||
|
import static com.google.android.exoplayer2.util.BundleableUtil.toBundleArrayList;
|
||||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -23,23 +25,27 @@ import android.graphics.Point;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.view.accessibility.CaptioningManager;
|
import android.view.accessibility.CaptioningManager;
|
||||||
import androidx.annotation.CallSuper;
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import com.google.android.exoplayer2.Bundleable;
|
import com.google.android.exoplayer2.Bundleable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
|
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
|
||||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constraint parameters for track selection.
|
* Constraint parameters for track selection.
|
||||||
@ -93,6 +99,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
// General
|
// General
|
||||||
private boolean forceLowestBitrate;
|
private boolean forceLowestBitrate;
|
||||||
private boolean forceHighestSupportedBitrate;
|
private boolean forceHighestSupportedBitrate;
|
||||||
|
private ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides;
|
||||||
private ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
|
private ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,6 +130,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
// General
|
// General
|
||||||
forceLowestBitrate = false;
|
forceLowestBitrate = false;
|
||||||
forceHighestSupportedBitrate = false;
|
forceHighestSupportedBitrate = false;
|
||||||
|
trackSelectionOverrides = ImmutableMap.of();
|
||||||
disabledTrackTypes = ImmutableSet.of();
|
disabledTrackTypes = ImmutableSet.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +232,17 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
bundle.getBoolean(
|
bundle.getBoolean(
|
||||||
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE),
|
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE),
|
||||||
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
|
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
|
||||||
|
List<TrackGroup> keys =
|
||||||
|
fromBundleNullableList(
|
||||||
|
TrackGroup.CREATOR,
|
||||||
|
bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)),
|
||||||
|
ImmutableList.of());
|
||||||
|
List<TrackSelectionOverride> values =
|
||||||
|
fromBundleNullableList(
|
||||||
|
TrackSelectionOverride.CREATOR,
|
||||||
|
bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDE_VALUES)),
|
||||||
|
ImmutableList.of());
|
||||||
|
trackSelectionOverrides = zipToMap(keys, values);
|
||||||
disabledTrackTypes =
|
disabledTrackTypes =
|
||||||
ImmutableSet.copyOf(
|
ImmutableSet.copyOf(
|
||||||
Ints.asList(
|
Ints.asList(
|
||||||
@ -238,6 +256,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
"preferredAudioLanguages",
|
"preferredAudioLanguages",
|
||||||
"preferredAudioMimeTypes",
|
"preferredAudioMimeTypes",
|
||||||
"preferredTextLanguages",
|
"preferredTextLanguages",
|
||||||
|
"trackSelectionOverrides",
|
||||||
"disabledTrackTypes",
|
"disabledTrackTypes",
|
||||||
})
|
})
|
||||||
private void init(@UnknownInitialization Builder this, TrackSelectionParameters parameters) {
|
private void init(@UnknownInitialization Builder this, TrackSelectionParameters parameters) {
|
||||||
@ -267,6 +286,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
// General
|
// General
|
||||||
forceLowestBitrate = parameters.forceLowestBitrate;
|
forceLowestBitrate = parameters.forceLowestBitrate;
|
||||||
forceHighestSupportedBitrate = parameters.forceHighestSupportedBitrate;
|
forceHighestSupportedBitrate = parameters.forceHighestSupportedBitrate;
|
||||||
|
trackSelectionOverrides = parameters.trackSelectionOverrides;
|
||||||
disabledTrackTypes = parameters.disabledTrackTypes;
|
disabledTrackTypes = parameters.disabledTrackTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +635,18 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the selection overrides.
|
||||||
|
*
|
||||||
|
* @param trackSelectionOverrides The track selection overrides.
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
public Builder setTrackSelectionOverrides(
|
||||||
|
Map<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) {
|
||||||
|
this.trackSelectionOverrides = ImmutableMap.copyOf(trackSelectionOverrides);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the disabled track types, preventing all tracks of those types from being selected for
|
* Sets the disabled track types, preventing all tracks of those types from being selected for
|
||||||
* playback.
|
* playback.
|
||||||
@ -659,6 +691,83 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
}
|
}
|
||||||
return listBuilder.build();
|
return listBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <K, V> ImmutableMap<@NonNull K, @NonNull V> zipToMap(
|
||||||
|
List<@NonNull K> keys, List<@NonNull V> values) {
|
||||||
|
ImmutableMap.Builder<@NonNull K, @NonNull V> builder = new ImmutableMap.Builder<>();
|
||||||
|
for (int i = 0; i < keys.size(); i++) {
|
||||||
|
builder.put(keys.get(i), values.get(i));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces the selection of {@link #tracks} for a {@link TrackGroup}.
|
||||||
|
*
|
||||||
|
* @see #trackSelectionOverrides
|
||||||
|
*/
|
||||||
|
public static final class TrackSelectionOverride implements Bundleable {
|
||||||
|
/** Force the selection of the associated {@link TrackGroup}, but no track will be played. */
|
||||||
|
public static final TrackSelectionOverride DISABLE =
|
||||||
|
new TrackSelectionOverride(ImmutableSet.of());
|
||||||
|
|
||||||
|
/** The index of tracks in a {@link TrackGroup} to be selected. */
|
||||||
|
public final ImmutableSet<Integer> tracks;
|
||||||
|
|
||||||
|
/** Constructs an instance to force {@code tracks} to be selected. */
|
||||||
|
public TrackSelectionOverride(ImmutableSet<Integer> tracks) {
|
||||||
|
this.tracks = tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TrackSelectionOverride that = (TrackSelectionOverride) obj;
|
||||||
|
return tracks.equals(that.tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return tracks.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bundleable implementation
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({
|
||||||
|
FIELD_TRACKS,
|
||||||
|
})
|
||||||
|
private @interface FieldNumber {}
|
||||||
|
|
||||||
|
private static final int FIELD_TRACKS = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putIntArray(keyForField(FIELD_TRACKS), Ints.toArray(tracks));
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */
|
||||||
|
public static final Creator<TrackSelectionOverride> CREATOR =
|
||||||
|
bundle -> {
|
||||||
|
@Nullable int[] tracks = bundle.getIntArray(keyForField(FIELD_TRACKS));
|
||||||
|
if (tracks == null) {
|
||||||
|
return DISABLE;
|
||||||
|
}
|
||||||
|
return new TrackSelectionOverride(ImmutableSet.copyOf(Ints.asList(tracks)));
|
||||||
|
};
|
||||||
|
|
||||||
|
private static String keyForField(@FieldNumber int field) {
|
||||||
|
return Integer.toString(field, Character.MAX_RADIX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -810,6 +919,30 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
* other constraints. The default value is {@code false}.
|
* other constraints. The default value is {@code false}.
|
||||||
*/
|
*/
|
||||||
public final boolean forceHighestSupportedBitrate;
|
public final boolean forceHighestSupportedBitrate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each {@link TrackGroup} in the map, forces the tracks associated with it to be selected for
|
||||||
|
* playback.
|
||||||
|
*
|
||||||
|
* <p>For example if {@code trackSelectionOverrides.equals(ImmutableMap.of(trackGroup,
|
||||||
|
* ImmutableSet.of(1, 2, 3)))}, the tracks 1, 2 and 3 of {@code trackGroup} will be selected.
|
||||||
|
*
|
||||||
|
* <p>If multiple of the current {@link TrackGroup}s of the same {@link C.TrackType} are
|
||||||
|
* overridden, it is undetermined which one(s) will be selected. For example if a {@link
|
||||||
|
* MediaItem} has 2 video track groups (for example 2 different angles), and both are overriden,
|
||||||
|
* it is undetermined which one will be selected.
|
||||||
|
*
|
||||||
|
* <p>If multiple tracks of the {@link TrackGroup} are overriden, all supported (see {@link
|
||||||
|
* C.FormatSupport}) will be selected.
|
||||||
|
*
|
||||||
|
* <p>If a {@link TrackGroup} is associated with an empty set of tracks, no tracks will be played.
|
||||||
|
* This is similar to {@link #disabledTrackTypes}, except it will only affect the playback of the
|
||||||
|
* associated {@link TrackGroup}. For example, if the {@link C#TRACK_TYPE_VIDEO} {@link
|
||||||
|
* TrackGroup} is associated with no tracks, no video will play until the next video starts.
|
||||||
|
*
|
||||||
|
* <p>The default value is that no {@link TrackGroup} selections are overridden (empty map).
|
||||||
|
*/
|
||||||
|
public final ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides;
|
||||||
/**
|
/**
|
||||||
* The track types that are disabled. No track of a disabled type will be selected, thus no track
|
* 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
|
* type contained in the set will be played. The default value is that no track type is disabled
|
||||||
@ -844,6 +977,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
// General
|
// General
|
||||||
this.forceLowestBitrate = builder.forceLowestBitrate;
|
this.forceLowestBitrate = builder.forceLowestBitrate;
|
||||||
this.forceHighestSupportedBitrate = builder.forceHighestSupportedBitrate;
|
this.forceHighestSupportedBitrate = builder.forceHighestSupportedBitrate;
|
||||||
|
this.trackSelectionOverrides = builder.trackSelectionOverrides;
|
||||||
this.disabledTrackTypes = builder.disabledTrackTypes;
|
this.disabledTrackTypes = builder.disabledTrackTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -887,6 +1021,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
// General
|
// General
|
||||||
&& forceLowestBitrate == other.forceLowestBitrate
|
&& forceLowestBitrate == other.forceLowestBitrate
|
||||||
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
|
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
|
||||||
|
&& trackSelectionOverrides.equals(other.trackSelectionOverrides)
|
||||||
&& disabledTrackTypes.equals(other.disabledTrackTypes);
|
&& disabledTrackTypes.equals(other.disabledTrackTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -919,6 +1054,7 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
// General
|
// General
|
||||||
result = 31 * result + (forceLowestBitrate ? 1 : 0);
|
result = 31 * result + (forceLowestBitrate ? 1 : 0);
|
||||||
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
|
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
|
||||||
|
result = 31 * result + trackSelectionOverrides.hashCode();
|
||||||
result = 31 * result + disabledTrackTypes.hashCode();
|
result = 31 * result + disabledTrackTypes.hashCode();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -950,6 +1086,8 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
FIELD_PREFERRED_AUDIO_MIME_TYPES,
|
FIELD_PREFERRED_AUDIO_MIME_TYPES,
|
||||||
FIELD_FORCE_LOWEST_BITRATE,
|
FIELD_FORCE_LOWEST_BITRATE,
|
||||||
FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE,
|
FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE,
|
||||||
|
FIELD_SELECTION_OVERRIDE_KEYS,
|
||||||
|
FIELD_SELECTION_OVERRIDE_VALUES,
|
||||||
FIELD_DISABLED_TRACK_TYPE,
|
FIELD_DISABLED_TRACK_TYPE,
|
||||||
})
|
})
|
||||||
private @interface FieldNumber {}
|
private @interface FieldNumber {}
|
||||||
@ -976,10 +1114,11 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
private static final int FIELD_PREFERRED_AUDIO_MIME_TYPES = 20;
|
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_LOWEST_BITRATE = 21;
|
||||||
private static final int FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE = 22;
|
private static final int FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE = 22;
|
||||||
private static final int FIELD_DISABLED_TRACK_TYPE = 23;
|
private static final int FIELD_SELECTION_OVERRIDE_KEYS = 23;
|
||||||
|
private static final int FIELD_SELECTION_OVERRIDE_VALUES = 24;
|
||||||
|
private static final int FIELD_DISABLED_TRACK_TYPE = 25;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@CallSuper
|
|
||||||
public Bundle toBundle() {
|
public Bundle toBundle() {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
|
|
||||||
@ -1019,6 +1158,12 @@ public class TrackSelectionParameters implements Bundleable {
|
|||||||
bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate);
|
bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate);
|
||||||
bundle.putBoolean(
|
bundle.putBoolean(
|
||||||
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate);
|
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate);
|
||||||
|
bundle.putParcelableArrayList(
|
||||||
|
keyForField(FIELD_SELECTION_OVERRIDE_KEYS),
|
||||||
|
toBundleArrayList(trackSelectionOverrides.keySet()));
|
||||||
|
bundle.putParcelableArrayList(
|
||||||
|
keyForField(FIELD_SELECTION_OVERRIDE_VALUES),
|
||||||
|
toBundleArrayList(trackSelectionOverrides.values()));
|
||||||
bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes));
|
bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes));
|
||||||
|
|
||||||
return bundle;
|
return bundle;
|
||||||
|
@ -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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
// 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 {
|
|||||||
// 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 {
|
|||||||
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;
|
|||||||
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;
|
||||||
@ -608,6 +609,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParametersBuilder setTrackSelectionOverrides(
|
||||||
|
Map<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) {
|
||||||
|
super.setTrackSelectionOverrides(trackSelectionOverrides);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParametersBuilder setDisabledTrackTypes(Set<@C.TrackType Integer> disabledTrackTypes) {
|
public ParametersBuilder setDisabledTrackTypes(Set<@C.TrackType Integer> disabledTrackTypes) {
|
||||||
super.setDisabledTrackTypes(disabledTrackTypes);
|
super.setDisabledTrackTypes(disabledTrackTypes);
|
||||||
@ -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;
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
.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 {
|
|||||||
.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();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user