From 29a099cf03236edc6d46a262d64621dfcdac8989 Mon Sep 17 00:00:00 2001 From: Yannick RUI Date: Fri, 12 Jul 2019 13:28:41 +0200 Subject: [PATCH 1/4] Switch text track score from the score based logic to a comparison based logic similar to the one we use for audio track selection (see AudioTrackScore). --- .../trackselection/DefaultTrackSelector.java | 154 ++++++++++-------- 1 file changed, 84 insertions(+), 70 deletions(-) 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 949bd178ea..511a974a0e 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 @@ -1552,38 +1552,30 @@ public class DefaultTrackSelector extends MappingTrackSelector { } } - int selectedTextTrackScore = Integer.MIN_VALUE; + TextTrackScore selectedTextTrackScore = null; int selectedTextRendererIndex = C.INDEX_UNSET; for (int i = 0; i < rendererCount; i++) { - int trackType = mappedTrackInfo.getRendererType(i); - switch (trackType) { - case C.TRACK_TYPE_VIDEO: - case C.TRACK_TYPE_AUDIO: - // Already done. Do nothing. - break; - case C.TRACK_TYPE_TEXT: - Pair textSelection = - selectTextTrack( - mappedTrackInfo.getTrackGroups(i), - rendererFormatSupports[i], - params, - selectedAudioLanguage); - if (textSelection != null && textSelection.second > selectedTextTrackScore) { - if (selectedTextRendererIndex != C.INDEX_UNSET) { - // We've already made a selection for another text renderer, but it had a lower score. - // Clear the selection for that renderer. - definitions[selectedTextRendererIndex] = null; - } - definitions[i] = textSelection.first; - selectedTextTrackScore = textSelection.second; - selectedTextRendererIndex = i; + // The below behaviour is different from video and audio track selection + // i.e. do not perform a text track pre selection if there are no preferredTextLanguage requested. + if (C.TRACK_TYPE_TEXT == mappedTrackInfo.getRendererType(i) && params.preferredTextLanguage != null) { + Pair textSelection = + selectTextTrack( + mappedTrackInfo.getTrackGroups(i), + rendererFormatSupports[i], + params); + if (textSelection != null + && (selectedTextTrackScore == null + || textSelection.second.compareTo(selectedTextTrackScore) > 0)) { + if (selectedTextRendererIndex != C.INDEX_UNSET) { + // We've already made a selection for another text renderer, but it had a lower + // score. Clear the selection for that renderer. + definitions[selectedTextRendererIndex] = null; } - break; - default: - definitions[i] = - selectOtherTrack( - trackType, mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params); - break; + TrackSelection.Definition definition = textSelection.first; + definitions[i] = definition; + selectedTextTrackScore = textSelection.second; + selectedTextRendererIndex = i; + } } } @@ -2051,22 +2043,20 @@ public class DefaultTrackSelector extends MappingTrackSelector { * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped * track, indexed by track group index and track index (in that order). * @param params The selector's current constraint parameters. - * @param selectedAudioLanguage The language of the selected audio track. May be null if the - * selected audio track declares no language or no audio track was selected. - * @return The {@link TrackSelection.Definition} and corresponding track score, or null if no + * selected text track declares no language or no text track was selected. + * @return The {@link TrackSelection.Definition} and corresponding {@link TextTrackScore}, or null if no * selection was made. * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ @Nullable - protected Pair selectTextTrack( + protected Pair selectTextTrack( TrackGroupArray groups, int[][] formatSupport, - Parameters params, - @Nullable String selectedAudioLanguage) + Parameters params) throws ExoPlaybackException { TrackGroup selectedGroup = null; - int selectedTrackIndex = 0; - int selectedTrackScore = 0; + int selectedTrackIndex = C.INDEX_UNSET; + TextTrackScore selectedTrackScore = null; for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { TrackGroup trackGroup = groups.get(groupIndex); int[] trackFormatSupport = formatSupport[groupIndex]; @@ -2074,39 +2064,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { if (isSupported(trackFormatSupport[trackIndex], params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); - int maskedSelectionFlags = - format.selectionFlags & ~params.disabledTextTrackSelectionFlags; - boolean isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; - boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; - int trackScore; - int languageScore = getFormatLanguageScore(format, params.preferredTextLanguage); - boolean trackHasNoLanguage = formatHasNoLanguage(format); - if (languageScore > 0 || (params.selectUndeterminedTextLanguage && trackHasNoLanguage)) { - if (isDefault) { - 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 = 7; - } else { - trackScore = 3; - } - trackScore += languageScore; - } else if (isDefault) { - trackScore = 2; - } else if (isForced - && (getFormatLanguageScore(format, selectedAudioLanguage) > 0 - || (trackHasNoLanguage && stringDefinesNoLanguage(selectedAudioLanguage)))) { - trackScore = 1; - } else { - // Track should not be selected. - continue; - } - if (isSupported(trackFormatSupport[trackIndex], false)) { - trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS; - } - if (trackScore > selectedTrackScore) { + TextTrackScore trackScore = new TextTrackScore(format, params, trackFormatSupport[trackIndex]); + if ((selectedTrackScore == null) || trackScore.compareTo(selectedTrackScore) > 0) { selectedGroup = trackGroup; selectedTrackIndex = trackIndex; selectedTrackScore = trackScore; @@ -2535,4 +2494,59 @@ public class DefaultTrackSelector extends MappingTrackSelector { } + /** Represents how well an text track matches the selection {@link Parameters}. */ + protected static final class TextTrackScore implements Comparable { + + private final boolean isWithinRendererCapabilities; + private final int preferredLanguageScore; + private final int localeLanguageMatchIndex; + private final int localeLanguageScore; + private final boolean isDefaultSelectionFlag; + + public TextTrackScore(Format format, Parameters parameters, int formatSupport) { + isWithinRendererCapabilities = isSupported(formatSupport, false); + preferredLanguageScore = getFormatLanguageScore(format, parameters.preferredTextLanguage); + isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; + String[] localeLanguages = Util.getSystemLanguageCodes(); + int bestMatchIndex = Integer.MAX_VALUE; + int bestMatchScore = 0; + for (int i = 0; i < localeLanguages.length; i++) { + int score = getFormatLanguageScore(format, localeLanguages[i]); + if (score > 0) { + bestMatchIndex = i; + bestMatchScore = score; + break; + } + } + localeLanguageMatchIndex = bestMatchIndex; + localeLanguageScore = bestMatchScore; + } + + /** + * Compares this score with another. + * + * @param other The other score to compare to. + * @return A positive integer if this score is better than the other. Zero if they are equal. A + * negative integer if this score is worse than the other. + */ + @Override + public int compareTo(@NonNull TextTrackScore other) { + if (this.isWithinRendererCapabilities != other.isWithinRendererCapabilities) { + return this.isWithinRendererCapabilities ? 1 : -1; + } + if (this.preferredLanguageScore != other.preferredLanguageScore) { + return compareInts(this.preferredLanguageScore, other.preferredLanguageScore); + } + if (this.isDefaultSelectionFlag != other.isDefaultSelectionFlag) { + return this.isDefaultSelectionFlag ? 1 : -1; + } + if (this.localeLanguageMatchIndex != other.localeLanguageMatchIndex) { + return -compareInts(this.localeLanguageMatchIndex, other.localeLanguageMatchIndex); + } + if (this.localeLanguageScore != other.localeLanguageScore) { + return compareInts(this.localeLanguageScore, other.localeLanguageScore); + } + return 0; + } + } } From af98883a7bffc6b8a760b84737012ddd5cfcd622 Mon Sep 17 00:00:00 2001 From: Yannick RUI Date: Mon, 15 Jul 2019 11:35:32 +0200 Subject: [PATCH 2/4] Reintroducing existing logic as requested here https://github.com/google/ExoPlayer/pull/6178#pullrequestreview-261298162 --- .../trackselection/DefaultTrackSelector.java | 131 ++++++++++-------- 1 file changed, 75 insertions(+), 56 deletions(-) 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 511a974a0e..c0de66516b 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 @@ -1555,29 +1555,39 @@ public class DefaultTrackSelector extends MappingTrackSelector { TextTrackScore selectedTextTrackScore = null; int selectedTextRendererIndex = C.INDEX_UNSET; for (int i = 0; i < rendererCount; i++) { - // The below behaviour is different from video and audio track selection - // i.e. do not perform a text track pre selection if there are no preferredTextLanguage requested. - if (C.TRACK_TYPE_TEXT == mappedTrackInfo.getRendererType(i) && params.preferredTextLanguage != null) { - Pair textSelection = - selectTextTrack( - mappedTrackInfo.getTrackGroups(i), - rendererFormatSupports[i], - params); - if (textSelection != null - && (selectedTextTrackScore == null - || textSelection.second.compareTo(selectedTextTrackScore) > 0)) { - if (selectedTextRendererIndex != C.INDEX_UNSET) { - // We've already made a selection for another text renderer, but it had a lower - // score. Clear the selection for that renderer. - definitions[selectedTextRendererIndex] = null; + int trackType = mappedTrackInfo.getRendererType(i); + switch (trackType) { + case C.TRACK_TYPE_VIDEO: + case C.TRACK_TYPE_AUDIO: + // Already done. Do nothing. + break; + case C.TRACK_TYPE_TEXT: + Pair textSelection = + selectTextTrack( + mappedTrackInfo.getTrackGroups(i), + rendererFormatSupports[i], + params, + selectedAudioLanguage); + if (textSelection != null + && (selectedTextTrackScore == null + || textSelection.second.compareTo(selectedTextTrackScore) > 0)) { + if (selectedTextRendererIndex != C.INDEX_UNSET) { + // We've already made a selection for another text renderer, but it had a lower + // score. Clear the selection for that renderer. + definitions[selectedTextRendererIndex] = null; + } + definitions[i] = textSelection.first; + selectedTextTrackScore = textSelection.second; + selectedTextRendererIndex = i; } - TrackSelection.Definition definition = textSelection.first; - definitions[i] = definition; - selectedTextTrackScore = textSelection.second; - selectedTextRendererIndex = i; + break; + default: + definitions[i] = + selectOtherTrack( + trackType, mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params); + break; } } - } return definitions; } @@ -2052,7 +2062,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { protected Pair selectTextTrack( TrackGroupArray groups, int[][] formatSupport, - Parameters params) + Parameters params, + @Nullable String selectedAudioLanguage) throws ExoPlaybackException { TrackGroup selectedGroup = null; int selectedTrackIndex = C.INDEX_UNSET; @@ -2064,7 +2075,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { if (isSupported(trackFormatSupport[trackIndex], params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); - TextTrackScore trackScore = new TextTrackScore(format, params, trackFormatSupport[trackIndex]); + TextTrackScore trackScore = new TextTrackScore(format, params, trackFormatSupport[trackIndex], selectedAudioLanguage); if ((selectedTrackScore == null) || trackScore.compareTo(selectedTrackScore) > 0) { selectedGroup = trackGroup; selectedTrackIndex = trackIndex; @@ -2497,29 +2508,49 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** Represents how well an text track matches the selection {@link Parameters}. */ protected static final class TextTrackScore implements Comparable { - private final boolean isWithinRendererCapabilities; - private final int preferredLanguageScore; - private final int localeLanguageMatchIndex; - private final int localeLanguageScore; - private final boolean isDefaultSelectionFlag; + private final boolean isDefault; + private final boolean isForced; + private final int languageScore; + private final boolean trackHasNoLanguage; + private int bestMatchScore = 0; - public TextTrackScore(Format format, Parameters parameters, int formatSupport) { - isWithinRendererCapabilities = isSupported(formatSupport, false); - preferredLanguageScore = getFormatLanguageScore(format, parameters.preferredTextLanguage); - isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; - String[] localeLanguages = Util.getSystemLanguageCodes(); - int bestMatchIndex = Integer.MAX_VALUE; - int bestMatchScore = 0; - for (int i = 0; i < localeLanguages.length; i++) { - int score = getFormatLanguageScore(format, localeLanguages[i]); - if (score > 0) { - bestMatchIndex = i; - bestMatchScore = score; - break; + public TextTrackScore( + Format format, + Parameters parameters, + int trackFormatSupport, + @Nullable String selectedAudioLanguage) { + languageScore = getFormatLanguageScore(format, parameters.preferredTextLanguage); + int maskedSelectionFlags = + format.selectionFlags & ~parameters.disabledTextTrackSelectionFlags; + isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; + isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; + trackHasNoLanguage = formatHasNoLanguage(format); + + if (languageScore > 0 || (parameters.selectUndeterminedTextLanguage && trackHasNoLanguage)) { + if (isDefault) { + bestMatchScore = 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. + bestMatchScore = 7; + } else { + bestMatchScore = 3; } + bestMatchScore += languageScore; + } else if (isDefault) { + bestMatchScore = 2; + } else if (isForced + && (languageScore > 0 + || (trackHasNoLanguage && stringDefinesNoLanguage(selectedAudioLanguage)))) { + bestMatchScore = 1; + } else { + // Track should not be selected. + bestMatchScore = -1; + } + if (isSupported(trackFormatSupport, false)) { + bestMatchScore += WITHIN_RENDERER_CAPABILITIES_BONUS; } - localeLanguageMatchIndex = bestMatchIndex; - localeLanguageScore = bestMatchScore; } /** @@ -2531,20 +2562,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ @Override public int compareTo(@NonNull TextTrackScore other) { - if (this.isWithinRendererCapabilities != other.isWithinRendererCapabilities) { - return this.isWithinRendererCapabilities ? 1 : -1; - } - if (this.preferredLanguageScore != other.preferredLanguageScore) { - return compareInts(this.preferredLanguageScore, other.preferredLanguageScore); - } - if (this.isDefaultSelectionFlag != other.isDefaultSelectionFlag) { - return this.isDefaultSelectionFlag ? 1 : -1; - } - if (this.localeLanguageMatchIndex != other.localeLanguageMatchIndex) { - return -compareInts(this.localeLanguageMatchIndex, other.localeLanguageMatchIndex); - } - if (this.localeLanguageScore != other.localeLanguageScore) { - return compareInts(this.localeLanguageScore, other.localeLanguageScore); + if (this.bestMatchScore != other.bestMatchScore) { + return compareInts(this.bestMatchScore, other.bestMatchScore); } return 0; } From 1909987dc8d63ef6504d7c872e3ce28b9cc560c7 Mon Sep 17 00:00:00 2001 From: Yannick RUI Date: Mon, 15 Jul 2019 16:05:01 +0200 Subject: [PATCH 3/4] Change all the conditions and scores that are currently in the constructor of TextTrackScore to comparisons in TextTrackScore.compareTo --- .../trackselection/DefaultTrackSelector.java | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) 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 c0de66516b..b5d282f8a7 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 @@ -2508,49 +2508,30 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** Represents how well an text track matches the selection {@link Parameters}. */ protected static final class TextTrackScore implements Comparable { + private final boolean isWithinRendererCapabilities; private final boolean isDefault; private final boolean isForced; - private final int languageScore; + private final int preferredLanguageScore; + private final int selectedAudioLanguageScore; private final boolean trackHasNoLanguage; - private int bestMatchScore = 0; + private final boolean selectUndeterminedTextLanguage; + private final boolean stringDefinesNoLang; public TextTrackScore( Format format, Parameters parameters, int trackFormatSupport, @Nullable String selectedAudioLanguage) { - languageScore = getFormatLanguageScore(format, parameters.preferredTextLanguage); + isWithinRendererCapabilities = isSupported(trackFormatSupport, false); int maskedSelectionFlags = format.selectionFlags & ~parameters.disabledTextTrackSelectionFlags; isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; + preferredLanguageScore = getFormatLanguageScore(format, parameters.preferredTextLanguage); + selectedAudioLanguageScore = getFormatLanguageScore(format, selectedAudioLanguage); trackHasNoLanguage = formatHasNoLanguage(format); - - if (languageScore > 0 || (parameters.selectUndeterminedTextLanguage && trackHasNoLanguage)) { - if (isDefault) { - bestMatchScore = 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. - bestMatchScore = 7; - } else { - bestMatchScore = 3; - } - bestMatchScore += languageScore; - } else if (isDefault) { - bestMatchScore = 2; - } else if (isForced - && (languageScore > 0 - || (trackHasNoLanguage && stringDefinesNoLanguage(selectedAudioLanguage)))) { - bestMatchScore = 1; - } else { - // Track should not be selected. - bestMatchScore = -1; - } - if (isSupported(trackFormatSupport, false)) { - bestMatchScore += WITHIN_RENDERER_CAPABILITIES_BONUS; - } + selectUndeterminedTextLanguage = parameters.selectUndeterminedTextLanguage; + stringDefinesNoLang = stringDefinesNoLanguage(selectedAudioLanguage); } /** @@ -2562,10 +2543,38 @@ public class DefaultTrackSelector extends MappingTrackSelector { */ @Override public int compareTo(@NonNull TextTrackScore other) { - if (this.bestMatchScore != other.bestMatchScore) { - return compareInts(this.bestMatchScore, other.bestMatchScore); + if (this.isWithinRendererCapabilities != other.isWithinRendererCapabilities) { + return this.isWithinRendererCapabilities ? 1 : -1; + } + if ((this.preferredLanguageScore > 0 || (this.selectUndeterminedTextLanguage && this.trackHasNoLanguage)) == + (other.preferredLanguageScore > 0 || (other.selectUndeterminedTextLanguage && other.trackHasNoLanguage))) { + if (this.preferredLanguageScore > 0 || (this.selectUndeterminedTextLanguage + && this.trackHasNoLanguage)) { + if (this.isDefault != other.isDefault) { + return this.isDefault ? 1 : -1; + } + if (this.isForced != other.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. + return !this.isForced ? 1 : -1; + } + return (this.preferredLanguageScore > other.preferredLanguageScore) ? 1 : -1; + } else { + if (this.isDefault != other.isDefault) { + return this.isDefault ? 1 : -1; + } + if ((this.isForced && (this.selectedAudioLanguageScore > 0 || (this.trackHasNoLanguage && this.stringDefinesNoLang))) != + (other.isForced && (other.selectedAudioLanguageScore > 0 || (other.trackHasNoLanguage && other.stringDefinesNoLang)))) { + return (this.isForced && (this.selectedAudioLanguageScore > 0 + || (this.trackHasNoLanguage && this.stringDefinesNoLang))) ? 1 : -1; + } + // Track should not be selected. + return -1; + } + } else { + return (this.preferredLanguageScore > 0 || (this.selectUndeterminedTextLanguage && this.trackHasNoLanguage)) ? 1 : -1; } - return 0; } } } From 8b554dc30a8d17f1f9d64b72e079e5c2bb82c31e Mon Sep 17 00:00:00 2001 From: Yannick RUI Date: Fri, 19 Jul 2019 08:38:47 +0200 Subject: [PATCH 4/4] Improve code readability and fix an issue with text tracks that should not be selected --- .../trackselection/DefaultTrackSelector.java | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) 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 b5d282f8a7..b830fa5b78 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 @@ -2076,7 +2076,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); TextTrackScore trackScore = new TextTrackScore(format, params, trackFormatSupport[trackIndex], selectedAudioLanguage); - if ((selectedTrackScore == null) || trackScore.compareTo(selectedTrackScore) > 0) { + if (trackScore.isWithinConstraints + && ((selectedTrackScore == null) || trackScore.compareTo(selectedTrackScore) > 0)) { selectedGroup = trackGroup; selectedTrackIndex = trackIndex; selectedTrackScore = trackScore; @@ -2514,8 +2515,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { private final int preferredLanguageScore; private final int selectedAudioLanguageScore; private final boolean trackHasNoLanguage; - private final boolean selectUndeterminedTextLanguage; - private final boolean stringDefinesNoLang; + private final boolean hasLanguageMatch; + private final boolean hasSelectedAudioLanguageMatch; + private final boolean isWithinConstraints; public TextTrackScore( Format format, @@ -2525,13 +2527,17 @@ public class DefaultTrackSelector extends MappingTrackSelector { isWithinRendererCapabilities = isSupported(trackFormatSupport, false); int maskedSelectionFlags = format.selectionFlags & ~parameters.disabledTextTrackSelectionFlags; - isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; + isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0; preferredLanguageScore = getFormatLanguageScore(format, parameters.preferredTextLanguage); selectedAudioLanguageScore = getFormatLanguageScore(format, selectedAudioLanguage); trackHasNoLanguage = formatHasNoLanguage(format); - selectUndeterminedTextLanguage = parameters.selectUndeterminedTextLanguage; - stringDefinesNoLang = stringDefinesNoLanguage(selectedAudioLanguage); + hasLanguageMatch = preferredLanguageScore > 0 + || (parameters.selectUndeterminedTextLanguage && trackHasNoLanguage); + hasSelectedAudioLanguageMatch = (selectedAudioLanguageScore > 0) + || (trackHasNoLanguage && stringDefinesNoLanguage(selectedAudioLanguage)); + isWithinConstraints = + (hasLanguageMatch || isDefault || (isForced && hasSelectedAudioLanguageMatch)); } /** @@ -2546,34 +2552,26 @@ public class DefaultTrackSelector extends MappingTrackSelector { if (this.isWithinRendererCapabilities != other.isWithinRendererCapabilities) { return this.isWithinRendererCapabilities ? 1 : -1; } - if ((this.preferredLanguageScore > 0 || (this.selectUndeterminedTextLanguage && this.trackHasNoLanguage)) == - (other.preferredLanguageScore > 0 || (other.selectUndeterminedTextLanguage && other.trackHasNoLanguage))) { - if (this.preferredLanguageScore > 0 || (this.selectUndeterminedTextLanguage - && this.trackHasNoLanguage)) { - if (this.isDefault != other.isDefault) { - return this.isDefault ? 1 : -1; - } - if (this.isForced != other.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. - return !this.isForced ? 1 : -1; - } - return (this.preferredLanguageScore > other.preferredLanguageScore) ? 1 : -1; - } else { - if (this.isDefault != other.isDefault) { - return this.isDefault ? 1 : -1; - } - if ((this.isForced && (this.selectedAudioLanguageScore > 0 || (this.trackHasNoLanguage && this.stringDefinesNoLang))) != - (other.isForced && (other.selectedAudioLanguageScore > 0 || (other.trackHasNoLanguage && other.stringDefinesNoLang)))) { - return (this.isForced && (this.selectedAudioLanguageScore > 0 - || (this.trackHasNoLanguage && this.stringDefinesNoLang))) ? 1 : -1; - } - // Track should not be selected. - return -1; + if (this.hasLanguageMatch != other.hasLanguageMatch) { + return this.hasLanguageMatch ? 1 : -1; + } + if (this.isDefault != other.isDefault) { + return this.isDefault ? 1 : -1; + } + if (this.hasLanguageMatch) { + if (this.isForced != other.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. + return !this.isForced ? 1 : -1; } + return this.preferredLanguageScore - other.preferredLanguageScore; } else { - return (this.preferredLanguageScore > 0 || (this.selectUndeterminedTextLanguage && this.trackHasNoLanguage)) ? 1 : -1; + if ((this.isForced && this.hasSelectedAudioLanguageMatch) != + (other.isForced && other.hasSelectedAudioLanguageMatch)) { + return (this.isForced && this.hasSelectedAudioLanguageMatch) ? 1 : -1; + } + return 0; } } }