Commit 7bbe213e by olly Committed by Oliver Woodman

Add option to select track that exceeds renderer capabilities

Leaving disabled by default for now, but we may want to consider
enabling it by default. Note that in V1 for ExtractorSampleSource
the behaviour was equivalent to this option being enabled, since
we didn't perform capabilities checks. For DASH/SS/HLS the V1
behaviour was equivalent to this option being disabled.

The type in PlayerActivity has been changed just to make it
easier to add a line that calls setParameters.

Issue: #2034
Issue: #2007
Issue: #2078

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=140477568
parent 2753664c
...@@ -55,7 +55,6 @@ import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource ...@@ -55,7 +55,6 @@ import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveVideoTrackSelection; import com.google.android.exoplayer2.trackselection.AdaptiveVideoTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
...@@ -109,7 +108,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay ...@@ -109,7 +108,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
private DataSource.Factory mediaDataSourceFactory; private DataSource.Factory mediaDataSourceFactory;
private SimpleExoPlayer player; private SimpleExoPlayer player;
private MappingTrackSelector trackSelector; private DefaultTrackSelector trackSelector;
private TrackSelectionHelper trackSelectionHelper; private TrackSelectionHelper trackSelectionHelper;
private DebugTextViewHelper debugViewHelper; private DebugTextViewHelper debugViewHelper;
private boolean playerNeedsSource; private boolean playerNeedsSource;
......
...@@ -55,6 +55,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -55,6 +55,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
public final int maxVideoWidth; public final int maxVideoWidth;
public final int maxVideoHeight; public final int maxVideoHeight;
public final boolean exceedVideoConstraintsIfNecessary; public final boolean exceedVideoConstraintsIfNecessary;
public final boolean exceedRendererCapabilitiesIfNecessary;
public final int viewportWidth; public final int viewportWidth;
public final int viewportHeight; public final int viewportHeight;
public final boolean orientationMayChange; public final boolean orientationMayChange;
...@@ -67,13 +68,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -67,13 +68,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* <li>Adaptation between different mime types is not allowed.</li> * <li>Adaptation between different mime types is not allowed.</li>
* <li>Non seamless adaptation is allowed.</li> * <li>Non seamless adaptation is allowed.</li>
* <li>No max limit for video width/height.</li> * <li>No max limit for video width/height.</li>
* <li>Video constraints are ignored if no supported selection can be made otherwise.</li> * <li>Video constraints are exceeded if no supported selection can be made otherwise.</li>
* <li>Renderer capabilities are not exceeded even if no supported selection can be made.</li>
* <li>No viewport width/height constraints are set.</li> * <li>No viewport width/height constraints are set.</li>
* </ul> * </ul>
*/ */
public Parameters() { public Parameters() {
this(null, null, false, true, Integer.MAX_VALUE, Integer.MAX_VALUE, true, Integer.MAX_VALUE, this(null, null, false, true, Integer.MAX_VALUE, Integer.MAX_VALUE, true, false,
Integer.MAX_VALUE, true); Integer.MAX_VALUE, Integer.MAX_VALUE, true);
} }
/** /**
...@@ -86,8 +88,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -86,8 +88,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param allowNonSeamlessAdaptiveness Whether non-seamless adaptation is allowed. * @param allowNonSeamlessAdaptiveness Whether non-seamless adaptation is allowed.
* @param maxVideoWidth Maximum allowed video width. * @param maxVideoWidth Maximum allowed video width.
* @param maxVideoHeight Maximum allowed video height. * @param maxVideoHeight Maximum allowed video height.
* @param exceedVideoConstraintsIfNecessary True to ignore video constraints when no selections * @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
* can be made otherwise. False to force constraints anyway. * selection can be made otherwise.
* @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no
* selection can be made otherwise.
* @param viewportWidth Viewport width in pixels. * @param viewportWidth Viewport width in pixels.
* @param viewportHeight Viewport height in pixels. * @param viewportHeight Viewport height in pixels.
* @param orientationMayChange Whether orientation may change during playback. * @param orientationMayChange Whether orientation may change during playback.
...@@ -95,7 +99,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -95,7 +99,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
public Parameters(String preferredAudioLanguage, String preferredTextLanguage, public Parameters(String preferredAudioLanguage, String preferredTextLanguage,
boolean allowMixedMimeAdaptiveness, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness, boolean allowNonSeamlessAdaptiveness,
int maxVideoWidth, int maxVideoHeight, boolean exceedVideoConstraintsIfNecessary, int maxVideoWidth, int maxVideoHeight, boolean exceedVideoConstraintsIfNecessary,
int viewportWidth, int viewportHeight, boolean orientationMayChange) { boolean exceedRendererCapabilitiesIfNecessary, int viewportWidth, int viewportHeight,
boolean orientationMayChange) {
this.preferredAudioLanguage = preferredAudioLanguage; this.preferredAudioLanguage = preferredAudioLanguage;
this.preferredTextLanguage = preferredTextLanguage; this.preferredTextLanguage = preferredTextLanguage;
this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness; this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness;
...@@ -103,6 +108,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -103,6 +108,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.maxVideoWidth = maxVideoWidth; this.maxVideoWidth = maxVideoWidth;
this.maxVideoHeight = maxVideoHeight; this.maxVideoHeight = maxVideoHeight;
this.exceedVideoConstraintsIfNecessary = exceedVideoConstraintsIfNecessary; this.exceedVideoConstraintsIfNecessary = exceedVideoConstraintsIfNecessary;
this.exceedRendererCapabilitiesIfNecessary = exceedRendererCapabilitiesIfNecessary;
this.viewportWidth = viewportWidth; this.viewportWidth = viewportWidth;
this.viewportHeight = viewportHeight; this.viewportHeight = viewportHeight;
this.orientationMayChange = orientationMayChange; this.orientationMayChange = orientationMayChange;
...@@ -124,7 +130,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -124,7 +130,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, orientationMayChange); exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
viewportHeight, orientationMayChange);
} }
/** /**
...@@ -140,9 +147,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -140,9 +147,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoHeight, exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
orientationMayChange); viewportHeight, orientationMayChange);
} }
/** /**
...@@ -156,9 +163,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -156,9 +163,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoHeight, exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
orientationMayChange); viewportHeight, orientationMayChange);
} }
/** /**
...@@ -172,9 +179,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -172,9 +179,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoHeight, exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
orientationMayChange); viewportHeight, orientationMayChange);
} }
/** /**
...@@ -189,9 +196,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -189,9 +196,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoHeight, exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
orientationMayChange); viewportHeight, orientationMayChange);
} }
/** /**
...@@ -216,8 +223,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -216,8 +223,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* Returns a {@link Parameters} instance with the provided * Returns a {@link Parameters} instance with the provided
* {@code exceedVideoConstraintsIfNecessary} value. * {@code exceedVideoConstraintsIfNecessary} value.
* *
* @param exceedVideoConstraintsIfNecessary True to ignore video constraints when no selections * @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no
* can be made otherwise. False to force constraints anyway. * selection can be made otherwise.
* @return A {@link Parameters} instance with the provided * @return A {@link Parameters} instance with the provided
* {@code exceedVideoConstraintsIfNecessary} value. * {@code exceedVideoConstraintsIfNecessary} value.
*/ */
...@@ -227,9 +234,29 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -227,9 +234,29 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoHeight, exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
orientationMayChange); viewportHeight, orientationMayChange);
}
/**
* Returns a {@link Parameters} instance with the provided
* {@code exceedRendererCapabilitiesIfNecessary} value.
*
* @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no
* selection can be made otherwise.
* @return A {@link Parameters} instance with the provided
* {@code exceedRendererCapabilitiesIfNecessary} value.
*/
public Parameters withExceedRendererCapabilitiesIfNecessary(
boolean exceedRendererCapabilitiesIfNecessary) {
if (exceedRendererCapabilitiesIfNecessary == this.exceedRendererCapabilitiesIfNecessary) {
return this;
}
return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
viewportHeight, orientationMayChange);
} }
/** /**
...@@ -247,9 +274,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -247,9 +274,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this; return this;
} }
return new Parameters(preferredAudioLanguage, preferredTextLanguage, return new Parameters(preferredAudioLanguage, preferredTextLanguage,
allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight,
maxVideoHeight, exceedVideoConstraintsIfNecessary, viewportWidth, viewportHeight, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, viewportWidth,
orientationMayChange); viewportHeight, orientationMayChange);
} }
/** /**
...@@ -289,6 +316,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -289,6 +316,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& allowNonSeamlessAdaptiveness == other.allowNonSeamlessAdaptiveness && allowNonSeamlessAdaptiveness == other.allowNonSeamlessAdaptiveness
&& maxVideoWidth == other.maxVideoWidth && maxVideoHeight == other.maxVideoHeight && maxVideoWidth == other.maxVideoWidth && maxVideoHeight == other.maxVideoHeight
&& exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary && exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
&& orientationMayChange == other.orientationMayChange && orientationMayChange == other.orientationMayChange
&& viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight && viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight
&& TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage) && TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage)
...@@ -304,6 +332,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -304,6 +332,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + maxVideoWidth; result = 31 * result + maxVideoWidth;
result = 31 * result + maxVideoHeight; result = 31 * result + maxVideoHeight;
result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0); result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
result = 31 * result + (orientationMayChange ? 1 : 0); result = 31 * result + (orientationMayChange ? 1 : 0);
result = 31 * result + viewportWidth; result = 31 * result + viewportWidth;
result = 31 * result + viewportHeight; result = 31 * result + viewportHeight;
...@@ -319,9 +348,10 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -319,9 +348,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
private static final float FRACTION_TO_CONSIDER_FULLSCREEN = 0.98f; private static final float FRACTION_TO_CONSIDER_FULLSCREEN = 0.98f;
private static final int[] NO_TRACKS = new int[0]; private static final int[] NO_TRACKS = new int[0];
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
private final TrackSelection.Factory adaptiveVideoTrackSelectionFactory; private final TrackSelection.Factory adaptiveVideoTrackSelectionFactory;
private final AtomicReference<Parameters> params; private final AtomicReference<Parameters> paramsReference;
/** /**
* Constructs an instance that does not support adaptive video. * Constructs an instance that does not support adaptive video.
...@@ -338,7 +368,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -338,7 +368,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/ */
public DefaultTrackSelector(TrackSelection.Factory adaptiveVideoTrackSelectionFactory) { public DefaultTrackSelector(TrackSelection.Factory adaptiveVideoTrackSelectionFactory) {
this.adaptiveVideoTrackSelectionFactory = adaptiveVideoTrackSelectionFactory; this.adaptiveVideoTrackSelectionFactory = adaptiveVideoTrackSelectionFactory;
params = new AtomicReference<>(new Parameters()); paramsReference = new AtomicReference<>(new Parameters());
} }
/** /**
...@@ -347,8 +377,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -347,8 +377,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param params The parameters for track selection. * @param params The parameters for track selection.
*/ */
public void setParameters(Parameters params) { public void setParameters(Parameters params) {
if (!this.params.get().equals(params)) { Assertions.checkNotNull(params);
this.params.set(Assertions.checkNotNull(params)); if (!paramsReference.getAndSet(params).equals(params)) {
invalidate(); invalidate();
} }
} }
...@@ -359,7 +389,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -359,7 +389,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @return The current selection parameters. * @return The current selection parameters.
*/ */
public Parameters getParameters() { public Parameters getParameters() {
return params.get(); return paramsReference.get();
} }
// MappingTrackSelector implementation. // MappingTrackSelector implementation.
...@@ -370,7 +400,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -370,7 +400,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
throws ExoPlaybackException { throws ExoPlaybackException {
// Make a track selection for each renderer. // Make a track selection for each renderer.
TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCapabilities.length]; TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCapabilities.length];
Parameters params = this.params.get(); Parameters params = paramsReference.get();
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:
...@@ -379,20 +409,23 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -379,20 +409,23 @@ public class DefaultTrackSelector extends MappingTrackSelector {
params.maxVideoHeight, params.allowNonSeamlessAdaptiveness, params.maxVideoHeight, params.allowNonSeamlessAdaptiveness,
params.allowMixedMimeAdaptiveness, params.viewportWidth, params.viewportHeight, params.allowMixedMimeAdaptiveness, params.viewportWidth, params.viewportHeight,
params.orientationMayChange, adaptiveVideoTrackSelectionFactory, params.orientationMayChange, adaptiveVideoTrackSelectionFactory,
params.exceedVideoConstraintsIfNecessary); params.exceedVideoConstraintsIfNecessary,
params.exceedRendererCapabilitiesIfNecessary);
break; break;
case C.TRACK_TYPE_AUDIO: case C.TRACK_TYPE_AUDIO:
rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i], rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i],
rendererFormatSupports[i], params.preferredAudioLanguage); rendererFormatSupports[i], params.preferredAudioLanguage,
params.exceedRendererCapabilitiesIfNecessary);
break; break;
case C.TRACK_TYPE_TEXT: case C.TRACK_TYPE_TEXT:
rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i], rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i],
rendererFormatSupports[i], params.preferredTextLanguage, rendererFormatSupports[i], params.preferredTextLanguage,
params.preferredAudioLanguage); params.preferredAudioLanguage, params.exceedRendererCapabilitiesIfNecessary);
break; break;
default: default:
rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(), rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(),
rendererTrackGroupArrays[i], rendererFormatSupports[i]); rendererTrackGroupArrays[i], rendererFormatSupports[i],
params.exceedRendererCapabilitiesIfNecessary);
break; break;
} }
} }
...@@ -406,7 +439,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -406,7 +439,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness, int viewportWidth, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness, int viewportWidth,
int viewportHeight, boolean orientationMayChange, int viewportHeight, boolean orientationMayChange,
TrackSelection.Factory adaptiveVideoTrackSelectionFactory, TrackSelection.Factory adaptiveVideoTrackSelectionFactory,
boolean exceedConstraintsIfNecessary) throws ExoPlaybackException { boolean exceedConstraintsIfNecessary, boolean exceedRendererCapabilitiesIfNecessary)
throws ExoPlaybackException {
TrackSelection selection = null; TrackSelection selection = null;
if (adaptiveVideoTrackSelectionFactory != null) { if (adaptiveVideoTrackSelectionFactory != null) {
selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport, selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport,
...@@ -416,7 +450,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -416,7 +450,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} }
if (selection == null) { if (selection == null) {
selection = selectFixedVideoTrack(groups, formatSupport, maxVideoWidth, maxVideoHeight, selection = selectFixedVideoTrack(groups, formatSupport, maxVideoWidth, maxVideoHeight,
viewportWidth, viewportHeight, orientationMayChange, exceedConstraintsIfNecessary); viewportWidth, viewportHeight, orientationMayChange, exceedConstraintsIfNecessary,
exceedRendererCapabilitiesIfNecessary);
} }
return selection; return selection;
} }
...@@ -512,7 +547,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -512,7 +547,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static boolean isSupportedAdaptiveVideoTrack(Format format, String mimeType, private static boolean isSupportedAdaptiveVideoTrack(Format format, String mimeType,
int formatSupport, int requiredAdaptiveSupport, int maxVideoWidth, int maxVideoHeight) { int formatSupport, int requiredAdaptiveSupport, int maxVideoWidth, int maxVideoHeight) {
return isSupported(formatSupport) && ((formatSupport & requiredAdaptiveSupport) != 0) return isSupported(formatSupport, false) && ((formatSupport & requiredAdaptiveSupport) != 0)
&& (mimeType == null || Util.areEqual(format.sampleMimeType, mimeType)) && (mimeType == null || Util.areEqual(format.sampleMimeType, mimeType))
&& (format.width == Format.NO_VALUE || format.width <= maxVideoWidth) && (format.width == Format.NO_VALUE || format.width <= maxVideoWidth)
&& (format.height == Format.NO_VALUE || format.height <= maxVideoHeight); && (format.height == Format.NO_VALUE || format.height <= maxVideoHeight);
...@@ -520,37 +555,44 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -520,37 +555,44 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static TrackSelection selectFixedVideoTrack(TrackGroupArray groups, private static TrackSelection selectFixedVideoTrack(TrackGroupArray groups,
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,
boolean exceedRendererCapabilitiesIfNecessary) {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = 0;
int selectedTrackScore = 0;
int selectedPixelCount = Format.NO_VALUE; int selectedPixelCount = Format.NO_VALUE;
boolean selectedIsWithinConstraints = false;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup group = groups.get(groupIndex); TrackGroup trackGroup = groups.get(groupIndex);
List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(group, viewportWidth, List<Integer> selectedTrackIndices = getViewportFilteredTrackIndices(trackGroup,
viewportHeight, orientationMayChange); viewportWidth, viewportHeight, orientationMayChange);
int[] trackFormatSupport = formatSupport[groupIndex]; int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex])) { if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) {
Format format = group.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
boolean isWithinConstraints = selectedTrackIndices.contains(trackIndex) boolean isWithinConstraints = selectedTrackIndices.contains(trackIndex)
&& (format.width == Format.NO_VALUE || format.width <= maxVideoWidth) && (format.width == Format.NO_VALUE || format.width <= maxVideoWidth)
&& (format.height == Format.NO_VALUE || format.height <= maxVideoHeight); && (format.height == Format.NO_VALUE || format.height <= maxVideoHeight);
int pixelCount = format.getPixelCount(); if (!isWithinConstraints && !exceedConstraintsIfNecessary) {
boolean selectTrack; // Track should not be selected.
if (selectedIsWithinConstraints) { continue;
selectTrack = isWithinConstraints }
&& comparePixelCounts(pixelCount, selectedPixelCount) > 0; int trackScore = isWithinConstraints ? 2 : 1;
} else { if (isSupported(trackFormatSupport[trackIndex], false)) {
selectTrack = isWithinConstraints || (exceedConstraintsIfNecessary trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
&& (selectedGroup == null }
|| comparePixelCounts(pixelCount, selectedPixelCount) < 0)); boolean selectTrack = trackScore > selectedTrackScore;
if (trackScore == selectedTrackScore) {
// Use the pixel count as a tie breaker. If we're within constraints prefer a higher
// pixel count, else prefer a lower count. If still tied then prefer the first track
// (i.e. the one that's already selected).
int pixelComparison = comparePixelCounts(format.getPixelCount(), selectedPixelCount);
selectTrack = isWithinConstraints ? pixelComparison > 0 : pixelComparison < 0;
} }
if (selectTrack) { if (selectTrack) {
selectedGroup = group; selectedGroup = trackGroup;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
selectedPixelCount = pixelCount; selectedTrackScore = trackScore;
selectedIsWithinConstraints = isWithinConstraints; selectedPixelCount = format.getPixelCount();
} }
} }
} }
...@@ -577,7 +619,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -577,7 +619,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Audio track selection implementation. // Audio track selection implementation.
protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport, protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport,
String preferredAudioLanguage) { String preferredAudioLanguage, boolean exceedRendererCapabilitiesIfNecessary) {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = 0;
int selectedTrackScore = 0; int selectedTrackScore = 0;
...@@ -585,7 +627,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -585,7 +627,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
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], exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
int trackScore; int trackScore;
...@@ -600,6 +642,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -600,6 +642,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
} else { } else {
trackScore = 1; trackScore = 1;
} }
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
}
if (trackScore > selectedTrackScore) { if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup; selectedGroup = trackGroup;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
...@@ -615,7 +660,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -615,7 +660,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Text track selection implementation. // Text track selection implementation.
protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport, protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
String preferredTextLanguage, String preferredAudioLanguage) { String preferredTextLanguage, String preferredAudioLanguage,
boolean exceedRendererCapabilitiesIfNecessary) {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = 0;
int selectedTrackScore = 0; int selectedTrackScore = 0;
...@@ -623,7 +669,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -623,7 +669,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
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], exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
boolean isForced = (format.selectionFlags & C.SELECTION_FLAG_FORCED) != 0; boolean isForced = (format.selectionFlags & C.SELECTION_FLAG_FORCED) != 0;
...@@ -648,7 +694,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -648,7 +694,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
trackScore = 1; trackScore = 1;
} }
} else { } else {
trackScore = 0; // Track should not be selected.
continue;
}
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
} }
if (trackScore > selectedTrackScore) { if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup; selectedGroup = trackGroup;
...@@ -665,7 +715,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -665,7 +715,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General track selection methods. // General track selection methods.
protected TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups, protected TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups,
int[][] formatSupport) { int[][] formatSupport, boolean exceedRendererCapabilitiesIfNecessary) {
TrackGroup selectedGroup = null; TrackGroup selectedGroup = null;
int selectedTrackIndex = 0; int selectedTrackIndex = 0;
int selectedTrackScore = 0; int selectedTrackScore = 0;
...@@ -673,10 +723,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -673,10 +723,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
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], exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex); Format format = trackGroup.getFormat(trackIndex);
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
int trackScore = isDefault ? 2 : 1; int trackScore = isDefault ? 2 : 1;
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
}
if (trackScore > selectedTrackScore) { if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup; selectedGroup = trackGroup;
selectedTrackIndex = trackIndex; selectedTrackIndex = trackIndex;
...@@ -689,12 +742,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -689,12 +742,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
: new FixedTrackSelection(selectedGroup, selectedTrackIndex); : new FixedTrackSelection(selectedGroup, selectedTrackIndex);
} }
private static boolean isSupported(int formatSupport) { protected static boolean isSupported(int formatSupport, boolean allowExceedsCapabilities) {
return (formatSupport & RendererCapabilities.FORMAT_SUPPORT_MASK) int maskedSupport = formatSupport & RendererCapabilities.FORMAT_SUPPORT_MASK;
== RendererCapabilities.FORMAT_HANDLED; return maskedSupport == RendererCapabilities.FORMAT_HANDLED || (allowExceedsCapabilities
&& maskedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES);
} }
private static boolean formatHasLanguage(Format format, String language) { protected static boolean formatHasLanguage(Format format, String language) {
return language != null && language.equals(Util.normalizeLanguageCode(format.language)); return language != null && language.equals(Util.normalizeLanguageCode(format.language));
} }
......
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