Fully document DefaultTrackSelector

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=162740498
This commit is contained in:
olly 2017-07-21 07:52:07 -07:00 committed by Oliver Woodman
parent 9bb8b240d2
commit 3eb85446a2

View file

@ -33,35 +33,115 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* A {@link MappingTrackSelector} suitable for most use cases.
* A default {@link TrackSelector} suitable for most use cases.
*
* <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
* selection process. For example an instance can specify a preferred language for
* the audio track, and impose constraints on the maximum video resolution that should be selected
* for adaptive playbacks. Modifying the parameters is simple:
* <pre>
* {@code
* Parameters currentParameters = trackSelector.getParameters();
* // Generate new parameters to prefer German audio and impose a maximum video size constraint.
* Parameters newParameters = currentParameters
* .withPreferredAudioLanguage("de")
* .withMaxVideoSize(1024, 768);
* // Set the new parameters on the selector.
* trackSelector.setParameters(newParameters);}
* </pre>
* There are several benefits to using constraint based track selection instead of specific track
* overrides:
* <ul>
* <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
* tracks before configuring the selector).</li>
* <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
* applied to periods whose tracks match those for which the override was set.</li>
* </ul>
*
* <h3>Track overrides, disabling renderers and tunneling</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 class is designed to be extensible by developers who wish to customize its behavior but do
* not wish to implement their own {@link MappingTrackSelector} or {@link TrackSelector} from
* scratch.
*/
public class DefaultTrackSelector extends MappingTrackSelector {
/**
* Holder for available configurations for the {@link DefaultTrackSelector}.
* Constraint parameters for {@link DefaultTrackSelector}.
*/
public static final class Parameters {
// Audio.
// Audio
/**
* The preferred language for audio, as well as for forced text tracks as defined by RFC 5646.
* {@code null} selects the default track, or the first track if there's no default.
*/
public final String preferredAudioLanguage;
// Text.
// Text
/**
* The preferred language for text tracks as defined by RFC 5646. {@code null} selects the
* default track if there is one, or no track otherwise.
*/
public final String preferredTextLanguage;
// Video.
public final boolean allowMixedMimeAdaptiveness;
public final boolean allowNonSeamlessAdaptiveness;
// Video
/**
* Maximum allowed video width.
*/
public final int maxVideoWidth;
/**
* Maximum allowed video height.
*/
public final int maxVideoHeight;
/**
* Maximum video bitrate.
*/
public final int maxVideoBitrate;
/**
* Whether to exceed video constraints when no selection can be made otherwise.
*/
public final boolean exceedVideoConstraintsIfNecessary;
public final boolean exceedRendererCapabilitiesIfNecessary;
/**
* Viewport width in pixels. Constrains video tracks selections for adaptive playbacks so that
* only tracks suitable for the viewport are selected.
*/
public final int viewportWidth;
/**
* Viewport height in pixels. Constrains video tracks selections for adaptive playbacks so that
* only tracks suitable for the viewport are selected.
*/
public final int viewportHeight;
public final boolean orientationMayChange;
/**
* Whether the viewport orientation may change during playback. Constrains video tracks
* selections for adaptive playbacks so that only tracks suitable for the viewport are selected.
*/
public final boolean viewportOrientationMayChange;
// General
/**
* Whether to allow adaptive selections containing mixed mime types.
*/
public final boolean allowMixedMimeAdaptiveness;
/**
* Whether to allow adaptive selections where adaptation may not be completely seamless.
*/
public final boolean allowNonSeamlessAdaptiveness;
/**
* Whether to exceed renderer capabilities when no selection can be made otherwise.
*/
public final boolean exceedRendererCapabilitiesIfNecessary;
/**
* Constructor with default selection parameters:
* Default parameters. The default values are:
* <ul>
* <li>No preferred audio language is set.</li>
* <li>No preferred text language is set.</li>
@ -71,7 +151,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* <li>No max video bitrate.</li>
* <li>Video constraints are exceeded if no supported selection can be made otherwise.</li>
* <li>Renderer capabilities are exceeded if no supported selection can be made.</li>
* <li>No viewport width/height constraints are set.</li>
* <li>No viewport constraints are set.</li>
* </ul>
*/
public Parameters() {
@ -80,29 +160,24 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
/**
* @param preferredAudioLanguage The preferred language for audio, as well as for forced text
* tracks as defined by RFC 5646. {@code null} to select the default track, or first track
* if there's no default.
* @param preferredTextLanguage The preferred language for text tracks as defined by RFC 5646.
* {@code null} to select the default track, or first track if there's no default.
* @param allowMixedMimeAdaptiveness Whether to allow selections to contain mixed mime types.
* @param allowNonSeamlessAdaptiveness Whether non-seamless adaptation is allowed.
* @param maxVideoWidth Maximum allowed video width.
* @param maxVideoHeight Maximum allowed video height.
* @param maxVideoBitrate Maximum allowed video bitrate.
* @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
* selection can be made otherwise.
* @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no
* selection can be made otherwise.
* @param viewportWidth Viewport width in pixels.
* @param viewportHeight Viewport height in pixels.
* @param orientationMayChange Whether orientation may change during playback.
* @param preferredAudioLanguage See {@link #preferredAudioLanguage}
* @param preferredTextLanguage See {@link #preferredTextLanguage}
* @param allowMixedMimeAdaptiveness See {@link #allowMixedMimeAdaptiveness}
* @param allowNonSeamlessAdaptiveness See {@link #allowNonSeamlessAdaptiveness}
* @param maxVideoWidth See {@link #maxVideoWidth}
* @param maxVideoHeight See {@link #maxVideoHeight}
* @param maxVideoBitrate See {@link #maxVideoBitrate}
* @param exceedVideoConstraintsIfNecessary See {@link #exceedVideoConstraintsIfNecessary}
* @param exceedRendererCapabilitiesIfNecessary See {@link #preferredTextLanguage}
* @param viewportWidth See {@link #viewportWidth}
* @param viewportHeight See {@link #viewportHeight}
* @param viewportOrientationMayChange See {@link #viewportOrientationMayChange}
*/
public Parameters(String preferredAudioLanguage, String preferredTextLanguage,
boolean allowMixedMimeAdaptiveness, boolean allowNonSeamlessAdaptiveness,
int maxVideoWidth, int maxVideoHeight, int maxVideoBitrate,
boolean exceedVideoConstraintsIfNecessary, boolean exceedRendererCapabilitiesIfNecessary,
int viewportWidth, int viewportHeight, boolean orientationMayChange) {
int viewportWidth, int viewportHeight, boolean viewportOrientationMayChange) {
this.preferredAudioLanguage = preferredAudioLanguage;
this.preferredTextLanguage = preferredTextLanguage;
this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness;
@ -114,17 +189,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.exceedRendererCapabilitiesIfNecessary = exceedRendererCapabilitiesIfNecessary;
this.viewportWidth = viewportWidth;
this.viewportHeight = viewportHeight;
this.orientationMayChange = orientationMayChange;
this.viewportOrientationMayChange = viewportOrientationMayChange;
}
/**
* Returns a {@link Parameters} instance with the provided preferred language for audio and
* forced text tracks.
* Returns an instance with the provided preferred language for audio and forced text tracks.
*
* @param preferredAudioLanguage The preferred language as defined by RFC 5646. {@code null} to
* select the default track, or first track if there's no default.
* @return A {@link Parameters} instance with the provided preferred language for audio and
* forced text tracks.
* @return An instance with the provided preferred language for audio and forced text tracks.
*/
public Parameters withPreferredAudioLanguage(String preferredAudioLanguage) {
preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage);
@ -134,15 +207,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided preferred language for text tracks.
* Returns an instance with the provided preferred language for text tracks.
*
* @param preferredTextLanguage The preferred language as defined by RFC 5646. {@code null} to
* select the default track, or no track if there's no default.
* @return A {@link Parameters} instance with the provided preferred language for text tracks.
* @return An instance with the provided preferred language for text tracks.
*/
public Parameters withPreferredTextLanguage(String preferredTextLanguage) {
preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage);
@ -152,14 +225,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided mixed mime adaptiveness allowance.
* Returns an instance with the provided mixed mime adaptiveness allowance.
*
* @param allowMixedMimeAdaptiveness Whether to allow selections to contain mixed mime types.
* @return A {@link Parameters} instance with the provided mixed mime adaptiveness allowance.
* @return An instance with the provided mixed mime adaptiveness allowance.
*/
public Parameters withAllowMixedMimeAdaptiveness(boolean allowMixedMimeAdaptiveness) {
if (allowMixedMimeAdaptiveness == this.allowMixedMimeAdaptiveness) {
@ -168,14 +241,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided seamless adaptiveness allowance.
* Returns an instance with the provided seamless adaptiveness allowance.
*
* @param allowNonSeamlessAdaptiveness Whether non-seamless adaptation is allowed.
* @return A {@link Parameters} instance with the provided seamless adaptiveness allowance.
* @return An instance with the provided seamless adaptiveness allowance.
*/
public Parameters withAllowNonSeamlessAdaptiveness(boolean allowNonSeamlessAdaptiveness) {
if (allowNonSeamlessAdaptiveness == this.allowNonSeamlessAdaptiveness) {
@ -184,15 +257,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided max video size.
* Returns an instance with the provided max video size.
*
* @param maxVideoWidth The max video width.
* @param maxVideoHeight The max video width.
* @return A {@link Parameters} instance with the provided max video size.
* @return An instance with the provided max video size.
*/
public Parameters withMaxVideoSize(int maxVideoWidth, int maxVideoHeight) {
if (maxVideoWidth == this.maxVideoWidth && maxVideoHeight == this.maxVideoHeight) {
@ -201,14 +274,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided max video bitrate.
* Returns an instance with the provided max video bitrate.
*
* @param maxVideoBitrate The max video bitrate.
* @return A {@link Parameters} instance with the provided max video bitrate.
* @return An instance with the provided max video bitrate.
*/
public Parameters withMaxVideoBitrate(int maxVideoBitrate) {
if (maxVideoBitrate == this.maxVideoBitrate) {
@ -217,13 +290,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Equivalent to {@code withMaxVideoSize(1279, 719)}.
*
* @return A {@link Parameters} instance with maximum standard definition as maximum video size.
* @return An instance with maximum standard definition as maximum video size.
*/
public Parameters withMaxVideoSizeSd() {
return withMaxVideoSize(1279, 719);
@ -232,20 +305,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
/**
* Equivalent to {@code withMaxVideoSize(Integer.MAX_VALUE, Integer.MAX_VALUE)}.
*
* @return A {@link Parameters} instance without video size constraints.
* @return An instance without video size constraints.
*/
public Parameters withoutVideoSizeConstraints() {
return withMaxVideoSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* Returns a {@link Parameters} instance with the provided
* {@code exceedVideoConstraintsIfNecessary} value.
* Returns an instance with the provided {@code exceedVideoConstraintsIfNecessary} value.
*
* @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
* selection can be made otherwise.
* @return A {@link Parameters} instance with the provided
* {@code exceedVideoConstraintsIfNecessary} value.
* @return An instance with the provided {@code exceedVideoConstraintsIfNecessary} value.
*/
public Parameters withExceedVideoConstraintsIfNecessary(
boolean exceedVideoConstraintsIfNecessary) {
@ -255,17 +326,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided
* {@code exceedRendererCapabilitiesIfNecessary} value.
* Returns an instance with the provided {@code exceedRendererCapabilitiesIfNecessary} value.
*
* @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no
* selection can be made otherwise.
* @return A {@link Parameters} instance with the provided
* {@code exceedRendererCapabilitiesIfNecessary} value.
* @return An instance with the provided {@code exceedRendererCapabilitiesIfNecessary} value.
*/
public Parameters withExceedRendererCapabilitiesIfNecessary(
boolean exceedRendererCapabilitiesIfNecessary) {
@ -275,48 +344,47 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided viewport size.
* Returns an instance with the provided viewport size.
*
* @param viewportWidth Viewport width in pixels.
* @param viewportHeight Viewport height in pixels.
* @param orientationMayChange Whether orientation may change during playback.
* @return A {@link Parameters} instance with the provided viewport size.
* @param viewportOrientationMayChange Whether orientation may change during playback.
* @return An instance with the provided viewport size.
*/
public Parameters withViewportSize(int viewportWidth, int viewportHeight,
boolean orientationMayChange) {
boolean viewportOrientationMayChange) {
if (viewportWidth == this.viewportWidth && viewportHeight == this.viewportHeight
&& orientationMayChange == this.orientationMayChange) {
&& viewportOrientationMayChange == this.viewportOrientationMayChange) {
return this;
}
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, orientationMayChange);
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns a {@link Parameters} instance where the viewport size is obtained from the provided
* {@link Context}.
* Returns an instance where the viewport size is obtained from the provided {@link Context}.
*
* @param context The context to obtain the viewport size from.
* @param orientationMayChange Whether orientation may change during playback.
* @return A {@link Parameters} instance where the viewport size is obtained from the provided
* {@link Context}.
* @param viewportOrientationMayChange Whether orientation may change during playback.
* @return An instance where the viewport size is obtained from the provided {@link Context}.
*/
public Parameters withViewportSizeFromContext(Context context, boolean orientationMayChange) {
public Parameters withViewportSizeFromContext(Context context,
boolean viewportOrientationMayChange) {
// Assume the viewport is fullscreen.
Point viewportSize = Util.getPhysicalDisplaySize(context);
return withViewportSize(viewportSize.x, viewportSize.y, orientationMayChange);
return withViewportSize(viewportSize.x, viewportSize.y, viewportOrientationMayChange);
}
/**
* Equivalent to {@code withViewportSize(Integer.MAX_VALUE, Integer.MAX_VALUE, true)}.
*
* @return A {@link Parameters} instance without viewport size constraints.
* @return An instance without viewport size constraints.
*/
public Parameters withoutViewportSizeConstraints() {
return withViewportSize(Integer.MAX_VALUE, Integer.MAX_VALUE, true);
@ -336,7 +404,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& maxVideoWidth == other.maxVideoWidth && maxVideoHeight == other.maxVideoHeight
&& exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
&& orientationMayChange == other.orientationMayChange
&& viewportOrientationMayChange == other.viewportOrientationMayChange
&& viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight
&& maxVideoBitrate == other.maxVideoBitrate
&& TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage)
@ -354,7 +422,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + maxVideoBitrate;
result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
result = 31 * result + (orientationMayChange ? 1 : 0);
result = 31 * result + (viewportOrientationMayChange ? 1 : 0);
result = 31 * result + viewportWidth;
result = 31 * result + viewportHeight;
return result;
@ -441,12 +509,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (C.TRACK_TYPE_VIDEO == rendererCapabilities[i].getTrackType()) {
if (!selectedVideoTracks) {
rendererTrackSelections[i] = selectVideoTrack(rendererCapabilities[i],
rendererTrackGroupArrays[i], rendererFormatSupports[i], params.maxVideoWidth,
params.maxVideoHeight, params.maxVideoBitrate, params.allowNonSeamlessAdaptiveness,
params.allowMixedMimeAdaptiveness, params.viewportWidth, params.viewportHeight,
params.orientationMayChange, adaptiveTrackSelectionFactory,
params.exceedVideoConstraintsIfNecessary,
params.exceedRendererCapabilitiesIfNecessary);
rendererTrackGroupArrays[i], rendererFormatSupports[i], params,
adaptiveTrackSelectionFactory);
selectedVideoTracks = rendererTrackSelections[i] != null;
}
seenVideoRendererWithMappedTracks |= rendererTrackGroupArrays[i].length > 0;
@ -463,8 +527,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
case C.TRACK_TYPE_AUDIO:
if (!selectedAudioTracks) {
rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i],
rendererFormatSupports[i], params.preferredAudioLanguage,
params.exceedRendererCapabilitiesIfNecessary, params.allowMixedMimeAdaptiveness,
rendererFormatSupports[i], params,
seenVideoRendererWithMappedTracks ? null : adaptiveTrackSelectionFactory);
selectedAudioTracks = rendererTrackSelections[i] != null;
}
@ -472,15 +535,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
case C.TRACK_TYPE_TEXT:
if (!selectedTextTracks) {
rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i],
rendererFormatSupports[i], params.preferredTextLanguage,
params.preferredAudioLanguage, params.exceedRendererCapabilitiesIfNecessary);
rendererFormatSupports[i], params);
selectedTextTracks = rendererTrackSelections[i] != null;
}
break;
default:
rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(),
rendererTrackGroupArrays[i], rendererFormatSupports[i],
params.exceedRendererCapabilitiesIfNecessary);
rendererTrackGroupArrays[i], rendererFormatSupports[i], params);
break;
}
}
@ -489,42 +550,48 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Video track selection implementation.
/**
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
* create a {@link TrackSelection} for a video renderer.
*
* @param rendererCapabilities The {@link RendererCapabilities} for the renderer.
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
* track, indexed by track group index and track index (in that order).
* @param params The selector's current constraint parameters.
* @param adaptiveTrackSelectionFactory A factory for generating adaptive track selections, or
* null if a fixed track selection is required.
* @return The {@link TrackSelection} for the renderer, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
protected TrackSelection selectVideoTrack(RendererCapabilities rendererCapabilities,
TrackGroupArray groups, int[][] formatSupport, int maxVideoWidth, int maxVideoHeight,
int maxVideoBitrate, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness,
int viewportWidth, int viewportHeight, boolean orientationMayChange,
TrackSelection.Factory adaptiveTrackSelectionFactory, boolean exceedConstraintsIfNecessary,
boolean exceedRendererCapabilitiesIfNecessary) throws ExoPlaybackException {
TrackGroupArray groups, int[][] formatSupport, Parameters params,
TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException {
TrackSelection selection = null;
if (adaptiveTrackSelectionFactory != null) {
selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport,
maxVideoWidth, maxVideoHeight, maxVideoBitrate, allowNonSeamlessAdaptiveness,
allowMixedMimeAdaptiveness, viewportWidth, viewportHeight,
orientationMayChange, adaptiveTrackSelectionFactory);
params, adaptiveTrackSelectionFactory);
}
if (selection == null) {
selection = selectFixedVideoTrack(groups, formatSupport, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, viewportWidth, viewportHeight, orientationMayChange,
exceedConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary);
selection = selectFixedVideoTrack(groups, formatSupport, params);
}
return selection;
}
private static TrackSelection selectAdaptiveVideoTrack(RendererCapabilities rendererCapabilities,
TrackGroupArray groups, int[][] formatSupport, int maxVideoWidth, int maxVideoHeight,
int maxVideoBitrate, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness,
int viewportWidth, int viewportHeight, boolean orientationMayChange,
TrackGroupArray groups, int[][] formatSupport, Parameters params,
TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException {
int requiredAdaptiveSupport = allowNonSeamlessAdaptiveness
int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness
? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS)
: RendererCapabilities.ADAPTIVE_SEAMLESS;
boolean allowMixedMimeTypes = allowMixedMimeAdaptiveness
boolean allowMixedMimeTypes = params.allowMixedMimeAdaptiveness
&& (rendererCapabilities.supportsMixedMimeTypeAdaptation() & requiredAdaptiveSupport) != 0;
for (int i = 0; i < groups.length; i++) {
TrackGroup group = groups.get(i);
int[] adaptiveTracks = getAdaptiveVideoTracksForGroup(group, formatSupport[i],
allowMixedMimeTypes, requiredAdaptiveSupport, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, viewportWidth, viewportHeight, orientationMayChange);
allowMixedMimeTypes, requiredAdaptiveSupport, params.maxVideoWidth, params.maxVideoHeight,
params.maxVideoBitrate, params.viewportWidth, params.viewportHeight,
params.viewportOrientationMayChange);
if (adaptiveTracks.length > 0) {
return adaptiveTrackSelectionFactory.createTrackSelection(group, adaptiveTracks);
}
@ -535,13 +602,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static int[] getAdaptiveVideoTracksForGroup(TrackGroup group, int[] formatSupport,
boolean allowMixedMimeTypes, int requiredAdaptiveSupport, int maxVideoWidth,
int maxVideoHeight, int maxVideoBitrate, int viewportWidth, int viewportHeight,
boolean orientationMayChange) {
boolean viewportOrientationMayChange) {
if (group.length < 2) {
return NO_TRACKS;
}
List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(group, viewportWidth,
viewportHeight, orientationMayChange);
viewportHeight, viewportOrientationMayChange);
if (selectedTrackIndices.size() < 2) {
return NO_TRACKS;
}
@ -612,9 +679,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
private static TrackSelection selectFixedVideoTrack(TrackGroupArray groups,
int[][] formatSupport, int maxVideoWidth, int maxVideoHeight, int maxVideoBitrate,
int viewportWidth, int viewportHeight, boolean orientationMayChange,
boolean exceedConstraintsIfNecessary, boolean exceedRendererCapabilitiesIfNecessary) {
int[][] formatSupport, Parameters params) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
@ -623,16 +688,17 @@ public class DefaultTrackSelector extends MappingTrackSelector {
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex);
List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(trackGroup,
viewportWidth, viewportHeight, orientationMayChange);
params.viewportWidth, params.viewportHeight, params.viewportOrientationMayChange);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
boolean isWithinConstraints = selectedTrackIndices.contains(trackIndex)
&& (format.width == Format.NO_VALUE || format.width <= maxVideoWidth)
&& (format.height == Format.NO_VALUE || format.height <= maxVideoHeight)
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxVideoBitrate);
if (!isWithinConstraints && !exceedConstraintsIfNecessary) {
&& (format.width == Format.NO_VALUE || format.width <= params.maxVideoWidth)
&& (format.height == Format.NO_VALUE || format.height <= params.maxVideoHeight)
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= params.maxVideoBitrate);
if (!isWithinConstraints && !params.exceedVideoConstraintsIfNecessary) {
// Track should not be selected.
continue;
}
@ -687,9 +753,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Audio track selection implementation.
/**
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
* create a {@link TrackSelection} for an audio renderer.
*
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
* track, indexed by track group index and track index (in that order).
* @param params The selector's current constraint parameters.
* @param adaptiveTrackSelectionFactory A factory for generating adaptive track selections, or
* null if a fixed track selection is required.
* @return The {@link TrackSelection} for the renderer, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport,
String preferredAudioLanguage, boolean exceedRendererCapabilitiesIfNecessary,
boolean allowMixedMimeAdaptiveness, TrackSelection.Factory adaptiveTrackSelectionFactory) {
Parameters params, TrackSelection.Factory adaptiveTrackSelectionFactory) {
int selectedGroupIndex = C.INDEX_UNSET;
int selectedTrackIndex = C.INDEX_UNSET;
int selectedTrackScore = 0;
@ -697,10 +775,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
int trackScore = getAudioTrackScore(trackFormatSupport[trackIndex],
preferredAudioLanguage, format);
params.preferredAudioLanguage, format);
if (trackScore > selectedTrackScore) {
selectedGroupIndex = groupIndex;
selectedTrackIndex = trackIndex;
@ -718,7 +797,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (adaptiveTrackSelectionFactory != null) {
// If the group of the track with the highest score allows it, try to enable adaptation.
int[] adaptiveTracks = getAdaptiveAudioTracks(selectedGroup,
formatSupport[selectedGroupIndex], allowMixedMimeAdaptiveness);
formatSupport[selectedGroupIndex], params.allowMixedMimeAdaptiveness);
if (adaptiveTracks.length > 0) {
return adaptiveTrackSelectionFactory.createTrackSelection(selectedGroup,
adaptiveTracks);
@ -802,9 +881,19 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Text track selection implementation.
/**
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
* create a {@link TrackSelection} for a text renderer.
*
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
* track, indexed by track group index and track index (in that order).
* @param params The selector's current constraint parameters.
* @return The {@link TrackSelection} for the renderer, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
String preferredTextLanguage, String preferredAudioLanguage,
boolean exceedRendererCapabilitiesIfNecessary) {
Parameters params) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
@ -812,12 +901,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
boolean isForced = (format.selectionFlags & C.SELECTION_FLAG_FORCED) != 0;
int trackScore;
if (formatHasLanguage(format, preferredTextLanguage)) {
if (formatHasLanguage(format, params.preferredTextLanguage)) {
if (isDefault) {
trackScore = 6;
} else if (!isForced) {
@ -831,7 +921,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} else if (isDefault) {
trackScore = 3;
} else if (isForced) {
if (formatHasLanguage(format, preferredAudioLanguage)) {
if (formatHasLanguage(format, params.preferredAudioLanguage)) {
trackScore = 2;
} else {
trackScore = 1;
@ -857,8 +947,20 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General track selection methods.
/**
* Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to
* create a {@link TrackSelection} for a renderer whose type is neither video, audio or text.
*
* @param trackType The type of the renderer.
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
* track, indexed by track group index and track index (in that order).
* @param params The selector's current constraint parameters.
* @return The {@link TrackSelection} for the renderer, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
protected TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups,
int[][] formatSupport, boolean exceedRendererCapabilitiesIfNecessary) {
int[][] formatSupport, Parameters params) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
@ -866,7 +968,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
int trackScore = isDefault ? 2 : 1;
@ -885,12 +988,34 @@ public class DefaultTrackSelector extends MappingTrackSelector {
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
}
/**
* Applies the {@link RendererCapabilities#FORMAT_SUPPORT_MASK} to a value obtained from
* {@link RendererCapabilities#supportsFormat(Format)}, returning true if the result is
* {@link RendererCapabilities#FORMAT_HANDLED} or if {@code allowExceedsCapabilities} is set
* and the result is {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}.
*
* @param formatSupport A value obtained from {@link RendererCapabilities#supportsFormat(Format)}.
* @param allowExceedsCapabilities Whether to return true if the format support component of the
* value is {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}.
* @return True if the format support component is {@link RendererCapabilities#FORMAT_HANDLED}, or
* if {@code allowExceedsCapabilities} is set and the format support component is
* {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}.
*/
protected static boolean isSupported(int formatSupport, boolean allowExceedsCapabilities) {
int maskedSupport = formatSupport & RendererCapabilities.FORMAT_SUPPORT_MASK;
return maskedSupport == RendererCapabilities.FORMAT_HANDLED || (allowExceedsCapabilities
&& maskedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES);
}
/**
* Returns whether a {@link Format} specifies a particular language, or {@code false} if
* {@code language} is null.
*
* @param format The {@link Format}.
* @param language The language.
* @return Whether the format specifies the language, or {@code false} if {@code language} is
* null.
*/
protected static boolean formatHasLanguage(Format format, String language) {
return language != null
&& TextUtils.equals(language, Util.normalizeLanguageCode(format.language));