Commit b15ceba7 by olly Committed by Oliver Woodman

Enhance DefaultTrackSelector part 2

- Support specifying a preferred text language.
- Score based selection for text/audio/other tracks.
- Prefer default tracks to non-default ones.
- Allow overriding of base select*Track methods.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=129626994
parent 95f41134
...@@ -34,7 +34,6 @@ import java.lang.reflect.Method; ...@@ -34,7 +34,6 @@ import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
/** /**
* A {@link MappingTrackSelector} that allows configuration of common parameters. * A {@link MappingTrackSelector} that allows configuration of common parameters.
...@@ -52,10 +51,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -52,10 +51,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final TrackSelection.Factory adaptiveVideoTrackSelectionFactory; private final TrackSelection.Factory adaptiveVideoTrackSelectionFactory;
// Audio and text. // Audio.
private String preferredLanguage; private String preferredAudioLanguage;
//Video. // Text.
private String preferredTextLanguage;
// Video.
private boolean allowMixedMimeAdaptiveness; private boolean allowMixedMimeAdaptiveness;
private boolean allowNonSeamlessAdaptiveness; private boolean allowNonSeamlessAdaptiveness;
private int maxVideoWidth; private int maxVideoWidth;
...@@ -97,14 +99,29 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -97,14 +99,29 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
/** /**
* Sets the preferred language for audio and text tracks. * Sets the preferred language for audio, as well as for forced text tracks.
* *
* @param preferredLanguage The language as defined by RFC 5646. * @param preferredAudioLanguage The preferred language as defined by RFC 5646. {@code null} to
* select the default track, or first track if there's no default.
*/ */
public void setPreferredLanguage(String preferredLanguage) { public void setPreferredLanguages(String preferredAudioLanguage) {
String adjustedPreferredLanguage = new Locale(preferredLanguage).getLanguage(); preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage);
if (!Util.areEqual(this.preferredLanguage, adjustedPreferredLanguage)) { if (!Util.areEqual(this.preferredAudioLanguage, preferredAudioLanguage)) {
this.preferredLanguage = adjustedPreferredLanguage; this.preferredAudioLanguage = preferredAudioLanguage;
invalidate();
}
}
/**
* Sets the preferred language for text tracks.
*
* @param preferredTextLanguage The preferred language as defined by RFC 5646. {@code null} to
* select the default track, or no track if there's no default.
*/
public void setPreferredTextLanguage(String preferredTextLanguage) {
preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage);
if (!Util.areEqual(this.preferredTextLanguage, preferredTextLanguage)) {
this.preferredTextLanguage = preferredTextLanguage;
invalidate(); invalidate();
} }
} }
...@@ -221,23 +238,23 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -221,23 +238,23 @@ public class DefaultTrackSelector extends MappingTrackSelector {
for (int i = 0; i < rendererCapabilities.length; i++) { for (int i = 0; i < rendererCapabilities.length; i++) {
switch (rendererCapabilities[i].getTrackType()) { switch (rendererCapabilities[i].getTrackType()) {
case C.TRACK_TYPE_VIDEO: case C.TRACK_TYPE_VIDEO:
rendererTrackSelections[i] = selectTrackForVideoRenderer(rendererCapabilities[i], rendererTrackSelections[i] = selectVideoTrack(rendererCapabilities[i],
rendererTrackGroupArrays[i], rendererFormatSupports[i], maxVideoWidth, maxVideoHeight, rendererTrackGroupArrays[i], rendererFormatSupports[i], maxVideoWidth, maxVideoHeight,
allowNonSeamlessAdaptiveness, allowMixedMimeAdaptiveness, viewportWidth, allowNonSeamlessAdaptiveness, allowMixedMimeAdaptiveness, viewportWidth,
viewportHeight, orientationMayChange, adaptiveVideoTrackSelectionFactory, viewportHeight, orientationMayChange, adaptiveVideoTrackSelectionFactory,
exceedVideoConstraintsIfNecessary); exceedVideoConstraintsIfNecessary);
break; break;
case C.TRACK_TYPE_AUDIO: case C.TRACK_TYPE_AUDIO:
rendererTrackSelections[i] = selectTrackForAudioRenderer(rendererTrackGroupArrays[i], rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i],
rendererFormatSupports[i], preferredLanguage); rendererFormatSupports[i], preferredAudioLanguage);
break; break;
case C.TRACK_TYPE_TEXT: case C.TRACK_TYPE_TEXT:
rendererTrackSelections[i] = selectTrackForTextRenderer(rendererTrackGroupArrays[i], rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i],
rendererFormatSupports[i], preferredLanguage); rendererFormatSupports[i], preferredTextLanguage, preferredAudioLanguage);
break; break;
default: default:
rendererTrackSelections[i] = selectFirstSupportedTrack(rendererTrackGroupArrays[i], rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(),
rendererFormatSupports[i]); rendererTrackGroupArrays[i], rendererFormatSupports[i]);
break; break;
} }
} }
...@@ -246,11 +263,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -246,11 +263,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Video track selection implementation. // Video track selection implementation.
private static TrackSelection selectTrackForVideoRenderer( protected TrackSelection selectVideoTrack(RendererCapabilities rendererCapabilities,
RendererCapabilities rendererCapabilities, TrackGroupArray groups, int[][] formatSupport, TrackGroupArray groups, int[][] formatSupport, int maxVideoWidth, int maxVideoHeight,
int maxVideoWidth, int maxVideoHeight, boolean allowNonSeamlessAdaptiveness, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness, int viewportWidth,
boolean allowMixedMimeAdaptiveness, int viewportWidth, int viewportHeight, int viewportHeight, boolean orientationMayChange,
boolean orientationMayChange, TrackSelection.Factory adaptiveVideoTrackSelectionFactory, TrackSelection.Factory adaptiveVideoTrackSelectionFactory,
boolean exceedConstraintsIfNecessary) throws ExoPlaybackException { boolean exceedConstraintsIfNecessary) throws ExoPlaybackException {
TrackSelection selection = null; TrackSelection selection = null;
if (adaptiveVideoTrackSelectionFactory != null) { if (adaptiveVideoTrackSelectionFactory != null) {
...@@ -371,7 +388,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -371,7 +388,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int[][] formatSupport, int maxVideoWidth, int maxVideoHeight, int viewportWidth, int[][] formatSupport, int maxVideoWidth, int maxVideoHeight, int viewportWidth,
int viewportHeight, boolean orientationMayChange, boolean exceedConstraintsIfNecessary) { int viewportHeight, boolean orientationMayChange, boolean exceedConstraintsIfNecessary) {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = -1; int selectedTrackIndex = 0;
int selectedPixelCount = Format.NO_VALUE; int selectedPixelCount = Format.NO_VALUE;
boolean selectedIsWithinConstraints = false; boolean selectedIsWithinConstraints = false;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
...@@ -425,65 +442,117 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -425,65 +442,117 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Audio track selection implementation. // Audio track selection implementation.
private static TrackSelection selectTrackForAudioRenderer(TrackGroupArray groups, protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport,
int[][] formatSupport, String preferredLanguage) { String preferredAudioLanguage) {
if (preferredLanguage != null) { TrackGroup selectedGroup = null;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { int selectedTrackIndex = 0;
TrackGroup trackGroup = groups.get(groupIndex); int selectedTrackScore = 0;
int[] trackFormatSupport = formatSupport[groupIndex]; for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { TrackGroup trackGroup = groups.get(groupIndex);
if (isSupported(trackFormatSupport[trackIndex]) int[] trackFormatSupport = formatSupport[groupIndex];
&& formatHasLanguage(trackGroup.getFormat(trackIndex), preferredLanguage)) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
return new FixedTrackSelection(trackGroup, trackIndex); if (isSupported(trackFormatSupport[trackIndex])) {
Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & Format.SELECTION_FLAG_DEFAULT) != 0;
int trackScore;
if (formatHasLanguage(format, preferredAudioLanguage)) {
if (isDefault) {
trackScore = 4;
} else {
trackScore = 3;
}
} else if (isDefault) {
trackScore = 2;
} else {
trackScore = 1;
}
if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup;
selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore;
} }
} }
} }
} }
// No preferred language was selected or no audio track presented the preferred language. return selectedGroup == null ? null
return selectFirstSupportedTrack(groups, formatSupport); : new FixedTrackSelection(selectedGroup, selectedTrackIndex);
} }
// Text track selection implementation. // Text track selection implementation.
private static TrackSelection selectTrackForTextRenderer(TrackGroupArray groups, protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
int[][] formatSupport, String preferredLanguage) { String preferredTextLanguage, String preferredAudioLanguage) {
TrackGroup firstForcedGroup = null; TrackGroup selectedGroup = null;
int firstForcedTrack = -1; int selectedTrackIndex = 0;
int selectedTrackScore = 0;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex); TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex]; int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex]) if (isSupported(trackFormatSupport[trackIndex])) {
&& (trackGroup.getFormat(trackIndex).selectionFlags Format format = trackGroup.getFormat(trackIndex);
& Format.SELECTION_FLAG_FORCED) != 0) { boolean isDefault = (format.selectionFlags & Format.SELECTION_FLAG_DEFAULT) != 0;
if (firstForcedGroup == null) { boolean isForced = (format.selectionFlags & Format.SELECTION_FLAG_FORCED) != 0;
firstForcedGroup = trackGroup; int trackScore;
firstForcedTrack = trackIndex; if (formatHasLanguage(format, preferredTextLanguage)) {
if (isDefault) {
trackScore = 6;
} 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 = 5;
} else {
trackScore = 4;
}
} else if (isDefault) {
trackScore = 3;
} else if (isForced) {
if (formatHasLanguage(format, preferredAudioLanguage)) {
trackScore = 2;
} else {
trackScore = 1;
}
} else {
trackScore = 0;
} }
if (formatHasLanguage(trackGroup.getFormat(trackIndex), preferredLanguage)) { if (trackScore > selectedTrackScore) {
return new FixedTrackSelection(trackGroup, trackIndex); selectedGroup = trackGroup;
selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore;
} }
} }
} }
} }
return firstForcedGroup == null ? null return selectedGroup == null ? null
: new FixedTrackSelection(firstForcedGroup, firstForcedTrack); : new FixedTrackSelection(selectedGroup, selectedTrackIndex);
} }
// General track selection methods. // General track selection methods.
private static TrackSelection selectFirstSupportedTrack(TrackGroupArray groups, protected TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups,
int[][] formatSupport) { int[][] formatSupport) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex); TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex]; int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex])) { if (isSupported(trackFormatSupport[trackIndex])) {
return new FixedTrackSelection(trackGroup, trackIndex); Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & Format.SELECTION_FLAG_DEFAULT) != 0;
int trackScore = isDefault ? 2 : 1;
if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup;
selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore;
}
} }
} }
} }
return null; return selectedGroup == null ? null
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
} }
private static boolean isSupported(int formatSupport) { private static boolean isSupported(int formatSupport) {
...@@ -492,7 +561,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -492,7 +561,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
private static boolean formatHasLanguage(Format format, String language) { private static boolean formatHasLanguage(Format format, String language) {
return language != null && language.equals(new Locale(format.language).getLanguage()); return language != null && language.equals(Util.normalizeLanguageCode(format.language));
} }
// Viewport size util methods. // Viewport size util methods.
...@@ -605,7 +674,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -605,7 +674,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay(); Display display = windowManager.getDefaultDisplay();
Point displaySize = new Point(); Point displaySize = new Point();
if (Util.SDK_INT >= 23) { if (Util.SDK_INT >= 23) {
getDisplaySizeV23(display, displaySize); getDisplaySizeV23(display, displaySize);
} else if (Util.SDK_INT >= 17) { } else if (Util.SDK_INT >= 17) {
......
...@@ -240,6 +240,16 @@ public final class Util { ...@@ -240,6 +240,16 @@ public final class Util {
} }
/** /**
* Returns a normalized RFC 5646 language code.
*
* @param language A possibly non-normalized RFC 5646 language code.
* @return The normalized code, or null if the input was null.
*/
public static String normalizeLanguageCode(String language) {
return language == null ? null : new Locale(language).getLanguage();
}
/**
* Returns a new byte array containing the code points of a {@link String} encoded using UTF-8. * Returns a new byte array containing the code points of a {@link String} encoded using UTF-8.
* *
* @param value The {@link String} whose bytes should be obtained. * @param value The {@link String} whose bytes should be obtained.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment