Move code unrelated to mapping to DefaultTrackSelector
Issue: #3915 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=192759210
This commit is contained in:
parent
0ee3963789
commit
67cde97a70
@ -29,10 +29,10 @@ import android.widget.CheckedTextView;
|
|||||||
import com.google.android.exoplayer2.RendererCapabilities;
|
import com.google.android.exoplayer2.RendererCapabilities;
|
||||||
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.SelectionOverride;
|
||||||
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.SelectionOverride;
|
|
||||||
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;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -46,7 +46,7 @@ import java.util.Arrays;
|
|||||||
private static final TrackSelection.Factory FIXED_FACTORY = new FixedTrackSelection.Factory();
|
private static final TrackSelection.Factory FIXED_FACTORY = new FixedTrackSelection.Factory();
|
||||||
private static final TrackSelection.Factory RANDOM_FACTORY = new RandomTrackSelection.Factory();
|
private static final TrackSelection.Factory RANDOM_FACTORY = new RandomTrackSelection.Factory();
|
||||||
|
|
||||||
private final MappingTrackSelector selector;
|
private final DefaultTrackSelector selector;
|
||||||
private final TrackSelection.Factory adaptiveTrackSelectionFactory;
|
private final TrackSelection.Factory adaptiveTrackSelectionFactory;
|
||||||
|
|
||||||
private MappedTrackInfo trackInfo;
|
private MappedTrackInfo trackInfo;
|
||||||
@ -63,11 +63,11 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param selector The track selector.
|
* @param selector The track selector.
|
||||||
* @param adaptiveTrackSelectionFactory A factory for adaptive {@link TrackSelection}s, or null
|
* @param adaptiveTrackSelectionFactory A factory for adaptive {@link TrackSelection}s, or null if
|
||||||
* if the selection helper should not support adaptive tracks.
|
* the selection helper should not support adaptive tracks.
|
||||||
*/
|
*/
|
||||||
public TrackSelectionHelper(MappingTrackSelector selector,
|
public TrackSelectionHelper(
|
||||||
TrackSelection.Factory adaptiveTrackSelectionFactory) {
|
DefaultTrackSelector selector, TrackSelection.Factory adaptiveTrackSelectionFactory) {
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
|
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
|
||||||
}
|
}
|
||||||
|
@ -21,59 +21,101 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.util.SparseBooleanArray;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.Player;
|
||||||
|
import com.google.android.exoplayer2.Renderer;
|
||||||
import com.google.android.exoplayer2.RendererCapabilities;
|
import com.google.android.exoplayer2.RendererCapabilities;
|
||||||
|
import com.google.android.exoplayer2.RendererConfiguration;
|
||||||
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.upstream.BandwidthMeter;
|
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default {@link TrackSelector} suitable for most use cases.
|
* A default {@link TrackSelector} suitable for most use cases.
|
||||||
*
|
*
|
||||||
* <h3>Constraint based track selection</h3>
|
* <h3>Constraint based track selection</h3>
|
||||||
* Whilst this selector supports setting specific track overrides, the recommended way of
|
*
|
||||||
* changing which tracks are selected is by setting {@link Parameters} that constrain the track
|
* Whilst this selector supports setting specific track overrides, the recommended way of changing
|
||||||
* selection process. For example an instance can specify a preferred language for
|
* which tracks are selected is by setting {@link Parameters} that constrain the track selection
|
||||||
* the audio track, and impose constraints on the maximum video resolution that should be selected
|
* process. For example an instance can specify a preferred language for the audio track, and impose
|
||||||
* for adaptive playbacks. Modifying the parameters is simple:
|
* constraints on the maximum video resolution that should be selected for adaptive playbacks.
|
||||||
* <pre>
|
* Modifying the parameters is simple:
|
||||||
* {@code
|
*
|
||||||
|
* <pre>{@code
|
||||||
* Parameters currentParameters = trackSelector.getParameters();
|
* Parameters currentParameters = trackSelector.getParameters();
|
||||||
* // Generate new parameters to prefer German audio and impose a maximum video size constraint.
|
* // Generate new parameters to prefer German audio and impose a maximum video size constraint.
|
||||||
* Parameters newParameters = currentParameters
|
* Parameters newParameters = currentParameters
|
||||||
* .withPreferredAudioLanguage("deu")
|
* .withPreferredAudioLanguage("deu")
|
||||||
* .withMaxVideoSize(1024, 768);
|
* .withMaxVideoSize(1024, 768);
|
||||||
* // Set the new parameters on the selector.
|
* // Set the new parameters on the selector.
|
||||||
* trackSelector.setParameters(newParameters);}
|
* trackSelector.setParameters(newParameters);
|
||||||
* </pre>
|
* }</pre>
|
||||||
|
*
|
||||||
* There are several benefits to using constraint based track selection instead of specific track
|
* There are several benefits to using constraint based track selection instead of specific track
|
||||||
* overrides:
|
* overrides:
|
||||||
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>You can specify constraints before knowing what tracks the media provides. This can
|
* <li>You can specify constraints before knowing what tracks the media provides. This can
|
||||||
* simplify track selection code (e.g. you don't have to listen for changes in the available
|
* simplify track selection code (e.g. you don't have to listen for changes in the available
|
||||||
* tracks before configuring the selector).</li>
|
* tracks before configuring the selector).
|
||||||
* <li>Constraints can be applied consistently across all periods in a complex piece of media,
|
* <li>Constraints can be applied consistently across all periods in a complex piece of media,
|
||||||
* even if those periods contain different tracks. In contrast, a specific track override is only
|
* even if those periods contain different tracks. In contrast, a specific track override is
|
||||||
* applied to periods whose tracks match those for which the override was set.</li>
|
* only applied to periods whose tracks match those for which the override was set.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <h3>Track overrides, disabling renderers and tunneling</h3>
|
* <h3>Track overrides</h3>
|
||||||
* This selector extends {@link MappingTrackSelector}, and so inherits its support for setting
|
|
||||||
* specific track overrides, disabling renderers and configuring tunneled media playback. See
|
|
||||||
* {@link MappingTrackSelector} for details.
|
|
||||||
*
|
*
|
||||||
* <h3>Extending this class</h3>
|
* This selector supports overriding of track selections for each renderer. To specify an override
|
||||||
* This class is designed to be extensible by developers who wish to customize its behavior but do
|
* for a renderer it's first necessary to obtain the tracks that have been mapped to it:
|
||||||
* not wish to implement their own {@link MappingTrackSelector} or {@link TrackSelector} from
|
*
|
||||||
* scratch.
|
* <pre>{@code
|
||||||
|
* MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
||||||
|
* TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
|
||||||
|
* : mappedTrackInfo.getTrackGroups(rendererIndex);
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so
|
||||||
|
* setting an override isn't possible. Note that a {@link Player.EventListener} registered on the
|
||||||
|
* player can be used to determine when the current tracks (and therefore the mapping) changes. If
|
||||||
|
* {@code rendererTrackGroups} is non-null then an override can be set. The next step is to query
|
||||||
|
* the properties of the available tracks to determine the {@code groupIndex} of the track group you
|
||||||
|
* want to select and the {@code trackIndices} within it. You can then create and set the override:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* trackSelector.setSelectionOverride(rendererIndex, rendererTrackGroups,
|
||||||
|
* new SelectionOverride(groupIndex, trackIndices));
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* If the override is {@code null} then no tracks will be selected.
|
||||||
|
*
|
||||||
|
* <p>Note that an override applies only when the track groups available to the renderer match the
|
||||||
|
* {@link TrackGroupArray} for which the override was specified. Overrides can be cleared using the
|
||||||
|
* {@code clearSelectionOverride} methods.
|
||||||
|
*
|
||||||
|
* <h3>Disabling renderers</h3>
|
||||||
|
*
|
||||||
|
* Renderers can be disabled using {@link #setRendererDisabled(int, boolean)}. Disabling a renderer
|
||||||
|
* differs from setting a {@code null} override because the renderer is disabled unconditionally,
|
||||||
|
* whereas a {@code null} override is applied only when the track groups available to the renderer
|
||||||
|
* match the {@link TrackGroupArray} for which it was specified.
|
||||||
|
*
|
||||||
|
* <h3>Tunneling</h3>
|
||||||
|
*
|
||||||
|
* Tunneled playback can be enabled in cases where the combination of renderers and selected tracks
|
||||||
|
* support it. See {@link #setTunnelingAudioSessionId(int)} for more details.
|
||||||
*/
|
*/
|
||||||
public class DefaultTrackSelector extends MappingTrackSelector {
|
public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
|
|
||||||
@ -587,6 +629,47 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A track selection override. */
|
||||||
|
public static class SelectionOverride {
|
||||||
|
|
||||||
|
public final TrackSelection.Factory factory;
|
||||||
|
public final int groupIndex;
|
||||||
|
public final int[] tracks;
|
||||||
|
public final int length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param factory A factory for creating selections from this override.
|
||||||
|
* @param groupIndex The overriding track group index.
|
||||||
|
* @param tracks The overriding track indices within the track group.
|
||||||
|
*/
|
||||||
|
public SelectionOverride(TrackSelection.Factory factory, int groupIndex, int... tracks) {
|
||||||
|
this.factory = factory;
|
||||||
|
this.groupIndex = groupIndex;
|
||||||
|
this.tracks = tracks;
|
||||||
|
this.length = tracks.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an selection from this override.
|
||||||
|
*
|
||||||
|
* @param groups The track groups whose selection is being overridden.
|
||||||
|
* @return The selection.
|
||||||
|
*/
|
||||||
|
public TrackSelection createTrackSelection(TrackGroupArray groups) {
|
||||||
|
return factory.createTrackSelection(groups.get(groupIndex), tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether this override contains the specified track index. */
|
||||||
|
public boolean containsTrack(int track) {
|
||||||
|
for (int overrideTrack : tracks) {
|
||||||
|
if (overrideTrack == track) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a dimension (i.e. width or height) of a video is greater or equal to this fraction of the
|
* If a dimension (i.e. width or height) of a video is greater or equal to this fraction of the
|
||||||
* corresponding viewport dimension, then the video is considered as filling the viewport (in that
|
* corresponding viewport dimension, then the video is considered as filling the viewport (in that
|
||||||
@ -598,6 +681,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
|
|
||||||
private final TrackSelection.Factory adaptiveTrackSelectionFactory;
|
private final TrackSelection.Factory adaptiveTrackSelectionFactory;
|
||||||
private final AtomicReference<Parameters> paramsReference;
|
private final AtomicReference<Parameters> paramsReference;
|
||||||
|
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
|
||||||
|
private final SparseBooleanArray rendererDisabledFlags;
|
||||||
|
|
||||||
|
private int tunnelingAudioSessionId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an instance that does not support adaptive track selection.
|
* Constructs an instance that does not support adaptive track selection.
|
||||||
@ -626,6 +713,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
public DefaultTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
|
public DefaultTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
|
||||||
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
|
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
|
||||||
paramsReference = new AtomicReference<>(Parameters.DEFAULT);
|
paramsReference = new AtomicReference<>(Parameters.DEFAULT);
|
||||||
|
selectionOverrides = new SparseArray<>();
|
||||||
|
rendererDisabledFlags = new SparseBooleanArray();
|
||||||
|
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -649,13 +739,220 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
return paramsReference.get();
|
return paramsReference.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents the
|
||||||
|
* selector from selecting any tracks for it.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @param disabled Whether the renderer is disabled.
|
||||||
|
*/
|
||||||
|
public final void setRendererDisabled(int rendererIndex, boolean disabled) {
|
||||||
|
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
||||||
|
// The disabled flag is unchanged.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rendererDisabledFlags.put(rendererIndex, disabled);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the renderer is disabled.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @return Whether the renderer is disabled.
|
||||||
|
*/
|
||||||
|
public final boolean getRendererDisabled(int rendererIndex) {
|
||||||
|
return rendererDisabledFlags.get(rendererIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the track selection for the renderer at the specified index.
|
||||||
|
*
|
||||||
|
* <p>When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the
|
||||||
|
* override is applied. When the {@link TrackGroupArray} does not match, the override has no
|
||||||
|
* effect. The override replaces any previous override for the specified {@link TrackGroupArray}
|
||||||
|
* for the specified {@link Renderer}.
|
||||||
|
*
|
||||||
|
* <p>Passing a {@code null} override will cause the renderer to be disabled when the {@link
|
||||||
|
* TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray} does
|
||||||
|
* not match a {@code null} override has no effect. Hence a {@code null} override differs from
|
||||||
|
* disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the renderer is
|
||||||
|
* disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as {@link
|
||||||
|
* #setRendererDisabled(int, boolean)} disables the renderer unconditionally.
|
||||||
|
*
|
||||||
|
* <p>To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)}, {@link
|
||||||
|
* #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
||||||
|
* @param override The override.
|
||||||
|
*/
|
||||||
|
public final void setSelectionOverride(
|
||||||
|
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
|
||||||
|
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||||
|
if (overrides == null) {
|
||||||
|
overrides = new HashMap<>();
|
||||||
|
selectionOverrides.put(rendererIndex, overrides);
|
||||||
|
}
|
||||||
|
if (overrides.containsKey(groups) && Util.areEqual(overrides.get(groups), override)) {
|
||||||
|
// The override is unchanged.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
overrides.put(groups, override);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether there is an override for the specified renderer and {@link TrackGroupArray}.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @param groups The {@link TrackGroupArray}.
|
||||||
|
* @return Whether there is an override.
|
||||||
|
*/
|
||||||
|
public final boolean hasSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||||
|
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||||
|
return overrides != null && overrides.containsKey(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the override for the specified renderer and {@link TrackGroupArray}.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @param groups The {@link TrackGroupArray}.
|
||||||
|
* @return The override, or null if no override exists.
|
||||||
|
*/
|
||||||
|
public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||||
|
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||||
|
return overrides != null ? overrides.get(groups) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears a track selection override for the specified renderer and {@link TrackGroupArray}.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
||||||
|
*/
|
||||||
|
public final void clearSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
||||||
|
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||||
|
if (overrides == null || !overrides.containsKey(groups)) {
|
||||||
|
// Nothing to clear.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
overrides.remove(groups);
|
||||||
|
if (overrides.isEmpty()) {
|
||||||
|
selectionOverrides.remove(rendererIndex);
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all track selection overrides for the specified renderer.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
*/
|
||||||
|
public final void clearSelectionOverrides(int rendererIndex) {
|
||||||
|
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
||||||
|
if (overrides == null || overrides.isEmpty()) {
|
||||||
|
// Nothing to clear.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectionOverrides.remove(rendererIndex);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clears all track selection overrides for all renderers. */
|
||||||
|
public final void clearSelectionOverrides() {
|
||||||
|
if (selectionOverrides.size() == 0) {
|
||||||
|
// Nothing to clear.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectionOverrides.clear();
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in
|
||||||
|
* tunneling mode. Session ids can be generated using {@link
|
||||||
|
* C#generateAudioSessionIdV21(Context)}. To disable tunneling pass {@link
|
||||||
|
* C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and supported
|
||||||
|
* by the audio and video renderers for the selected tracks.
|
||||||
|
*
|
||||||
|
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
||||||
|
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
||||||
|
*/
|
||||||
|
public void setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
||||||
|
if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
|
||||||
|
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MappingTrackSelector implementation.
|
// MappingTrackSelector implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities,
|
protected final Pair<RendererConfiguration[], TrackSelection[]> selectTracks(
|
||||||
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
|
RendererCapabilities[] rendererCapabilities, MappedTrackInfo mappedTrackInfo)
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
int rendererCount = rendererCapabilities.length;
|
||||||
|
TrackSelection[] rendererTrackSelections =
|
||||||
|
selectAllTracks(rendererCapabilities, mappedTrackInfo);
|
||||||
|
|
||||||
|
// Apply track disabling and overriding.
|
||||||
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
|
if (rendererDisabledFlags.get(i)) {
|
||||||
|
rendererTrackSelections[i] = null;
|
||||||
|
} else {
|
||||||
|
TrackGroupArray rendererTrackGroup = mappedTrackInfo.getTrackGroups(i);
|
||||||
|
if (hasSelectionOverride(i, rendererTrackGroup)) {
|
||||||
|
SelectionOverride override = selectionOverrides.get(i).get(rendererTrackGroup);
|
||||||
|
rendererTrackSelections[i] =
|
||||||
|
override == null ? null : override.createTrackSelection(rendererTrackGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the renderer configurations to the default configuration for all renderers with
|
||||||
|
// selections, and null otherwise.
|
||||||
|
RendererConfiguration[] rendererConfigurations =
|
||||||
|
new RendererConfiguration[rendererCapabilities.length];
|
||||||
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
|
boolean forceRendererDisabled = rendererDisabledFlags.get(i);
|
||||||
|
boolean rendererEnabled =
|
||||||
|
!forceRendererDisabled
|
||||||
|
&& (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE
|
||||||
|
|| rendererTrackSelections[i] != null);
|
||||||
|
rendererConfigurations[i] = rendererEnabled ? RendererConfiguration.DEFAULT : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure audio and video renderers to use tunneling if appropriate.
|
||||||
|
maybeConfigureRenderersForTunneling(
|
||||||
|
mappedTrackInfo,
|
||||||
|
rendererCapabilities,
|
||||||
|
rendererConfigurations,
|
||||||
|
rendererTrackSelections,
|
||||||
|
tunnelingAudioSessionId);
|
||||||
|
|
||||||
|
return Pair.create(rendererConfigurations, rendererTrackSelections);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track selection prior to overrides and disabled flags being applied.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from {@link #selectTracks(RendererCapabilities[], MappedTrackInfo)} to make a track
|
||||||
|
* selection for each renderer, prior to overrides and disabled flags being applied.
|
||||||
|
*
|
||||||
|
* <p>The implementation should not account for overrides and disabled flags. Track selections
|
||||||
|
* generated by this method will be overridden to account for these properties.
|
||||||
|
*
|
||||||
|
* @param rendererCapabilities The {@link RendererCapabilities} of each renderer.
|
||||||
|
* @param mappedTrackInfo Mapped track information.
|
||||||
|
* @return Track selections for each renderer. A null selection indicates the renderer should be
|
||||||
|
* disabled, unless RendererCapabilities#getTrackType()} is {@link C#TRACK_TYPE_NONE}.
|
||||||
|
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
|
||||||
|
*/
|
||||||
|
protected TrackSelection[] selectAllTracks(
|
||||||
|
RendererCapabilities[] rendererCapabilities, MappedTrackInfo mappedTrackInfo)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
// Make a track selection for each renderer.
|
|
||||||
int rendererCount = rendererCapabilities.length;
|
int rendererCount = rendererCapabilities.length;
|
||||||
TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount];
|
TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount];
|
||||||
Parameters params = paramsReference.get();
|
Parameters params = paramsReference.get();
|
||||||
@ -665,12 +962,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
for (int i = 0; i < rendererCount; i++) {
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
if (C.TRACK_TYPE_VIDEO == rendererCapabilities[i].getTrackType()) {
|
if (C.TRACK_TYPE_VIDEO == rendererCapabilities[i].getTrackType()) {
|
||||||
if (!selectedVideoTracks) {
|
if (!selectedVideoTracks) {
|
||||||
rendererTrackSelections[i] = selectVideoTrack(rendererCapabilities[i],
|
rendererTrackSelections[i] =
|
||||||
rendererTrackGroupArrays[i], rendererFormatSupports[i], params,
|
selectVideoTrack(
|
||||||
adaptiveTrackSelectionFactory);
|
rendererCapabilities[i],
|
||||||
|
mappedTrackInfo.getTrackGroups(i),
|
||||||
|
mappedTrackInfo.getRendererTrackSupport(i),
|
||||||
|
params,
|
||||||
|
adaptiveTrackSelectionFactory);
|
||||||
selectedVideoTracks = rendererTrackSelections[i] != null;
|
selectedVideoTracks = rendererTrackSelections[i] != null;
|
||||||
}
|
}
|
||||||
seenVideoRendererWithMappedTracks |= rendererTrackGroupArrays[i].length > 0;
|
seenVideoRendererWithMappedTracks |= mappedTrackInfo.getTrackGroups(i).length > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,33 +984,44 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
break;
|
break;
|
||||||
case C.TRACK_TYPE_AUDIO:
|
case C.TRACK_TYPE_AUDIO:
|
||||||
if (!selectedAudioTracks) {
|
if (!selectedAudioTracks) {
|
||||||
rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i],
|
rendererTrackSelections[i] =
|
||||||
rendererFormatSupports[i], params,
|
selectAudioTrack(
|
||||||
seenVideoRendererWithMappedTracks ? null : adaptiveTrackSelectionFactory);
|
mappedTrackInfo.getTrackGroups(i),
|
||||||
|
mappedTrackInfo.getRendererTrackSupport(i),
|
||||||
|
params,
|
||||||
|
seenVideoRendererWithMappedTracks ? null : adaptiveTrackSelectionFactory);
|
||||||
selectedAudioTracks = rendererTrackSelections[i] != null;
|
selectedAudioTracks = rendererTrackSelections[i] != null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case C.TRACK_TYPE_TEXT:
|
case C.TRACK_TYPE_TEXT:
|
||||||
if (!selectedTextTracks) {
|
if (!selectedTextTracks) {
|
||||||
rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i],
|
rendererTrackSelections[i] =
|
||||||
rendererFormatSupports[i], params);
|
selectTextTrack(
|
||||||
|
mappedTrackInfo.getTrackGroups(i),
|
||||||
|
mappedTrackInfo.getRendererTrackSupport(i),
|
||||||
|
params);
|
||||||
selectedTextTracks = rendererTrackSelections[i] != null;
|
selectedTextTracks = rendererTrackSelections[i] != null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(),
|
rendererTrackSelections[i] =
|
||||||
rendererTrackGroupArrays[i], rendererFormatSupports[i], params);
|
selectOtherTrack(
|
||||||
|
rendererCapabilities[i].getTrackType(),
|
||||||
|
mappedTrackInfo.getTrackGroups(i),
|
||||||
|
mappedTrackInfo.getRendererTrackSupport(i),
|
||||||
|
params);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rendererTrackSelections;
|
return rendererTrackSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Video track selection implementation.
|
// Video track selection implementation.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
|
* Called by {@link #selectTracks(RendererCapabilities[], MappedTrackInfo)} to create a {@link
|
||||||
* create a {@link TrackSelection} for a video renderer.
|
* TrackSelection} for a video renderer.
|
||||||
*
|
*
|
||||||
* @param rendererCapabilities The {@link RendererCapabilities} for the renderer.
|
* @param rendererCapabilities The {@link RendererCapabilities} for the renderer.
|
||||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||||
@ -721,9 +1033,13 @@ 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 TrackSelection selectVideoTrack(RendererCapabilities rendererCapabilities,
|
protected TrackSelection selectVideoTrack(
|
||||||
TrackGroupArray groups, int[][] formatSupport, Parameters params,
|
RendererCapabilities rendererCapabilities,
|
||||||
TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException {
|
TrackGroupArray groups,
|
||||||
|
int[][] formatSupport,
|
||||||
|
Parameters params,
|
||||||
|
TrackSelection.Factory adaptiveTrackSelectionFactory)
|
||||||
|
throws ExoPlaybackException {
|
||||||
TrackSelection selection = null;
|
TrackSelection selection = null;
|
||||||
if (!params.forceLowestBitrate && adaptiveTrackSelectionFactory != null) {
|
if (!params.forceLowestBitrate && adaptiveTrackSelectionFactory != null) {
|
||||||
selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport,
|
selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport,
|
||||||
@ -896,25 +1212,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
|
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two format values for order. A known value is considered greater than
|
|
||||||
* {@link Format#NO_VALUE}.
|
|
||||||
*
|
|
||||||
* @param first The first value.
|
|
||||||
* @param second The second value.
|
|
||||||
* @return A negative integer if the first value is less than the second. Zero if they are equal.
|
|
||||||
* A positive integer if the first value is greater than the second.
|
|
||||||
*/
|
|
||||||
private static int compareFormatValues(int first, int second) {
|
|
||||||
return first == Format.NO_VALUE ? (second == Format.NO_VALUE ? 0 : -1)
|
|
||||||
: (second == Format.NO_VALUE ? 1 : (first - second));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio track selection implementation.
|
// Audio track selection implementation.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
|
* Called by {@link #selectTracks(RendererCapabilities[], MappedTrackInfo)} to create a {@link
|
||||||
* create a {@link TrackSelection} for an audio renderer.
|
* TrackSelection} for an audio renderer.
|
||||||
*
|
*
|
||||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||||
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
||||||
@ -925,8 +1227,11 @@ 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 TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport,
|
protected TrackSelection selectAudioTrack(
|
||||||
Parameters params, TrackSelection.Factory adaptiveTrackSelectionFactory)
|
TrackGroupArray groups,
|
||||||
|
int[][] formatSupport,
|
||||||
|
Parameters params,
|
||||||
|
TrackSelection.Factory adaptiveTrackSelectionFactory)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
int selectedTrackIndex = C.INDEX_UNSET;
|
int selectedTrackIndex = C.INDEX_UNSET;
|
||||||
int selectedGroupIndex = C.INDEX_UNSET;
|
int selectedGroupIndex = C.INDEX_UNSET;
|
||||||
@ -1021,8 +1326,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
// Text track selection implementation.
|
// Text track selection implementation.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
|
* Called by {@link #selectTracks(RendererCapabilities[], MappedTrackInfo)} to create a {@link
|
||||||
* create a {@link TrackSelection} for a text renderer.
|
* TrackSelection} for a text renderer.
|
||||||
*
|
*
|
||||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||||
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
|
||||||
@ -1031,8 +1336,9 @@ 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 TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
|
protected TrackSelection selectTextTrack(
|
||||||
Parameters params) throws ExoPlaybackException {
|
TrackGroupArray groups, int[][] formatSupport, Parameters params)
|
||||||
|
throws ExoPlaybackException {
|
||||||
TrackGroup selectedGroup = null;
|
TrackGroup selectedGroup = null;
|
||||||
int selectedTrackIndex = 0;
|
int selectedTrackIndex = 0;
|
||||||
int selectedTrackScore = 0;
|
int selectedTrackScore = 0;
|
||||||
@ -1092,8 +1398,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
// General track selection methods.
|
// General track selection methods.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
|
* Called by {@link #selectTracks(RendererCapabilities[], MappedTrackInfo)} to create a {@link
|
||||||
* create a {@link TrackSelection} for a renderer whose type is neither video, audio or text.
|
* TrackSelection} for a renderer whose type is neither video, audio or text.
|
||||||
*
|
*
|
||||||
* @param trackType The type of the renderer.
|
* @param trackType The type of the renderer.
|
||||||
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
* @param groups The {@link TrackGroupArray} mapped to the renderer.
|
||||||
@ -1103,8 +1409,9 @@ 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 TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups,
|
protected TrackSelection selectOtherTrack(
|
||||||
int[][] formatSupport, Parameters params) throws ExoPlaybackException {
|
int trackType, TrackGroupArray groups, int[][] formatSupport, Parameters params)
|
||||||
|
throws ExoPlaybackException {
|
||||||
TrackGroup selectedGroup = null;
|
TrackGroup selectedGroup = null;
|
||||||
int selectedTrackIndex = 0;
|
int selectedTrackIndex = 0;
|
||||||
int selectedTrackScore = 0;
|
int selectedTrackScore = 0;
|
||||||
@ -1132,6 +1439,111 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
|
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility methods.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether tunneling should be enabled, replacing {@link RendererConfiguration}s in
|
||||||
|
* {@code rendererConfigurations} with configurations that enable tunneling on the appropriate
|
||||||
|
* renderers if so.
|
||||||
|
*
|
||||||
|
* @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which {@link
|
||||||
|
* TrackSelection}s are to be generated.
|
||||||
|
* @param rendererConfigurations The renderer configurations. Configurations may be replaced with
|
||||||
|
* ones that enable tunneling as a result of this call.
|
||||||
|
* @param trackSelections The renderer track selections.
|
||||||
|
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
|
||||||
|
* C#AUDIO_SESSION_ID_UNSET} if tunneling should not be enabled.
|
||||||
|
*/
|
||||||
|
private static void maybeConfigureRenderersForTunneling(
|
||||||
|
MappedTrackInfo mappedTrackInfo,
|
||||||
|
RendererCapabilities[] rendererCapabilities,
|
||||||
|
RendererConfiguration[] rendererConfigurations,
|
||||||
|
TrackSelection[] trackSelections,
|
||||||
|
int tunnelingAudioSessionId) {
|
||||||
|
if (tunnelingAudioSessionId == C.AUDIO_SESSION_ID_UNSET) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check whether we can enable tunneling. To enable tunneling we require exactly one audio and
|
||||||
|
// one video renderer to support tunneling and have a selection.
|
||||||
|
int tunnelingAudioRendererIndex = -1;
|
||||||
|
int tunnelingVideoRendererIndex = -1;
|
||||||
|
boolean enableTunneling = true;
|
||||||
|
for (int i = 0; i < rendererCapabilities.length; i++) {
|
||||||
|
int rendererType = rendererCapabilities[i].getTrackType();
|
||||||
|
TrackSelection trackSelection = trackSelections[i];
|
||||||
|
if ((rendererType == C.TRACK_TYPE_AUDIO || rendererType == C.TRACK_TYPE_VIDEO)
|
||||||
|
&& trackSelection != null) {
|
||||||
|
if (rendererSupportsTunneling(
|
||||||
|
mappedTrackInfo.getRendererTrackSupport(i),
|
||||||
|
mappedTrackInfo.getTrackGroups(i),
|
||||||
|
trackSelection)) {
|
||||||
|
if (rendererType == C.TRACK_TYPE_AUDIO) {
|
||||||
|
if (tunnelingAudioRendererIndex != -1) {
|
||||||
|
enableTunneling = false;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
tunnelingAudioRendererIndex = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tunnelingVideoRendererIndex != -1) {
|
||||||
|
enableTunneling = false;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
tunnelingVideoRendererIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enableTunneling &= tunnelingAudioRendererIndex != -1 && tunnelingVideoRendererIndex != -1;
|
||||||
|
if (enableTunneling) {
|
||||||
|
RendererConfiguration tunnelingRendererConfiguration =
|
||||||
|
new RendererConfiguration(tunnelingAudioSessionId);
|
||||||
|
rendererConfigurations[tunnelingAudioRendererIndex] = tunnelingRendererConfiguration;
|
||||||
|
rendererConfigurations[tunnelingVideoRendererIndex] = tunnelingRendererConfiguration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a renderer supports tunneling for a {@link TrackSelection}.
|
||||||
|
*
|
||||||
|
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each track,
|
||||||
|
* indexed by group index and track index (in that order).
|
||||||
|
* @param trackGroups The {@link TrackGroupArray}s for the renderer.
|
||||||
|
* @param selection The track selection.
|
||||||
|
* @return Whether the renderer supports tunneling for the {@link TrackSelection}.
|
||||||
|
*/
|
||||||
|
private static boolean rendererSupportsTunneling(
|
||||||
|
int[][] formatSupport, TrackGroupArray trackGroups, TrackSelection selection) {
|
||||||
|
if (selection == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup());
|
||||||
|
for (int i = 0; i < selection.length(); i++) {
|
||||||
|
int trackFormatSupport = formatSupport[trackGroupIndex][selection.getIndexInTrackGroup(i)];
|
||||||
|
if ((trackFormatSupport & RendererCapabilities.TUNNELING_SUPPORT_MASK)
|
||||||
|
!= RendererCapabilities.TUNNELING_SUPPORTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two format values for order. A known value is considered greater than {@link
|
||||||
|
* Format#NO_VALUE}.
|
||||||
|
*
|
||||||
|
* @param first The first value.
|
||||||
|
* @param second The second value.
|
||||||
|
* @return A negative integer if the first value is less than the second. Zero if they are equal.
|
||||||
|
* A positive integer if the first value is greater than the second.
|
||||||
|
*/
|
||||||
|
private static int compareFormatValues(int first, int second) {
|
||||||
|
return first == Format.NO_VALUE
|
||||||
|
? (second == Format.NO_VALUE ? 0 : -1)
|
||||||
|
: (second == Format.NO_VALUE ? 1 : (first - second));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the {@link RendererCapabilities#FORMAT_SUPPORT_MASK} to a value obtained from
|
* Applies the {@link RendererCapabilities#FORMAT_SUPPORT_MASK} to a value obtained from
|
||||||
* {@link RendererCapabilities#supportsFormat(Format)}, returning true if the result is
|
* {@link RendererCapabilities#supportsFormat(Format)}, returning true if the result is
|
||||||
@ -1175,8 +1587,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
&& TextUtils.equals(language, Util.normalizeLanguageCode(format.language));
|
&& TextUtils.equals(language, Util.normalizeLanguageCode(format.language));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Viewport size util methods.
|
|
||||||
|
|
||||||
private static List<Integer> getViewportFilteredTrackIndices(TrackGroup group, int viewportWidth,
|
private static List<Integer> getViewportFilteredTrackIndices(TrackGroup group, int viewportWidth,
|
||||||
int viewportHeight, boolean orientationMayChange) {
|
int viewportHeight, boolean orientationMayChange) {
|
||||||
// Initially include all indices.
|
// Initially include all indices.
|
||||||
|
@ -15,13 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.trackselection;
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.util.SparseArray;
|
import android.util.Pair;
|
||||||
import android.util.SparseBooleanArray;
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Player;
|
|
||||||
import com.google.android.exoplayer2.Renderer;
|
import com.google.android.exoplayer2.Renderer;
|
||||||
import com.google.android.exoplayer2.RendererCapabilities;
|
import com.google.android.exoplayer2.RendererCapabilities;
|
||||||
import com.google.android.exoplayer2.RendererConfiguration;
|
import com.google.android.exoplayer2.RendererConfiguration;
|
||||||
@ -31,51 +28,11 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for {@link TrackSelector}s that first establish a mapping between {@link TrackGroup}s
|
* Base class for {@link TrackSelector}s that first establish a mapping between {@link TrackGroup}s
|
||||||
* and {@link Renderer}s, and then from that mapping create a {@link TrackSelection} for each
|
* and {@link Renderer}s, and then from that mapping create a {@link TrackSelection} for each
|
||||||
* renderer.
|
* renderer.
|
||||||
*
|
|
||||||
* <h3>Track overrides</h3>
|
|
||||||
* Mapping track selectors support overriding of track selections for each renderer. To specify an
|
|
||||||
* override for a renderer it's first necessary to obtain the tracks that have been mapped to it:
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
|
||||||
* TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
|
|
||||||
* : mappedTrackInfo.getTrackGroups(rendererIndex);}
|
|
||||||
* </pre>
|
|
||||||
* If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so
|
|
||||||
* setting an override isn't possible. Note that a {@link Player.EventListener} registered on the
|
|
||||||
* player can be used to determine when the current tracks (and therefore the mapping) changes. If
|
|
||||||
* {@code rendererTrackGroups} is non-null then an override can be set. The next step is to query
|
|
||||||
* the properties of the available tracks to determine the {@code groupIndex} of the track group you
|
|
||||||
* want to select and the {@code trackIndices} within it. You can then create and set the override:
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* trackSelector.setSelectionOverride(rendererIndex, rendererTrackGroups,
|
|
||||||
* new SelectionOverride(trackSelectionFactory, groupIndex, trackIndices));}
|
|
||||||
* </pre>
|
|
||||||
* where {@code trackSelectionFactory} is a {@link TrackSelection.Factory} for generating concrete
|
|
||||||
* {@link TrackSelection} instances for the override. It's also possible to pass {@code null} as the
|
|
||||||
* selection override if you don't want any tracks to be selected.
|
|
||||||
* <p>
|
|
||||||
* Note that an override applies only when the track groups available to the renderer match the
|
|
||||||
* {@link TrackGroupArray} for which the override was specified. Overrides can be cleared using
|
|
||||||
* the {@code clearSelectionOverride} methods.
|
|
||||||
*
|
|
||||||
* <h3>Disabling renderers</h3>
|
|
||||||
* Renderers can be disabled using {@link #setRendererDisabled(int, boolean)}. Disabling a renderer
|
|
||||||
* differs from setting a {@code null} override because the renderer is disabled unconditionally,
|
|
||||||
* whereas a {@code null} override is applied only when the track groups available to the renderer
|
|
||||||
* match the {@link TrackGroupArray} for which it was specified.
|
|
||||||
*
|
|
||||||
* <h3>Tunneling</h3>
|
|
||||||
* Tunneled playback can be enabled in cases where the combination of renderers and selected tracks
|
|
||||||
* support it. See {@link #setTunnelingAudioSessionId(int)} for more details.
|
|
||||||
*/
|
*/
|
||||||
public abstract class MappingTrackSelector extends TrackSelector {
|
public abstract class MappingTrackSelector extends TrackSelector {
|
||||||
|
|
||||||
@ -147,6 +104,18 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
return trackGroups[rendererIndex];
|
return trackGroups[rendererIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the extent to which a renderer can play each of the tracks in the track groups mapped
|
||||||
|
* to it.
|
||||||
|
*
|
||||||
|
* @param rendererIndex The renderer index.
|
||||||
|
* @return The result of {@link RendererCapabilities#supportsFormat} for each track mapped to
|
||||||
|
* the renderer, indexed by track group and track index (in that order).
|
||||||
|
*/
|
||||||
|
public int[][] getRendererTrackSupport(int rendererIndex) {
|
||||||
|
return formatSupport[rendererIndex];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extent to which a renderer can play the tracks in the track groups mapped to it.
|
* Returns the extent to which a renderer can play the tracks in the track groups mapped to it.
|
||||||
*
|
*
|
||||||
@ -295,64 +264,19 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// TODO: Make DefaultTrackSelector.SelectionOverride final when this is removed.
|
||||||
* A track selection override.
|
/** @deprecated Use {@link DefaultTrackSelector.SelectionOverride} */
|
||||||
*/
|
@Deprecated
|
||||||
public static final class SelectionOverride {
|
public static final class SelectionOverride extends DefaultTrackSelector.SelectionOverride {
|
||||||
|
|
||||||
public final TrackSelection.Factory factory;
|
|
||||||
public final int groupIndex;
|
|
||||||
public final int[] tracks;
|
|
||||||
public final int length;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param factory A factory for creating selections from this override.
|
|
||||||
* @param groupIndex The overriding track group index.
|
|
||||||
* @param tracks The overriding track indices within the track group.
|
|
||||||
*/
|
|
||||||
public SelectionOverride(TrackSelection.Factory factory, int groupIndex, int... tracks) {
|
public SelectionOverride(TrackSelection.Factory factory, int groupIndex, int... tracks) {
|
||||||
this.factory = factory;
|
super(factory, groupIndex, tracks);
|
||||||
this.groupIndex = groupIndex;
|
|
||||||
this.tracks = tracks;
|
|
||||||
this.length = tracks.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an selection from this override.
|
|
||||||
*
|
|
||||||
* @param groups The track groups whose selection is being overridden.
|
|
||||||
* @return The selection.
|
|
||||||
*/
|
|
||||||
public TrackSelection createTrackSelection(TrackGroupArray groups) {
|
|
||||||
return factory.createTrackSelection(groups.get(groupIndex), tracks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether this override contains the specified track index.
|
|
||||||
*/
|
|
||||||
public boolean containsTrack(int track) {
|
|
||||||
for (int overrideTrack : tracks) {
|
|
||||||
if (overrideTrack == track) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
|
|
||||||
private final SparseBooleanArray rendererDisabledFlags;
|
|
||||||
private int tunnelingAudioSessionId;
|
|
||||||
|
|
||||||
private MappedTrackInfo currentMappedTrackInfo;
|
private MappedTrackInfo currentMappedTrackInfo;
|
||||||
|
|
||||||
public MappingTrackSelector() {
|
|
||||||
selectionOverrides = new SparseArray<>();
|
|
||||||
rendererDisabledFlags = new SparseBooleanArray();
|
|
||||||
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the mapping information for the currently active track selection, or null if no
|
* Returns the mapping information for the currently active track selection, or null if no
|
||||||
* selection is currently active.
|
* selection is currently active.
|
||||||
@ -361,158 +285,13 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
return currentMappedTrackInfo;
|
return currentMappedTrackInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents the
|
|
||||||
* selector from selecting any tracks for it.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
* @param disabled Whether the renderer is disabled.
|
|
||||||
*/
|
|
||||||
public final void setRendererDisabled(int rendererIndex, boolean disabled) {
|
|
||||||
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
|
|
||||||
// The disabled flag is unchanged.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rendererDisabledFlags.put(rendererIndex, disabled);
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the renderer is disabled.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
* @return Whether the renderer is disabled.
|
|
||||||
*/
|
|
||||||
public final boolean getRendererDisabled(int rendererIndex) {
|
|
||||||
return rendererDisabledFlags.get(rendererIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the track selection for the renderer at the specified index.
|
|
||||||
* <p>
|
|
||||||
* When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the override
|
|
||||||
* is applied. When the {@link TrackGroupArray} does not match, the override has no effect. The
|
|
||||||
* override replaces any previous override for the specified {@link TrackGroupArray} for the
|
|
||||||
* specified {@link Renderer}.
|
|
||||||
* <p>
|
|
||||||
* Passing a {@code null} override will cause the renderer to be disabled when the
|
|
||||||
* {@link TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray}
|
|
||||||
* does not match a {@code null} override has no effect. Hence a {@code null} override differs
|
|
||||||
* from disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the
|
|
||||||
* renderer is disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as
|
|
||||||
* {@link #setRendererDisabled(int, boolean)} disables the renderer unconditionally.
|
|
||||||
* <p>
|
|
||||||
* To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)},
|
|
||||||
* {@link #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
* @param groups The {@link TrackGroupArray} for which the override should be applied.
|
|
||||||
* @param override The override.
|
|
||||||
*/
|
|
||||||
public final void setSelectionOverride(int rendererIndex, TrackGroupArray groups,
|
|
||||||
SelectionOverride override) {
|
|
||||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
|
||||||
if (overrides == null) {
|
|
||||||
overrides = new HashMap<>();
|
|
||||||
selectionOverrides.put(rendererIndex, overrides);
|
|
||||||
}
|
|
||||||
if (overrides.containsKey(groups) && Util.areEqual(overrides.get(groups), override)) {
|
|
||||||
// The override is unchanged.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
overrides.put(groups, override);
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether there is an override for the specified renderer and {@link TrackGroupArray}.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
* @param groups The {@link TrackGroupArray}.
|
|
||||||
* @return Whether there is an override.
|
|
||||||
*/
|
|
||||||
public final boolean hasSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
|
||||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
|
||||||
return overrides != null && overrides.containsKey(groups);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the override for the specified renderer and {@link TrackGroupArray}.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
* @param groups The {@link TrackGroupArray}.
|
|
||||||
* @return The override, or null if no override exists.
|
|
||||||
*/
|
|
||||||
public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
|
||||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
|
||||||
return overrides != null ? overrides.get(groups) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears a track selection override for the specified renderer and {@link TrackGroupArray}.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
|
|
||||||
*/
|
|
||||||
public final void clearSelectionOverride(int rendererIndex, TrackGroupArray groups) {
|
|
||||||
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
|
|
||||||
if (overrides == null || !overrides.containsKey(groups)) {
|
|
||||||
// Nothing to clear.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
overrides.remove(groups);
|
|
||||||
if (overrides.isEmpty()) {
|
|
||||||
selectionOverrides.remove(rendererIndex);
|
|
||||||
}
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all track selection overrides for the specified renderer.
|
|
||||||
*
|
|
||||||
* @param rendererIndex The renderer index.
|
|
||||||
*/
|
|
||||||
public final void clearSelectionOverrides(int rendererIndex) {
|
|
||||||
Map<TrackGroupArray, ?> overrides = selectionOverrides.get(rendererIndex);
|
|
||||||
if (overrides == null || overrides.isEmpty()) {
|
|
||||||
// Nothing to clear.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectionOverrides.remove(rendererIndex);
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all track selection overrides for all renderers.
|
|
||||||
*/
|
|
||||||
public final void clearSelectionOverrides() {
|
|
||||||
if (selectionOverrides.size() == 0) {
|
|
||||||
// Nothing to clear.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectionOverrides.clear();
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in
|
|
||||||
* tunneling mode. Session ids can be generated using
|
|
||||||
* {@link C#generateAudioSessionIdV21(Context)}. To disable tunneling pass
|
|
||||||
* {@link C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and
|
|
||||||
* supported by the audio and video renderers for the selected tracks.
|
|
||||||
*
|
|
||||||
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or
|
|
||||||
* {@link C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
|
|
||||||
*/
|
|
||||||
public void setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
|
|
||||||
if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
|
|
||||||
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrackSelector implementation.
|
// TrackSelector implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onSelectionActivated(Object info) {
|
||||||
|
currentMappedTrackInfo = (MappedTrackInfo) info;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities,
|
public final TrackSelectorResult selectTracks(RendererCapabilities[] rendererCapabilities,
|
||||||
TrackGroupArray trackGroups) throws ExoPlaybackException {
|
TrackGroupArray trackGroups) throws ExoPlaybackException {
|
||||||
@ -562,75 +341,33 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
TrackGroupArray unassociatedTrackGroupArray = new TrackGroupArray(Arrays.copyOf(
|
TrackGroupArray unassociatedTrackGroupArray = new TrackGroupArray(Arrays.copyOf(
|
||||||
rendererTrackGroups[rendererCapabilities.length], unassociatedTrackGroupCount));
|
rendererTrackGroups[rendererCapabilities.length], unassociatedTrackGroupCount));
|
||||||
|
|
||||||
TrackSelection[] trackSelections = selectTracks(rendererCapabilities, rendererTrackGroupArrays,
|
|
||||||
rendererFormatSupports);
|
|
||||||
|
|
||||||
// Apply track disabling and overriding.
|
|
||||||
for (int i = 0; i < rendererCapabilities.length; i++) {
|
|
||||||
if (rendererDisabledFlags.get(i)) {
|
|
||||||
trackSelections[i] = null;
|
|
||||||
} else {
|
|
||||||
TrackGroupArray rendererTrackGroup = rendererTrackGroupArrays[i];
|
|
||||||
if (hasSelectionOverride(i, rendererTrackGroup)) {
|
|
||||||
SelectionOverride override = selectionOverrides.get(i).get(rendererTrackGroup);
|
|
||||||
trackSelections[i] = override == null ? null
|
|
||||||
: override.createTrackSelection(rendererTrackGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean[] rendererEnabled = determineEnabledRenderers(rendererCapabilities, trackSelections);
|
|
||||||
|
|
||||||
// Package up the track information and selections.
|
// Package up the track information and selections.
|
||||||
MappedTrackInfo mappedTrackInfo = new MappedTrackInfo(rendererTrackTypes,
|
MappedTrackInfo mappedTrackInfo =
|
||||||
rendererTrackGroupArrays, mixedMimeTypeAdaptationSupport, rendererFormatSupports,
|
new MappedTrackInfo(
|
||||||
unassociatedTrackGroupArray);
|
rendererTrackTypes,
|
||||||
|
rendererTrackGroupArrays,
|
||||||
|
mixedMimeTypeAdaptationSupport,
|
||||||
|
rendererFormatSupports,
|
||||||
|
unassociatedTrackGroupArray);
|
||||||
|
|
||||||
// Initialize the renderer configurations to the default configuration for all renderers with
|
Pair<RendererConfiguration[], TrackSelection[]> result =
|
||||||
// selections, and null otherwise.
|
selectTracks(rendererCapabilities, mappedTrackInfo);
|
||||||
RendererConfiguration[] rendererConfigurations =
|
return new TrackSelectorResult(result.first, result.second, mappedTrackInfo);
|
||||||
new RendererConfiguration[rendererCapabilities.length];
|
|
||||||
for (int i = 0; i < rendererCapabilities.length; i++) {
|
|
||||||
rendererConfigurations[i] = rendererEnabled[i] ? RendererConfiguration.DEFAULT : null;
|
|
||||||
}
|
|
||||||
// Configure audio and video renderers to use tunneling if appropriate.
|
|
||||||
maybeConfigureRenderersForTunneling(rendererCapabilities, rendererTrackGroupArrays,
|
|
||||||
rendererFormatSupports, rendererConfigurations, trackSelections, tunnelingAudioSessionId);
|
|
||||||
|
|
||||||
return new TrackSelectorResult(rendererConfigurations, trackSelections, mappedTrackInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean[] determineEnabledRenderers(RendererCapabilities[] rendererCapabilities,
|
|
||||||
TrackSelection[] trackSelections) {
|
|
||||||
boolean[] rendererEnabled = new boolean[trackSelections.length];
|
|
||||||
for (int i = 0; i < rendererEnabled.length; i++) {
|
|
||||||
boolean forceRendererDisabled = rendererDisabledFlags.get(i);
|
|
||||||
rendererEnabled[i] = !forceRendererDisabled
|
|
||||||
&& (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE
|
|
||||||
|| trackSelections[i] != null);
|
|
||||||
}
|
|
||||||
return rendererEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onSelectionActivated(Object info) {
|
|
||||||
currentMappedTrackInfo = (MappedTrackInfo) info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an array of renderer capabilities and the {@link TrackGroupArray}s mapped to each of
|
* Given mapped track information, returns a track selection and configuration for each renderer.
|
||||||
* them, provides a {@link TrackSelection} per renderer.
|
|
||||||
*
|
*
|
||||||
* @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which
|
* @param rendererCapabilities The {@link RendererCapabilities} of each renderer.
|
||||||
* {@link TrackSelection}s are to be generated.
|
* @param mappedTrackInfo Mapped track information.
|
||||||
* @param rendererTrackGroupArrays The {@link TrackGroupArray}s mapped to each of the renderers.
|
* @return A pair consisting of the track selections and configurations for each renderer. A null
|
||||||
* @param rendererFormatSupports The result of {@link RendererCapabilities#supportsFormat} for
|
* configuration indicates the renderer should be disabled, in which case the track selection
|
||||||
* each mapped track, indexed by renderer index, track group index and track index (in that
|
* will also be null. A track selection may also be null for a non-disabled renderer if {@link
|
||||||
* order).
|
* RendererCapabilities#getTrackType()} is {@link C#TRACK_TYPE_NONE}.
|
||||||
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
|
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
|
||||||
*/
|
*/
|
||||||
protected abstract TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities,
|
protected abstract Pair<RendererConfiguration[], TrackSelection[]> selectTracks(
|
||||||
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
|
RendererCapabilities[] rendererCapabilities, MappedTrackInfo mappedTrackInfo)
|
||||||
throws ExoPlaybackException;
|
throws ExoPlaybackException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -712,92 +449,4 @@ public abstract class MappingTrackSelector extends TrackSelector {
|
|||||||
return mixedMimeTypeAdaptationSupport;
|
return mixedMimeTypeAdaptationSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether tunneling should be enabled, replacing {@link RendererConfiguration}s in
|
|
||||||
* {@code rendererConfigurations} with configurations that enable tunneling on the appropriate
|
|
||||||
* renderers if so.
|
|
||||||
*
|
|
||||||
* @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which
|
|
||||||
* {@link TrackSelection}s are to be generated.
|
|
||||||
* @param rendererTrackGroupArrays An array of {@link TrackGroupArray}s where each entry
|
|
||||||
* corresponds to the renderer of equal index in {@code renderers}.
|
|
||||||
* @param rendererFormatSupports Maps every available track to a specific level of support as
|
|
||||||
* defined by the renderer {@code FORMAT_*} constants.
|
|
||||||
* @param rendererConfigurations The renderer configurations. Configurations may be replaced with
|
|
||||||
* ones that enable tunneling as a result of this call.
|
|
||||||
* @param trackSelections The renderer track selections.
|
|
||||||
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or
|
|
||||||
* {@link C#AUDIO_SESSION_ID_UNSET} if tunneling should not be enabled.
|
|
||||||
*/
|
|
||||||
private static void maybeConfigureRenderersForTunneling(
|
|
||||||
RendererCapabilities[] rendererCapabilities, TrackGroupArray[] rendererTrackGroupArrays,
|
|
||||||
int[][][] rendererFormatSupports, RendererConfiguration[] rendererConfigurations,
|
|
||||||
TrackSelection[] trackSelections, int tunnelingAudioSessionId) {
|
|
||||||
if (tunnelingAudioSessionId == C.AUDIO_SESSION_ID_UNSET) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check whether we can enable tunneling. To enable tunneling we require exactly one audio and
|
|
||||||
// one video renderer to support tunneling and have a selection.
|
|
||||||
int tunnelingAudioRendererIndex = -1;
|
|
||||||
int tunnelingVideoRendererIndex = -1;
|
|
||||||
boolean enableTunneling = true;
|
|
||||||
for (int i = 0; i < rendererCapabilities.length; i++) {
|
|
||||||
int rendererType = rendererCapabilities[i].getTrackType();
|
|
||||||
TrackSelection trackSelection = trackSelections[i];
|
|
||||||
if ((rendererType == C.TRACK_TYPE_AUDIO || rendererType == C.TRACK_TYPE_VIDEO)
|
|
||||||
&& trackSelection != null) {
|
|
||||||
if (rendererSupportsTunneling(rendererFormatSupports[i], rendererTrackGroupArrays[i],
|
|
||||||
trackSelection)) {
|
|
||||||
if (rendererType == C.TRACK_TYPE_AUDIO) {
|
|
||||||
if (tunnelingAudioRendererIndex != -1) {
|
|
||||||
enableTunneling = false;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
tunnelingAudioRendererIndex = i;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tunnelingVideoRendererIndex != -1) {
|
|
||||||
enableTunneling = false;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
tunnelingVideoRendererIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enableTunneling &= tunnelingAudioRendererIndex != -1 && tunnelingVideoRendererIndex != -1;
|
|
||||||
if (enableTunneling) {
|
|
||||||
RendererConfiguration tunnelingRendererConfiguration =
|
|
||||||
new RendererConfiguration(tunnelingAudioSessionId);
|
|
||||||
rendererConfigurations[tunnelingAudioRendererIndex] = tunnelingRendererConfiguration;
|
|
||||||
rendererConfigurations[tunnelingVideoRendererIndex] = tunnelingRendererConfiguration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a renderer supports tunneling for a {@link TrackSelection}.
|
|
||||||
*
|
|
||||||
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each
|
|
||||||
* track, indexed by group index and track index (in that order).
|
|
||||||
* @param trackGroups The {@link TrackGroupArray}s for the renderer.
|
|
||||||
* @param selection The track selection.
|
|
||||||
* @return Whether the renderer supports tunneling for the {@link TrackSelection}.
|
|
||||||
*/
|
|
||||||
private static boolean rendererSupportsTunneling(int[][] formatSupport,
|
|
||||||
TrackGroupArray trackGroups, TrackSelection selection) {
|
|
||||||
if (selection == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup());
|
|
||||||
for (int i = 0; i < selection.length(); i++) {
|
|
||||||
int trackFormatSupport = formatSupport[trackGroupIndex][selection.getIndexInTrackGroup(i)];
|
|
||||||
if ((trackFormatSupport & RendererCapabilities.TUNNELING_SUPPORT_MASK)
|
|
||||||
!= RendererCapabilities.TUNNELING_SUPPORTED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -668,7 +668,7 @@ public final class ExoPlayerTest {
|
|||||||
.start()
|
.start()
|
||||||
.blockUntilEnded(TIMEOUT_MS);
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
|
List<FakeTrackSelection> createdTrackSelections = trackSelector.getAllTrackSelections();
|
||||||
int numSelectionsEnabled = 0;
|
int numSelectionsEnabled = 0;
|
||||||
// Assert that all tracks selection are disabled at the end of the playback.
|
// Assert that all tracks selection are disabled at the end of the playback.
|
||||||
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
||||||
@ -676,9 +676,7 @@ public final class ExoPlayerTest {
|
|||||||
numSelectionsEnabled += trackSelection.enableCount;
|
numSelectionsEnabled += trackSelection.enableCount;
|
||||||
}
|
}
|
||||||
// There are 2 renderers, and track selections are made once (1 period).
|
// There are 2 renderers, and track selections are made once (1 period).
|
||||||
// Track selections are not reused, so there are 2 track selections made.
|
|
||||||
assertThat(createdTrackSelections).hasSize(2);
|
assertThat(createdTrackSelections).hasSize(2);
|
||||||
// There should be 2 track selections enabled in total.
|
|
||||||
assertThat(numSelectionsEnabled).isEqualTo(2);
|
assertThat(numSelectionsEnabled).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,7 +697,7 @@ public final class ExoPlayerTest {
|
|||||||
.start()
|
.start()
|
||||||
.blockUntilEnded(TIMEOUT_MS);
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
|
List<FakeTrackSelection> createdTrackSelections = trackSelector.getAllTrackSelections();
|
||||||
int numSelectionsEnabled = 0;
|
int numSelectionsEnabled = 0;
|
||||||
// Assert that all tracks selection are disabled at the end of the playback.
|
// Assert that all tracks selection are disabled at the end of the playback.
|
||||||
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
||||||
@ -707,9 +705,7 @@ public final class ExoPlayerTest {
|
|||||||
numSelectionsEnabled += trackSelection.enableCount;
|
numSelectionsEnabled += trackSelection.enableCount;
|
||||||
}
|
}
|
||||||
// There are 2 renderers, and track selections are made twice (2 periods).
|
// There are 2 renderers, and track selections are made twice (2 periods).
|
||||||
// Track selections are not reused, so there are 4 track selections made.
|
|
||||||
assertThat(createdTrackSelections).hasSize(4);
|
assertThat(createdTrackSelections).hasSize(4);
|
||||||
// There should be 4 track selections enabled in total.
|
|
||||||
assertThat(numSelectionsEnabled).isEqualTo(4);
|
assertThat(numSelectionsEnabled).isEqualTo(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,23 +735,21 @@ public final class ExoPlayerTest {
|
|||||||
.start()
|
.start()
|
||||||
.blockUntilEnded(TIMEOUT_MS);
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
|
List<FakeTrackSelection> createdTrackSelections = trackSelector.getAllTrackSelections();
|
||||||
int numSelectionsEnabled = 0;
|
int numSelectionsEnabled = 0;
|
||||||
// Assert that all tracks selection are disabled at the end of the playback.
|
// Assert that all tracks selection are disabled at the end of the playback.
|
||||||
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
||||||
assertThat(trackSelection.isEnabled).isFalse();
|
assertThat(trackSelection.isEnabled).isFalse();
|
||||||
numSelectionsEnabled += trackSelection.enableCount;
|
numSelectionsEnabled += trackSelection.enableCount;
|
||||||
}
|
}
|
||||||
// There are 2 renderers, and track selections are made twice.
|
// There are 2 renderers, and track selections are made twice. The second time one renderer is
|
||||||
// Track selections are not reused, so there are 4 track selections made.
|
// disabled, so only one out of the two track selections is enabled.
|
||||||
assertThat(createdTrackSelections).hasSize(4);
|
assertThat(createdTrackSelections).hasSize(4);
|
||||||
// Initially there are 2 track selections enabled.
|
|
||||||
// The second time one renderer is disabled, so only 1 track selection should be enabled.
|
|
||||||
assertThat(numSelectionsEnabled).isEqualTo(3);
|
assertThat(numSelectionsEnabled).isEqualTo(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAllActivatedTrackSelectionAreReleasedWhenTrackSelectionsAreUsed()
|
public void testAllActivatedTrackSelectionAreReleasedWhenTrackSelectionsAreReused()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
|
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
|
||||||
MediaSource mediaSource =
|
MediaSource mediaSource =
|
||||||
@ -780,18 +774,17 @@ public final class ExoPlayerTest {
|
|||||||
.start()
|
.start()
|
||||||
.blockUntilEnded(TIMEOUT_MS);
|
.blockUntilEnded(TIMEOUT_MS);
|
||||||
|
|
||||||
List<FakeTrackSelection> createdTrackSelections = trackSelector.getSelectedTrackSelections();
|
List<FakeTrackSelection> createdTrackSelections = trackSelector.getAllTrackSelections();
|
||||||
int numSelectionsEnabled = 0;
|
int numSelectionsEnabled = 0;
|
||||||
// Assert that all tracks selection are disabled at the end of the playback.
|
// Assert that all tracks selection are disabled at the end of the playback.
|
||||||
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
for (FakeTrackSelection trackSelection : createdTrackSelections) {
|
||||||
assertThat(trackSelection.isEnabled).isFalse();
|
assertThat(trackSelection.isEnabled).isFalse();
|
||||||
numSelectionsEnabled += trackSelection.enableCount;
|
numSelectionsEnabled += trackSelection.enableCount;
|
||||||
}
|
}
|
||||||
// There are 2 renderers, and track selections are made twice.
|
// There are 2 renderers, and track selections are made twice. The second time one renderer is
|
||||||
// TrackSelections are reused, so there are only 2 track selections made for 2 renderers.
|
// disabled, and the selector re-uses the previous selection for the enabled renderer. So we
|
||||||
|
// expect two track selections, one of which will have been enabled twice.
|
||||||
assertThat(createdTrackSelections).hasSize(2);
|
assertThat(createdTrackSelections).hasSize(2);
|
||||||
// Initially there are 2 track selections enabled.
|
|
||||||
// The second time one renderer is disabled, so only 1 track selection should be enabled.
|
|
||||||
assertThat(numSelectionsEnabled).isEqualTo(3);
|
assertThat(numSelectionsEnabled).isEqualTo(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,10 +17,12 @@ package com.google.android.exoplayer2.trackselection;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.RendererCapabilities;
|
import com.google.android.exoplayer2.RendererCapabilities;
|
||||||
|
import com.google.android.exoplayer2.RendererConfiguration;
|
||||||
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.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
@ -90,25 +92,28 @@ public final class MappingTrackSelectorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingTrackSelector} that returns a fixed result from
|
* A {@link MappingTrackSelector} that stashes the {@link MappedTrackInfo} passed to {@link
|
||||||
* {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])}.
|
* #selectTracks(RendererCapabilities[], MappedTrackInfo)}.
|
||||||
*/
|
*/
|
||||||
private static final class FakeMappingTrackSelector extends MappingTrackSelector {
|
private static final class FakeMappingTrackSelector extends MappingTrackSelector {
|
||||||
|
|
||||||
private TrackGroupArray[] lastRendererTrackGroupArrays;
|
private MappedTrackInfo lastMappedTrackInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities,
|
protected Pair<RendererConfiguration[], TrackSelection[]> selectTracks(
|
||||||
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
|
RendererCapabilities[] rendererCapabilities, MappedTrackInfo mappedTrackInfo)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
lastRendererTrackGroupArrays = rendererTrackGroupArrays;
|
lastMappedTrackInfo = mappedTrackInfo;
|
||||||
return new TrackSelection[rendererCapabilities.length];
|
return Pair.create(
|
||||||
|
new RendererConfiguration[rendererCapabilities.length],
|
||||||
|
new TrackSelection[rendererCapabilities.length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertMappedTrackGroups(int rendererIndex, TrackGroup... expected) {
|
public void assertMappedTrackGroups(int rendererIndex, TrackGroup... expected) {
|
||||||
assertThat(lastRendererTrackGroupArrays[rendererIndex].length).isEqualTo(expected.length);
|
TrackGroupArray rendererTrackGroupArray = lastMappedTrackInfo.getTrackGroups(rendererIndex);
|
||||||
|
assertThat(rendererTrackGroupArray.length).isEqualTo(expected.length);
|
||||||
for (int i = 0; i < expected.length; i++) {
|
for (int i = 0; i < expected.length; i++) {
|
||||||
assertThat(lastRendererTrackGroupArrays[rendererIndex].get(i)).isEqualTo(expected[i]);
|
assertThat(rendererTrackGroupArray.get(i)).isEqualTo(expected[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,25 +394,30 @@ public final class DashTestRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities,
|
protected TrackSelection[] selectAllTracks(
|
||||||
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
|
RendererCapabilities[] rendererCapabilities, MappedTrackInfo mappedTrackInfo)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
Assertions.checkState(rendererCapabilities[VIDEO_RENDERER_INDEX].getTrackType()
|
Assertions.checkState(rendererCapabilities[VIDEO_RENDERER_INDEX].getTrackType()
|
||||||
== C.TRACK_TYPE_VIDEO);
|
== C.TRACK_TYPE_VIDEO);
|
||||||
Assertions.checkState(rendererCapabilities[AUDIO_RENDERER_INDEX].getTrackType()
|
Assertions.checkState(rendererCapabilities[AUDIO_RENDERER_INDEX].getTrackType()
|
||||||
== C.TRACK_TYPE_AUDIO);
|
== C.TRACK_TYPE_AUDIO);
|
||||||
Assertions.checkState(rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].length == 1);
|
TrackGroupArray videoTrackGroups = mappedTrackInfo.getTrackGroups(VIDEO_RENDERER_INDEX);
|
||||||
Assertions.checkState(rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].length == 1);
|
TrackGroupArray audioTrackGroups = mappedTrackInfo.getTrackGroups(AUDIO_RENDERER_INDEX);
|
||||||
|
Assertions.checkState(videoTrackGroups.length == 1);
|
||||||
|
Assertions.checkState(audioTrackGroups.length == 1);
|
||||||
TrackSelection[] selections = new TrackSelection[rendererCapabilities.length];
|
TrackSelection[] selections = new TrackSelection[rendererCapabilities.length];
|
||||||
selections[VIDEO_RENDERER_INDEX] = new RandomTrackSelection(
|
selections[VIDEO_RENDERER_INDEX] =
|
||||||
rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].get(0),
|
new RandomTrackSelection(
|
||||||
getVideoTrackIndices(rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].get(0),
|
videoTrackGroups.get(0),
|
||||||
rendererFormatSupports[VIDEO_RENDERER_INDEX][0], videoFormatIds,
|
getVideoTrackIndices(
|
||||||
canIncludeAdditionalVideoFormats),
|
videoTrackGroups.get(0),
|
||||||
0 /* seed */);
|
mappedTrackInfo.getRendererTrackSupport(VIDEO_RENDERER_INDEX)[0],
|
||||||
selections[AUDIO_RENDERER_INDEX] = new FixedTrackSelection(
|
videoFormatIds,
|
||||||
rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].get(0),
|
canIncludeAdditionalVideoFormats),
|
||||||
getTrackIndex(rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].get(0), audioFormatId));
|
0 /* seed */);
|
||||||
|
selections[AUDIO_RENDERER_INDEX] =
|
||||||
|
new FixedTrackSelection(
|
||||||
|
audioTrackGroups.get(0), getTrackIndex(audioTrackGroups.get(0), audioFormatId));
|
||||||
includedAdditionalVideoFormats =
|
includedAdditionalVideoFormats =
|
||||||
selections[VIDEO_RENDERER_INDEX].length() > videoFormatIds.length;
|
selections[VIDEO_RENDERER_INDEX].length() > videoFormatIds.length;
|
||||||
return selections;
|
return selections;
|
||||||
|
@ -21,14 +21,15 @@ import com.google.android.exoplayer2.RendererCapabilities;
|
|||||||
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.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** A fake {@link DefaultTrackSelector} 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> selectedTrackSelections = new ArrayList<>();
|
private final List<FakeTrackSelection> trackSelections = new ArrayList<>();
|
||||||
private final boolean mayReuseTrackSelection;
|
private final boolean mayReuseTrackSelection;
|
||||||
|
|
||||||
public FakeTrackSelector() {
|
public FakeTrackSelector() {
|
||||||
@ -45,39 +46,35 @@ public class FakeTrackSelector extends DefaultTrackSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TrackSelection[] selectTracks(
|
protected TrackSelection[] selectAllTracks(
|
||||||
RendererCapabilities[] rendererCapabilities,
|
RendererCapabilities[] rendererCapabilities, MappedTrackInfo mappedTrackInfo)
|
||||||
TrackGroupArray[] rendererTrackGroupArrays,
|
|
||||||
int[][][] rendererFormatSupports)
|
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
List<FakeTrackSelection> resultList = new ArrayList<>();
|
TrackSelection[] selections = new TrackSelection[mappedTrackInfo.length];
|
||||||
for (TrackGroupArray trackGroupArray : rendererTrackGroupArrays) {
|
for (int i = 0; i < mappedTrackInfo.length; i++) {
|
||||||
TrackGroup trackGroup = trackGroupArray.get(0);
|
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(i);
|
||||||
FakeTrackSelection trackSelectionForRenderer = reuseOrCreateTrackSelection(trackGroup);
|
boolean hasTracks = trackGroupArray.length > 0;
|
||||||
resultList.add(trackSelectionForRenderer);
|
selections[i] = hasTracks ? reuseOrCreateTrackSelection(trackGroupArray.get(0)) : null;
|
||||||
}
|
}
|
||||||
return resultList.toArray(new TrackSelection[resultList.size()]);
|
return selections;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private FakeTrackSelection reuseOrCreateTrackSelection(TrackGroup trackGroup) {
|
private FakeTrackSelection reuseOrCreateTrackSelection(TrackGroup trackGroup) {
|
||||||
FakeTrackSelection trackSelectionForRenderer = null;
|
|
||||||
if (mayReuseTrackSelection) {
|
if (mayReuseTrackSelection) {
|
||||||
for (FakeTrackSelection selectedTrackSelection : selectedTrackSelections) {
|
for (FakeTrackSelection trackSelection : trackSelections) {
|
||||||
if (selectedTrackSelection.getTrackGroup().equals(trackGroup)) {
|
if (trackSelection.getTrackGroup().equals(trackGroup)) {
|
||||||
trackSelectionForRenderer = selectedTrackSelection;
|
return trackSelection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (trackSelectionForRenderer == null) {
|
FakeTrackSelection trackSelection = new FakeTrackSelection(trackGroup);
|
||||||
trackSelectionForRenderer = new FakeTrackSelection(trackGroup);
|
trackSelections.add(trackSelection);
|
||||||
selectedTrackSelections.add(trackSelectionForRenderer);
|
return trackSelection;
|
||||||
}
|
|
||||||
return trackSelectionForRenderer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns list of all {@link FakeTrackSelection}s that this track selector has made so far. */
|
/** Returns list of all {@link FakeTrackSelection}s that this track selector has made so far. */
|
||||||
public List<FakeTrackSelection> getSelectedTrackSelections() {
|
public List<FakeTrackSelection> getAllTrackSelections() {
|
||||||
return selectedTrackSelections;
|
return trackSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user