Correct tie-breaking rules when selecting fixed video track

This commit is contained in:
Arnold Szabo 2020-05-31 23:40:10 +03:00
parent dfec0338c5
commit a1ebffd238

View File

@ -1498,6 +1498,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static final float FRACTION_TO_CONSIDER_FULLSCREEN = 0.98f; private static final float FRACTION_TO_CONSIDER_FULLSCREEN = 0.98f;
private static final int[] NO_TRACKS = new int[0]; private static final int[] NO_TRACKS = new int[0];
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000; private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
/**
* In case when both min and max constraints are set, give the track higher score which satisfies
* the max constraints, as it is more important to not violate the max constraints than min
* constraints, because it's more likely to play successfully when max constraints are satisfied.
*/
private static final int SATISFIES_MIN_CONSTRAINTS_BONUS = 1;
private static final int SATISFIES_MAX_CONSTRAINTS_BONUS = 2;
private final TrackSelection.Factory trackSelectionFactory; private final TrackSelection.Factory trackSelectionFactory;
private final AtomicReference<Parameters> parametersReference; private final AtomicReference<Parameters> parametersReference;
@ -2040,8 +2048,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int selectedTrackScore = 0; int selectedTrackScore = 0;
int selectedBitrate = Format.NO_VALUE; int selectedBitrate = Format.NO_VALUE;
int selectedPixelCount = Format.NO_VALUE; int selectedPixelCount = Format.NO_VALUE;
boolean selectedSatisfiesMaxConstraints;
boolean selectedSatisfiesMinConstraints;
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);
List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(trackGroup, List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(trackGroup,
@ -2060,50 +2066,68 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& (format.width == Format.NO_VALUE || format.width <= params.maxVideoWidth) && (format.width == Format.NO_VALUE || format.width <= params.maxVideoWidth)
&& (format.height == Format.NO_VALUE || format.height <= params.maxVideoHeight) && (format.height == Format.NO_VALUE || format.height <= params.maxVideoHeight)
&& (format.frameRate == Format.NO_VALUE && (format.frameRate == Format.NO_VALUE
|| format.frameRate <= params.maxVideoFrameRate) || format.frameRate <= params.maxVideoFrameRate)
&& (format.bitrate == Format.NO_VALUE && (format.bitrate == Format.NO_VALUE
|| format.bitrate <= params.maxVideoBitrate); || format.bitrate <= params.maxVideoBitrate);
boolean satisfiesMinConstraints = boolean satisfiesMinConstraints =
selectedTrackIndices.contains(trackIndex) selectedTrackIndices.contains(trackIndex)
&& (format.width == Format.NO_VALUE || format.width >= params.minVideoWidth) && (format.width == Format.NO_VALUE || format.width >= params.minVideoWidth)
&& (format.height == Format.NO_VALUE || format.height >= params.minVideoHeight) && (format.height == Format.NO_VALUE || format.height >= params.minVideoHeight)
&& (format.frameRate == Format.NO_VALUE && (format.frameRate == Format.NO_VALUE
|| format.frameRate >= params.minVideoFrameRate) || format.frameRate >= params.minVideoFrameRate)
&& (format.bitrate == Format.NO_VALUE && (format.bitrate == Format.NO_VALUE
|| format.bitrate >= params.minVideoBitrate); || format.bitrate >= params.minVideoBitrate);
if (!satisfiesMaxConstraints && !params.exceedVideoConstraintsIfNecessary) { if (!satisfiesMaxConstraints && !params.exceedVideoConstraintsIfNecessary) {
// Track should not be selected. // Track should not be selected.
continue; continue;
} }
int trackScore = 1; int trackScore = 1;
if (satisfiesMaxConstraints) {
trackScore += 1;
}
if (satisfiesMinConstraints) {
trackScore += 1;
}
boolean isWithinCapabilities = isSupported(trackFormatSupport[trackIndex], false); boolean isWithinCapabilities = isSupported(trackFormatSupport[trackIndex], false);
if (isWithinCapabilities) { if (isWithinCapabilities) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS; trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
} }
if (satisfiesMaxConstraints) {
trackScore += SATISFIES_MAX_CONSTRAINTS_BONUS;
}
if (satisfiesMinConstraints) {
trackScore += SATISFIES_MIN_CONSTRAINTS_BONUS;
}
boolean selectTrack = trackScore > selectedTrackScore; boolean selectTrack = trackScore > selectedTrackScore;
// Handling tie-breaking scenarios.
if (trackScore == selectedTrackScore) { if (trackScore == selectedTrackScore) {
// TODO handle tie breaker cases correctly.
int bitrateComparison = compareFormatValues(format.bitrate, selectedBitrate); int bitrateComparison = compareFormatValues(format.bitrate, selectedBitrate);
if (params.forceLowestBitrate && bitrateComparison != 0) { if (params.forceLowestBitrate && bitrateComparison != 0) {
// Use bitrate as a tie breaker, preferring the lower bitrate. // Use bitrate as a tie breaker, preferring the lower bitrate.
selectTrack = bitrateComparison < 0; selectTrack = bitrateComparison < 0;
} else { } else {
// Use the pixel count as a tie breaker (or bitrate if pixel counts are tied). If // Use the pixel count as a tie breaker (or bitrate if pixel counts are tied).
// 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 formatPixelCount = format.getPixelCount();
int comparisonResult = formatPixelCount != selectedPixelCount int comparisonResult = formatPixelCount != selectedPixelCount
? compareFormatValues(formatPixelCount, selectedPixelCount) ? compareFormatValues(formatPixelCount, selectedPixelCount)
: compareFormatValues(format.bitrate, selectedBitrate); : compareFormatValues(format.bitrate, selectedBitrate);
selectTrack = isWithinCapabilities && satisfiesMaxConstraints // If it's not within the capabilities, always pick lower quality because it's more
? comparisonResult > 0 : comparisonResult < 0; // likely to play successfully.
if (!isWithinCapabilities) {
selectTrack = comparisonResult < 0;
} else {
if (satisfiesMinConstraints && satisfiesMaxConstraints) {
// Both constraints are satisfied, pick higher quality.
selectTrack = comparisonResult > 0;
} else if (!satisfiesMinConstraints && satisfiesMaxConstraints) {
// Min constraints are not satisfied but the max constraints are, pick higher
// quality, because that's what gets us closest to satisfying the violated min
// constraints.
selectTrack = comparisonResult > 0;
} else if (satisfiesMinConstraints) {
// Min constraints are satisfied but not the max constraints, pick lower quality
// because that's what gets us closest to satisfying the violated max constraints.
selectTrack = comparisonResult > 0;
} else {
// Neither min or max constraints are not satisfied, pick lower quality because
// it's more likely to play successfully.
selectTrack = comparisonResult < 0;
}
}
} }
} }
if (selectTrack) { if (selectTrack) {
@ -2112,8 +2136,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
selectedTrackScore = trackScore; selectedTrackScore = trackScore;
selectedBitrate = format.bitrate; selectedBitrate = format.bitrate;
selectedPixelCount = format.getPixelCount(); selectedPixelCount = format.getPixelCount();
selectedSatisfiesMaxConstraints = satisfiesMaxConstraints;
selectedSatisfiesMinConstraints = satisfiesMinConstraints;
} }
} }
} }