Avoid selecting a forced text track that doesn't match the audio selection

Assuming there is no text language preference.

PiperOrigin-RevId: 244176667
This commit is contained in:
aquilescanta 2019-04-18 14:41:45 +01:00 committed by Andrew Lewis
parent fe65f002a5
commit 4ea2463856
3 changed files with 40 additions and 44 deletions

View file

@ -44,7 +44,7 @@
* MP3: Fix ID3 frame unsychronization * MP3: Fix ID3 frame unsychronization
([#5673](https://github.com/google/ExoPlayer/issues/5673)). ([#5673](https://github.com/google/ExoPlayer/issues/5673)).
* MP3: Fix playback of badly clipped files * MP3: Fix playback of badly clipped files
([#5772](https://github.com/google/ExoPlayer/issues/5772)). ([#5772](https://github.com/google/ExoPlayer/issues/5772)).
* MPEG-TS: Enable HDMV DTS stream detection only if a flag is set. By default * MPEG-TS: Enable HDMV DTS stream detection only if a flag is set. By default
(i.e. if the flag is not set), the 0x82 elementary stream type is now (i.e. if the flag is not set), the 0x82 elementary stream type is now
treated as an SCTE subtitle track treated as an SCTE subtitle track
@ -55,6 +55,8 @@
* Update `TrackSelection.Factory` interface to support creating all track * Update `TrackSelection.Factory` interface to support creating all track
selections together. selections together.
* Allow to specify a selection reason for a `SelectionOverride`. * Allow to specify a selection reason for a `SelectionOverride`.
* When no text language preference matches, only select forced text tracks
whose language matches the selected audio language.
* UI: * UI:
* Update `DefaultTimeBar` based on duration of media and add parameter to set * Update `DefaultTimeBar` based on duration of media and add parameter to set
the minimum update interval to control the smoothness of the updates the minimum update interval to control the smoothness of the updates

View file

@ -2070,29 +2070,25 @@ public class DefaultTrackSelector extends MappingTrackSelector {
boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0;
int trackScore; int trackScore;
int languageScore = getFormatLanguageScore(format, params.preferredTextLanguage); int languageScore = getFormatLanguageScore(format, params.preferredTextLanguage);
if (languageScore > 0 boolean trackHasNoLanguage = formatHasNoLanguage(format);
|| (params.selectUndeterminedTextLanguage && formatHasNoLanguage(format))) { if (languageScore > 0 || (params.selectUndeterminedTextLanguage && trackHasNoLanguage)) {
if (isDefault) { if (isDefault) {
trackScore = 17; trackScore = 11;
} else if (!isForced) { } else if (!isForced) {
// Prefer non-forced to forced if a preferred text language has been specified. Where // Prefer non-forced to forced if a preferred text language has been specified. Where
// both are provided the non-forced track will usually contain the forced subtitles as // both are provided the non-forced track will usually contain the forced subtitles as
// a subset. // a subset.
trackScore = 13; trackScore = 7;
} else { } else {
trackScore = 9; trackScore = 3;
} }
trackScore += languageScore; trackScore += languageScore;
} else if (isDefault) { } else if (isDefault) {
trackScore = 8; trackScore = 2;
} else if (isForced) { } else if (isForced
int preferredAudioLanguageScore = && (getFormatLanguageScore(format, selectedAudioLanguage) > 0
getFormatLanguageScore(format, params.preferredAudioLanguage); || (trackHasNoLanguage && stringDefinesNoLanguage(selectedAudioLanguage)))) {
if (preferredAudioLanguageScore > 0) { trackScore = 1;
trackScore = 4 + preferredAudioLanguageScore;
} else {
trackScore = 1 + getFormatLanguageScore(format, selectedAudioLanguage);
}
} else { } else {
// Track should not be selected. // Track should not be selected.
continue; continue;
@ -2281,15 +2277,19 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& maskedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES); && maskedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES);
} }
/** /** Equivalent to {@link #stringDefinesNoLanguage stringDefinesNoLanguage(format.language)}. */
* Returns whether a {@link Format} does not define a language.
*
* @param format The {@link Format}.
* @return Whether the {@link Format} does not define a language.
*/
protected static boolean formatHasNoLanguage(Format format) { protected static boolean formatHasNoLanguage(Format format) {
return TextUtils.isEmpty(format.language) return stringDefinesNoLanguage(format.language);
|| TextUtils.equals(format.language, C.LANGUAGE_UNDETERMINED); }
/**
* Returns whether the given string does not define a language.
*
* @param language The string.
* @return Whether the given string does not define a language.
*/
protected static boolean stringDefinesNoLanguage(@Nullable String language) {
return TextUtils.isEmpty(language) || TextUtils.equals(language, C.LANGUAGE_UNDETERMINED);
} }
/** /**

View file

@ -910,13 +910,8 @@ public final class DefaultTrackSelectorTest {
result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE); result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, defaultOnly); assertFixedSelection(result.selections.get(0), trackGroups, defaultOnly);
// With no language preference and no text track flagged as default, the first forced should be // Default flags are disabled and no language preference is provided, so no text track is
// selected. // selected.
trackGroups = wrapFormats(forcedOnly, noFlag);
result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, forcedOnly);
// Default flags are disabled, so the first track flagged as forced should be selected.
trackGroups = wrapFormats(defaultOnly, noFlag, forcedOnly, forcedDefault); trackGroups = wrapFormats(defaultOnly, noFlag, forcedOnly, forcedDefault);
trackSelector.setParameters( trackSelector.setParameters(
Parameters.DEFAULT Parameters.DEFAULT
@ -924,15 +919,7 @@ public final class DefaultTrackSelectorTest {
.setDisabledTextTrackSelectionFlags(C.SELECTION_FLAG_DEFAULT) .setDisabledTextTrackSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.build()); .build());
result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE); result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, forcedOnly); assertNoSelection(result.selections.get(0));
// Default flags are disabled, but there is a text track flagged as forced whose language
// matches the preferred audio language.
trackGroups = wrapFormats(forcedDefault, forcedOnly, defaultOnly, noFlag, forcedOnlySpanish);
trackSelector.setParameters(
trackSelector.getParameters().buildUpon().setPreferredTextLanguage("spa").build());
result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections.get(0), trackGroups, forcedOnlySpanish);
// All selection flags are disabled and there is no language preference, so nothing should be // All selection flags are disabled and there is no language preference, so nothing should be
// selected. // selected.
@ -977,6 +964,11 @@ public final class DefaultTrackSelectorTest {
buildTextFormat(/* id= */ "forcedEnglish", /* language= */ "eng", C.SELECTION_FLAG_FORCED); buildTextFormat(/* id= */ "forcedEnglish", /* language= */ "eng", C.SELECTION_FLAG_FORCED);
Format forcedGerman = Format forcedGerman =
buildTextFormat(/* id= */ "forcedGerman", /* language= */ "deu", C.SELECTION_FLAG_FORCED); buildTextFormat(/* id= */ "forcedGerman", /* language= */ "deu", C.SELECTION_FLAG_FORCED);
Format forcedNoLanguage =
buildTextFormat(
/* id= */ "forcedNoLanguage",
/* language= */ C.LANGUAGE_UNDETERMINED,
C.SELECTION_FLAG_FORCED);
Format audio = buildAudioFormat(/* id= */ "audio"); Format audio = buildAudioFormat(/* id= */ "audio");
Format germanAudio = Format germanAudio =
buildAudioFormat( buildAudioFormat(
@ -994,16 +986,18 @@ public final class DefaultTrackSelectorTest {
ALL_TEXT_FORMAT_SUPPORTED_RENDERER_CAPABILITIES ALL_TEXT_FORMAT_SUPPORTED_RENDERER_CAPABILITIES
}; };
// The audio declares no language. The first forced text track should be selected. // Neither the audio nor the forced text track define a language. We select them both under the
TrackGroupArray trackGroups = wrapFormats(audio, forcedEnglish, forcedGerman); // assumption that they have matching language.
TrackGroupArray trackGroups = wrapFormats(audio, forcedNoLanguage);
TrackSelectorResult result = TrackSelectorResult result =
trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE); trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections.get(1), trackGroups, forcedEnglish); assertFixedSelection(result.selections.get(1), trackGroups, forcedNoLanguage);
// Ditto. // No forced text track should be selected because none of the forced text tracks' languages
trackGroups = wrapFormats(audio, forcedGerman, forcedEnglish); // matches the selected audio language.
trackGroups = wrapFormats(audio, forcedEnglish, forcedGerman);
result = trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE); result = trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE);
assertFixedSelection(result.selections.get(1), trackGroups, forcedGerman); assertNoSelection(result.selections.get(1));
// The audio declares german. The german forced track should be selected. // The audio declares german. The german forced track should be selected.
trackGroups = wrapFormats(germanAudio, forcedGerman, forcedEnglish); trackGroups = wrapFormats(germanAudio, forcedGerman, forcedEnglish);