diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 514528698f..c3ddb1d5e0 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -44,7 +44,7 @@ * MP3: Fix ID3 frame unsychronization ([#5673](https://github.com/google/ExoPlayer/issues/5673)). * 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 (i.e. if the flag is not set), the 0x82 elementary stream type is now treated as an SCTE subtitle track @@ -55,6 +55,8 @@ * Update `TrackSelection.Factory` interface to support creating all track selections together. * 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: * Update `DefaultTimeBar` based on duration of media and add parameter to set the minimum update interval to control the smoothness of the updates diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index f25f1a979c..3200e40495 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -2070,29 +2070,25 @@ public class DefaultTrackSelector extends MappingTrackSelector { boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; int trackScore; int languageScore = getFormatLanguageScore(format, params.preferredTextLanguage); - if (languageScore > 0 - || (params.selectUndeterminedTextLanguage && formatHasNoLanguage(format))) { + boolean trackHasNoLanguage = formatHasNoLanguage(format); + if (languageScore > 0 || (params.selectUndeterminedTextLanguage && trackHasNoLanguage)) { if (isDefault) { - trackScore = 17; + trackScore = 11; } else if (!isForced) { // 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 // a subset. - trackScore = 13; + trackScore = 7; } else { - trackScore = 9; + trackScore = 3; } trackScore += languageScore; } else if (isDefault) { - trackScore = 8; - } else if (isForced) { - int preferredAudioLanguageScore = - getFormatLanguageScore(format, params.preferredAudioLanguage); - if (preferredAudioLanguageScore > 0) { - trackScore = 4 + preferredAudioLanguageScore; - } else { - trackScore = 1 + getFormatLanguageScore(format, selectedAudioLanguage); - } + trackScore = 2; + } else if (isForced + && (getFormatLanguageScore(format, selectedAudioLanguage) > 0 + || (trackHasNoLanguage && stringDefinesNoLanguage(selectedAudioLanguage)))) { + trackScore = 1; } else { // Track should not be selected. continue; @@ -2281,15 +2277,19 @@ public class DefaultTrackSelector extends MappingTrackSelector { && maskedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES); } - /** - * 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. - */ + /** Equivalent to {@link #stringDefinesNoLanguage stringDefinesNoLanguage(format.language)}. */ protected static boolean formatHasNoLanguage(Format format) { - return TextUtils.isEmpty(format.language) - || TextUtils.equals(format.language, C.LANGUAGE_UNDETERMINED); + return stringDefinesNoLanguage(format.language); + } + + /** + * 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); } /** diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java index 3091e46456..83fe34db97 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java @@ -910,13 +910,8 @@ public final class DefaultTrackSelectorTest { result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE); 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. - 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); trackSelector.setParameters( Parameters.DEFAULT @@ -924,15 +919,7 @@ public final class DefaultTrackSelectorTest { .setDisabledTextTrackSelectionFlags(C.SELECTION_FLAG_DEFAULT) .build()); result = trackSelector.selectTracks(textRendererCapabilities, trackGroups, periodId, TIMELINE); - assertFixedSelection(result.selections.get(0), trackGroups, forcedOnly); - - // 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); + assertNoSelection(result.selections.get(0)); // All selection flags are disabled and there is no language preference, so nothing should be // selected. @@ -977,6 +964,11 @@ public final class DefaultTrackSelectorTest { buildTextFormat(/* id= */ "forcedEnglish", /* language= */ "eng", C.SELECTION_FLAG_FORCED); Format forcedGerman = 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 germanAudio = buildAudioFormat( @@ -994,16 +986,18 @@ public final class DefaultTrackSelectorTest { ALL_TEXT_FORMAT_SUPPORTED_RENDERER_CAPABILITIES }; - // The audio declares no language. The first forced text track should be selected. - TrackGroupArray trackGroups = wrapFormats(audio, forcedEnglish, forcedGerman); + // Neither the audio nor the forced text track define a language. We select them both under the + // assumption that they have matching language. + TrackGroupArray trackGroups = wrapFormats(audio, forcedNoLanguage); TrackSelectorResult result = trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE); - assertFixedSelection(result.selections.get(1), trackGroups, forcedEnglish); + assertFixedSelection(result.selections.get(1), trackGroups, forcedNoLanguage); - // Ditto. - trackGroups = wrapFormats(audio, forcedGerman, forcedEnglish); + // No forced text track should be selected because none of the forced text tracks' languages + // matches the selected audio language. + trackGroups = wrapFormats(audio, forcedEnglish, forcedGerman); 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. trackGroups = wrapFormats(germanAudio, forcedGerman, forcedEnglish);