Commit df862782 by Oliver Woodman

Merge pull request #7451 from szaboa:dev-v2-4511

PiperOrigin-RevId: 315995776
parents 5612ac50 a1ebffd2
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* Core library: * Core library:
* Implement getTag for SilenceMediaSource. * Implement getTag for SilenceMediaSource.
* Add `Player.getTrackSelector` to access track selector from UI module.
* Added `TextComponent.getCurrentCues` because the current cues are no * Added `TextComponent.getCurrentCues` because the current cues are no
longer forwarded to a new `TextOutput` in `SimpleExoPlayer` longer forwarded to a new `TextOutput` in `SimpleExoPlayer`
automatically. automatically.
...@@ -76,7 +75,6 @@ ...@@ -76,7 +75,6 @@
`DecoderVideoRenderer` and `DecoderAudioRenderer` respectively, and `DecoderVideoRenderer` and `DecoderAudioRenderer` respectively, and
generalized to work with `Decoder` rather than `SimpleDecoder`. generalized to work with `Decoder` rather than `SimpleDecoder`.
* Add media item based playlist API to Player. * Add media item based playlist API to Player.
* Remove deprecated members in `DefaultTrackSelector`.
* Add `Player.DeviceComponent` and implement it for `SimpleExoPlayer` so * Add `Player.DeviceComponent` and implement it for `SimpleExoPlayer` so
that the device volume can be controlled by player. that the device volume can be controlled by player.
* Parse track titles from Matroska files * Parse track titles from Matroska files
...@@ -92,6 +90,12 @@ ...@@ -92,6 +90,12 @@
ongoing load should be canceled. Only supported by HLS streams so far. ongoing load should be canceled. Only supported by HLS streams so far.
([#2848](https://github.com/google/ExoPlayer/issues/2848)). ([#2848](https://github.com/google/ExoPlayer/issues/2848)).
* Video: Pass frame rate hint to `Surface.setFrameRate` on Android R devices. * Video: Pass frame rate hint to `Surface.setFrameRate` on Android R devices.
* Track selection:
* Add `Player.getTrackSelector`.
* Remove deprecated members in `DefaultTrackSelector`.
* Add `DefaultTrackSelector` constraints for minimum video resolution,
bitrate and frame rate
([#4511](https://github.com/google/ExoPlayer/issues/4511)).
* Text: * Text:
* Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming * Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming
later). later).
......
...@@ -169,6 +169,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -169,6 +169,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private int maxVideoHeight; private int maxVideoHeight;
private int maxVideoFrameRate; private int maxVideoFrameRate;
private int maxVideoBitrate; private int maxVideoBitrate;
private int minVideoWidth;
private int minVideoHeight;
private int minVideoFrameRate;
private int minVideoBitrate;
private boolean exceedVideoConstraintsIfNecessary; private boolean exceedVideoConstraintsIfNecessary;
private boolean allowVideoMixedMimeTypeAdaptiveness; private boolean allowVideoMixedMimeTypeAdaptiveness;
private boolean allowVideoNonSeamlessAdaptiveness; private boolean allowVideoNonSeamlessAdaptiveness;
...@@ -230,6 +234,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -230,6 +234,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoHeight = initialValues.maxVideoHeight; maxVideoHeight = initialValues.maxVideoHeight;
maxVideoFrameRate = initialValues.maxVideoFrameRate; maxVideoFrameRate = initialValues.maxVideoFrameRate;
maxVideoBitrate = initialValues.maxVideoBitrate; maxVideoBitrate = initialValues.maxVideoBitrate;
minVideoWidth = initialValues.minVideoWidth;
minVideoHeight = initialValues.minVideoHeight;
minVideoFrameRate = initialValues.minVideoFrameRate;
minVideoBitrate = initialValues.minVideoBitrate;
exceedVideoConstraintsIfNecessary = initialValues.exceedVideoConstraintsIfNecessary; exceedVideoConstraintsIfNecessary = initialValues.exceedVideoConstraintsIfNecessary;
allowVideoMixedMimeTypeAdaptiveness = initialValues.allowVideoMixedMimeTypeAdaptiveness; allowVideoMixedMimeTypeAdaptiveness = initialValues.allowVideoMixedMimeTypeAdaptiveness;
allowVideoNonSeamlessAdaptiveness = initialValues.allowVideoNonSeamlessAdaptiveness; allowVideoNonSeamlessAdaptiveness = initialValues.allowVideoNonSeamlessAdaptiveness;
...@@ -310,8 +318,43 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -310,8 +318,43 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* Sets whether to exceed the {@link #setMaxVideoSize(int, int)} and {@link * Sets the minimum allowed video width and height.
* #setMaxAudioBitrate(int)} constraints when no selection can be made otherwise. *
* @param minVideoWidth Minimum allowed video width in pixels.
* @param minVideoHeight Minimum allowed video height in pixels.
* @return This builder.
*/
public ParametersBuilder setMinVideoSize(int minVideoWidth, int minVideoHeight) {
this.minVideoWidth = minVideoWidth;
this.minVideoHeight = minVideoHeight;
return this;
}
/**
* Sets the minimum allowed video frame rate.
*
* @param minVideoFrameRate Minimum allowed video frame rate in hertz.
* @return This builder.
*/
public ParametersBuilder setMinVideoFrameRate(int minVideoFrameRate) {
this.minVideoFrameRate = minVideoFrameRate;
return this;
}
/**
* Sets the minimum allowed video bitrate.
*
* @param minVideoBitrate Minimum allowed video bitrate in bits per second.
* @return This builder.
*/
public ParametersBuilder setMinVideoBitrate(int minVideoBitrate) {
this.minVideoBitrate = minVideoBitrate;
return this;
}
/**
* Sets whether to exceed the {@link #setMaxVideoBitrate}, {@link #setMaxVideoSize(int, int)}
* and {@link #setMaxVideoFrameRate} constraints when no selection can be made otherwise.
* *
* @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no * @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
* selection can be made otherwise. * selection can be made otherwise.
...@@ -712,6 +755,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -712,6 +755,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoHeight, maxVideoHeight,
maxVideoFrameRate, maxVideoFrameRate,
maxVideoBitrate, maxVideoBitrate,
minVideoWidth,
minVideoHeight,
minVideoFrameRate,
minVideoBitrate,
exceedVideoConstraintsIfNecessary, exceedVideoConstraintsIfNecessary,
allowVideoMixedMimeTypeAdaptiveness, allowVideoMixedMimeTypeAdaptiveness,
allowVideoNonSeamlessAdaptiveness, allowVideoNonSeamlessAdaptiveness,
...@@ -837,6 +884,17 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -837,6 +884,17 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* Integer#MAX_VALUE} (i.e. no constraint). * Integer#MAX_VALUE} (i.e. no constraint).
*/ */
public final int maxVideoBitrate; public final int maxVideoBitrate;
/** Minimum allowed video width in pixels. The default value is 0 (i.e. no constraint). */
public final int minVideoWidth;
/** Minimum allowed video height in pixels. The default value is 0 (i.e. no constraint). */
public final int minVideoHeight;
/** Minimum allowed video frame rate in hertz. The default value is 0 (i.e. no constraint). */
public final int minVideoFrameRate;
/**
* Minimum allowed video bitrate in bits per second. The default value is 0 (i.e. no
* constraint).
*/
public final int minVideoBitrate;
/** /**
* Whether to exceed the {@link #maxVideoWidth}, {@link #maxVideoHeight} and {@link * Whether to exceed the {@link #maxVideoWidth}, {@link #maxVideoHeight} and {@link
* #maxVideoBitrate} constraints when no selection can be made otherwise. The default value is * #maxVideoBitrate} constraints when no selection can be made otherwise. The default value is
...@@ -945,6 +1003,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -945,6 +1003,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int maxVideoHeight, int maxVideoHeight,
int maxVideoFrameRate, int maxVideoFrameRate,
int maxVideoBitrate, int maxVideoBitrate,
int minVideoWidth,
int minVideoHeight,
int minVideoFrameRate,
int minVideoBitrate,
boolean exceedVideoConstraintsIfNecessary, boolean exceedVideoConstraintsIfNecessary,
boolean allowVideoMixedMimeTypeAdaptiveness, boolean allowVideoMixedMimeTypeAdaptiveness,
boolean allowVideoNonSeamlessAdaptiveness, boolean allowVideoNonSeamlessAdaptiveness,
...@@ -983,6 +1045,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -983,6 +1045,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.maxVideoHeight = maxVideoHeight; this.maxVideoHeight = maxVideoHeight;
this.maxVideoFrameRate = maxVideoFrameRate; this.maxVideoFrameRate = maxVideoFrameRate;
this.maxVideoBitrate = maxVideoBitrate; this.maxVideoBitrate = maxVideoBitrate;
this.minVideoWidth = minVideoWidth;
this.minVideoHeight = minVideoHeight;
this.minVideoFrameRate = minVideoFrameRate;
this.minVideoBitrate = minVideoBitrate;
this.exceedVideoConstraintsIfNecessary = exceedVideoConstraintsIfNecessary; this.exceedVideoConstraintsIfNecessary = exceedVideoConstraintsIfNecessary;
this.allowVideoMixedMimeTypeAdaptiveness = allowVideoMixedMimeTypeAdaptiveness; this.allowVideoMixedMimeTypeAdaptiveness = allowVideoMixedMimeTypeAdaptiveness;
this.allowVideoNonSeamlessAdaptiveness = allowVideoNonSeamlessAdaptiveness; this.allowVideoNonSeamlessAdaptiveness = allowVideoNonSeamlessAdaptiveness;
...@@ -1014,6 +1080,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1014,6 +1080,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.maxVideoHeight = in.readInt(); this.maxVideoHeight = in.readInt();
this.maxVideoFrameRate = in.readInt(); this.maxVideoFrameRate = in.readInt();
this.maxVideoBitrate = in.readInt(); this.maxVideoBitrate = in.readInt();
this.minVideoWidth = in.readInt();
this.minVideoHeight = in.readInt();
this.minVideoFrameRate = in.readInt();
this.minVideoBitrate = in.readInt();
this.exceedVideoConstraintsIfNecessary = Util.readBoolean(in); this.exceedVideoConstraintsIfNecessary = Util.readBoolean(in);
this.allowVideoMixedMimeTypeAdaptiveness = Util.readBoolean(in); this.allowVideoMixedMimeTypeAdaptiveness = Util.readBoolean(in);
this.allowVideoNonSeamlessAdaptiveness = Util.readBoolean(in); this.allowVideoNonSeamlessAdaptiveness = Util.readBoolean(in);
...@@ -1095,6 +1165,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1095,6 +1165,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& maxVideoHeight == other.maxVideoHeight && maxVideoHeight == other.maxVideoHeight
&& maxVideoFrameRate == other.maxVideoFrameRate && maxVideoFrameRate == other.maxVideoFrameRate
&& maxVideoBitrate == other.maxVideoBitrate && maxVideoBitrate == other.maxVideoBitrate
&& minVideoWidth == other.minVideoWidth
&& minVideoHeight == other.minVideoHeight
&& minVideoFrameRate == other.minVideoFrameRate
&& minVideoBitrate == other.minVideoBitrate
&& exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary && exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary
&& allowVideoMixedMimeTypeAdaptiveness == other.allowVideoMixedMimeTypeAdaptiveness && allowVideoMixedMimeTypeAdaptiveness == other.allowVideoMixedMimeTypeAdaptiveness
&& allowVideoNonSeamlessAdaptiveness == other.allowVideoNonSeamlessAdaptiveness && allowVideoNonSeamlessAdaptiveness == other.allowVideoNonSeamlessAdaptiveness
...@@ -1127,6 +1201,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1127,6 +1201,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + maxVideoHeight; result = 31 * result + maxVideoHeight;
result = 31 * result + maxVideoFrameRate; result = 31 * result + maxVideoFrameRate;
result = 31 * result + maxVideoBitrate; result = 31 * result + maxVideoBitrate;
result = 31 * result + minVideoWidth;
result = 31 * result + minVideoHeight;
result = 31 * result + minVideoFrameRate;
result = 31 * result + minVideoBitrate;
result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0); result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (allowVideoMixedMimeTypeAdaptiveness ? 1 : 0); result = 31 * result + (allowVideoMixedMimeTypeAdaptiveness ? 1 : 0);
result = 31 * result + (allowVideoNonSeamlessAdaptiveness ? 1 : 0); result = 31 * result + (allowVideoNonSeamlessAdaptiveness ? 1 : 0);
...@@ -1164,6 +1242,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1164,6 +1242,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
dest.writeInt(maxVideoHeight); dest.writeInt(maxVideoHeight);
dest.writeInt(maxVideoFrameRate); dest.writeInt(maxVideoFrameRate);
dest.writeInt(maxVideoBitrate); dest.writeInt(maxVideoBitrate);
dest.writeInt(minVideoWidth);
dest.writeInt(minVideoHeight);
dest.writeInt(minVideoFrameRate);
dest.writeInt(minVideoBitrate);
Util.writeBoolean(dest, exceedVideoConstraintsIfNecessary); Util.writeBoolean(dest, exceedVideoConstraintsIfNecessary);
Util.writeBoolean(dest, allowVideoMixedMimeTypeAdaptiveness); Util.writeBoolean(dest, allowVideoMixedMimeTypeAdaptiveness);
Util.writeBoolean(dest, allowVideoNonSeamlessAdaptiveness); Util.writeBoolean(dest, allowVideoNonSeamlessAdaptiveness);
...@@ -1407,7 +1489,12 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1407,7 +1489,12 @@ 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];
// 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 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;
private final TrackSelection.Factory trackSelectionFactory; private final TrackSelection.Factory trackSelectionFactory;
private final AtomicReference<Parameters> parametersReference; private final AtomicReference<Parameters> parametersReference;
...@@ -1751,6 +1838,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1751,6 +1838,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
params.maxVideoHeight, params.maxVideoHeight,
params.maxVideoFrameRate, params.maxVideoFrameRate,
params.maxVideoBitrate, params.maxVideoBitrate,
params.minVideoWidth,
params.minVideoHeight,
params.minVideoFrameRate,
params.minVideoBitrate,
params.viewportWidth, params.viewportWidth,
params.viewportHeight, params.viewportHeight,
params.viewportOrientationMayChange); params.viewportOrientationMayChange);
...@@ -1770,6 +1861,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1770,6 +1861,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int maxVideoHeight, int maxVideoHeight,
int maxVideoFrameRate, int maxVideoFrameRate,
int maxVideoBitrate, int maxVideoBitrate,
int minVideoWidth,
int minVideoHeight,
int minVideoFrameRate,
int minVideoBitrate,
int viewportWidth, int viewportWidth,
int viewportHeight, int viewportHeight,
boolean viewportOrientationMayChange) { boolean viewportOrientationMayChange) {
...@@ -1802,6 +1897,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1802,6 +1897,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoHeight, maxVideoHeight,
maxVideoFrameRate, maxVideoFrameRate,
maxVideoBitrate, maxVideoBitrate,
minVideoWidth,
minVideoHeight,
minVideoFrameRate,
minVideoBitrate,
selectedTrackIndices); selectedTrackIndices);
if (countForMimeType > selectedMimeTypeTrackCount) { if (countForMimeType > selectedMimeTypeTrackCount) {
selectedMimeType = sampleMimeType; selectedMimeType = sampleMimeType;
...@@ -1821,6 +1920,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1821,6 +1920,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoHeight, maxVideoHeight,
maxVideoFrameRate, maxVideoFrameRate,
maxVideoBitrate, maxVideoBitrate,
minVideoWidth,
minVideoHeight,
minVideoFrameRate,
minVideoBitrate,
selectedTrackIndices); selectedTrackIndices);
return selectedTrackIndices.size() < 2 ? NO_TRACKS : Ints.toArray(selectedTrackIndices); return selectedTrackIndices.size() < 2 ? NO_TRACKS : Ints.toArray(selectedTrackIndices);
...@@ -1835,6 +1938,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1835,6 +1938,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int maxVideoHeight, int maxVideoHeight,
int maxVideoFrameRate, int maxVideoFrameRate,
int maxVideoBitrate, int maxVideoBitrate,
int minVideoWidth,
int minVideoHeight,
int minVideoFrameRate,
int minVideoBitrate,
List<Integer> selectedTrackIndices) { List<Integer> selectedTrackIndices) {
int adaptiveTrackCount = 0; int adaptiveTrackCount = 0;
for (int i = 0; i < selectedTrackIndices.size(); i++) { for (int i = 0; i < selectedTrackIndices.size(); i++) {
...@@ -1847,7 +1954,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1847,7 +1954,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoWidth, maxVideoWidth,
maxVideoHeight, maxVideoHeight,
maxVideoFrameRate, maxVideoFrameRate,
maxVideoBitrate)) { maxVideoBitrate,
minVideoWidth,
minVideoHeight,
minVideoFrameRate,
minVideoBitrate)) {
adaptiveTrackCount++; adaptiveTrackCount++;
} }
} }
...@@ -1863,6 +1974,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1863,6 +1974,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int maxVideoHeight, int maxVideoHeight,
int maxVideoFrameRate, int maxVideoFrameRate,
int maxVideoBitrate, int maxVideoBitrate,
int minVideoWidth,
int minVideoHeight,
int minVideoFrameRate,
int minVideoBitrate,
List<Integer> selectedTrackIndices) { List<Integer> selectedTrackIndices) {
for (int i = selectedTrackIndices.size() - 1; i >= 0; i--) { for (int i = selectedTrackIndices.size() - 1; i >= 0; i--) {
int trackIndex = selectedTrackIndices.get(i); int trackIndex = selectedTrackIndices.get(i);
...@@ -1874,7 +1989,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1874,7 +1989,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoWidth, maxVideoWidth,
maxVideoHeight, maxVideoHeight,
maxVideoFrameRate, maxVideoFrameRate,
maxVideoBitrate)) { maxVideoBitrate,
minVideoWidth,
minVideoHeight,
minVideoFrameRate,
minVideoBitrate)) {
selectedTrackIndices.remove(i); selectedTrackIndices.remove(i);
} }
} }
...@@ -1888,24 +2007,32 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1888,24 +2007,32 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int maxVideoWidth, int maxVideoWidth,
int maxVideoHeight, int maxVideoHeight,
int maxVideoFrameRate, int maxVideoFrameRate,
int maxVideoBitrate) { int maxVideoBitrate,
int minVideoWidth,
int minVideoHeight,
int minVideoFrameRate,
int minVideoBitrate) {
if ((format.roleFlags & C.ROLE_FLAG_TRICK_PLAY) != 0) { if ((format.roleFlags & C.ROLE_FLAG_TRICK_PLAY) != 0) {
// Ignore trick-play tracks for now. // Ignore trick-play tracks for now.
return false; return false;
} }
return isSupported(formatSupport, false) return isSupported(formatSupport, /* allowExceedsCapabilities= */ false)
&& ((formatSupport & requiredAdaptiveSupport) != 0) && ((formatSupport & requiredAdaptiveSupport) != 0)
&& (mimeType == null || Util.areEqual(format.sampleMimeType, mimeType)) && (mimeType == null || Util.areEqual(format.sampleMimeType, mimeType))
&& (format.width == Format.NO_VALUE || format.width <= maxVideoWidth) && (format.width == Format.NO_VALUE
&& (format.height == Format.NO_VALUE || format.height <= maxVideoHeight) || (minVideoWidth <= format.width && format.width <= maxVideoWidth))
&& (format.frameRate == Format.NO_VALUE || format.frameRate <= maxVideoFrameRate) && (format.height == Format.NO_VALUE
&& (format.bitrate == Format.NO_VALUE || format.bitrate <= maxVideoBitrate); || (minVideoHeight <= format.height && format.height <= maxVideoHeight))
&& (format.frameRate == Format.NO_VALUE
|| (minVideoFrameRate <= format.frameRate && format.frameRate <= maxVideoFrameRate))
&& (format.bitrate == Format.NO_VALUE
|| (minVideoBitrate <= format.bitrate && format.bitrate <= maxVideoBitrate));
} }
@Nullable @Nullable
private static TrackSelection.Definition selectFixedVideoTrack( private static TrackSelection.Definition selectFixedVideoTrack(
TrackGroupArray groups, @Capabilities int[][] formatSupports, Parameters params) { TrackGroupArray groups, @Capabilities int[][] formatSupports, Parameters params) {
TrackGroup selectedGroup = null; @Nullable TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = 0;
int selectedTrackScore = 0; int selectedTrackScore = 0;
int selectedBitrate = Format.NO_VALUE; int selectedBitrate = Format.NO_VALUE;
...@@ -1923,7 +2050,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1923,7 +2050,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
if (isSupported(trackFormatSupport[trackIndex], if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) { params.exceedRendererCapabilitiesIfNecessary)) {
boolean isWithinConstraints = boolean satisfiesMaxConstraints =
selectedTrackIndices.contains(trackIndex) selectedTrackIndices.contains(trackIndex)
&& (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)
...@@ -1931,32 +2058,62 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1931,32 +2058,62 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|| 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);
if (!isWithinConstraints && !params.exceedVideoConstraintsIfNecessary) { 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) {
// Track should not be selected. // Track should not be selected.
continue; continue;
} }
int trackScore = isWithinConstraints ? 2 : 1; int 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_VIDEO_CONSTRAINTS_BONUS;
}
if (satisfiesMinConstraints) {
trackScore += SATISFIES_MIN_VIDEO_CONSTRAINTS_BONUS;
}
boolean selectTrack = trackScore > selectedTrackScore; boolean selectTrack = trackScore > selectedTrackScore;
if (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); 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 tiebreaker, 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 pixel count as a tiebreaker, followed by bitrate if pixel counts are equal.
// 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 && isWithinConstraints if (!isWithinCapabilities) {
? comparisonResult > 0 : comparisonResult < 0; // 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 (selectTrack) {
......
...@@ -131,51 +131,16 @@ public final class DefaultTrackSelectorTest { ...@@ -131,51 +131,16 @@ public final class DefaultTrackSelectorTest {
trackSelector.init(invalidationListener, bandwidthMeter); trackSelector.init(invalidationListener, bandwidthMeter);
} }
/** Tests {@link Parameters} {@link android.os.Parcelable} implementation. */
@Test @Test
public void parametersParcelable() { public void parameters_buildUponThenBuild_isEqual() {
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides = new SparseArray<>(); Parameters parameters = buildParametersForEqualsTest();
Map<TrackGroupArray, SelectionOverride> videoOverrides = new HashMap<>(); assertThat(parameters.buildUpon().build()).isEqualTo(parameters);
videoOverrides.put(new TrackGroupArray(VIDEO_TRACK_GROUP), new SelectionOverride(0, 1)); }
selectionOverrides.put(2, videoOverrides);
SparseBooleanArray rendererDisabledFlags = new SparseBooleanArray();
rendererDisabledFlags.put(3, true);
Parameters parametersToParcel = /** Tests {@link Parameters} {@link android.os.Parcelable} implementation. */
new Parameters( @Test
// Video public void parameters_parcelAndUnParcelable() {
/* maxVideoWidth= */ 0, Parameters parametersToParcel = buildParametersForEqualsTest();
/* maxVideoHeight= */ 1,
/* maxVideoFrameRate= */ 2,
/* maxVideoBitrate= */ 3,
/* exceedVideoConstraintsIfNecessary= */ false,
/* allowVideoMixedMimeTypeAdaptiveness= */ true,
/* allowVideoNonSeamlessAdaptiveness= */ false,
/* viewportWidth= */ 4,
/* viewportHeight= */ 5,
/* viewportOrientationMayChange= */ true,
// Audio
/* preferredAudioLanguage= */ "en",
/* maxAudioChannelCount= */ 6,
/* maxAudioBitrate= */ 7,
/* exceedAudioConstraintsIfNecessary= */ false,
/* allowAudioMixedMimeTypeAdaptiveness= */ true,
/* allowAudioMixedSampleRateAdaptiveness= */ false,
/* allowAudioMixedChannelCountAdaptiveness= */ true,
// Text
/* preferredTextLanguage= */ "de",
/* preferredTextRoleFlags= */ C.ROLE_FLAG_CAPTION,
/* selectUndeterminedTextLanguage= */ true,
/* disabledTextTrackSelectionFlags= */ 8,
// General
/* forceLowestBitrate= */ false,
/* forceHighestSupportedBitrate= */ true,
/* exceedRendererCapabilitiesIfNecessary= */ false,
/* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET,
// Overrides
selectionOverrides,
rendererDisabledFlags);
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
parametersToParcel.writeToParcel(parcel, 0); parametersToParcel.writeToParcel(parcel, 0);
...@@ -1511,6 +1476,61 @@ public final class DefaultTrackSelectorTest { ...@@ -1511,6 +1476,61 @@ public final class DefaultTrackSelectorTest {
} }
/** /**
* Returns {@link Parameters} suitable for simple round trip equality tests.
*
* <p>Primitive variables are set to different values (to the extent that this is possible), to
* increase the probability of such tests failing if they accidentally compare mismatched
* variables.
*/
private static Parameters buildParametersForEqualsTest() {
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides = new SparseArray<>();
Map<TrackGroupArray, SelectionOverride> videoOverrides = new HashMap<>();
videoOverrides.put(new TrackGroupArray(VIDEO_TRACK_GROUP), new SelectionOverride(0, 1));
selectionOverrides.put(2, videoOverrides);
SparseBooleanArray rendererDisabledFlags = new SparseBooleanArray();
rendererDisabledFlags.put(3, true);
return new Parameters(
// Video
/* maxVideoWidth= */ 0,
/* maxVideoHeight= */ 1,
/* maxVideoFrameRate= */ 2,
/* maxVideoBitrate= */ 3,
/* minVideoWidth= */ 4,
/* minVideoHeight= */ 5,
/* minVideoFrameRate= */ 6,
/* minVideoBitrate= */ 7,
/* exceedVideoConstraintsIfNecessary= */ false,
/* allowVideoMixedMimeTypeAdaptiveness= */ true,
/* allowVideoNonSeamlessAdaptiveness= */ false,
/* viewportWidth= */ 8,
/* viewportHeight= */ 9,
/* viewportOrientationMayChange= */ true,
// Audio
/* preferredAudioLanguage= */ "en",
/* maxAudioChannelCount= */ 10,
/* maxAudioBitrate= */ 11,
/* exceedAudioConstraintsIfNecessary= */ false,
/* allowAudioMixedMimeTypeAdaptiveness= */ true,
/* allowAudioMixedSampleRateAdaptiveness= */ false,
/* allowAudioMixedChannelCountAdaptiveness= */ true,
// Text
/* preferredTextLanguage= */ "de",
/* preferredTextRoleFlags= */ C.ROLE_FLAG_CAPTION,
/* selectUndeterminedTextLanguage= */ true,
/* disabledTextTrackSelectionFlags= */ 12,
// General
/* forceLowestBitrate= */ false,
/* forceHighestSupportedBitrate= */ true,
/* exceedRendererCapabilitiesIfNecessary= */ false,
/* tunnelingAudioSessionId= */ 13,
// Overrides
selectionOverrides,
rendererDisabledFlags);
}
/**
* A {@link RendererCapabilities} that advertises support for all formats of a given type using * A {@link RendererCapabilities} that advertises support for all formats of a given type using
* a provided support value. For any format that does not have the given track type, * a provided support value. For any format that does not have the given track type,
* {@link #supportsFormat(Format)} will return {@link #FORMAT_UNSUPPORTED_TYPE}. * {@link #supportsFormat(Format)} will return {@link #FORMAT_UNSUPPORTED_TYPE}.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment