mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Use consistent scoring style in DefaultTrackSelector.
We currently mix point-based systems with Comparable-based systems. This switches all scoring to using Comparable and modernizes it by using ComparisonChain. Using Comparator chains is more maintainable than point systems because the reader doesn't have to think about all combinatorial combinations of points. PiperOrigin-RevId: 322766278
This commit is contained in:
parent
d25178844c
commit
50ddfccdb9
1 changed files with 181 additions and 182 deletions
|
|
@ -38,6 +38,8 @@ import com.google.android.exoplayer2.source.TrackGroup;
|
|||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.primitives.Ints;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -1488,12 +1490,15 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
private static final float FRACTION_TO_CONSIDER_FULLSCREEN = 0.98f;
|
||||
private static final int[] NO_TRACKS = new int[0];
|
||||
|
||||
// Constants that are added to a track's score when certain conditions are met. Higher scoring
|
||||
// tracks are selected over those with lower scores.
|
||||
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
|
||||
private static final int SATISFIES_MIN_VIDEO_CONSTRAINTS_BONUS = 1;
|
||||
private static final int SATISFIES_MAX_VIDEO_CONSTRAINTS_BONUS = 2;
|
||||
/** Ordering of two format values. A known value is considered greater than Format#NO_VALUE. */
|
||||
private static final Ordering<Integer> FORMAT_VALUE_ORDERING =
|
||||
Ordering.from(
|
||||
(first, second) ->
|
||||
first == Format.NO_VALUE
|
||||
? (second == Format.NO_VALUE ? 0 : -1)
|
||||
: (second == Format.NO_VALUE ? 1 : (first - second)));
|
||||
/** Ordering where all elements are equal. */
|
||||
private static final Ordering<Integer> NO_ORDER = Ordering.from((first, second) -> 0);
|
||||
|
||||
private final TrackSelection.Factory trackSelectionFactory;
|
||||
private final AtomicReference<Parameters> parametersReference;
|
||||
|
|
@ -1690,13 +1695,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
}
|
||||
}
|
||||
|
||||
AudioTrackScore selectedAudioTrackScore = null;
|
||||
String selectedAudioLanguage = null;
|
||||
@Nullable AudioTrackScore selectedAudioTrackScore = null;
|
||||
@Nullable String selectedAudioLanguage = null;
|
||||
int selectedAudioRendererIndex = C.INDEX_UNSET;
|
||||
for (int i = 0; i < rendererCount; i++) {
|
||||
if (C.TRACK_TYPE_AUDIO == mappedTrackInfo.getRendererType(i)) {
|
||||
boolean enableAdaptiveTrackSelection =
|
||||
allowMultipleAdaptiveSelections || !seenVideoRendererWithMappedTracks;
|
||||
@Nullable
|
||||
Pair<TrackSelection.Definition, AudioTrackScore> audioSelection =
|
||||
selectAudioTrack(
|
||||
mappedTrackInfo.getTrackGroups(i),
|
||||
|
|
@ -1722,7 +1728,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
}
|
||||
}
|
||||
|
||||
TextTrackScore selectedTextTrackScore = null;
|
||||
@Nullable TextTrackScore selectedTextTrackScore = null;
|
||||
int selectedTextRendererIndex = C.INDEX_UNSET;
|
||||
for (int i = 0; i < rendererCount; i++) {
|
||||
int trackType = mappedTrackInfo.getRendererType(i);
|
||||
|
|
@ -1732,6 +1738,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
// Already done. Do nothing.
|
||||
break;
|
||||
case C.TRACK_TYPE_TEXT:
|
||||
@Nullable
|
||||
Pair<TrackSelection.Definition, TextTrackScore> textSelection =
|
||||
selectTextTrack(
|
||||
mappedTrackInfo.getTrackGroups(i),
|
||||
|
|
@ -2019,15 +2026,17 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
@Nullable
|
||||
private static TrackSelection.Definition selectFixedVideoTrack(
|
||||
TrackGroupArray groups, @Capabilities int[][] formatSupports, Parameters params) {
|
||||
int selectedTrackIndex = C.INDEX_UNSET;
|
||||
@Nullable TrackGroup selectedGroup = null;
|
||||
int selectedTrackIndex = 0;
|
||||
int selectedTrackScore = 0;
|
||||
int selectedBitrate = Format.NO_VALUE;
|
||||
int selectedPixelCount = Format.NO_VALUE;
|
||||
@Nullable VideoTrackScore selectedTrackScore = null;
|
||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = groups.get(groupIndex);
|
||||
List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(trackGroup,
|
||||
params.viewportWidth, params.viewportHeight, params.viewportOrientationMayChange);
|
||||
List<Integer> viewportFilteredTrackIndices =
|
||||
getViewportFilteredTrackIndices(
|
||||
trackGroup,
|
||||
params.viewportWidth,
|
||||
params.viewportHeight,
|
||||
params.viewportOrientationMayChange);
|
||||
@Capabilities int[] trackFormatSupport = formatSupports[groupIndex];
|
||||
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
||||
Format format = trackGroup.getFormat(trackIndex);
|
||||
|
|
@ -2037,82 +2046,25 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
}
|
||||
if (isSupported(trackFormatSupport[trackIndex],
|
||||
params.exceedRendererCapabilitiesIfNecessary)) {
|
||||
boolean satisfiesMaxConstraints =
|
||||
selectedTrackIndices.contains(trackIndex)
|
||||
&& (format.width == Format.NO_VALUE || format.width <= params.maxVideoWidth)
|
||||
&& (format.height == Format.NO_VALUE || format.height <= params.maxVideoHeight)
|
||||
&& (format.frameRate == Format.NO_VALUE
|
||||
|| format.frameRate <= params.maxVideoFrameRate)
|
||||
&& (format.bitrate == Format.NO_VALUE
|
||||
|| format.bitrate <= params.maxVideoBitrate);
|
||||
boolean satisfiesMinConstraints =
|
||||
selectedTrackIndices.contains(trackIndex)
|
||||
&& (format.width == Format.NO_VALUE || format.width >= params.minVideoWidth)
|
||||
&& (format.height == Format.NO_VALUE || format.height >= params.minVideoHeight)
|
||||
&& (format.frameRate == Format.NO_VALUE
|
||||
|| format.frameRate >= params.minVideoFrameRate)
|
||||
&& (format.bitrate == Format.NO_VALUE
|
||||
|| format.bitrate >= params.minVideoBitrate);
|
||||
if (!satisfiesMaxConstraints && !params.exceedVideoConstraintsIfNecessary) {
|
||||
VideoTrackScore trackScore =
|
||||
new VideoTrackScore(
|
||||
format,
|
||||
params,
|
||||
trackFormatSupport[trackIndex],
|
||||
viewportFilteredTrackIndices.contains(trackIndex));
|
||||
if (!trackScore.isWithinMaxConstraints && !params.exceedVideoConstraintsIfNecessary) {
|
||||
// Track should not be selected.
|
||||
continue;
|
||||
}
|
||||
int trackScore = 1;
|
||||
boolean isWithinCapabilities = isSupported(trackFormatSupport[trackIndex], false);
|
||||
if (isWithinCapabilities) {
|
||||
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
|
||||
}
|
||||
if (satisfiesMaxConstraints) {
|
||||
trackScore += SATISFIES_MAX_VIDEO_CONSTRAINTS_BONUS;
|
||||
}
|
||||
if (satisfiesMinConstraints) {
|
||||
trackScore += SATISFIES_MIN_VIDEO_CONSTRAINTS_BONUS;
|
||||
}
|
||||
boolean selectTrack = trackScore > selectedTrackScore;
|
||||
if (trackScore == selectedTrackScore) {
|
||||
// The current selection and the track being evaluated have the same score. Apply
|
||||
// tiebreaking logic to choose between them.
|
||||
int bitrateComparison = compareFormatValues(format.bitrate, selectedBitrate);
|
||||
if (params.forceLowestBitrate && bitrateComparison != 0) {
|
||||
// Use bitrate as a tiebreaker, preferring the lower bitrate.
|
||||
selectTrack = bitrateComparison < 0;
|
||||
} else {
|
||||
// Use pixel count as a tiebreaker, followed by bitrate if pixel counts are equal.
|
||||
int formatPixelCount = format.getPixelCount();
|
||||
int comparisonResult = formatPixelCount != selectedPixelCount
|
||||
? compareFormatValues(formatPixelCount, selectedPixelCount)
|
||||
: compareFormatValues(format.bitrate, selectedBitrate);
|
||||
if (!isWithinCapabilities) {
|
||||
// We're not within capabilities, so pick the lower quality because it's more likely
|
||||
// to play successfully.
|
||||
selectTrack = comparisonResult < 0;
|
||||
} else if (satisfiesMinConstraints && satisfiesMaxConstraints) {
|
||||
// All constraints are satisfied, so pick the higher quality.
|
||||
selectTrack = comparisonResult > 0;
|
||||
} else if (!satisfiesMinConstraints && satisfiesMaxConstraints) {
|
||||
// Pick the higher quality because it gets us closest to satisfying the violated min
|
||||
// constraints.
|
||||
selectTrack = comparisonResult > 0;
|
||||
} else if (satisfiesMinConstraints) { // !satisfiesMaxConstraints
|
||||
// Pick the lower quality because it gets us closest to satisfying the violated max
|
||||
// constraints.
|
||||
selectTrack = comparisonResult > 0;
|
||||
} else { // !satisfiesMinConstraints && !satisfiesMaxConstraints
|
||||
// Arbitrarily pick the lower quality.
|
||||
selectTrack = comparisonResult < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectTrack) {
|
||||
if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) {
|
||||
selectedGroup = trackGroup;
|
||||
selectedTrackIndex = trackIndex;
|
||||
selectedTrackScore = trackScore;
|
||||
selectedBitrate = format.bitrate;
|
||||
selectedPixelCount = format.getPixelCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedGroup == null
|
||||
? null
|
||||
: new TrackSelection.Definition(selectedGroup, selectedTrackIndex);
|
||||
|
|
@ -2146,7 +2098,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
throws ExoPlaybackException {
|
||||
int selectedTrackIndex = C.INDEX_UNSET;
|
||||
int selectedGroupIndex = C.INDEX_UNSET;
|
||||
AudioTrackScore selectedTrackScore = null;
|
||||
@Nullable AudioTrackScore selectedTrackScore = null;
|
||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = groups.get(groupIndex);
|
||||
@Capabilities int[] trackFormatSupport = formatSupports[groupIndex];
|
||||
|
|
@ -2272,9 +2224,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
Parameters params,
|
||||
@Nullable String selectedAudioLanguage)
|
||||
throws ExoPlaybackException {
|
||||
TrackGroup selectedGroup = null;
|
||||
@Nullable TrackGroup selectedGroup = null;
|
||||
int selectedTrackIndex = C.INDEX_UNSET;
|
||||
TextTrackScore selectedTrackScore = null;
|
||||
@Nullable TextTrackScore selectedTrackScore = null;
|
||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = groups.get(groupIndex);
|
||||
@Capabilities int[] trackFormatSupport = formatSupport[groupIndex];
|
||||
|
|
@ -2319,9 +2271,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
protected TrackSelection.Definition selectOtherTrack(
|
||||
int trackType, TrackGroupArray groups, @Capabilities int[][] formatSupport, Parameters params)
|
||||
throws ExoPlaybackException {
|
||||
TrackGroup selectedGroup = null;
|
||||
@Nullable TrackGroup selectedGroup = null;
|
||||
int selectedTrackIndex = 0;
|
||||
int selectedTrackScore = 0;
|
||||
@Nullable OtherTrackScore selectedTrackScore = null;
|
||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = groups.get(groupIndex);
|
||||
@Capabilities int[] trackFormatSupport = formatSupport[groupIndex];
|
||||
|
|
@ -2329,12 +2281,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
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;
|
||||
if (isSupported(trackFormatSupport[trackIndex], false)) {
|
||||
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
|
||||
}
|
||||
if (trackScore > selectedTrackScore) {
|
||||
OtherTrackScore trackScore = new OtherTrackScore(format, trackFormatSupport[trackIndex]);
|
||||
if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) {
|
||||
selectedGroup = trackGroup;
|
||||
selectedTrackIndex = trackIndex;
|
||||
selectedTrackScore = trackScore;
|
||||
|
|
@ -2437,21 +2385,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two format values for order. A known value is considered greater than {@link
|
||||
* Format#NO_VALUE}.
|
||||
*
|
||||
* @param first The first value.
|
||||
* @param second The second value.
|
||||
* @return A negative integer if the first value is less than the second. Zero if they are equal.
|
||||
* A positive integer if the first value is greater than the second.
|
||||
*/
|
||||
private static int compareFormatValues(int first, int second) {
|
||||
return first == Format.NO_VALUE
|
||||
? (second == Format.NO_VALUE ? 0 : -1)
|
||||
: (second == Format.NO_VALUE ? 1 : (first - second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@link FormatSupport} in the given {@link Capabilities} is {@link
|
||||
* RendererCapabilities#FORMAT_HANDLED} or if {@code allowExceedsCapabilities} is set and the
|
||||
|
|
@ -2590,16 +2523,75 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two integers in a safe way avoiding potential overflow.
|
||||
*
|
||||
* @param first The first value.
|
||||
* @param second The second value.
|
||||
* @return A negative integer if the first value is less than the second. Zero if they are equal.
|
||||
* A positive integer if the first value is greater than the second.
|
||||
*/
|
||||
private static int compareInts(int first, int second) {
|
||||
return first > second ? 1 : (second > first ? -1 : 0);
|
||||
/** Represents how well a video track matches the selection {@link Parameters}. */
|
||||
protected static final class VideoTrackScore implements Comparable<VideoTrackScore> {
|
||||
|
||||
/**
|
||||
* Whether the provided format is within the parameter maximum constraints. If {@code false},
|
||||
* the format should not be selected.
|
||||
*/
|
||||
public final boolean isWithinMaxConstraints;
|
||||
|
||||
private final Parameters parameters;
|
||||
private final boolean isWithinMinConstraints;
|
||||
private final boolean isWithinRendererCapabilities;
|
||||
private final int bitrate;
|
||||
private final int pixelCount;
|
||||
|
||||
public VideoTrackScore(
|
||||
Format format,
|
||||
Parameters parameters,
|
||||
@Capabilities int formatSupport,
|
||||
boolean isSuitableForViewport) {
|
||||
this.parameters = parameters;
|
||||
isWithinMaxConstraints =
|
||||
isSuitableForViewport
|
||||
&& (format.width == Format.NO_VALUE || format.width <= parameters.maxVideoWidth)
|
||||
&& (format.height == Format.NO_VALUE || format.height <= parameters.maxVideoHeight)
|
||||
&& (format.frameRate == Format.NO_VALUE
|
||||
|| format.frameRate <= parameters.maxVideoFrameRate)
|
||||
&& (format.bitrate == Format.NO_VALUE
|
||||
|| format.bitrate <= parameters.maxVideoBitrate);
|
||||
isWithinMinConstraints =
|
||||
isSuitableForViewport
|
||||
&& (format.width == Format.NO_VALUE || format.width >= parameters.minVideoWidth)
|
||||
&& (format.height == Format.NO_VALUE || format.height >= parameters.minVideoHeight)
|
||||
&& (format.frameRate == Format.NO_VALUE
|
||||
|| format.frameRate >= parameters.minVideoFrameRate)
|
||||
&& (format.bitrate == Format.NO_VALUE
|
||||
|| format.bitrate >= parameters.minVideoBitrate);
|
||||
isWithinRendererCapabilities =
|
||||
isSupported(formatSupport, /* allowExceedsCapabilities= */ false);
|
||||
bitrate = format.bitrate;
|
||||
pixelCount = format.getPixelCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(VideoTrackScore other) {
|
||||
// The preferred ordering by video quality depends on the constraints:
|
||||
// - Not within renderer capabilities: Prefer lower quality because it's more likely to play.
|
||||
// - Within min and max constraints: Prefer higher quality.
|
||||
// - Within max constraints only: Prefer higher quality because it gets us closest to
|
||||
// satisfying the violated min constraints.
|
||||
// - Within min constraints only: Prefer lower quality because it gets us closest to
|
||||
// satisfying the violated max constraints.
|
||||
// - Outside min and max constraints: Arbitrarily prefer lower quality.
|
||||
Ordering<Integer> qualityOrdering =
|
||||
isWithinMaxConstraints && isWithinRendererCapabilities
|
||||
? FORMAT_VALUE_ORDERING
|
||||
: FORMAT_VALUE_ORDERING.reverse();
|
||||
return ComparisonChain.start()
|
||||
.compareFalseFirst(this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
|
||||
.compareFalseFirst(this.isWithinMaxConstraints, other.isWithinMaxConstraints)
|
||||
.compareFalseFirst(this.isWithinMinConstraints, other.isWithinMinConstraints)
|
||||
.compare(
|
||||
this.bitrate,
|
||||
other.bitrate,
|
||||
parameters.forceLowestBitrate ? FORMAT_VALUE_ORDERING.reverse() : NO_ORDER)
|
||||
.compare(this.pixelCount, other.pixelCount, qualityOrdering)
|
||||
.compare(this.bitrate, other.bitrate, qualityOrdering)
|
||||
.result();
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents how well an audio track matches the selection {@link Parameters}. */
|
||||
|
|
@ -2625,7 +2617,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
public AudioTrackScore(Format format, Parameters parameters, @Capabilities int formatSupport) {
|
||||
this.parameters = parameters;
|
||||
this.language = normalizeUndeterminedLanguageToNull(format.language);
|
||||
isWithinRendererCapabilities = isSupported(formatSupport, false);
|
||||
isWithinRendererCapabilities =
|
||||
isSupported(formatSupport, /* allowExceedsCapabilities= */ false);
|
||||
preferredLanguageScore =
|
||||
getFormatLanguageScore(
|
||||
format,
|
||||
|
|
@ -2665,44 +2658,34 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
@Override
|
||||
public int compareTo(AudioTrackScore other) {
|
||||
if (this.isWithinRendererCapabilities != other.isWithinRendererCapabilities) {
|
||||
return this.isWithinRendererCapabilities ? 1 : -1;
|
||||
}
|
||||
if (this.preferredLanguageScore != other.preferredLanguageScore) {
|
||||
return compareInts(this.preferredLanguageScore, other.preferredLanguageScore);
|
||||
}
|
||||
if (this.isWithinConstraints != other.isWithinConstraints) {
|
||||
return this.isWithinConstraints ? 1 : -1;
|
||||
}
|
||||
if (parameters.forceLowestBitrate) {
|
||||
int bitrateComparison = compareFormatValues(bitrate, other.bitrate);
|
||||
if (bitrateComparison != 0) {
|
||||
return bitrateComparison > 0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
if (this.isDefaultSelectionFlag != other.isDefaultSelectionFlag) {
|
||||
return this.isDefaultSelectionFlag ? 1 : -1;
|
||||
}
|
||||
if (this.localeLanguageMatchIndex != other.localeLanguageMatchIndex) {
|
||||
return -compareInts(this.localeLanguageMatchIndex, other.localeLanguageMatchIndex);
|
||||
}
|
||||
if (this.localeLanguageScore != other.localeLanguageScore) {
|
||||
return compareInts(this.localeLanguageScore, other.localeLanguageScore);
|
||||
}
|
||||
// If the formats are within constraints and renderer capabilities then prefer higher values
|
||||
// of channel count, sample rate and bit rate in that order. Otherwise, prefer lower values.
|
||||
int resultSign = isWithinConstraints && isWithinRendererCapabilities ? 1 : -1;
|
||||
if (this.channelCount != other.channelCount) {
|
||||
return resultSign * compareInts(this.channelCount, other.channelCount);
|
||||
}
|
||||
if (this.sampleRate != other.sampleRate) {
|
||||
return resultSign * compareInts(this.sampleRate, other.sampleRate);
|
||||
}
|
||||
if (Util.areEqual(this.language, other.language)) {
|
||||
// Only compare bit rates of tracks with the same or unknown language.
|
||||
return resultSign * compareInts(this.bitrate, other.bitrate);
|
||||
}
|
||||
return 0;
|
||||
Ordering<Integer> qualityOrdering =
|
||||
isWithinConstraints && isWithinRendererCapabilities
|
||||
? FORMAT_VALUE_ORDERING
|
||||
: FORMAT_VALUE_ORDERING.reverse();
|
||||
return ComparisonChain.start()
|
||||
.compareFalseFirst(this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
|
||||
.compare(this.preferredLanguageScore, other.preferredLanguageScore)
|
||||
.compareFalseFirst(this.isWithinConstraints, other.isWithinConstraints)
|
||||
.compare(
|
||||
this.bitrate,
|
||||
other.bitrate,
|
||||
parameters.forceLowestBitrate ? FORMAT_VALUE_ORDERING.reverse() : NO_ORDER)
|
||||
.compareFalseFirst(this.isDefaultSelectionFlag, other.isDefaultSelectionFlag)
|
||||
.compare(
|
||||
this.localeLanguageMatchIndex,
|
||||
other.localeLanguageMatchIndex,
|
||||
Ordering.natural().reverse())
|
||||
.compare(this.localeLanguageScore, other.localeLanguageScore)
|
||||
.compare(this.channelCount, other.channelCount, qualityOrdering)
|
||||
.compare(this.sampleRate, other.sampleRate, qualityOrdering)
|
||||
.compare(
|
||||
this.bitrate,
|
||||
other.bitrate,
|
||||
// Only compare bit rates of tracks with matching language information.
|
||||
Util.areEqual(this.language, other.language) ? qualityOrdering : NO_ORDER)
|
||||
.result();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2717,7 +2700,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
|
||||
private final boolean isWithinRendererCapabilities;
|
||||
private final boolean isDefault;
|
||||
private final boolean hasPreferredIsForcedFlag;
|
||||
private final boolean isForced;
|
||||
private final int preferredLanguageScore;
|
||||
private final int preferredRoleFlagsScore;
|
||||
private final int selectedAudioLanguageScore;
|
||||
|
|
@ -2733,7 +2716,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
int maskedSelectionFlags =
|
||||
format.selectionFlags & ~parameters.disabledTextTrackSelectionFlags;
|
||||
isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
|
||||
boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0;
|
||||
isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0;
|
||||
preferredLanguageScore =
|
||||
getFormatLanguageScore(
|
||||
format, parameters.preferredTextLanguage, parameters.selectUndeterminedTextLanguage);
|
||||
|
|
@ -2741,11 +2724,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
Integer.bitCount(format.roleFlags & parameters.preferredTextRoleFlags);
|
||||
hasCaptionRoleFlags =
|
||||
(format.roleFlags & (C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND)) != 0;
|
||||
// Prefer non-forced to forced if a preferred text language has been matched. Where both are
|
||||
// provided the non-forced track will usually contain the forced subtitles as a subset.
|
||||
// Otherwise, prefer a forced track.
|
||||
hasPreferredIsForcedFlag =
|
||||
(preferredLanguageScore > 0 && !isForced) || (preferredLanguageScore == 0 && isForced);
|
||||
boolean selectedAudioLanguageUndetermined =
|
||||
normalizeUndeterminedLanguageToNull(selectedAudioLanguage) == null;
|
||||
selectedAudioLanguageScore =
|
||||
|
|
@ -2766,28 +2744,49 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||
*/
|
||||
@Override
|
||||
public int compareTo(TextTrackScore other) {
|
||||
if (this.isWithinRendererCapabilities != other.isWithinRendererCapabilities) {
|
||||
return this.isWithinRendererCapabilities ? 1 : -1;
|
||||
ComparisonChain chain =
|
||||
ComparisonChain.start()
|
||||
.compareFalseFirst(
|
||||
this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
|
||||
.compare(this.preferredLanguageScore, other.preferredLanguageScore)
|
||||
.compare(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore)
|
||||
.compareFalseFirst(this.isDefault, other.isDefault)
|
||||
.compare(
|
||||
this.isForced,
|
||||
other.isForced,
|
||||
// Prefer non-forced to forced if a preferred text language has been matched.
|
||||
// Where both are provided the non-forced track will usually contain the forced
|
||||
// subtitles as a subset. Otherwise, prefer a forced track.
|
||||
preferredLanguageScore == 0 ? Ordering.natural() : Ordering.natural().reverse())
|
||||
.compare(this.selectedAudioLanguageScore, other.selectedAudioLanguageScore);
|
||||
if (preferredRoleFlagsScore == 0) {
|
||||
chain = chain.compareTrueFirst(this.hasCaptionRoleFlags, other.hasCaptionRoleFlags);
|
||||
}
|
||||
if (this.preferredLanguageScore != other.preferredLanguageScore) {
|
||||
return compareInts(this.preferredLanguageScore, other.preferredLanguageScore);
|
||||
}
|
||||
if (this.preferredRoleFlagsScore != other.preferredRoleFlagsScore) {
|
||||
return compareInts(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore);
|
||||
}
|
||||
if (this.isDefault != other.isDefault) {
|
||||
return this.isDefault ? 1 : -1;
|
||||
}
|
||||
if (this.hasPreferredIsForcedFlag != other.hasPreferredIsForcedFlag) {
|
||||
return this.hasPreferredIsForcedFlag ? 1 : -1;
|
||||
}
|
||||
if (this.selectedAudioLanguageScore != other.selectedAudioLanguageScore) {
|
||||
return compareInts(this.selectedAudioLanguageScore, other.selectedAudioLanguageScore);
|
||||
}
|
||||
if (preferredRoleFlagsScore == 0 && this.hasCaptionRoleFlags != other.hasCaptionRoleFlags) {
|
||||
return this.hasCaptionRoleFlags ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
return chain.result();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents how well any other track (non video, audio or text) matches the selection {@link
|
||||
* Parameters}.
|
||||
*/
|
||||
protected static final class OtherTrackScore implements Comparable<OtherTrackScore> {
|
||||
|
||||
private final boolean isDefault;
|
||||
private final boolean isWithinRendererCapabilities;
|
||||
|
||||
public OtherTrackScore(Format format, @Capabilities int trackFormatSupport) {
|
||||
isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
|
||||
isWithinRendererCapabilities =
|
||||
isSupported(trackFormatSupport, /* allowExceedsCapabilities= */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(OtherTrackScore other) {
|
||||
return ComparisonChain.start()
|
||||
.compareFalseFirst(this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
|
||||
.compareFalseFirst(this.isDefault, other.isDefault)
|
||||
.result();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue