Add TrackSelection.Factory createTrackSelections

createTrackSelections decides whether to create an adaptive or a fixed track seletion to create.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=222231011
This commit is contained in:
eguven 2018-11-20 05:32:51 -08:00 committed by Oliver Woodman
parent 55cc0df558
commit 527f2cf730
5 changed files with 196 additions and 136 deletions

View File

@ -1006,8 +1006,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param groups The {@link TrackGroupArray}. * @param groups The {@link TrackGroupArray}.
* @return The override, or null if no override exists. * @return The override, or null if no override exists.
*/ */
public final @Nullable SelectionOverride getSelectionOverride( @Nullable
int rendererIndex, TrackGroupArray groups) { public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex); Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
return overrides != null ? overrides.get(groups) : null; return overrides != null ? overrides.get(groups) : null;
} }
@ -1327,10 +1327,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static final int[] NO_TRACKS = new int[0]; private static final int[] NO_TRACKS = new int[0];
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000; private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
private final TrackSelection.Factory adaptiveTrackSelectionFactory; private final TrackSelection.Factory trackSelectionFactory;
private final AtomicReference<Parameters> parametersReference; private final AtomicReference<Parameters> parametersReference;
/** Constructs an instance that uses a default factory to create adaptive track selections. */
public DefaultTrackSelector() { public DefaultTrackSelector() {
this(new AdaptiveTrackSelection.Factory()); this(new AdaptiveTrackSelection.Factory());
} }
@ -1345,13 +1344,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this(new AdaptiveTrackSelection.Factory(bandwidthMeter)); this(new AdaptiveTrackSelection.Factory(bandwidthMeter));
} }
/** /** @param trackSelectionFactory A factory for {@link TrackSelection}s. */
* Constructs an instance that uses a factory to create adaptive track selections. public DefaultTrackSelector(TrackSelection.Factory trackSelectionFactory) {
* this.trackSelectionFactory = trackSelectionFactory;
* @param adaptiveTrackSelectionFactory A factory for adaptive {@link TrackSelection}s.
*/
public DefaultTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
parametersReference = new AtomicReference<>(Parameters.DEFAULT); parametersReference = new AtomicReference<>(Parameters.DEFAULT);
} }
@ -1420,8 +1415,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
/** @deprecated Use {@link Parameters#getSelectionOverride(int, TrackGroupArray)}. */ /** @deprecated Use {@link Parameters#getSelectionOverride(int, TrackGroupArray)}. */
@Deprecated @Deprecated
public final @Nullable SelectionOverride getSelectionOverride( @Nullable
int rendererIndex, TrackGroupArray groups) { public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
return getParameters().getSelectionOverride(rendererIndex, groups); return getParameters().getSelectionOverride(rendererIndex, groups);
} }
@ -1460,7 +1455,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
throws ExoPlaybackException { throws ExoPlaybackException {
Parameters params = parametersReference.get(); Parameters params = parametersReference.get();
int rendererCount = mappedTrackInfo.getRendererCount(); int rendererCount = mappedTrackInfo.getRendererCount();
@NullableType TrackSelection[] rendererTrackSelections = TrackSelection.@NullableType Definition[] definitions =
selectAllTracks( selectAllTracks(
mappedTrackInfo, mappedTrackInfo,
rendererFormatSupports, rendererFormatSupports,
@ -1470,28 +1465,24 @@ 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++) {
if (params.getRendererDisabled(i)) { if (params.getRendererDisabled(i)) {
rendererTrackSelections[i] = null; definitions[i] = null;
} else { continue;
}
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); SelectionOverride override = params.getSelectionOverride(i, rendererTrackGroups);
if (override == null) { definitions[i] =
rendererTrackSelections[i] = null; override == null
} else if (override.length == 1) { ? null
rendererTrackSelections[i] = : new TrackSelection.Definition(
new FixedTrackSelection( rendererTrackGroups.get(override.groupIndex), override.tracks);
rendererTrackGroups.get(override.groupIndex), override.tracks[0]);
} else {
rendererTrackSelections[i] =
adaptiveTrackSelectionFactory.createTrackSelection(
rendererTrackGroups.get(override.groupIndex),
getBandwidthMeter(),
override.tracks);
}
}
} }
} }
@NullableType
TrackSelection[] rendererTrackSelections =
trackSelectionFactory.createTrackSelections(definitions, getBandwidthMeter());
// Initialize the renderer configurations to the default configuration for all renderers with // Initialize the renderer configurations to the default configuration for all renderers with
// selections, and null otherwise. // selections, and null otherwise.
@NullableType RendererConfiguration[] rendererConfigurations = @NullableType RendererConfiguration[] rendererConfigurations =
@ -1530,32 +1521,33 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* each mapped track, indexed by renderer, track group and track (in that order). * each mapped track, indexed by renderer, track group and track (in that order).
* @param rendererMixedMimeTypeAdaptationSupports The result of {@link * @param rendererMixedMimeTypeAdaptationSupports The result of {@link
* RendererCapabilities#supportsMixedMimeTypeAdaptation()} for each renderer. * RendererCapabilities#supportsMixedMimeTypeAdaptation()} for each renderer.
* @return Track selections for each renderer. A null selection indicates the renderer should be * @return The {@link TrackSelection.Definition}s for the renderers. A null entry indicates no
* disabled, unless RendererCapabilities#getTrackType()} is {@link C#TRACK_TYPE_NONE}. * selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks. * @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/ */
protected @NullableType TrackSelection[] selectAllTracks( protected TrackSelection.@NullableType Definition[] selectAllTracks(
MappedTrackInfo mappedTrackInfo, MappedTrackInfo mappedTrackInfo,
int[][][] rendererFormatSupports, int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports, int[] rendererMixedMimeTypeAdaptationSupports,
Parameters params) Parameters params)
throws ExoPlaybackException { throws ExoPlaybackException {
int rendererCount = mappedTrackInfo.getRendererCount(); int rendererCount = mappedTrackInfo.getRendererCount();
@NullableType TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount]; TrackSelection.@NullableType Definition[] definitions =
new TrackSelection.Definition[rendererCount];
boolean seenVideoRendererWithMappedTracks = false; boolean seenVideoRendererWithMappedTracks = false;
boolean selectedVideoTracks = false; boolean selectedVideoTracks = false;
for (int i = 0; i < rendererCount; i++) { for (int i = 0; i < rendererCount; i++) {
if (C.TRACK_TYPE_VIDEO == mappedTrackInfo.getRendererType(i)) { if (C.TRACK_TYPE_VIDEO == mappedTrackInfo.getRendererType(i)) {
if (!selectedVideoTracks) { if (!selectedVideoTracks) {
rendererTrackSelections[i] = definitions[i] =
selectVideoTrack( selectVideoTrack(
mappedTrackInfo.getTrackGroups(i), mappedTrackInfo.getTrackGroups(i),
rendererFormatSupports[i], rendererFormatSupports[i],
rendererMixedMimeTypeAdaptationSupports[i], rendererMixedMimeTypeAdaptationSupports[i],
params, params,
adaptiveTrackSelectionFactory); /* enableAdaptiveTrackSelection= */ true);
selectedVideoTracks = rendererTrackSelections[i] != null; selectedVideoTracks = definitions[i] != null;
} }
seenVideoRendererWithMappedTracks |= mappedTrackInfo.getTrackGroups(i).length > 0; seenVideoRendererWithMappedTracks |= mappedTrackInfo.getTrackGroups(i).length > 0;
} }
@ -1572,49 +1564,49 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Already done. Do nothing. // Already done. Do nothing.
break; break;
case C.TRACK_TYPE_AUDIO: case C.TRACK_TYPE_AUDIO:
Pair<TrackSelection, AudioTrackScore> audioSelection = Pair<TrackSelection.Definition, AudioTrackScore> audioSelection =
selectAudioTrack( selectAudioTrack(
mappedTrackInfo.getTrackGroups(i), mappedTrackInfo.getTrackGroups(i),
rendererFormatSupports[i], rendererFormatSupports[i],
rendererMixedMimeTypeAdaptationSupports[i], rendererMixedMimeTypeAdaptationSupports[i],
params, params,
seenVideoRendererWithMappedTracks ? null : adaptiveTrackSelectionFactory); !seenVideoRendererWithMappedTracks);
if (audioSelection != null if (audioSelection != null
&& (selectedAudioTrackScore == null && (selectedAudioTrackScore == null
|| audioSelection.second.compareTo(selectedAudioTrackScore) > 0)) { || audioSelection.second.compareTo(selectedAudioTrackScore) > 0)) {
if (selectedAudioRendererIndex != C.INDEX_UNSET) { if (selectedAudioRendererIndex != C.INDEX_UNSET) {
// We've already made a selection for another audio renderer, but it had a lower // We've already made a selection for another audio renderer, but it had a lower
// score. Clear the selection for that renderer. // score. Clear the selection for that renderer.
rendererTrackSelections[selectedAudioRendererIndex] = null; definitions[selectedAudioRendererIndex] = null;
} }
rendererTrackSelections[i] = audioSelection.first; definitions[i] = audioSelection.first;
selectedAudioTrackScore = audioSelection.second; selectedAudioTrackScore = audioSelection.second;
selectedAudioRendererIndex = i; selectedAudioRendererIndex = i;
} }
break; break;
case C.TRACK_TYPE_TEXT: case C.TRACK_TYPE_TEXT:
Pair<TrackSelection, Integer> textSelection = Pair<TrackSelection.Definition, Integer> textSelection =
selectTextTrack(mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params); selectTextTrack(mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params);
if (textSelection != null && textSelection.second > selectedTextTrackScore) { if (textSelection != null && textSelection.second > selectedTextTrackScore) {
if (selectedTextRendererIndex != C.INDEX_UNSET) { if (selectedTextRendererIndex != C.INDEX_UNSET) {
// We've already made a selection for another text renderer, but it had a lower score. // We've already made a selection for another text renderer, but it had a lower score.
// Clear the selection for that renderer. // Clear the selection for that renderer.
rendererTrackSelections[selectedTextRendererIndex] = null; definitions[selectedTextRendererIndex] = null;
} }
rendererTrackSelections[i] = textSelection.first; definitions[i] = textSelection.first;
selectedTextTrackScore = textSelection.second; selectedTextTrackScore = textSelection.second;
selectedTextRendererIndex = i; selectedTextRendererIndex = i;
} }
break; break;
default: default:
rendererTrackSelections[i] = definitions[i] =
selectOtherTrack( selectOtherTrack(
trackType, mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params); trackType, mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params);
break; break;
} }
} }
return rendererTrackSelections; return definitions;
} }
// Video track selection implementation. // Video track selection implementation.
@ -1629,45 +1621,38 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param mixedMimeTypeAdaptationSupports The result of {@link * @param mixedMimeTypeAdaptationSupports The result of {@link
* RendererCapabilities#supportsMixedMimeTypeAdaptation()} for the renderer. * RendererCapabilities#supportsMixedMimeTypeAdaptation()} for the renderer.
* @param params The selector's current constraint parameters. * @param params The selector's current constraint parameters.
* @param adaptiveTrackSelectionFactory A factory for generating adaptive track selections, or * @param enableAdaptiveTrackSelection Whether adaptive track selection is allowed.
* null if a fixed track selection is required. * @return The {@link TrackSelection.Definition} for the renderer, or null if no selection was
* @return The {@link TrackSelection} for the renderer, or null if no selection was made. * made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks. * @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/ */
protected @Nullable TrackSelection selectVideoTrack( @Nullable
protected TrackSelection.Definition selectVideoTrack(
TrackGroupArray groups, TrackGroupArray groups,
int[][] formatSupports, int[][] formatSupports,
int mixedMimeTypeAdaptationSupports, int mixedMimeTypeAdaptationSupports,
Parameters params, Parameters params,
@Nullable TrackSelection.Factory adaptiveTrackSelectionFactory) boolean enableAdaptiveTrackSelection)
throws ExoPlaybackException { throws ExoPlaybackException {
TrackSelection selection = null; TrackSelection.Definition definition = null;
if (!params.forceHighestSupportedBitrate if (!params.forceHighestSupportedBitrate
&& !params.forceLowestBitrate && !params.forceLowestBitrate
&& adaptiveTrackSelectionFactory != null) { && enableAdaptiveTrackSelection) {
selection = definition =
selectAdaptiveVideoTrack( selectAdaptiveVideoTrack(groups, formatSupports, mixedMimeTypeAdaptationSupports, params);
groups,
formatSupports,
mixedMimeTypeAdaptationSupports,
params,
adaptiveTrackSelectionFactory,
getBandwidthMeter());
} }
if (selection == null) { if (definition == null) {
selection = selectFixedVideoTrack(groups, formatSupports, params); definition = selectFixedVideoTrack(groups, formatSupports, params);
} }
return selection; return definition;
} }
private static @Nullable TrackSelection selectAdaptiveVideoTrack( @Nullable
private static TrackSelection.Definition selectAdaptiveVideoTrack(
TrackGroupArray groups, TrackGroupArray groups,
int[][] formatSupport, int[][] formatSupport,
int mixedMimeTypeAdaptationSupports, int mixedMimeTypeAdaptationSupports,
Parameters params, Parameters params) {
TrackSelection.Factory adaptiveTrackSelectionFactory,
BandwidthMeter bandwidthMeter)
throws ExoPlaybackException {
int requiredAdaptiveSupport = int requiredAdaptiveSupport =
params.allowVideoNonSeamlessAdaptiveness params.allowVideoNonSeamlessAdaptiveness
? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS) ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS)
@ -1691,8 +1676,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
params.viewportHeight, params.viewportHeight,
params.viewportOrientationMayChange); params.viewportOrientationMayChange);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
return adaptiveTrackSelectionFactory.createTrackSelection( return new TrackSelection.Definition(group, adaptiveTracks);
group, bandwidthMeter, adaptiveTracks);
} }
} }
return null; return null;
@ -1835,7 +1819,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxVideoBitrate); && (format.bitrate == Format.NO_VALUE || format.bitrate <= maxVideoBitrate);
} }
private static @Nullable TrackSelection selectFixedVideoTrack( @Nullable
private static TrackSelection.Definition selectFixedVideoTrack(
TrackGroupArray groups, int[][] formatSupports, Parameters params) { TrackGroupArray groups, int[][] formatSupports, Parameters params) {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = 0;
@ -1897,8 +1882,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
} }
} }
return selectedGroup == null ? null return selectedGroup == null
: new FixedTrackSelection(selectedGroup, selectedTrackIndex); ? null
: new TrackSelection.Definition(selectedGroup, selectedTrackIndex);
} }
// Audio track selection implementation. // Audio track selection implementation.
@ -1913,19 +1899,19 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param mixedMimeTypeAdaptationSupports The result of {@link * @param mixedMimeTypeAdaptationSupports The result of {@link
* RendererCapabilities#supportsMixedMimeTypeAdaptation()} for the renderer. * RendererCapabilities#supportsMixedMimeTypeAdaptation()} for the renderer.
* @param params The selector's current constraint parameters. * @param params The selector's current constraint parameters.
* @param adaptiveTrackSelectionFactory A factory for generating adaptive track selections, or * @param enableAdaptiveTrackSelection Whether adaptive track selection is allowed.
* null if a fixed track selection is required. * @return The {@link TrackSelection.Definition} and corresponding {@link AudioTrackScore}, or
* @return The {@link TrackSelection} and corresponding {@link AudioTrackScore}, or null if no * null if no selection was made.
* selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks. * @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected @Nullable Pair<TrackSelection, AudioTrackScore> selectAudioTrack( @Nullable
protected Pair<TrackSelection.Definition, AudioTrackScore> selectAudioTrack(
TrackGroupArray groups, TrackGroupArray groups,
int[][] formatSupports, int[][] formatSupports,
int mixedMimeTypeAdaptationSupports, int mixedMimeTypeAdaptationSupports,
Parameters params, Parameters params,
@Nullable TrackSelection.Factory adaptiveTrackSelectionFactory) boolean enableAdaptiveTrackSelection)
throws ExoPlaybackException { throws ExoPlaybackException {
int selectedTrackIndex = C.INDEX_UNSET; int selectedTrackIndex = C.INDEX_UNSET;
int selectedGroupIndex = C.INDEX_UNSET; int selectedGroupIndex = C.INDEX_UNSET;
@ -1958,10 +1944,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
TrackGroup selectedGroup = groups.get(selectedGroupIndex); TrackGroup selectedGroup = groups.get(selectedGroupIndex);
TrackSelection selection = null; TrackSelection.Definition definition = null;
if (!params.forceHighestSupportedBitrate if (!params.forceHighestSupportedBitrate
&& !params.forceLowestBitrate && !params.forceLowestBitrate
&& adaptiveTrackSelectionFactory != null) { && enableAdaptiveTrackSelection) {
// If the group of the track with the highest score allows it, try to enable adaptation. // If the group of the track with the highest score allows it, try to enable adaptation.
int[] adaptiveTracks = int[] adaptiveTracks =
getAdaptiveAudioTracks( getAdaptiveAudioTracks(
@ -1970,17 +1956,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
params.allowAudioMixedMimeTypeAdaptiveness, params.allowAudioMixedMimeTypeAdaptiveness,
params.allowAudioMixedSampleRateAdaptiveness); params.allowAudioMixedSampleRateAdaptiveness);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
selection = definition = new TrackSelection.Definition(selectedGroup, adaptiveTracks);
adaptiveTrackSelectionFactory.createTrackSelection(
selectedGroup, getBandwidthMeter(), adaptiveTracks);
} }
} }
if (selection == null) { if (definition == null) {
// We didn't make an adaptive selection, so make a fixed one instead. // We didn't make an adaptive selection, so make a fixed one instead.
selection = new FixedTrackSelection(selectedGroup, selectedTrackIndex); definition = new TrackSelection.Definition(selectedGroup, selectedTrackIndex);
} }
return Pair.create(selection, Assertions.checkNotNull(selectedTrackScore)); return Pair.create(definition, Assertions.checkNotNull(selectedTrackScore));
} }
private static int[] getAdaptiveAudioTracks( private static int[] getAdaptiveAudioTracks(
@ -2076,11 +2060,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
* track, indexed by track group index and track index (in that order). * track, indexed by track group index and track index (in that order).
* @param params The selector's current constraint parameters. * @param params The selector's current constraint parameters.
* @return The {@link TrackSelection} and corresponding track score, or null if no selection was * @return The {@link TrackSelection.Definition} and corresponding track score, or null if no
* made. * selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks. * @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/ */
protected @Nullable Pair<TrackSelection, Integer> selectTextTrack( @Nullable
protected Pair<TrackSelection.Definition, Integer> selectTextTrack(
TrackGroupArray groups, int[][] formatSupport, Parameters params) TrackGroupArray groups, int[][] formatSupport, Parameters params)
throws ExoPlaybackException { throws ExoPlaybackException {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
@ -2138,7 +2123,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return selectedGroup == null return selectedGroup == null
? null ? null
: Pair.create( : Pair.create(
new FixedTrackSelection(selectedGroup, selectedTrackIndex), selectedTrackScore); new TrackSelection.Definition(selectedGroup, selectedTrackIndex), selectedTrackScore);
} }
// General track selection methods. // General track selection methods.
@ -2155,7 +2140,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @return The {@link TrackSelection} for the renderer, or null if no selection was made. * @return The {@link TrackSelection} for the renderer, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks. * @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/ */
protected @Nullable TrackSelection selectOtherTrack( @Nullable
protected TrackSelection.Definition selectOtherTrack(
int trackType, TrackGroupArray groups, int[][] formatSupport, Parameters params) int trackType, TrackGroupArray groups, int[][] formatSupport, Parameters params)
throws ExoPlaybackException { throws ExoPlaybackException {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
@ -2181,8 +2167,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
} }
} }
return selectedGroup == null ? null return selectedGroup == null
: new FixedTrackSelection(selectedGroup, selectedTrackIndex); ? null
: new TrackSelection.Definition(selectedGroup, selectedTrackIndex);
} }
// Utility methods. // Utility methods.

View File

@ -22,7 +22,9 @@ import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk; import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** /**
* A track selection consisting of a static subset of selected tracks belonging to a {@link * A track selection consisting of a static subset of selected tracks belonging to a {@link
@ -35,6 +37,24 @@ import java.util.List;
*/ */
public interface TrackSelection { public interface TrackSelection {
/** Contains of a subset of selected tracks belonging to a {@link TrackGroup}. */
final class Definition {
/** The {@link TrackGroup} which tracks belong to. */
public final TrackGroup group;
/** The indices of the selected tracks in {@link #group}. */
public final int[] tracks;
/**
* @param group The {@link TrackGroup}. Must not be null.
* @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be
* null or empty. May be in any order.
*/
public Definition(TrackGroup group, int... tracks) {
this.group = group;
this.tracks = tracks;
}
}
/** /**
* Factory for {@link TrackSelection} instances. * Factory for {@link TrackSelection} instances.
*/ */
@ -51,6 +71,33 @@ public interface TrackSelection {
*/ */
TrackSelection createTrackSelection( TrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks); TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks);
/**
* Creates a new selection for each {@link Definition}.
*
* @param definitions A {@link Definition} array. May include null values.
* @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks.
* @return The created selections. For null entries in {@code definitions} returns null values.
*/
default @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
boolean createdAdaptiveTrackSelection = false;
for (int i = 0; i < definitions.length; i++) {
Definition definition = definitions[i];
if (definition == null) {
continue;
}
if (definition.tracks.length > 1) {
Assertions.checkState(!createdAdaptiveTrackSelection);
createdAdaptiveTrackSelection = true;
selections[i] = createTrackSelection(definition.group, bandwidthMeter, definition.tracks);
} else {
selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]);
}
}
return selections;
}
} }
/** /**

View File

@ -773,7 +773,7 @@ public final class ExoPlayerTest {
} }
// There are 2 renderers, and track selections are made twice. The second time one renderer is // There are 2 renderers, and track selections are made twice. The second time one renderer is
// disabled, so only one out of the two track selections is enabled. // disabled, so only one out of the two track selections is enabled.
assertThat(createdTrackSelections).hasSize(4); assertThat(createdTrackSelections).hasSize(3);
assertThat(numSelectionsEnabled).isEqualTo(3); assertThat(numSelectionsEnabled).isEqualTo(3);
} }

View File

@ -50,7 +50,6 @@ import com.google.android.exoplayer2.testutil.HostActivity;
import com.google.android.exoplayer2.testutil.HostActivity.HostedTest; import com.google.android.exoplayer2.testutil.HostActivity.HostedTest;
import com.google.android.exoplayer2.testutil.MetricsLogger; import com.google.android.exoplayer2.testutil.MetricsLogger;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.RandomTrackSelection; import com.google.android.exoplayer2.trackselection.RandomTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
@ -382,6 +381,7 @@ public final class DashTestRunner {
private DashTestTrackSelector(String tag, String audioFormatId, String[] videoFormatIds, private DashTestTrackSelector(String tag, String audioFormatId, String[] videoFormatIds,
boolean canIncludeAdditionalVideoFormats) { boolean canIncludeAdditionalVideoFormats) {
super(new RandomTrackSelection.Factory(/* seed= */ 0));
this.tag = tag; this.tag = tag;
this.audioFormatId = audioFormatId; this.audioFormatId = audioFormatId;
this.videoFormatIds = videoFormatIds; this.videoFormatIds = videoFormatIds;
@ -389,7 +389,7 @@ public final class DashTestRunner {
} }
@Override @Override
protected TrackSelection[] selectAllTracks( protected TrackSelection.Definition[] selectAllTracks(
MappedTrackInfo mappedTrackInfo, MappedTrackInfo mappedTrackInfo,
int[][][] rendererFormatSupports, int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports, int[] rendererMixedMimeTypeAdaptationSupports,
@ -403,22 +403,22 @@ public final class DashTestRunner {
TrackGroupArray audioTrackGroups = mappedTrackInfo.getTrackGroups(AUDIO_RENDERER_INDEX); TrackGroupArray audioTrackGroups = mappedTrackInfo.getTrackGroups(AUDIO_RENDERER_INDEX);
Assertions.checkState(videoTrackGroups.length == 1); Assertions.checkState(videoTrackGroups.length == 1);
Assertions.checkState(audioTrackGroups.length == 1); Assertions.checkState(audioTrackGroups.length == 1);
TrackSelection[] selections = new TrackSelection[mappedTrackInfo.getRendererCount()]; TrackSelection.Definition[] definitions =
selections[VIDEO_RENDERER_INDEX] = new TrackSelection.Definition[mappedTrackInfo.getRendererCount()];
new RandomTrackSelection( definitions[VIDEO_RENDERER_INDEX] =
new TrackSelection.Definition(
videoTrackGroups.get(0), videoTrackGroups.get(0),
getVideoTrackIndices( getVideoTrackIndices(
videoTrackGroups.get(0), videoTrackGroups.get(0),
rendererFormatSupports[VIDEO_RENDERER_INDEX][0], rendererFormatSupports[VIDEO_RENDERER_INDEX][0],
videoFormatIds, videoFormatIds,
canIncludeAdditionalVideoFormats), canIncludeAdditionalVideoFormats));
0 /* seed */); definitions[AUDIO_RENDERER_INDEX] =
selections[AUDIO_RENDERER_INDEX] = new TrackSelection.Definition(
new FixedTrackSelection(
audioTrackGroups.get(0), getTrackIndex(audioTrackGroups.get(0), audioFormatId)); audioTrackGroups.get(0), getTrackIndex(audioTrackGroups.get(0), audioFormatId));
includedAdditionalVideoFormats = includedAdditionalVideoFormats =
selections[VIDEO_RENDERER_INDEX].length() > videoFormatIds.length; definitions[VIDEO_RENDERER_INDEX].tracks.length > videoFormatIds.length;
return selections; return definitions;
} }
private int[] getVideoTrackIndices( private int[] getVideoTrackIndices(

View File

@ -15,21 +15,19 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import android.support.annotation.NonNull;
import com.google.android.exoplayer2.ExoPlaybackException;
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.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** A fake {@link MappingTrackSelector} that returns {@link FakeTrackSelection}s. */ /** A fake {@link MappingTrackSelector} that returns {@link FakeTrackSelection}s. */
public class FakeTrackSelector extends DefaultTrackSelector { public class FakeTrackSelector extends DefaultTrackSelector {
private final List<FakeTrackSelection> trackSelections = new ArrayList<>(); private final FakeTrackSelectionFactory fakeTrackSelectionFactory;
private final boolean mayReuseTrackSelection;
public FakeTrackSelector() { public FakeTrackSelector() {
this(false); this(false);
@ -41,28 +39,48 @@ public class FakeTrackSelector extends DefaultTrackSelector {
* using the same {@link TrackGroup}. * using the same {@link TrackGroup}.
*/ */
public FakeTrackSelector(boolean mayReuseTrackSelection) { public FakeTrackSelector(boolean mayReuseTrackSelection) {
this.mayReuseTrackSelection = mayReuseTrackSelection; this(new FakeTrackSelectionFactory(mayReuseTrackSelection));
}
private FakeTrackSelector(FakeTrackSelectionFactory fakeTrackSelectionFactory) {
super(fakeTrackSelectionFactory);
this.fakeTrackSelectionFactory = fakeTrackSelectionFactory;
} }
@Override @Override
protected TrackSelection[] selectAllTracks( protected TrackSelection.Definition[] selectAllTracks(
MappedTrackInfo mappedTrackInfo, MappedTrackInfo mappedTrackInfo,
int[][][] rendererFormatSupports, int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports, int[] rendererMixedMimeTypeAdaptationSupports,
Parameters params) Parameters params) {
throws ExoPlaybackException {
int rendererCount = mappedTrackInfo.getRendererCount(); int rendererCount = mappedTrackInfo.getRendererCount();
TrackSelection[] selections = new TrackSelection[rendererCount]; TrackSelection.Definition[] definitions = new TrackSelection.Definition[rendererCount];
for (int i = 0; i < rendererCount; i++) { for (int i = 0; i < rendererCount; i++) {
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i); TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
boolean hasTracks = trackGroupArray.length > 0; boolean hasTracks = trackGroupArray.length > 0;
selections[i] = hasTracks ? reuseOrCreateTrackSelection(trackGroupArray.get(0)) : null; definitions[i] = hasTracks ? new TrackSelection.Definition(trackGroupArray.get(0)) : null;
} }
return selections; return definitions;
} }
@NonNull /** Returns list of all {@link FakeTrackSelection}s that this track selector has made so far. */
private FakeTrackSelection reuseOrCreateTrackSelection(TrackGroup trackGroup) { public List<FakeTrackSelection> getAllTrackSelections() {
return fakeTrackSelectionFactory.trackSelections;
}
private static class FakeTrackSelectionFactory implements TrackSelection.Factory {
private final List<FakeTrackSelection> trackSelections;
private final boolean mayReuseTrackSelection;
public FakeTrackSelectionFactory(boolean mayReuseTrackSelection) {
this.mayReuseTrackSelection = mayReuseTrackSelection;
trackSelections = new ArrayList<>();
}
@Override
public TrackSelection createTrackSelection(
TrackGroup trackGroup, BandwidthMeter bandwidthMeter, int... tracks) {
if (mayReuseTrackSelection) { if (mayReuseTrackSelection) {
for (FakeTrackSelection trackSelection : trackSelections) { for (FakeTrackSelection trackSelection : trackSelections) {
if (trackSelection.getTrackGroup().equals(trackGroup)) { if (trackSelection.getTrackGroup().equals(trackGroup)) {
@ -75,9 +93,17 @@ public class FakeTrackSelector extends DefaultTrackSelector {
return trackSelection; return trackSelection;
} }
/** Returns list of all {@link FakeTrackSelection}s that this track selector has made so far. */ @Override
public List<FakeTrackSelection> getAllTrackSelections() { public TrackSelection[] createTrackSelections(
return trackSelections; TrackSelection.Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
for (int i = 0; i < definitions.length; i++) {
TrackSelection.Definition definition = definitions[i];
if (definition != null) {
selections[i] = createTrackSelection(definition.group, bandwidthMeter, definition.tracks);
}
}
return selections;
}
} }
} }