Add options for controlling audio track selection

Issue: #3314

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=219158729
This commit is contained in:
olly 2018-10-29 11:08:22 -07:00 committed by Oliver Woodman
parent 069e3cbf7d
commit 7eeeb40d24
3 changed files with 519 additions and 77 deletions

View File

@ -6,6 +6,8 @@
here ([#2826](https://github.com/google/ExoPlayer/issues/2826)). here ([#2826](https://github.com/google/ExoPlayer/issues/2826)).
* Improve initial bandwidth meter estimates using the current country and * Improve initial bandwidth meter estimates using the current country and
network type. network type.
* Add options for controlling audio track selections to `DefaultTrackSelector`
([#3314](https://github.com/google/ExoPlayer/issues/3314)).
* Do not retry failed loads whose error is `FileNotFoundException`. * Do not retry failed loads whose error is `FileNotFoundException`.
* Add convenience methods `Player.next`, `Player.previous`, `Player.hasNext` * Add convenience methods `Player.next`, `Player.previous`, `Player.hasNext`
and `Player.hasPrevious` and `Player.hasPrevious`

View File

@ -170,11 +170,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private int maxVideoFrameRate; private int maxVideoFrameRate;
private int maxVideoBitrate; private int maxVideoBitrate;
private boolean exceedVideoConstraintsIfNecessary; private boolean exceedVideoConstraintsIfNecessary;
private boolean allowVideoMixedMimeTypeAdaptiveness;
private boolean allowVideoNonSeamlessAdaptiveness;
private int viewportWidth; private int viewportWidth;
private int viewportHeight; private int viewportHeight;
private boolean viewportOrientationMayChange; private boolean viewportOrientationMayChange;
// Audio // Audio
@Nullable private String preferredAudioLanguage; @Nullable private String preferredAudioLanguage;
private int maxAudioChannelCount;
private int maxAudioBitrate;
private boolean exceedAudioConstraintsIfNecessary;
private boolean allowAudioMixedMimeTypeAdaptiveness;
private boolean allowAudioMixedSampleRateAdaptiveness;
// Text // Text
@Nullable private String preferredTextLanguage; @Nullable private String preferredTextLanguage;
private boolean selectUndeterminedTextLanguage; private boolean selectUndeterminedTextLanguage;
@ -182,8 +189,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
private boolean forceLowestBitrate; private boolean forceLowestBitrate;
private boolean forceHighestSupportedBitrate; private boolean forceHighestSupportedBitrate;
private boolean allowMixedMimeAdaptiveness;
private boolean allowNonSeamlessAdaptiveness;
private boolean exceedRendererCapabilitiesIfNecessary; private boolean exceedRendererCapabilitiesIfNecessary;
private int tunnelingAudioSessionId; private int tunnelingAudioSessionId;
@ -203,11 +208,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoFrameRate = initialValues.maxVideoFrameRate; maxVideoFrameRate = initialValues.maxVideoFrameRate;
maxVideoBitrate = initialValues.maxVideoBitrate; maxVideoBitrate = initialValues.maxVideoBitrate;
exceedVideoConstraintsIfNecessary = initialValues.exceedVideoConstraintsIfNecessary; exceedVideoConstraintsIfNecessary = initialValues.exceedVideoConstraintsIfNecessary;
allowVideoMixedMimeTypeAdaptiveness = initialValues.allowVideoMixedMimeTypeAdaptiveness;
allowVideoNonSeamlessAdaptiveness = initialValues.allowVideoNonSeamlessAdaptiveness;
viewportWidth = initialValues.viewportWidth; viewportWidth = initialValues.viewportWidth;
viewportHeight = initialValues.viewportHeight; viewportHeight = initialValues.viewportHeight;
viewportOrientationMayChange = initialValues.viewportOrientationMayChange; viewportOrientationMayChange = initialValues.viewportOrientationMayChange;
// Audio // Audio
preferredAudioLanguage = initialValues.preferredAudioLanguage; preferredAudioLanguage = initialValues.preferredAudioLanguage;
maxAudioChannelCount = initialValues.maxAudioChannelCount;
maxAudioBitrate = initialValues.maxAudioBitrate;
exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary;
allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness;
allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness;
// Text // Text
preferredTextLanguage = initialValues.preferredTextLanguage; preferredTextLanguage = initialValues.preferredTextLanguage;
selectUndeterminedTextLanguage = initialValues.selectUndeterminedTextLanguage; selectUndeterminedTextLanguage = initialValues.selectUndeterminedTextLanguage;
@ -215,8 +227,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
forceLowestBitrate = initialValues.forceLowestBitrate; forceLowestBitrate = initialValues.forceLowestBitrate;
forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate; forceHighestSupportedBitrate = initialValues.forceHighestSupportedBitrate;
allowMixedMimeAdaptiveness = initialValues.allowMixedMimeAdaptiveness;
allowNonSeamlessAdaptiveness = initialValues.allowNonSeamlessAdaptiveness;
exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary; exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary;
tunnelingAudioSessionId = initialValues.tunnelingAudioSessionId; tunnelingAudioSessionId = initialValues.tunnelingAudioSessionId;
// Overrides // Overrides
@ -286,6 +296,28 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
/**
* See {@link Parameters#allowVideoMixedMimeTypeAdaptiveness}.
*
* @return This builder.
*/
public ParametersBuilder setAllowVideoMixedMimeTypeAdaptiveness(
boolean allowVideoMixedMimeTypeAdaptiveness) {
this.allowVideoMixedMimeTypeAdaptiveness = allowVideoMixedMimeTypeAdaptiveness;
return this;
}
/**
* See {@link Parameters#allowVideoNonSeamlessAdaptiveness}.
*
* @return This builder.
*/
public ParametersBuilder setAllowVideoNonSeamlessAdaptiveness(
boolean allowVideoNonSeamlessAdaptiveness) {
this.allowVideoNonSeamlessAdaptiveness = allowVideoNonSeamlessAdaptiveness;
return this;
}
/** /**
* Equivalent to calling {@link #setViewportSize(int, int, boolean)} with the viewport size * Equivalent to calling {@link #setViewportSize(int, int, boolean)} with the viewport size
* obtained from {@link Util#getPhysicalDisplaySize(Context)}. * obtained from {@link Util#getPhysicalDisplaySize(Context)}.
@ -340,6 +372,59 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
/**
* See {@link Parameters#maxAudioChannelCount}.
*
* @return This builder.
*/
public ParametersBuilder setMaxAudioChannelCount(int maxAudioChannelCount) {
this.maxAudioChannelCount = maxAudioChannelCount;
return this;
}
/**
* See {@link Parameters#maxAudioBitrate}.
*
* @return This builder.
*/
public ParametersBuilder setMaxAudioBitrate(int maxAudioBitrate) {
this.maxAudioBitrate = maxAudioBitrate;
return this;
}
/**
* See {@link Parameters#exceedAudioConstraintsIfNecessary}.
*
* @return This builder.
*/
public ParametersBuilder setExceedAudioConstraintsIfNecessary(
boolean exceedAudioConstraintsIfNecessary) {
this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary;
return this;
}
/**
* See {@link Parameters#allowAudioMixedMimeTypeAdaptiveness}.
*
* @return This builder.
*/
public ParametersBuilder setAllowAudioMixedMimeTypeAdaptiveness(
boolean allowAudioMixedMimeTypeAdaptiveness) {
this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness;
return this;
}
/**
* See {@link Parameters#allowAudioMixedSampleRateAdaptiveness}.
*
* @return This builder.
*/
public ParametersBuilder setAllowAudioMixedSampleRateAdaptiveness(
boolean allowAudioMixedSampleRateAdaptiveness) {
this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness;
return this;
}
// Text // Text
/** /**
@ -397,23 +482,20 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* See {@link Parameters#allowMixedMimeAdaptiveness}. * @deprecated Use {@link #setAllowVideoMixedMimeTypeAdaptiveness(boolean)} and {@link
* * #setAllowAudioMixedMimeTypeAdaptiveness(boolean)}.
* @return This builder.
*/ */
@Deprecated
public ParametersBuilder setAllowMixedMimeAdaptiveness(boolean allowMixedMimeAdaptiveness) { public ParametersBuilder setAllowMixedMimeAdaptiveness(boolean allowMixedMimeAdaptiveness) {
this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness; setAllowAudioMixedMimeTypeAdaptiveness(allowMixedMimeAdaptiveness);
setAllowVideoMixedMimeTypeAdaptiveness(allowMixedMimeAdaptiveness);
return this; return this;
} }
/** /** @deprecated Use {@link #setAllowVideoNonSeamlessAdaptiveness(boolean)} */
* See {@link Parameters#allowNonSeamlessAdaptiveness}. @Deprecated
*
* @return This builder.
*/
public ParametersBuilder setAllowNonSeamlessAdaptiveness(boolean allowNonSeamlessAdaptiveness) { public ParametersBuilder setAllowNonSeamlessAdaptiveness(boolean allowNonSeamlessAdaptiveness) {
this.allowNonSeamlessAdaptiveness = allowNonSeamlessAdaptiveness; return setAllowVideoNonSeamlessAdaptiveness(allowNonSeamlessAdaptiveness);
return this;
} }
/** /**
@ -563,11 +645,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
maxVideoFrameRate, maxVideoFrameRate,
maxVideoBitrate, maxVideoBitrate,
exceedVideoConstraintsIfNecessary, exceedVideoConstraintsIfNecessary,
allowVideoMixedMimeTypeAdaptiveness,
allowVideoNonSeamlessAdaptiveness,
viewportWidth, viewportWidth,
viewportHeight, viewportHeight,
viewportOrientationMayChange, viewportOrientationMayChange,
// Audio // Audio
preferredAudioLanguage, preferredAudioLanguage,
maxAudioChannelCount,
maxAudioBitrate,
exceedAudioConstraintsIfNecessary,
allowAudioMixedMimeTypeAdaptiveness,
allowAudioMixedSampleRateAdaptiveness,
// Text // Text
preferredTextLanguage, preferredTextLanguage,
selectUndeterminedTextLanguage, selectUndeterminedTextLanguage,
@ -575,8 +664,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
forceLowestBitrate, forceLowestBitrate,
forceHighestSupportedBitrate, forceHighestSupportedBitrate,
allowMixedMimeAdaptiveness,
allowNonSeamlessAdaptiveness,
exceedRendererCapabilitiesIfNecessary, exceedRendererCapabilitiesIfNecessary,
tunnelingAudioSessionId, tunnelingAudioSessionId,
// Overrides // Overrides
@ -638,6 +725,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* {@code true}. * {@code true}.
*/ */
public final boolean exceedVideoConstraintsIfNecessary; public final boolean exceedVideoConstraintsIfNecessary;
/**
* Whether to allow adaptive video selections containing mixed mime types. Adaptations between
* different mime types may not be completely seamless, in which case {@link
* #allowVideoNonSeamlessAdaptiveness} also needs to be {@code true} for mixed mime type
* selections to be made. The default value is {@code false}.
*/
public final boolean allowVideoMixedMimeTypeAdaptiveness;
/**
* Whether to allow adaptive video selections where adaptation may not be completely seamless.
* The default value is {@code true}.
*/
public final boolean allowVideoNonSeamlessAdaptiveness;
/** /**
* Viewport width in pixels. Constrains video track selections for adaptive content so that only * Viewport width in pixels. Constrains video track selections for adaptive content so that only
* tracks suitable for the viewport are selected. The default value is {@link Integer#MAX_VALUE} * tracks suitable for the viewport are selected. The default value is {@link Integer#MAX_VALUE}
@ -664,6 +763,30 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* {@code null}. * {@code null}.
*/ */
@Nullable public final String preferredAudioLanguage; @Nullable public final String preferredAudioLanguage;
/**
* Maximum allowed audio channel count. The default value is {@link Integer#MAX_VALUE} (i.e. no
* constraint).
*/
public final int maxAudioChannelCount;
/**
* Maximum audio bitrate. The default value is {@link Integer#MAX_VALUE} (i.e. no constraint).
*/
public final int maxAudioBitrate;
/**
* Whether to exceed the {@link #maxAudioChannelCount} and {@link #maxAudioBitrate} constraints
* when no selection can be made otherwise. The default value is {@code true}.
*/
public final boolean exceedAudioConstraintsIfNecessary;
/**
* Whether to allow adaptive audio selections containing mixed mime types. Adaptations between
* different mime types may not be completely seamless. The default value is {@code false}.
*/
public final boolean allowAudioMixedMimeTypeAdaptiveness;
/**
* Whether to allow adaptive audio selections containing mixed sample rates. Adaptations between
* different sample rates may not be completely seamless. The default value is {@code false}.
*/
public final boolean allowAudioMixedSampleRateAdaptiveness;
// Text // Text
/** /**
@ -695,15 +818,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public final boolean forceHighestSupportedBitrate; public final boolean forceHighestSupportedBitrate;
/** /**
* Whether to allow adaptive selections containing mixed mime types. The default value is {@code * @deprecated Use {@link #allowVideoMixedMimeTypeAdaptiveness} and {@link
* false}. * #allowAudioMixedMimeTypeAdaptiveness}.
*/ */
public final boolean allowMixedMimeAdaptiveness; @Deprecated public final boolean allowMixedMimeAdaptiveness;
/** /** @deprecated Use {@link #allowVideoNonSeamlessAdaptiveness}. */
* Whether to allow adaptive selections where adaptation may not be completely seamless. The @Deprecated public final boolean allowNonSeamlessAdaptiveness;
* default value is {@code true}.
*/
public final boolean allowNonSeamlessAdaptiveness;
/** /**
* Whether to exceed renderer capabilities when no selection can be made otherwise. * Whether to exceed renderer capabilities when no selection can be made otherwise.
* *
@ -729,11 +849,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
/* maxVideoFrameRate= */ Integer.MAX_VALUE, /* maxVideoFrameRate= */ Integer.MAX_VALUE,
/* maxVideoBitrate= */ Integer.MAX_VALUE, /* maxVideoBitrate= */ Integer.MAX_VALUE,
/* exceedVideoConstraintsIfNecessary= */ true, /* exceedVideoConstraintsIfNecessary= */ true,
/* allowVideoMixedMimeTypeAdaptiveness= */ false,
/* allowVideoNonSeamlessAdaptiveness= */ true,
/* viewportWidth= */ Integer.MAX_VALUE, /* viewportWidth= */ Integer.MAX_VALUE,
/* viewportHeight= */ Integer.MAX_VALUE, /* viewportHeight= */ Integer.MAX_VALUE,
/* viewportOrientationMayChange= */ true, /* viewportOrientationMayChange= */ true,
// Audio // Audio
/* preferredAudioLanguage= */ null, /* preferredAudioLanguage= */ null,
/* maxAudioChannelCount= */ Integer.MAX_VALUE,
/* maxAudioBitrate= */ Integer.MAX_VALUE,
/* exceedAudioConstraintsIfNecessary= */ true,
/* allowAudioMixedMimeTypeAdaptiveness= */ false,
/* allowAudioMixedSampleRateAdaptiveness= */ false,
// Text // Text
/* preferredTextLanguage= */ null, /* preferredTextLanguage= */ null,
/* selectUndeterminedTextLanguage= */ false, /* selectUndeterminedTextLanguage= */ false,
@ -741,8 +868,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
/* forceLowestBitrate= */ false, /* forceLowestBitrate= */ false,
/* forceHighestSupportedBitrate= */ false, /* forceHighestSupportedBitrate= */ false,
/* allowMixedMimeAdaptiveness= */ false,
/* allowNonSeamlessAdaptiveness= */ true,
/* exceedRendererCapabilitiesIfNecessary= */ true, /* exceedRendererCapabilitiesIfNecessary= */ true,
/* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET, /* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET,
// Overrides // Overrides
@ -757,11 +882,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int maxVideoFrameRate, int maxVideoFrameRate,
int maxVideoBitrate, int maxVideoBitrate,
boolean exceedVideoConstraintsIfNecessary, boolean exceedVideoConstraintsIfNecessary,
boolean allowVideoMixedMimeTypeAdaptiveness,
boolean allowVideoNonSeamlessAdaptiveness,
int viewportWidth, int viewportWidth,
int viewportHeight, int viewportHeight,
boolean viewportOrientationMayChange, boolean viewportOrientationMayChange,
// Audio // Audio
@Nullable String preferredAudioLanguage, @Nullable String preferredAudioLanguage,
int maxAudioChannelCount,
int maxAudioBitrate,
boolean exceedAudioConstraintsIfNecessary,
boolean allowAudioMixedMimeTypeAdaptiveness,
boolean allowAudioMixedSampleRateAdaptiveness,
// Text // Text
@Nullable String preferredTextLanguage, @Nullable String preferredTextLanguage,
boolean selectUndeterminedTextLanguage, boolean selectUndeterminedTextLanguage,
@ -769,8 +901,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
boolean forceLowestBitrate, boolean forceLowestBitrate,
boolean forceHighestSupportedBitrate, boolean forceHighestSupportedBitrate,
boolean allowMixedMimeAdaptiveness,
boolean allowNonSeamlessAdaptiveness,
boolean exceedRendererCapabilitiesIfNecessary, boolean exceedRendererCapabilitiesIfNecessary,
int tunnelingAudioSessionId, int tunnelingAudioSessionId,
// Overrides // Overrides
@ -782,11 +912,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.maxVideoFrameRate = maxVideoFrameRate; this.maxVideoFrameRate = maxVideoFrameRate;
this.maxVideoBitrate = maxVideoBitrate; this.maxVideoBitrate = maxVideoBitrate;
this.exceedVideoConstraintsIfNecessary = exceedVideoConstraintsIfNecessary; this.exceedVideoConstraintsIfNecessary = exceedVideoConstraintsIfNecessary;
this.allowVideoMixedMimeTypeAdaptiveness = allowVideoMixedMimeTypeAdaptiveness;
this.allowVideoNonSeamlessAdaptiveness = allowVideoNonSeamlessAdaptiveness;
this.viewportWidth = viewportWidth; this.viewportWidth = viewportWidth;
this.viewportHeight = viewportHeight; this.viewportHeight = viewportHeight;
this.viewportOrientationMayChange = viewportOrientationMayChange; this.viewportOrientationMayChange = viewportOrientationMayChange;
// Audio // Audio
this.preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage); this.preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage);
this.maxAudioChannelCount = maxAudioChannelCount;
this.maxAudioBitrate = maxAudioBitrate;
this.exceedAudioConstraintsIfNecessary = exceedAudioConstraintsIfNecessary;
this.allowAudioMixedMimeTypeAdaptiveness = allowAudioMixedMimeTypeAdaptiveness;
this.allowAudioMixedSampleRateAdaptiveness = allowAudioMixedSampleRateAdaptiveness;
// Text // Text
this.preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage); this.preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage);
this.selectUndeterminedTextLanguage = selectUndeterminedTextLanguage; this.selectUndeterminedTextLanguage = selectUndeterminedTextLanguage;
@ -794,13 +931,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
this.forceLowestBitrate = forceLowestBitrate; this.forceLowestBitrate = forceLowestBitrate;
this.forceHighestSupportedBitrate = forceHighestSupportedBitrate; this.forceHighestSupportedBitrate = forceHighestSupportedBitrate;
this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness;
this.allowNonSeamlessAdaptiveness = allowNonSeamlessAdaptiveness;
this.exceedRendererCapabilitiesIfNecessary = exceedRendererCapabilitiesIfNecessary; this.exceedRendererCapabilitiesIfNecessary = exceedRendererCapabilitiesIfNecessary;
this.tunnelingAudioSessionId = tunnelingAudioSessionId; this.tunnelingAudioSessionId = tunnelingAudioSessionId;
// Overrides // Overrides
this.selectionOverrides = selectionOverrides; this.selectionOverrides = selectionOverrides;
this.rendererDisabledFlags = rendererDisabledFlags; this.rendererDisabledFlags = rendererDisabledFlags;
// Deprecated fields.
this.allowMixedMimeAdaptiveness = allowVideoMixedMimeTypeAdaptiveness;
this.allowNonSeamlessAdaptiveness = allowVideoNonSeamlessAdaptiveness;
} }
/* package */ Parameters(Parcel in) { /* package */ Parameters(Parcel in) {
@ -810,11 +948,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.maxVideoFrameRate = in.readInt(); this.maxVideoFrameRate = in.readInt();
this.maxVideoBitrate = in.readInt(); this.maxVideoBitrate = in.readInt();
this.exceedVideoConstraintsIfNecessary = Util.readBoolean(in); this.exceedVideoConstraintsIfNecessary = Util.readBoolean(in);
this.allowVideoMixedMimeTypeAdaptiveness = Util.readBoolean(in);
this.allowVideoNonSeamlessAdaptiveness = Util.readBoolean(in);
this.viewportWidth = in.readInt(); this.viewportWidth = in.readInt();
this.viewportHeight = in.readInt(); this.viewportHeight = in.readInt();
this.viewportOrientationMayChange = Util.readBoolean(in); this.viewportOrientationMayChange = Util.readBoolean(in);
// Audio // Audio
this.preferredAudioLanguage = in.readString(); this.preferredAudioLanguage = in.readString();
this.maxAudioChannelCount = in.readInt();
this.maxAudioBitrate = in.readInt();
this.exceedAudioConstraintsIfNecessary = Util.readBoolean(in);
this.allowAudioMixedMimeTypeAdaptiveness = Util.readBoolean(in);
this.allowAudioMixedSampleRateAdaptiveness = Util.readBoolean(in);
// Text // Text
this.preferredTextLanguage = in.readString(); this.preferredTextLanguage = in.readString();
this.selectUndeterminedTextLanguage = Util.readBoolean(in); this.selectUndeterminedTextLanguage = Util.readBoolean(in);
@ -822,13 +967,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
this.forceLowestBitrate = Util.readBoolean(in); this.forceLowestBitrate = Util.readBoolean(in);
this.forceHighestSupportedBitrate = Util.readBoolean(in); this.forceHighestSupportedBitrate = Util.readBoolean(in);
this.allowMixedMimeAdaptiveness = Util.readBoolean(in);
this.allowNonSeamlessAdaptiveness = Util.readBoolean(in);
this.exceedRendererCapabilitiesIfNecessary = Util.readBoolean(in); this.exceedRendererCapabilitiesIfNecessary = Util.readBoolean(in);
this.tunnelingAudioSessionId = in.readInt(); this.tunnelingAudioSessionId = in.readInt();
// Overrides // Overrides
this.selectionOverrides = readSelectionOverrides(in); this.selectionOverrides = readSelectionOverrides(in);
this.rendererDisabledFlags = in.readSparseBooleanArray(); this.rendererDisabledFlags = in.readSparseBooleanArray();
// Deprecated fields.
this.allowMixedMimeAdaptiveness = allowVideoMixedMimeTypeAdaptiveness;
this.allowNonSeamlessAdaptiveness = allowVideoNonSeamlessAdaptiveness;
} }
/** /**
@ -887,11 +1033,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& maxVideoFrameRate == other.maxVideoFrameRate && maxVideoFrameRate == other.maxVideoFrameRate
&& maxVideoBitrate == other.maxVideoBitrate && maxVideoBitrate == other.maxVideoBitrate
&& exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary && exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary
&& allowVideoMixedMimeTypeAdaptiveness == other.allowVideoMixedMimeTypeAdaptiveness
&& allowVideoNonSeamlessAdaptiveness == other.allowVideoNonSeamlessAdaptiveness
&& viewportOrientationMayChange == other.viewportOrientationMayChange && viewportOrientationMayChange == other.viewportOrientationMayChange
&& viewportWidth == other.viewportWidth && viewportWidth == other.viewportWidth
&& viewportHeight == other.viewportHeight && viewportHeight == other.viewportHeight
// Audio // Audio
&& TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage) && TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage)
&& maxAudioChannelCount == other.maxAudioChannelCount
&& maxAudioBitrate == other.maxAudioBitrate
&& exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary
&& allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness
&& allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness
// Text // Text
&& TextUtils.equals(preferredTextLanguage, other.preferredTextLanguage) && TextUtils.equals(preferredTextLanguage, other.preferredTextLanguage)
&& selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage && selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage
@ -899,8 +1052,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
&& forceLowestBitrate == other.forceLowestBitrate && forceLowestBitrate == other.forceLowestBitrate
&& forceHighestSupportedBitrate == other.forceHighestSupportedBitrate && forceHighestSupportedBitrate == other.forceHighestSupportedBitrate
&& allowMixedMimeAdaptiveness == other.allowMixedMimeAdaptiveness
&& allowNonSeamlessAdaptiveness == other.allowNonSeamlessAdaptiveness
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary && exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
&& tunnelingAudioSessionId == other.tunnelingAudioSessionId && tunnelingAudioSessionId == other.tunnelingAudioSessionId
// Overrides // Overrides
@ -917,12 +1068,19 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + maxVideoFrameRate; result = 31 * result + maxVideoFrameRate;
result = 31 * result + maxVideoBitrate; result = 31 * result + maxVideoBitrate;
result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0); result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (allowVideoMixedMimeTypeAdaptiveness ? 1 : 0);
result = 31 * result + (allowVideoNonSeamlessAdaptiveness ? 1 : 0);
result = 31 * result + (viewportOrientationMayChange ? 1 : 0); result = 31 * result + (viewportOrientationMayChange ? 1 : 0);
result = 31 * result + viewportWidth; result = 31 * result + viewportWidth;
result = 31 * result + viewportHeight; result = 31 * result + viewportHeight;
// Audio // Audio
result = result =
31 * result + (preferredAudioLanguage == null ? 0 : preferredAudioLanguage.hashCode()); 31 * result + (preferredAudioLanguage == null ? 0 : preferredAudioLanguage.hashCode());
result = 31 * result + maxAudioChannelCount;
result = 31 * result + maxAudioBitrate;
result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0);
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
// Text // Text
result = 31 * result + (preferredTextLanguage == null ? 0 : preferredTextLanguage.hashCode()); result = 31 * result + (preferredTextLanguage == null ? 0 : preferredTextLanguage.hashCode());
result = 31 * result + (selectUndeterminedTextLanguage ? 1 : 0); result = 31 * result + (selectUndeterminedTextLanguage ? 1 : 0);
@ -930,8 +1088,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
result = 31 * result + (forceLowestBitrate ? 1 : 0); result = 31 * result + (forceLowestBitrate ? 1 : 0);
result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0); result = 31 * result + (forceHighestSupportedBitrate ? 1 : 0);
result = 31 * result + (allowMixedMimeAdaptiveness ? 1 : 0);
result = 31 * result + (allowNonSeamlessAdaptiveness ? 1 : 0);
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0); result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
result = 31 * result + tunnelingAudioSessionId; result = 31 * result + tunnelingAudioSessionId;
// Overrides (omitted from hashCode). // Overrides (omitted from hashCode).
@ -953,11 +1109,18 @@ public class DefaultTrackSelector extends MappingTrackSelector {
dest.writeInt(maxVideoFrameRate); dest.writeInt(maxVideoFrameRate);
dest.writeInt(maxVideoBitrate); dest.writeInt(maxVideoBitrate);
Util.writeBoolean(dest, exceedVideoConstraintsIfNecessary); Util.writeBoolean(dest, exceedVideoConstraintsIfNecessary);
Util.writeBoolean(dest, allowVideoMixedMimeTypeAdaptiveness);
Util.writeBoolean(dest, allowVideoNonSeamlessAdaptiveness);
dest.writeInt(viewportWidth); dest.writeInt(viewportWidth);
dest.writeInt(viewportHeight); dest.writeInt(viewportHeight);
Util.writeBoolean(dest, viewportOrientationMayChange); Util.writeBoolean(dest, viewportOrientationMayChange);
// Audio // Audio
dest.writeString(preferredAudioLanguage); dest.writeString(preferredAudioLanguage);
dest.writeInt(maxAudioChannelCount);
dest.writeInt(maxAudioBitrate);
Util.writeBoolean(dest, exceedAudioConstraintsIfNecessary);
Util.writeBoolean(dest, allowAudioMixedMimeTypeAdaptiveness);
Util.writeBoolean(dest, allowAudioMixedSampleRateAdaptiveness);
// Text // Text
dest.writeString(preferredTextLanguage); dest.writeString(preferredTextLanguage);
Util.writeBoolean(dest, selectUndeterminedTextLanguage); Util.writeBoolean(dest, selectUndeterminedTextLanguage);
@ -965,8 +1128,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General // General
Util.writeBoolean(dest, forceLowestBitrate); Util.writeBoolean(dest, forceLowestBitrate);
Util.writeBoolean(dest, forceHighestSupportedBitrate); Util.writeBoolean(dest, forceHighestSupportedBitrate);
Util.writeBoolean(dest, allowMixedMimeAdaptiveness);
Util.writeBoolean(dest, allowNonSeamlessAdaptiveness);
Util.writeBoolean(dest, exceedRendererCapabilitiesIfNecessary); Util.writeBoolean(dest, exceedRendererCapabilitiesIfNecessary);
dest.writeInt(tunnelingAudioSessionId); dest.writeInt(tunnelingAudioSessionId);
// Overrides // Overrides
@ -1322,11 +1483,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
rendererTrackGroups.get(override.groupIndex), override.tracks[0]); rendererTrackGroups.get(override.groupIndex), override.tracks[0]);
} else { } else {
rendererTrackSelections[i] = rendererTrackSelections[i] =
Assertions.checkNotNull(adaptiveTrackSelectionFactory) adaptiveTrackSelectionFactory.createTrackSelection(
.createTrackSelection( rendererTrackGroups.get(override.groupIndex),
rendererTrackGroups.get(override.groupIndex), getBandwidthMeter(),
getBandwidthMeter(), override.tracks);
override.tracks);
} }
} }
} }
@ -1508,11 +1668,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
TrackSelection.Factory adaptiveTrackSelectionFactory, TrackSelection.Factory adaptiveTrackSelectionFactory,
BandwidthMeter bandwidthMeter) BandwidthMeter bandwidthMeter)
throws ExoPlaybackException { throws ExoPlaybackException {
int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness int requiredAdaptiveSupport =
? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS) params.allowVideoNonSeamlessAdaptiveness
: RendererCapabilities.ADAPTIVE_SEAMLESS; ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS)
: RendererCapabilities.ADAPTIVE_SEAMLESS;
boolean allowMixedMimeTypes = boolean allowMixedMimeTypes =
params.allowMixedMimeAdaptiveness params.allowVideoMixedMimeTypeAdaptiveness
&& (mixedMimeTypeAdaptationSupports & requiredAdaptiveSupport) != 0; && (mixedMimeTypeAdaptationSupports & requiredAdaptiveSupport) != 0;
for (int i = 0; i < groups.length; i++) { for (int i = 0; i < groups.length; i++) {
TrackGroup group = groups.get(i); TrackGroup group = groups.get(i);
@ -1530,8 +1691,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
params.viewportHeight, params.viewportHeight,
params.viewportOrientationMayChange); params.viewportOrientationMayChange);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
return Assertions.checkNotNull(adaptiveTrackSelectionFactory) return adaptiveTrackSelectionFactory.createTrackSelection(
.createTrackSelection(group, bandwidthMeter, adaptiveTracks); group, bandwidthMeter, adaptiveTracks);
} }
} }
return null; return null;
@ -1758,6 +1919,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* selection was made. * selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks. * @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/ */
@SuppressWarnings("unused")
protected @Nullable Pair<TrackSelection, AudioTrackScore> selectAudioTrack( protected @Nullable Pair<TrackSelection, AudioTrackScore> selectAudioTrack(
TrackGroupArray groups, TrackGroupArray groups,
int[][] formatSupports, int[][] formatSupports,
@ -1777,6 +1939,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
Format format = trackGroup.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
AudioTrackScore trackScore = AudioTrackScore trackScore =
new AudioTrackScore(format, params, trackFormatSupport[trackIndex]); new AudioTrackScore(format, params, trackFormatSupport[trackIndex]);
if (!trackScore.isWithinConstraints && !params.exceedAudioConstraintsIfNecessary) {
// Track should not be selected.
continue;
}
if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) { if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) {
selectedGroupIndex = groupIndex; selectedGroupIndex = groupIndex;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
@ -1799,7 +1965,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// 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 = int[] adaptiveTracks =
getAdaptiveAudioTracks( getAdaptiveAudioTracks(
selectedGroup, formatSupports[selectedGroupIndex], params.allowMixedMimeAdaptiveness); selectedGroup,
formatSupports[selectedGroupIndex],
params.allowAudioMixedMimeTypeAdaptiveness,
params.allowAudioMixedSampleRateAdaptiveness);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
selection = selection =
adaptiveTrackSelectionFactory.createTrackSelection( adaptiveTrackSelectionFactory.createTrackSelection(
@ -1814,18 +1983,27 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return Pair.create(selection, Assertions.checkNotNull(selectedTrackScore)); return Pair.create(selection, Assertions.checkNotNull(selectedTrackScore));
} }
private static int[] getAdaptiveAudioTracks(TrackGroup group, int[] formatSupport, private static int[] getAdaptiveAudioTracks(
boolean allowMixedMimeTypes) { TrackGroup group,
int[] formatSupport,
boolean allowMixedMimeTypeAdaptiveness,
boolean allowMixedSampleRateAdaptiveness) {
int selectedConfigurationTrackCount = 0; int selectedConfigurationTrackCount = 0;
AudioConfigurationTuple selectedConfiguration = null; AudioConfigurationTuple selectedConfiguration = null;
HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>(); HashSet<AudioConfigurationTuple> seenConfigurationTuples = new HashSet<>();
for (int i = 0; i < group.length; i++) { for (int i = 0; i < group.length; i++) {
Format format = group.getFormat(i); Format format = group.getFormat(i);
AudioConfigurationTuple configuration = new AudioConfigurationTuple( AudioConfigurationTuple configuration =
format.channelCount, format.sampleRate, new AudioConfigurationTuple(
allowMixedMimeTypes ? null : format.sampleMimeType); format.channelCount, format.sampleRate, format.sampleMimeType);
if (seenConfigurationTuples.add(configuration)) { if (seenConfigurationTuples.add(configuration)) {
int configurationCount = getAdaptiveAudioTrackCount(group, formatSupport, configuration); int configurationCount =
getAdaptiveAudioTrackCount(
group,
formatSupport,
configuration,
allowMixedMimeTypeAdaptiveness,
allowMixedSampleRateAdaptiveness);
if (configurationCount > selectedConfigurationTrackCount) { if (configurationCount > selectedConfigurationTrackCount) {
selectedConfiguration = configuration; selectedConfiguration = configuration;
selectedConfigurationTrackCount = configurationCount; selectedConfigurationTrackCount = configurationCount;
@ -1838,7 +2016,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int index = 0; int index = 0;
for (int i = 0; i < group.length; i++) { for (int i = 0; i < group.length; i++) {
if (isSupportedAdaptiveAudioTrack( if (isSupportedAdaptiveAudioTrack(
group.getFormat(i), formatSupport[i], Assertions.checkNotNull(selectedConfiguration))) { group.getFormat(i),
formatSupport[i],
Assertions.checkNotNull(selectedConfiguration),
allowMixedMimeTypeAdaptiveness,
allowMixedSampleRateAdaptiveness)) {
adaptiveIndices[index++] = i; adaptiveIndices[index++] = i;
} }
} }
@ -1847,23 +2029,41 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return NO_TRACKS; return NO_TRACKS;
} }
private static int getAdaptiveAudioTrackCount(TrackGroup group, int[] formatSupport, private static int getAdaptiveAudioTrackCount(
AudioConfigurationTuple configuration) { TrackGroup group,
int[] formatSupport,
AudioConfigurationTuple configuration,
boolean allowMixedMimeTypeAdaptiveness,
boolean allowMixedSampleRateAdaptiveness) {
int count = 0; int count = 0;
for (int i = 0; i < group.length; i++) { for (int i = 0; i < group.length; i++) {
if (isSupportedAdaptiveAudioTrack(group.getFormat(i), formatSupport[i], configuration)) { if (isSupportedAdaptiveAudioTrack(
group.getFormat(i),
formatSupport[i],
configuration,
allowMixedMimeTypeAdaptiveness,
allowMixedSampleRateAdaptiveness)) {
count++; count++;
} }
} }
return count; return count;
} }
private static boolean isSupportedAdaptiveAudioTrack(Format format, int formatSupport, private static boolean isSupportedAdaptiveAudioTrack(
AudioConfigurationTuple configuration) { Format format,
return isSupported(formatSupport, false) && format.channelCount == configuration.channelCount int formatSupport,
&& format.sampleRate == configuration.sampleRate AudioConfigurationTuple configuration,
&& (configuration.mimeType == null boolean allowMixedMimeTypeAdaptiveness,
|| TextUtils.equals(configuration.mimeType, format.sampleMimeType)); boolean allowMixedSampleRateAdaptiveness) {
return isSupported(formatSupport, false)
&& (format.channelCount != Format.NO_VALUE
&& format.channelCount == configuration.channelCount)
&& (allowMixedMimeTypeAdaptiveness
|| (format.sampleMimeType != null
&& TextUtils.equals(format.sampleMimeType, configuration.mimeType)))
&& (allowMixedSampleRateAdaptiveness
|| (format.sampleRate != Format.NO_VALUE
&& format.sampleRate == configuration.sampleRate));
} }
// Text track selection implementation. // Text track selection implementation.
@ -2202,6 +2402,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
/** Represents how well an audio track matches the selection {@link Parameters}. */ /** Represents how well an audio track matches the selection {@link Parameters}. */
protected static final class AudioTrackScore implements Comparable<AudioTrackScore> { protected static final class AudioTrackScore implements Comparable<AudioTrackScore> {
public final boolean isWithinConstraints;
private final Parameters parameters; private final Parameters parameters;
private final int withinRendererCapabilitiesScore; private final int withinRendererCapabilitiesScore;
private final int matchLanguageScore; private final int matchLanguageScore;
@ -2218,6 +2420,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
channelCount = format.channelCount; channelCount = format.channelCount;
sampleRate = format.sampleRate; sampleRate = format.sampleRate;
bitrate = format.bitrate; bitrate = format.bitrate;
isWithinConstraints =
(format.bitrate == Format.NO_VALUE || format.bitrate <= parameters.maxAudioBitrate)
&& (format.channelCount == Format.NO_VALUE
|| format.channelCount <= parameters.maxAudioChannelCount);
} }
/** /**
@ -2236,6 +2442,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (this.matchLanguageScore != other.matchLanguageScore) { if (this.matchLanguageScore != other.matchLanguageScore) {
return compareInts(this.matchLanguageScore, other.matchLanguageScore); return compareInts(this.matchLanguageScore, other.matchLanguageScore);
} }
if (this.isWithinConstraints != other.isWithinConstraints) {
return this.isWithinConstraints ? 1 : -1;
}
if (parameters.forceLowestBitrate) { if (parameters.forceLowestBitrate) {
int bitrateComparison = compareFormatValues(bitrate, other.bitrate); int bitrateComparison = compareFormatValues(bitrate, other.bitrate);
if (bitrateComparison != 0) { if (bitrateComparison != 0) {
@ -2245,9 +2454,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (this.defaultSelectionFlagScore != other.defaultSelectionFlagScore) { if (this.defaultSelectionFlagScore != other.defaultSelectionFlagScore) {
return compareInts(this.defaultSelectionFlagScore, other.defaultSelectionFlagScore); return compareInts(this.defaultSelectionFlagScore, other.defaultSelectionFlagScore);
} }
// If the formats are within renderer capabilities then prefer higher values of channel count, // If the formats are within constraints and renderer capabilities then prefer higher values
// sample rate and bit rate in that order. Otherwise, prefer lower values. // of channel count, sample rate and bit rate in that order. Otherwise, prefer lower values.
int resultSign = withinRendererCapabilitiesScore == 1 ? 1 : -1; int resultSign = isWithinConstraints && withinRendererCapabilitiesScore == 1 ? 1 : -1;
if (this.channelCount != other.channelCount) { if (this.channelCount != other.channelCount) {
return resultSign * compareInts(this.channelCount, other.channelCount); return resultSign * compareInts(this.channelCount, other.channelCount);
} }

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.trackselection; package com.google.android.exoplayer2.trackselection;
import static com.google.android.exoplayer2.RendererCapabilities.ADAPTIVE_NOT_SEAMLESS;
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES; import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES;
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED; import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED;
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE; import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE;
@ -132,21 +133,26 @@ public final class DefaultTrackSelectorTest {
/* maxVideoFrameRate= */ 2, /* maxVideoFrameRate= */ 2,
/* maxVideoBitrate= */ 3, /* maxVideoBitrate= */ 3,
/* exceedVideoConstraintsIfNecessary= */ false, /* exceedVideoConstraintsIfNecessary= */ false,
/* allowVideoMixedMimeTypeAdaptiveness= */ true,
/* allowVideoNonSeamlessAdaptiveness= */ false,
/* viewportWidth= */ 4, /* viewportWidth= */ 4,
/* viewportHeight= */ 5, /* viewportHeight= */ 5,
/* viewportOrientationMayChange= */ true, /* viewportOrientationMayChange= */ true,
// Audio // Audio
/* preferredAudioLanguage= */ "en", /* preferredAudioLanguage= */ "en",
/* maxAudioChannelCount= */ 6,
/* maxAudioBitrate= */ 7,
/* exceedAudioConstraintsIfNecessary= */ false,
/* allowAudioMixedMimeTypeAdaptiveness= */ true,
/* allowAudioMixedSampleRateAdaptiveness= */ false,
// Text // Text
/* preferredTextLanguage= */ "de", /* preferredTextLanguage= */ "de",
/* selectUndeterminedTextLanguage= */ false, /* selectUndeterminedTextLanguage= */ true,
/* disabledTextTrackSelectionFlags= */ 6, /* disabledTextTrackSelectionFlags= */ 8,
// General // General
/* forceLowestBitrate= */ true, /* forceLowestBitrate= */ false,
/* forceHighestSupportedBitrate= */ false, /* forceHighestSupportedBitrate= */ true,
/* allowMixedMimeAdaptiveness= */ true, /* exceedRendererCapabilitiesIfNecessary= */ false,
/* allowNonSeamlessAdaptiveness= */ false,
/* exceedRendererCapabilitiesIfNecessary= */ true,
/* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET, /* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET,
// Overrides // Overrides
selectionOverrides, selectionOverrides,
@ -1090,6 +1096,137 @@ public final class DefaultTrackSelectorTest {
assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1); assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1);
} }
@Test
public void testSelectTracksWithMultipleAudioTracksWithMixedSampleRates() throws Exception {
Format highSampleRateAudioFormat =
buildAudioFormatWithSampleRate("44100", /* sampleRate= */ 44100);
Format lowSampleRateAudioFormat =
buildAudioFormatWithSampleRate("22050", /* sampleRate= */ 22050);
// Should not adapt between mixed sample rates by default, so we expect a fixed selection
// containing the higher sample rate stream.
TrackGroupArray trackGroups =
singleTrackGroup(highSampleRateAudioFormat, lowSampleRateAudioFormat);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, highSampleRateAudioFormat);
// The same applies if the tracks are provided in the opposite order.
trackGroups = singleTrackGroup(lowSampleRateAudioFormat, highSampleRateAudioFormat);
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, highSampleRateAudioFormat);
// If we explicitly enable mixed sample rate adaptiveness, expect an adaptive selection.
trackSelector.setParameters(
Parameters.DEFAULT.buildUpon().setAllowAudioMixedSampleRateAdaptiveness(true));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1);
}
@Test
public void testSelectTracksWithMultipleAudioTracksWithMixedMimeTypes() throws Exception {
Format aacAudioFormat = buildAudioFormatWithMimeType("aac", MimeTypes.AUDIO_AAC);
Format opusAudioFormat = buildAudioFormatWithMimeType("opus", MimeTypes.AUDIO_OPUS);
// Should not adapt between mixed mime types by default, so we expect a fixed selection
// containing the first stream.
TrackGroupArray trackGroups = singleTrackGroup(aacAudioFormat, opusAudioFormat);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, aacAudioFormat);
// The same applies if the tracks are provided in the opposite order.
trackGroups = singleTrackGroup(opusAudioFormat, aacAudioFormat);
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, opusAudioFormat);
// If we explicitly enable mixed mime type adaptiveness, expect an adaptive selection.
trackSelector.setParameters(
Parameters.DEFAULT.buildUpon().setAllowAudioMixedMimeTypeAdaptiveness(true));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1);
}
@Test
public void testSelectTracksWithMultipleAudioTracksWithMixedChannelCounts() throws Exception {
Format stereoAudioFormat =
buildAudioFormatWithChannelCount("2-channels", /* channelCount= */ 2);
Format surroundAudioFormat =
buildAudioFormatWithChannelCount("5-channels", /* channelCount= */ 5);
// Should not adapt between different channel counts, so we expect a fixed selection containing
// the track with more channels.
TrackGroupArray trackGroups = singleTrackGroup(stereoAudioFormat, surroundAudioFormat);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, surroundAudioFormat);
// The same applies if the tracks are provided in the opposite order.
trackGroups = singleTrackGroup(surroundAudioFormat, stereoAudioFormat);
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, surroundAudioFormat);
// If we constrain the channel count to 4 we expect a fixed selection containing the track with
// fewer channels.
trackSelector.setParameters(Parameters.DEFAULT.buildUpon().setMaxAudioChannelCount(4));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, stereoAudioFormat);
// If we constrain the channel count to 2 we expect a fixed selection containing the track with
// fewer channels.
trackSelector.setParameters(Parameters.DEFAULT.buildUpon().setMaxAudioChannelCount(2));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, stereoAudioFormat);
// If we constrain the channel count to 1 we expect a fixed selection containing the track with
// fewer channels.
trackSelector.setParameters(Parameters.DEFAULT.buildUpon().setMaxAudioChannelCount(1));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, stereoAudioFormat);
// If we disable exceeding of constraints we expect no selection.
trackSelector.setParameters(
Parameters.DEFAULT
.buildUpon()
.setMaxAudioChannelCount(1)
.setExceedAudioConstraintsIfNecessary(false));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertNoSelection(result.selections.get(0));
}
@Test @Test
public void testSelectTracksWithMultipleAudioTracksOverrideReturnsAdaptiveTrackSelection() public void testSelectTracksWithMultipleAudioTracksOverrideReturnsAdaptiveTrackSelection()
throws Exception { throws Exception {
@ -1164,6 +1301,70 @@ public final class DefaultTrackSelectorTest {
assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1); assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1);
} }
@Test
public void testSelectTracksWithMultipleVideoTracksWithNonSeamlessAdaptiveness()
throws Exception {
FakeRendererCapabilities nonSeamlessVideoCapabilities =
new FakeRendererCapabilities(C.TRACK_TYPE_VIDEO, FORMAT_HANDLED | ADAPTIVE_NOT_SEAMLESS);
// Should do non-seamless adaptiveness by default, so expect an adaptive selection.
TrackGroupArray trackGroups = singleTrackGroup(buildVideoFormat("0"), buildVideoFormat("1"));
trackSelector.setParameters(
Parameters.DEFAULT.buildUpon().setAllowVideoNonSeamlessAdaptiveness(true));
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {nonSeamlessVideoCapabilities},
trackGroups,
periodId,
TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1);
// If we explicitly disable non-seamless adaptiveness, expect a fixed selection.
trackSelector.setParameters(
Parameters.DEFAULT.buildUpon().setAllowVideoNonSeamlessAdaptiveness(false));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {nonSeamlessVideoCapabilities},
trackGroups,
periodId,
TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups.get(0), 0);
}
@Test
public void testSelectTracksWithMultipleVideoTracksWithMixedMimeTypes() throws Exception {
Format h264VideoFormat = buildVideoFormatWithMimeType("h264", MimeTypes.VIDEO_H264);
Format h265VideoFormat = buildVideoFormatWithMimeType("h265", MimeTypes.VIDEO_H265);
// Should not adapt between mixed mime types by default, so we expect a fixed selection
// containing the first stream.
TrackGroupArray trackGroups = singleTrackGroup(h264VideoFormat, h265VideoFormat);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, h264VideoFormat);
// The same applies if the tracks are provided in the opposite order.
trackGroups = singleTrackGroup(h265VideoFormat, h264VideoFormat);
result =
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections.get(0), trackGroups, h265VideoFormat);
// If we explicitly enable mixed mime type adaptiveness, expect an adaptive selection.
trackSelector.setParameters(
Parameters.DEFAULT.buildUpon().setAllowVideoMixedMimeTypeAdaptiveness(true));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections.get(0), trackGroups.get(0), 0, 1);
}
@Test @Test
public void testSelectTracksWithMultipleVideoTracksOverrideReturnsAdaptiveTrackSelection() public void testSelectTracksWithMultipleVideoTracksOverrideReturnsAdaptiveTrackSelection()
throws Exception { throws Exception {
@ -1277,6 +1478,36 @@ public final class DefaultTrackSelectorTest {
/* sampleRate= */ 44100); /* sampleRate= */ 44100);
} }
private static Format buildAudioFormatWithSampleRate(String id, int sampleRate) {
return buildAudioFormat(
id,
MimeTypes.AUDIO_AAC,
/* language= */ null,
/* selectionFlags= */ 0,
/* channelCount= */ 2,
sampleRate);
}
private static Format buildAudioFormatWithChannelCount(String id, int channelCount) {
return buildAudioFormat(
id,
MimeTypes.AUDIO_AAC,
/* language= */ null,
/* selectionFlags= */ 0,
channelCount,
/* sampleRate= */ 44100);
}
private static Format buildAudioFormatWithMimeType(String id, String mimeType) {
return buildAudioFormat(
id,
mimeType,
/* language= */ null,
/* selectionFlags= */ 0,
/* channelCount= */ 2,
/* sampleRate= */ 44100);
}
private static Format buildAudioFormat(String id) { private static Format buildAudioFormat(String id) {
return buildAudioFormat( return buildAudioFormat(
id, id,