Add option to set preferred audio role flags in DefaultTrackSelector

We already have the eequivalent option for text tracks.

PiperOrigin-RevId: 351999287
This commit is contained in:
tonihei 2021-01-15 14:48:30 +00:00 committed by Oliver Woodman
parent d2950c2e97
commit 68fd23a967
4 changed files with 110 additions and 0 deletions

View File

@ -141,6 +141,7 @@
* Add option to specify multiple preferred audio or text languages.
* Add option to specify preferred MIME type(s) for video and audio
([#8320](https://github.com/google/ExoPlayer/issues/8320)).
* Add option to specify preferred audio role flags.
* Forward `Timeline` and `MediaPeriodId` to `TrackSelection.Factory`.
* DASH:
* Support low-latency DASH playback (`availabilityTimeOffset` and

View File

@ -489,6 +489,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this;
}
@Override
public ParametersBuilder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAudioRoleFlags) {
super.setPreferredAudioRoleFlags(preferredAudioRoleFlags);
return this;
}
/**
* Sets the maximum allowed audio channel count.
*
@ -843,6 +849,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
preferredVideoMimeTypes,
// Audio
preferredAudioLanguages,
preferredAudioRoleFlags,
maxAudioChannelCount,
maxAudioBitrate,
exceedAudioConstraintsIfNecessary,
@ -1112,6 +1119,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
ImmutableList<String> preferredVideoMimeTypes,
// Audio
ImmutableList<String> preferredAudioLanguages,
@C.RoleFlags int preferredAudioRoleFlags,
int maxAudioChannelCount,
int maxAudioBitrate,
boolean exceedAudioConstraintsIfNecessary,
@ -1135,6 +1143,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
SparseBooleanArray rendererDisabledFlags) {
super(
preferredAudioLanguages,
preferredAudioRoleFlags,
preferredTextLanguages,
preferredTextRoleFlags,
selectUndeterminedTextLanguage,
@ -2724,6 +2733,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final boolean isWithinRendererCapabilities;
private final int preferredLanguageScore;
private final int preferredLanguageIndex;
private final int preferredRoleFlagsScore;
private final int localeLanguageMatchIndex;
private final int localeLanguageScore;
private final boolean isDefaultSelectionFlag;
@ -2753,6 +2763,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
preferredLanguageIndex = bestLanguageIndex;
preferredLanguageScore = bestLanguageScore;
preferredRoleFlagsScore =
Integer.bitCount(format.roleFlags & parameters.preferredAudioRoleFlags);
isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
channelCount = format.channelCount;
sampleRate = format.sampleRate;
@ -2809,6 +2821,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
other.preferredLanguageIndex,
Ordering.natural().reverse())
.compare(this.preferredLanguageScore, other.preferredLanguageScore)
.compare(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore)
.compareFalseFirst(this.isWithinConstraints, other.isWithinConstraints)
.compare(
this.preferredMimeTypeMatchIndex,

View File

@ -40,6 +40,7 @@ public class TrackSelectionParameters implements Parcelable {
public static class Builder {
/* package */ ImmutableList<String> preferredAudioLanguages;
@C.RoleFlags /* package */ int preferredAudioRoleFlags;
/* package */ ImmutableList<String> preferredTextLanguages;
@C.RoleFlags /* package */ int preferredTextRoleFlags;
/* package */ boolean selectUndeterminedTextLanguage;
@ -63,6 +64,7 @@ public class TrackSelectionParameters implements Parcelable {
@Deprecated
public Builder() {
preferredAudioLanguages = ImmutableList.of();
preferredAudioRoleFlags = 0;
preferredTextLanguages = ImmutableList.of();
preferredTextRoleFlags = 0;
selectUndeterminedTextLanguage = false;
@ -75,6 +77,7 @@ public class TrackSelectionParameters implements Parcelable {
*/
/* package */ Builder(TrackSelectionParameters initialValues) {
preferredAudioLanguages = initialValues.preferredAudioLanguages;
preferredAudioRoleFlags = initialValues.preferredAudioRoleFlags;
preferredTextLanguages = initialValues.preferredTextLanguages;
preferredTextRoleFlags = initialValues.preferredTextRoleFlags;
selectUndeterminedTextLanguage = initialValues.selectUndeterminedTextLanguage;
@ -111,6 +114,17 @@ public class TrackSelectionParameters implements Parcelable {
return this;
}
/**
* Sets the preferred {@link C.RoleFlags} for audio tracks.
*
* @param preferredAudioRoleFlags Preferred audio role flags.
* @return This builder.
*/
public Builder setPreferredAudioRoleFlags(@C.RoleFlags int preferredAudioRoleFlags) {
this.preferredAudioRoleFlags = preferredAudioRoleFlags;
return this;
}
/**
* Sets the preferred language and role flags for text tracks based on the accessibility
* settings of {@link CaptioningManager}.
@ -201,6 +215,7 @@ public class TrackSelectionParameters implements Parcelable {
return new TrackSelectionParameters(
// Audio
preferredAudioLanguages,
preferredAudioRoleFlags,
// Text
preferredTextLanguages,
preferredTextRoleFlags,
@ -262,6 +277,11 @@ public class TrackSelectionParameters implements Parcelable {
* default. The default value is an empty list.
*/
public final ImmutableList<String> preferredAudioLanguages;
/**
* The preferred {@link C.RoleFlags} for audio tracks. {@code 0} selects the default track if
* there is one, or the first track if there's no default. The default value is {@code 0}.
*/
@C.RoleFlags public final int preferredAudioRoleFlags;
/**
* The preferred languages for text tracks as IETF BCP 47 conformant tags in order of preference.
* An empty list selects the default track if there is one, or no track otherwise. The default
@ -290,12 +310,14 @@ public class TrackSelectionParameters implements Parcelable {
/* package */ TrackSelectionParameters(
ImmutableList<String> preferredAudioLanguages,
@C.RoleFlags int preferredAudioRoleFlags,
ImmutableList<String> preferredTextLanguages,
@C.RoleFlags int preferredTextRoleFlags,
boolean selectUndeterminedTextLanguage,
@C.SelectionFlags int disabledTextTrackSelectionFlags) {
// Audio
this.preferredAudioLanguages = preferredAudioLanguages;
this.preferredAudioRoleFlags = preferredAudioRoleFlags;
// Text
this.preferredTextLanguages = preferredTextLanguages;
this.preferredTextRoleFlags = preferredTextRoleFlags;
@ -307,6 +329,7 @@ public class TrackSelectionParameters implements Parcelable {
ArrayList<String> preferredAudioLanguages = new ArrayList<>();
in.readList(preferredAudioLanguages, /* loader= */ null);
this.preferredAudioLanguages = ImmutableList.copyOf(preferredAudioLanguages);
this.preferredAudioRoleFlags = in.readInt();
ArrayList<String> preferredTextLanguages = new ArrayList<>();
in.readList(preferredTextLanguages, /* loader= */ null);
this.preferredTextLanguages = ImmutableList.copyOf(preferredTextLanguages);
@ -331,6 +354,7 @@ public class TrackSelectionParameters implements Parcelable {
}
TrackSelectionParameters other = (TrackSelectionParameters) obj;
return preferredAudioLanguages.equals(other.preferredAudioLanguages)
&& preferredAudioRoleFlags == other.preferredAudioRoleFlags
&& preferredTextLanguages.equals(other.preferredTextLanguages)
&& preferredTextRoleFlags == other.preferredTextRoleFlags
&& selectUndeterminedTextLanguage == other.selectUndeterminedTextLanguage
@ -341,6 +365,7 @@ public class TrackSelectionParameters implements Parcelable {
public int hashCode() {
int result = 1;
result = 31 * result + preferredAudioLanguages.hashCode();
result = 31 * result + preferredAudioRoleFlags;
result = 31 * result + preferredTextLanguages.hashCode();
result = 31 * result + preferredTextRoleFlags;
result = 31 * result + (selectUndeterminedTextLanguage ? 1 : 0);
@ -358,6 +383,7 @@ public class TrackSelectionParameters implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(preferredAudioLanguages);
dest.writeInt(preferredAudioRoleFlags);
dest.writeList(preferredTextLanguages);
dest.writeInt(preferredTextRoleFlags);
Util.writeBoolean(dest, selectUndeterminedTextLanguage);

View File

@ -383,6 +383,75 @@ public final class DefaultTrackSelectorTest {
assertFixedSelection(result.selections.get(0), trackGroups, enAudioFormat);
}
/**
* Tests that track selector will select audio track with the highest number of matching role
* flags given by {@link Parameters}.
*/
@Test
public void selectTracks_withPreferredAudioRoleFlags_selectPreferredTrack() throws Exception {
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
Format noRoleFlags = formatBuilder.build();
Format lessRoleFlags = formatBuilder.setRoleFlags(C.ROLE_FLAG_CAPTION).build();
Format moreRoleFlags =
formatBuilder
.setRoleFlags(C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_COMMENTARY | C.ROLE_FLAG_DUB)
.build();
TrackGroupArray trackGroups = wrapFormats(noRoleFlags, moreRoleFlags, lessRoleFlags);
trackSelector.setParameters(
defaultParameters
.buildUpon()
.setPreferredAudioRoleFlags(C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_COMMENTARY));
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, moreRoleFlags);
}
/**
* Tests that track selector with select default audio track if no role flag preference is
* specified by {@link Parameters}.
*/
@Test
public void selectTracks_withoutPreferredAudioRoleFlags_selectsDefaultTrack() throws Exception {
Format firstFormat = AUDIO_FORMAT;
Format defaultFormat =
AUDIO_FORMAT.buildUpon().setSelectionFlags(C.SELECTION_FLAG_DEFAULT).build();
Format roleFlagFormat = AUDIO_FORMAT.buildUpon().setRoleFlags(C.ROLE_FLAG_CAPTION).build();
TrackGroupArray trackGroups = wrapFormats(firstFormat, defaultFormat, roleFlagFormat);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, defaultFormat);
}
/**
* Tests that track selector with select the first audio track if no role flag preference is
* specified by {@link Parameters} and no default track exists.
*/
@Test
public void selectTracks_withoutPreferredAudioRoleFlagsOrDefaultTrack_selectsFirstTrack()
throws Exception {
Format firstFormat = AUDIO_FORMAT;
Format roleFlagFormat = AUDIO_FORMAT.buildUpon().setRoleFlags(C.ROLE_FLAG_CAPTION).build();
TrackGroupArray trackGroups = wrapFormats(firstFormat, roleFlagFormat);
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, firstFormat);
}
/**
* Tests that track selector will prefer selecting audio track with language that match preferred
* language given by {@link Parameters} over track with {@link C#SELECTION_FLAG_DEFAULT}.
@ -1667,6 +1736,7 @@ public final class DefaultTrackSelectorTest {
/* preferredVideoMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_AV1, MimeTypes.VIDEO_H264),
// Audio
/* preferredAudioLanguages= */ ImmutableList.of("zh", "jp"),
/* preferredAudioRoleFlags= */ C.ROLE_FLAG_COMMENTARY,
/* maxAudioChannelCount= */ 10,
/* maxAudioBitrate= */ 11,
/* exceedAudioConstraintsIfNecessary= */ false,