Commit 442aa781 by Oliver Woodman

Merge pull request #7814 from zubcoco:dev-v2

PiperOrigin-RevId: 330366909
parents 99dbb764 7bfde6a5
......@@ -6,6 +6,8 @@
* Add `SampleQueue.discardUpstreamFrom` so upstream samples can be
discarded by timestamp.
* Add `SampleQueue.getLargestReadTimestampUs`.
* Track selection:
* Add option to specify multiple preferred audio or text languages.
### 2.12.0 (not yet released - targeted for 2020-09-03) ###
......
......@@ -39,6 +39,7 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
import java.util.ArrayList;
......@@ -450,6 +451,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this;
}
@Override
public ParametersBuilder setPreferredAudioLanguages(String... preferredAudioLanguages) {
super.setPreferredAudioLanguages(preferredAudioLanguages);
return this;
}
/**
* Sets the maximum allowed audio channel count.
*
......@@ -547,6 +554,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
@Override
public ParametersBuilder setPreferredTextLanguages(String... preferredTextLanguages) {
super.setPreferredTextLanguages(preferredTextLanguages);
return this;
}
@Override
public ParametersBuilder setPreferredTextRoleFlags(@C.RoleFlags int preferredTextRoleFlags) {
super.setPreferredTextRoleFlags(preferredTextRoleFlags);
return this;
......@@ -767,7 +780,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
viewportHeight,
viewportOrientationMayChange,
// Audio
preferredAudioLanguage,
preferredAudioLanguages,
maxAudioChannelCount,
maxAudioBitrate,
exceedAudioConstraintsIfNecessary,
......@@ -775,7 +788,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
allowAudioMixedSampleRateAdaptiveness,
allowAudioMixedChannelCountAdaptiveness,
// Text
preferredTextLanguage,
preferredTextLanguages,
preferredTextRoleFlags,
selectUndeterminedTextLanguage,
disabledTextTrackSelectionFlags,
......@@ -1015,7 +1028,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int viewportHeight,
boolean viewportOrientationMayChange,
// Audio
@Nullable String preferredAudioLanguage,
ImmutableList<String> preferredAudioLanguages,
int maxAudioChannelCount,
int maxAudioBitrate,
boolean exceedAudioConstraintsIfNecessary,
......@@ -1023,7 +1036,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
boolean allowAudioMixedSampleRateAdaptiveness,
boolean allowAudioMixedChannelCountAdaptiveness,
// Text
@Nullable String preferredTextLanguage,
ImmutableList<String> preferredTextLanguages,
@C.RoleFlags int preferredTextRoleFlags,
boolean selectUndeterminedTextLanguage,
@C.SelectionFlags int disabledTextTrackSelectionFlags,
......@@ -1036,8 +1049,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>> selectionOverrides,
SparseBooleanArray rendererDisabledFlags) {
super(
preferredAudioLanguage,
preferredTextLanguage,
preferredAudioLanguages,
preferredTextLanguages,
preferredTextRoleFlags,
selectUndeterminedTextLanguage,
disabledTextTrackSelectionFlags);
......@@ -2607,6 +2620,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final Parameters parameters;
private final boolean isWithinRendererCapabilities;
private final int preferredLanguageScore;
private final int preferredLanguageIndex;
private final int localeLanguageMatchIndex;
private final int localeLanguageScore;
private final boolean isDefaultSelectionFlag;
......@@ -2619,11 +2633,22 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.language = normalizeUndeterminedLanguageToNull(format.language);
isWithinRendererCapabilities =
isSupported(formatSupport, /* allowExceedsCapabilities= */ false);
preferredLanguageScore =
getFormatLanguageScore(
format,
parameters.preferredAudioLanguage,
/* allowUndeterminedFormatLanguage= */ false);
int bestLanguageScore = 0;
int bestLanguageIndex = Integer.MAX_VALUE;
for (int i = 0; i < parameters.preferredAudioLanguages.size(); i++) {
int score =
getFormatLanguageScore(
format,
parameters.preferredAudioLanguages.get(i),
/* allowUndeterminedFormatLanguage= */ false);
if (score > 0) {
bestLanguageIndex = i;
bestLanguageScore = score;
break;
}
}
preferredLanguageIndex = bestLanguageIndex;
preferredLanguageScore = bestLanguageScore;
isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
channelCount = format.channelCount;
sampleRate = format.sampleRate;
......@@ -2666,6 +2691,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
: FORMAT_VALUE_ORDERING.reverse();
return ComparisonChain.start()
.compareFalseFirst(this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
.compare(
this.preferredLanguageIndex,
other.preferredLanguageIndex,
Ordering.natural().reverse())
.compare(this.preferredLanguageScore, other.preferredLanguageScore)
.compareFalseFirst(this.isWithinConstraints, other.isWithinConstraints)
.compare(
......@@ -2701,6 +2730,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final boolean isWithinRendererCapabilities;
private final boolean isDefault;
private final boolean isForced;
private final int preferredLanguageIndex;
private final int preferredLanguageScore;
private final int preferredRoleFlagsScore;
private final int selectedAudioLanguageScore;
......@@ -2717,9 +2747,26 @@ public class DefaultTrackSelector extends MappingTrackSelector {
format.selectionFlags & ~parameters.disabledTextTrackSelectionFlags;
isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0;
preferredLanguageScore =
getFormatLanguageScore(
format, parameters.preferredTextLanguage, parameters.selectUndeterminedTextLanguage);
int bestLanguageIndex = Integer.MAX_VALUE;
int bestLanguageScore = 0;
// Compare against empty (unset) language if no preference is given to allow the selection of
// a text track with undetermined language.
ImmutableList<String> preferredLanguages =
parameters.preferredTextLanguages.isEmpty()
? ImmutableList.of("")
: parameters.preferredTextLanguages;
for (int i = 0; i < preferredLanguages.size(); i++) {
int score =
getFormatLanguageScore(
format, preferredLanguages.get(i), parameters.selectUndeterminedTextLanguage);
if (score > 0) {
bestLanguageIndex = i;
bestLanguageScore = score;
break;
}
}
preferredLanguageIndex = bestLanguageIndex;
preferredLanguageScore = bestLanguageScore;
preferredRoleFlagsScore =
Integer.bitCount(format.roleFlags & parameters.preferredTextRoleFlags);
hasCaptionRoleFlags =
......@@ -2730,7 +2777,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
getFormatLanguageScore(format, selectedAudioLanguage, selectedAudioLanguageUndetermined);
isWithinConstraints =
preferredLanguageScore > 0
|| (parameters.preferredTextLanguage == null && preferredRoleFlagsScore > 0)
|| (parameters.preferredTextLanguages.isEmpty() && preferredRoleFlagsScore > 0)
|| isDefault
|| (isForced && selectedAudioLanguageScore > 0);
}
......@@ -2748,6 +2795,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
ComparisonChain.start()
.compareFalseFirst(
this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
.compare(
this.preferredLanguageIndex,
other.preferredLanguageIndex,
Ordering.natural().reverse())
.compare(this.preferredLanguageScore, other.preferredLanguageScore)
.compare(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore)
.compareFalseFirst(this.isDefault, other.isDefault)
......
......@@ -19,6 +19,7 @@ import static com.google.android.exoplayer2.RendererCapabilities.ADAPTIVE_NOT_SE
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES;
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED;
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE;
import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_NOT_SUPPORTED;
import static com.google.android.exoplayer2.RendererConfiguration.DEFAULT;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
......@@ -37,6 +38,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
......@@ -50,6 +52,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationLi
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
......@@ -67,7 +70,8 @@ public final class DefaultTrackSelectorTest {
private static final RendererCapabilities ALL_TEXT_FORMAT_SUPPORTED_RENDERER_CAPABILITIES =
new FakeRendererCapabilities(C.TRACK_TYPE_TEXT);
private static final RendererCapabilities ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES =
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO, FORMAT_EXCEEDS_CAPABILITIES);
new FakeRendererCapabilities(
C.TRACK_TYPE_AUDIO, RendererCapabilities.create(FORMAT_EXCEEDS_CAPABILITIES));
private static final RendererCapabilities VIDEO_CAPABILITIES =
new FakeRendererCapabilities(C.TRACK_TYPE_VIDEO);
......@@ -1318,7 +1322,10 @@ public final class DefaultTrackSelectorTest {
@Test
public void selectTracksWithMultipleVideoTracksWithNonSeamlessAdaptiveness() throws Exception {
FakeRendererCapabilities nonSeamlessVideoCapabilities =
new FakeRendererCapabilities(C.TRACK_TYPE_VIDEO, FORMAT_HANDLED | ADAPTIVE_NOT_SEAMLESS);
new FakeRendererCapabilities(
C.TRACK_TYPE_VIDEO,
RendererCapabilities.create(
FORMAT_HANDLED, ADAPTIVE_NOT_SEAMLESS, TUNNELING_NOT_SUPPORTED));
// Should do non-seamless adaptiveness by default, so expect an adaptive selection.
Format.Builder formatBuilder = VIDEO_FORMAT.buildUpon();
......@@ -1508,7 +1515,7 @@ public final class DefaultTrackSelectorTest {
/* viewportHeight= */ 9,
/* viewportOrientationMayChange= */ true,
// Audio
/* preferredAudioLanguage= */ "en",
/* preferredAudioLanguages= */ ImmutableList.of("zh", "jp"),
/* maxAudioChannelCount= */ 10,
/* maxAudioBitrate= */ 11,
/* exceedAudioConstraintsIfNecessary= */ false,
......@@ -1516,10 +1523,10 @@ public final class DefaultTrackSelectorTest {
/* allowAudioMixedSampleRateAdaptiveness= */ false,
/* allowAudioMixedChannelCountAdaptiveness= */ true,
// Text
/* preferredTextLanguage= */ "de",
/* preferredTextLanguages= */ ImmutableList.of("de", "en"),
/* preferredTextRoleFlags= */ C.ROLE_FLAG_CAPTION,
/* selectUndeterminedTextLanguage= */ true,
/* disabledTextTrackSelectionFlags= */ 12,
/* disabledTextTrackSelectionFlags= */ C.SELECTION_FLAG_AUTOSELECT,
// General
/* forceLowestBitrate= */ false,
/* forceHighestSupportedBitrate= */ true,
......
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