Add a "forceLowestBitrate" option to DefaultTrackSelector

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=169668371
This commit is contained in:
aquilescanta 2017-09-22 03:22:02 -07:00 committed by Oliver Woodman
parent 25a9177ce3
commit 4fb18453e1

View File

@ -127,6 +127,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
public final boolean viewportOrientationMayChange; public final boolean viewportOrientationMayChange;
// General // General
/**
* Whether to force selection of the single lowest bitrate audio and video tracks that comply
* with all other constraints.
*/
public final boolean forceLowestBitrate;
/** /**
* Whether to allow adaptive selections containing mixed mime types. * Whether to allow adaptive selections containing mixed mime types.
*/ */
@ -145,6 +150,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* <ul> * <ul>
* <li>No preferred audio language is set.</li> * <li>No preferred audio language is set.</li>
* <li>No preferred text language is set.</li> * <li>No preferred text language is set.</li>
* <li>Lowest bitrate track selections are not forced.</li>
* <li>Adaptation between different mime types is not allowed.</li> * <li>Adaptation between different mime types is not allowed.</li>
* <li>Non seamless adaptation is allowed.</li> * <li>Non seamless adaptation is allowed.</li>
* <li>No max limit for video width/height.</li> * <li>No max limit for video width/height.</li>
@ -155,13 +161,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* </ul> * </ul>
*/ */
public Parameters() { public Parameters() {
this(null, null, false, true, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, true, this(null, null, false, false, true, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
true, Integer.MAX_VALUE, Integer.MAX_VALUE, true); true, true, Integer.MAX_VALUE, Integer.MAX_VALUE, true);
} }
/** /**
* @param preferredAudioLanguage See {@link #preferredAudioLanguage} * @param preferredAudioLanguage See {@link #preferredAudioLanguage}
* @param preferredTextLanguage See {@link #preferredTextLanguage} * @param preferredTextLanguage See {@link #preferredTextLanguage}
* @param forceLowestBitrate See {@link #forceLowestBitrate}.
* @param allowMixedMimeAdaptiveness See {@link #allowMixedMimeAdaptiveness} * @param allowMixedMimeAdaptiveness See {@link #allowMixedMimeAdaptiveness}
* @param allowNonSeamlessAdaptiveness See {@link #allowNonSeamlessAdaptiveness} * @param allowNonSeamlessAdaptiveness See {@link #allowNonSeamlessAdaptiveness}
* @param maxVideoWidth See {@link #maxVideoWidth} * @param maxVideoWidth See {@link #maxVideoWidth}
@ -174,12 +181,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param viewportOrientationMayChange See {@link #viewportOrientationMayChange} * @param viewportOrientationMayChange See {@link #viewportOrientationMayChange}
*/ */
public Parameters(String preferredAudioLanguage, String preferredTextLanguage, public Parameters(String preferredAudioLanguage, String preferredTextLanguage,
boolean allowMixedMimeAdaptiveness, boolean allowNonSeamlessAdaptiveness, boolean forceLowestBitrate, boolean allowMixedMimeAdaptiveness,
int maxVideoWidth, int maxVideoHeight, int maxVideoBitrate, boolean allowNonSeamlessAdaptiveness, int maxVideoWidth, int maxVideoHeight,
boolean exceedVideoConstraintsIfNecessary, boolean exceedRendererCapabilitiesIfNecessary, int maxVideoBitrate, boolean exceedVideoConstraintsIfNecessary,
int viewportWidth, int viewportHeight, boolean viewportOrientationMayChange) { boolean exceedRendererCapabilitiesIfNecessary, int viewportWidth, int viewportHeight,
boolean viewportOrientationMayChange) {
this.preferredAudioLanguage = preferredAudioLanguage; this.preferredAudioLanguage = preferredAudioLanguage;
this.preferredTextLanguage = preferredTextLanguage; this.preferredTextLanguage = preferredTextLanguage;
this.forceLowestBitrate = forceLowestBitrate;
this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness; this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness;
this.allowNonSeamlessAdaptiveness = allowNonSeamlessAdaptiveness; this.allowNonSeamlessAdaptiveness = allowNonSeamlessAdaptiveness;
this.maxVideoWidth = maxVideoWidth; this.maxVideoWidth = maxVideoWidth;
@ -200,7 +209,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (TextUtils.equals(preferredAudioLanguage, this.preferredAudioLanguage)) { if (TextUtils.equals(preferredAudioLanguage, this.preferredAudioLanguage)) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -214,7 +223,20 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (TextUtils.equals(preferredTextLanguage, this.preferredTextLanguage)) { if (TextUtils.equals(preferredTextLanguage, this.preferredTextLanguage)) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange);
}
/**
* Returns an instance with the provided {@link #forceLowestBitrate}.
*/
public Parameters withForceLowestBitrate(boolean forceLowestBitrate) {
if (forceLowestBitrate == this.forceLowestBitrate) {
return this;
}
return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -227,7 +249,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (allowMixedMimeAdaptiveness == this.allowMixedMimeAdaptiveness) { if (allowMixedMimeAdaptiveness == this.allowMixedMimeAdaptiveness) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -240,7 +262,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (allowNonSeamlessAdaptiveness == this.allowNonSeamlessAdaptiveness) { if (allowNonSeamlessAdaptiveness == this.allowNonSeamlessAdaptiveness) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -253,7 +275,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (maxVideoWidth == this.maxVideoWidth && maxVideoHeight == this.maxVideoHeight) { if (maxVideoWidth == this.maxVideoWidth && maxVideoHeight == this.maxVideoHeight) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -266,7 +288,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (maxVideoBitrate == this.maxVideoBitrate) { if (maxVideoBitrate == this.maxVideoBitrate) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -298,7 +320,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (exceedVideoConstraintsIfNecessary == this.exceedVideoConstraintsIfNecessary) { if (exceedVideoConstraintsIfNecessary == this.exceedVideoConstraintsIfNecessary) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -312,7 +334,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (exceedRendererCapabilitiesIfNecessary == this.exceedRendererCapabilitiesIfNecessary) { if (exceedRendererCapabilitiesIfNecessary == this.exceedRendererCapabilitiesIfNecessary) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -328,7 +350,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& viewportOrientationMayChange == this.viewportOrientationMayChange) { && viewportOrientationMayChange == this.viewportOrientationMayChange) {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage, forceLowestBitrate,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary,
viewportWidth, viewportHeight, viewportOrientationMayChange); viewportWidth, viewportHeight, viewportOrientationMayChange);
@ -366,7 +388,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return false; return false;
} }
Parameters other = (Parameters) obj; Parameters other = (Parameters) obj;
return allowMixedMimeAdaptiveness == other.allowMixedMimeAdaptiveness return forceLowestBitrate == other.forceLowestBitrate
&& allowMixedMimeAdaptiveness == other.allowMixedMimeAdaptiveness
&& allowNonSeamlessAdaptiveness == other.allowNonSeamlessAdaptiveness && allowNonSeamlessAdaptiveness == other.allowNonSeamlessAdaptiveness
&& maxVideoWidth == other.maxVideoWidth && maxVideoHeight == other.maxVideoHeight && maxVideoWidth == other.maxVideoWidth && maxVideoHeight == other.maxVideoHeight
&& exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary && exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary
@ -382,6 +405,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
public int hashCode() { public int hashCode() {
int result = preferredAudioLanguage.hashCode(); int result = preferredAudioLanguage.hashCode();
result = 31 * result + preferredTextLanguage.hashCode(); result = 31 * result + preferredTextLanguage.hashCode();
result = 31 * result + (forceLowestBitrate ? 1 : 0);
result = 31 * result + (allowMixedMimeAdaptiveness ? 1 : 0); result = 31 * result + (allowMixedMimeAdaptiveness ? 1 : 0);
result = 31 * result + (allowNonSeamlessAdaptiveness ? 1 : 0); result = 31 * result + (allowNonSeamlessAdaptiveness ? 1 : 0);
result = 31 * result + maxVideoWidth; result = 31 * result + maxVideoWidth;
@ -535,7 +559,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
TrackGroupArray groups, int[][] formatSupport, Parameters params, TrackGroupArray groups, int[][] formatSupport, Parameters params,
TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException { TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException {
TrackSelection selection = null; TrackSelection selection = null;
if (adaptiveTrackSelectionFactory != null) { if (!params.forceLowestBitrate && adaptiveTrackSelectionFactory != null) {
selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport, selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport,
params, adaptiveTrackSelectionFactory); params, adaptiveTrackSelectionFactory);
} }
@ -676,20 +700,22 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
boolean selectTrack = trackScore > selectedTrackScore; boolean selectTrack = trackScore > selectedTrackScore;
if (trackScore == selectedTrackScore) { if (trackScore == selectedTrackScore) {
// Use the pixel count as a tie breaker (or bitrate if pixel counts are tied). If we're if (params.forceLowestBitrate) {
// within constraints prefer a higher pixel count (or bitrate), else prefer a lower // Use bitrate as a tie breaker, preferring the lower bitrate.
// count (or bitrate). If still tied then prefer the first track (i.e. the one that's selectTrack = compareFormatValues(format.bitrate, selectedBitrate) < 0;
// already selected).
int comparisonResult;
int formatPixelCount = format.getPixelCount();
if (formatPixelCount != selectedPixelCount) {
comparisonResult = compareFormatValues(format.getPixelCount(), selectedPixelCount);
} else { } else {
comparisonResult = compareFormatValues(format.bitrate, selectedBitrate); // Use the pixel count as a tie breaker (or bitrate if pixel counts are tied). If
} // we're within constraints prefer a higher pixel count (or bitrate), else prefer a
// lower count (or bitrate). If still tied then prefer the first track (i.e. the one
// that's already selected).
int formatPixelCount = format.getPixelCount();
int comparisonResult = formatPixelCount != selectedPixelCount
? compareFormatValues(formatPixelCount, selectedPixelCount)
: compareFormatValues(format.bitrate, selectedBitrate);
selectTrack = isWithinCapabilities && isWithinConstraints selectTrack = isWithinCapabilities && isWithinConstraints
? comparisonResult > 0 : comparisonResult < 0; ? comparisonResult > 0 : comparisonResult < 0;
} }
}
if (selectTrack) { if (selectTrack) {
selectedGroup = trackGroup; selectedGroup = trackGroup;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
@ -739,6 +765,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int selectedGroupIndex = C.INDEX_UNSET; int selectedGroupIndex = C.INDEX_UNSET;
int selectedTrackIndex = C.INDEX_UNSET; int selectedTrackIndex = C.INDEX_UNSET;
int selectedTrackScore = 0; int selectedTrackScore = 0;
int selectedBitrate = Format.NO_VALUE;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex); TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex]; int[] trackFormatSupport = formatSupport[groupIndex];
@ -748,10 +775,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
Format format = trackGroup.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
int trackScore = getAudioTrackScore(trackFormatSupport[trackIndex], int trackScore = getAudioTrackScore(trackFormatSupport[trackIndex],
params.preferredAudioLanguage, format); params.preferredAudioLanguage, format);
if (trackScore > selectedTrackScore) { if (trackScore > selectedTrackScore
|| (trackScore == selectedTrackScore && params.forceLowestBitrate
&& compareFormatValues(format.bitrate, selectedBitrate) < 0)) {
selectedGroupIndex = groupIndex; selectedGroupIndex = groupIndex;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore; selectedTrackScore = trackScore;
selectedBitrate = format.bitrate;
} }
} }
} }
@ -762,7 +792,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
TrackGroup selectedGroup = groups.get(selectedGroupIndex); TrackGroup selectedGroup = groups.get(selectedGroupIndex);
if (adaptiveTrackSelectionFactory != null) { if (!params.forceLowestBitrate && adaptiveTrackSelectionFactory != null) {
// If the group of the track with the highest score allows it, try to enable adaptation. // If the group of the track with the highest score allows it, try to enable adaptation.
int[] adaptiveTracks = getAdaptiveAudioTracks(selectedGroup, int[] adaptiveTracks = getAdaptiveAudioTracks(selectedGroup,
formatSupport[selectedGroupIndex], params.allowMixedMimeAdaptiveness); formatSupport[selectedGroupIndex], params.allowMixedMimeAdaptiveness);