mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Fully document DefaultTrackSelector
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162740498
This commit is contained in:
parent
9bb8b240d2
commit
3eb85446a2
1 changed files with 256 additions and 131 deletions
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Reference in a new issue