Update DefaultTrackSelector to use more conditions when selecting audio track
Update the audio track selection logic in DefaultTrackSelector: - When forcing lowest bitrate, use bitrate as tie-breaker when track scores are the same, prefer the lower bitrate. - Otherwise, use one of the following values as tie-breaker in order: - ChannelCount - SampleRate - BitRate If the format being checked is within renderer's capabilities, select it if it has higher tie-break value, else, select it if it has lower tie-break value. If all tie-break values are the same, prefer the already selected track. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=171803092
This commit is contained in:
parent
5d4fa335f9
commit
763f663d01
@ -762,10 +762,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||
protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport,
|
||||
Parameters params, TrackSelection.Factory adaptiveTrackSelectionFactory)
|
||||
throws ExoPlaybackException {
|
||||
int selectedGroupIndex = C.INDEX_UNSET;
|
||||
int selectedTrackIndex = C.INDEX_UNSET;
|
||||
int selectedTrackScore = 0;
|
||||
int selectedBitrate = Format.NO_VALUE;
|
||||
int selectedGroupIndex = C.INDEX_UNSET;
|
||||
AudioTrackScore selectedTrackScore = null;
|
||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||
TrackGroup trackGroup = groups.get(groupIndex);
|
||||
int[] trackFormatSupport = formatSupport[groupIndex];
|
||||
@ -773,15 +772,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||
if (isSupported(trackFormatSupport[trackIndex],
|
||||
params.exceedRendererCapabilitiesIfNecessary)) {
|
||||
Format format = trackGroup.getFormat(trackIndex);
|
||||
int trackScore = getAudioTrackScore(trackFormatSupport[trackIndex],
|
||||
params.preferredAudioLanguage, format);
|
||||
if (trackScore > selectedTrackScore
|
||||
|| (trackScore == selectedTrackScore && params.forceLowestBitrate
|
||||
&& compareFormatValues(format.bitrate, selectedBitrate) < 0)) {
|
||||
AudioTrackScore trackScore =
|
||||
new AudioTrackScore(format, params, trackFormatSupport[trackIndex]);
|
||||
if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) {
|
||||
selectedGroupIndex = groupIndex;
|
||||
selectedTrackIndex = trackIndex;
|
||||
selectedTrackScore = trackScore;
|
||||
selectedBitrate = format.bitrate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -804,27 +800,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||
return new FixedTrackSelection(selectedGroup, selectedTrackIndex);
|
||||
}
|
||||
|
||||
private static int getAudioTrackScore(int formatSupport, String preferredLanguage,
|
||||
Format format) {
|
||||
boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
|
||||
int trackScore;
|
||||
if (formatHasLanguage(format, preferredLanguage)) {
|
||||
if (isDefault) {
|
||||
trackScore = 4;
|
||||
} else {
|
||||
trackScore = 3;
|
||||
}
|
||||
} else if (isDefault) {
|
||||
trackScore = 2;
|
||||
} else {
|
||||
trackScore = 1;
|
||||
}
|
||||
if (isSupported(formatSupport, false)) {
|
||||
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
|
||||
}
|
||||
return trackScore;
|
||||
}
|
||||
|
||||
private static int[] getAdaptiveAudioTracks(TrackGroup group, int[] formatSupport,
|
||||
boolean allowMixedMimeTypes) {
|
||||
int selectedConfigurationTrackCount = 0;
|
||||
@ -1090,6 +1065,103 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of how well a track fits with our track selection {@link Parameters}.
|
||||
*
|
||||
* <p>This is used to rank different audio tracks relatively with each other.
|
||||
*/
|
||||
private static final class AudioTrackScore implements Comparable<AudioTrackScore> {
|
||||
private final Parameters parameters;
|
||||
private final int withinRendererCapabilitiesScore;
|
||||
private final int matchLanguageScore;
|
||||
private final int defaultSelectionFlagScore;
|
||||
private final int channelCount;
|
||||
private final int sampleRate;
|
||||
private final int bitrate;
|
||||
|
||||
public AudioTrackScore(Format format, Parameters parameters, int formatSupport) {
|
||||
this.parameters = parameters;
|
||||
withinRendererCapabilitiesScore = isSupported(formatSupport, false) ? 1 : 0;
|
||||
matchLanguageScore = formatHasLanguage(format, parameters.preferredAudioLanguage) ? 1 : 0;
|
||||
defaultSelectionFlagScore = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0 ? 1 : 0;
|
||||
channelCount = format.channelCount;
|
||||
sampleRate = format.sampleRate;
|
||||
bitrate = format.bitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the score of the current track format with another {@link AudioTrackScore}.
|
||||
*
|
||||
* @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(AudioTrackScore other) {
|
||||
if (this.withinRendererCapabilitiesScore != other.withinRendererCapabilitiesScore) {
|
||||
return compareInts(this.withinRendererCapabilitiesScore,
|
||||
other.withinRendererCapabilitiesScore);
|
||||
} else if (this.matchLanguageScore != other.matchLanguageScore) {
|
||||
return compareInts(this.matchLanguageScore, other.matchLanguageScore);
|
||||
} else if (this.defaultSelectionFlagScore != other.defaultSelectionFlagScore) {
|
||||
return compareInts(this.defaultSelectionFlagScore, other.defaultSelectionFlagScore);
|
||||
} else if (parameters.forceLowestBitrate) {
|
||||
return compareInts(other.bitrate, this.bitrate);
|
||||
} else {
|
||||
// If the format are within renderer capabilities, prefer higher values of channel count,
|
||||
// sample rate and bit rate in that order. Otherwise, prefer lower values.
|
||||
int resultSign = withinRendererCapabilitiesScore == 1 ? 1 : -1;
|
||||
if (this.channelCount != other.channelCount) {
|
||||
return resultSign * compareInts(this.channelCount, other.channelCount);
|
||||
} else if (this.sampleRate != other.sampleRate) {
|
||||
return resultSign * compareInts(this.sampleRate, other.sampleRate);
|
||||
}
|
||||
return resultSign * compareInts(this.bitrate, other.bitrate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioTrackScore that = (AudioTrackScore) o;
|
||||
|
||||
return withinRendererCapabilitiesScore == that.withinRendererCapabilitiesScore
|
||||
&& matchLanguageScore == that.matchLanguageScore
|
||||
&& defaultSelectionFlagScore == that.defaultSelectionFlagScore
|
||||
&& channelCount == that.channelCount && sampleRate == that.sampleRate
|
||||
&& bitrate == that.bitrate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = withinRendererCapabilitiesScore;
|
||||
result = 31 * result + matchLanguageScore;
|
||||
result = 31 * result + defaultSelectionFlagScore;
|
||||
result = 31 * result + channelCount;
|
||||
result = 31 * result + sampleRate;
|
||||
result = 31 * result + bitrate;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two integers in a safe way and avoiding potential overflow.
|
||||
*
|
||||
* @param first The first value.
|
||||
* @param second The second value.
|
||||
* @return A negative integer if the first value is less than the second. Zero if they are equal.
|
||||
* A positive integer if the first value is greater than the second.
|
||||
*/
|
||||
private static int compareInts(int first, int second) {
|
||||
return first > second ? 1 : (second > first ? -1 : 0);
|
||||
}
|
||||
|
||||
private static final class AudioConfigurationTuple {
|
||||
|
||||
public final int channelCount;
|
||||
|
@ -0,0 +1,660 @@
|
||||
package com.google.android.exoplayer2.trackselection;
|
||||
|
||||
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES;
|
||||
import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
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.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultTrackSelector}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = Config.TARGET_SDK, manifest = Config.NONE)
|
||||
public final class DefaultTrackSelectorTest {
|
||||
|
||||
private static final Parameters DEFAULT_PARAMETERS = new Parameters();
|
||||
private static final RendererCapabilities ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES =
|
||||
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO);
|
||||
private static final RendererCapabilities ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES =
|
||||
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO, FORMAT_EXCEEDS_CAPABILITIES);
|
||||
|
||||
@Mock
|
||||
private InvalidationListener invalidationListener;
|
||||
|
||||
private DefaultTrackSelector trackSelector;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
initMocks(this);
|
||||
trackSelector = new DefaultTrackSelector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will not call
|
||||
* {@link InvalidationListener#onTrackSelectionsInvalidated()} when it's set with default
|
||||
* values of {@link Parameters}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetParameterWithDefaultParametersDoesNotNotifyInvalidationListener()
|
||||
throws Exception {
|
||||
trackSelector.init(invalidationListener);
|
||||
trackSelector.setParameters(DEFAULT_PARAMETERS);
|
||||
|
||||
verify(invalidationListener, never()).onTrackSelectionsInvalidated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will call {@link InvalidationListener#onTrackSelectionsInvalidated()}
|
||||
* when it's set with non-default values of {@link Parameters}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetParameterWithNonDefaultParameterNotifyInvalidationListener()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withPreferredAudioLanguage("en");
|
||||
trackSelector.init(invalidationListener);
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
verify(invalidationListener).onTrackSelectionsInvalidated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will not call
|
||||
* {@link InvalidationListener#onTrackSelectionsInvalidated()} again when it's set with
|
||||
* the same values of {@link Parameters}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetParameterWithSameParametersDoesNotNotifyInvalidationListenerAgain()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withPreferredAudioLanguage("en");
|
||||
trackSelector.init(invalidationListener);
|
||||
trackSelector.setParameters(parameters);
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
verify(invalidationListener, times(1)).onTrackSelectionsInvalidated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio track with {@link C#SELECTION_FLAG_DEFAULT}
|
||||
* given default values of {@link Parameters}.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksSelectTrackWithSelectionFlag() throws Exception {
|
||||
Format audioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format formatWithSelectionFlag =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, C.SELECTION_FLAG_DEFAULT, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(formatWithSelectionFlag, audioFormat));
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(formatWithSelectionFlag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio track with language that match preferred language
|
||||
* given by {@link Parameters}.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksSelectPreferredAudioLanguage()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withPreferredAudioLanguage("en");
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
Format frAudioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, "fr");
|
||||
Format enAudioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, "en");
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(frAudioFormat, enAudioFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(enAudioFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer selecting audio track with language that match preferred
|
||||
* language given by {@link Parameters} over track with {@link C#SELECTION_FLAG_DEFAULT}.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksSelectPreferredAudioLanguageOverSelectionFlag()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withPreferredAudioLanguage("en");
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
Format frAudioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, C.SELECTION_FLAG_DEFAULT, "fr");
|
||||
Format enAudioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, "en");
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(frAudioFormat, enAudioFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(enAudioFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer tracks that are within renderer's capabilities over
|
||||
* track that exceed renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksPreferTrackWithinCapabilities()
|
||||
throws Exception {
|
||||
Format supportedFormat =
|
||||
Format.createAudioSampleFormat("supportedFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format exceededFormat =
|
||||
Format.createAudioSampleFormat("exceededFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
|
||||
Map<String, Integer> mappedCapabilities = new HashMap<>();
|
||||
mappedCapabilities.put(supportedFormat.id, FORMAT_HANDLED);
|
||||
mappedCapabilities.put(exceededFormat.id, FORMAT_EXCEEDS_CAPABILITIES);
|
||||
RendererCapabilities mappedAudioRendererCapabilities =
|
||||
new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, mappedCapabilities);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {mappedAudioRendererCapabilities},
|
||||
singleTrackGroup(exceededFormat, supportedFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(supportedFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select a track that exceeds the renderer's capabilities when
|
||||
* there are no other choice, given the default {@link Parameters}.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksWithNoTrackWithinCapabilitiesSelectExceededCapabilityTrack()
|
||||
throws Exception {
|
||||
|
||||
Format audioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(audioFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(audioFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will return a null track selection for a renderer when
|
||||
* all tracks exceed that renderer's capabilities when {@link Parameters} does not allow
|
||||
* exceeding-capabilities tracks.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksWithNoTrackWithinCapabilitiesAndSetByParamsReturnNoSelection()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withExceedRendererCapabilitiesIfNecessary(false);
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
Format audioFormat =
|
||||
Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(audioFormat));
|
||||
|
||||
assertThat(result.selections.get(0)).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer tracks that are within renderer's capabilities over
|
||||
* tracks that have {@link C#SELECTION_FLAG_DEFAULT} but exceed renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksPreferTrackWithinCapabilitiesOverSelectionFlag()
|
||||
throws Exception {
|
||||
Format supportedFormat =
|
||||
Format.createAudioSampleFormat("supportedFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format exceededWithSelectionFlagFormat =
|
||||
Format.createAudioSampleFormat("exceededFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, C.SELECTION_FLAG_DEFAULT, null);
|
||||
|
||||
Map<String, Integer> mappedCapabilities = new HashMap<>();
|
||||
mappedCapabilities.put(supportedFormat.id, FORMAT_HANDLED);
|
||||
mappedCapabilities.put(exceededWithSelectionFlagFormat.id, FORMAT_EXCEEDS_CAPABILITIES);
|
||||
RendererCapabilities mappedAudioRendererCapabilities =
|
||||
new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, mappedCapabilities);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {mappedAudioRendererCapabilities},
|
||||
singleTrackGroup(exceededWithSelectionFlagFormat, supportedFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(supportedFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer tracks that are within renderer's capabilities over
|
||||
* track that have language matching preferred audio given by {@link Parameters} but exceed
|
||||
* renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksPreferTrackWithinCapabilitiesOverPreferredLanguage()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withPreferredAudioLanguage("en");
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
Format supportedFrFormat =
|
||||
Format.createAudioSampleFormat("supportedFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, "fr");
|
||||
Format exceededEnFormat =
|
||||
Format.createAudioSampleFormat("exceededFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, "en");
|
||||
|
||||
Map<String, Integer> mappedCapabilities = new HashMap<>();
|
||||
mappedCapabilities.put(exceededEnFormat.id, FORMAT_EXCEEDS_CAPABILITIES);
|
||||
mappedCapabilities.put(supportedFrFormat.id, FORMAT_HANDLED);
|
||||
RendererCapabilities mappedAudioRendererCapabilities =
|
||||
new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, mappedCapabilities);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {mappedAudioRendererCapabilities},
|
||||
singleTrackGroup(exceededEnFormat, supportedFrFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(supportedFrFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer tracks that are within renderer's capabilities over
|
||||
* track that have both language matching preferred audio given by {@link Parameters} and
|
||||
* {@link C#SELECTION_FLAG_DEFAULT}, but exceed renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksPreferTrackWithinCapabilitiesOverSelectionFlagAndPreferredLanguage()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withPreferredAudioLanguage("en");
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
Format supportedFrFormat =
|
||||
Format.createAudioSampleFormat("supportedFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, "fr");
|
||||
Format exceededDefaultSelectionEnFormat =
|
||||
Format.createAudioSampleFormat("exceededFormat", MimeTypes.AUDIO_AAC, null,
|
||||
Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, C.SELECTION_FLAG_DEFAULT, "en");
|
||||
|
||||
Map<String, Integer> mappedCapabilities = new HashMap<>();
|
||||
mappedCapabilities.put(exceededDefaultSelectionEnFormat.id, FORMAT_EXCEEDS_CAPABILITIES);
|
||||
mappedCapabilities.put(supportedFrFormat.id, FORMAT_HANDLED);
|
||||
RendererCapabilities mappedAudioRendererCapabilities =
|
||||
new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, mappedCapabilities);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {mappedAudioRendererCapabilities},
|
||||
singleTrackGroup(exceededDefaultSelectionEnFormat, supportedFrFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(supportedFrFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with higher num channel when other factors
|
||||
* are the same, and tracks are within renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksWithinCapabilitiesSelectHigherNumChannel()
|
||||
throws Exception {
|
||||
Format lowerChannelFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherChannelFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 6, 44100, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherChannelFormat, lowerChannelFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(higherChannelFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with higher sample rate when other factors
|
||||
* are the same, and tracks are within renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksWithinCapabilitiesSelectHigherSampleRate()
|
||||
throws Exception {
|
||||
Format higherSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format lowerSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 22050, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherSampleRateFormat, lowerSampleRateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(higherSampleRateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with higher bit-rate when other factors
|
||||
* are the same, and tracks are within renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksWithinCapabilitiesSelectHigherBitrate()
|
||||
throws Exception {
|
||||
Format lowerBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 15000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 30000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(lowerBitrateFormat, higherBitrateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(higherBitrateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
|
||||
* higher sample rate when other factors are the same, and tracks are within renderer's
|
||||
* capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksPreferHigherNumChannelBeforeSampleRate()
|
||||
throws Exception {
|
||||
Format lowerChannelHigherSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherChannelLowerSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 6, 22050, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherChannelLowerSampleRateFormat, lowerChannelHigherSampleRateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat())
|
||||
.isEqualTo(higherChannelLowerSampleRateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer audio tracks with higher sample rate over tracks with
|
||||
* higher bitrate when other factors are the same, and tracks are within renderer's
|
||||
* capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksPreferHigherSampleRateBeforeBitrate()
|
||||
throws Exception {
|
||||
Format higherSampleRateLowerBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 15000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format lowerSampleRateHigherBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 30000,
|
||||
Format.NO_VALUE, 2, 22050, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherSampleRateLowerBitrateFormat, lowerSampleRateHigherBitrateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat())
|
||||
.isEqualTo(higherSampleRateLowerBitrateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with lower num channel when other factors
|
||||
* are the same, and tracks exceed renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksExceedingCapabilitiesSelectLowerNumChannel()
|
||||
throws Exception {
|
||||
Format lowerChannelFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherChannelFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 6, 44100, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherChannelFormat, lowerChannelFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(lowerChannelFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with lower sample rate when other factors
|
||||
* are the same, and tracks exceed renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksExceedingCapabilitiesSelectLowerSampleRate()
|
||||
throws Exception {
|
||||
Format lowerSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 22050, null, null, 0, null);
|
||||
Format higherSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherSampleRateFormat, lowerSampleRateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(lowerSampleRateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with lower bit-rate when other factors
|
||||
* are the same, and tracks exceed renderer's capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksExceedingCapabilitiesSelectLowerBitrate()
|
||||
throws Exception {
|
||||
Format lowerBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 15000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 30000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(lowerBitrateFormat, higherBitrateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(lowerBitrateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer audio tracks with lower channel count over tracks with
|
||||
* lower sample rate when other factors are the same, and tracks are within renderer's
|
||||
* capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksExceedingCapabilitiesPreferLowerNumChannelBeforeSampleRate()
|
||||
throws Exception {
|
||||
Format lowerChannelHigherSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherChannelLowerSampleRateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE,
|
||||
Format.NO_VALUE, 6, 22050, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherChannelLowerSampleRateFormat, lowerChannelHigherSampleRateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat())
|
||||
.isEqualTo(lowerChannelHigherSampleRateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will prefer audio tracks with lower sample rate over tracks with
|
||||
* lower bitrate when other factors are the same, and tracks are within renderer's
|
||||
* capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksExceedingCapabilitiesPreferLowerSampleRateBeforeBitrate()
|
||||
throws Exception {
|
||||
Format higherSampleRateLowerBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 15000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format lowerSampleRateHigherBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 30000,
|
||||
Format.NO_VALUE, 2, 22050, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_EXCEEDED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(higherSampleRateLowerBitrateFormat, lowerSampleRateHigherBitrateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat())
|
||||
.isEqualTo(lowerSampleRateHigherBitrateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that track selector will select audio tracks with lower bitrate when {@link Parameters}
|
||||
* indicate lowest bitrate preference, even when tracks are within capabilities.
|
||||
*/
|
||||
@Test
|
||||
public void testSelectTracksWithinCapabilitiesAndForceLowestBitrateSelectLowerBitrate()
|
||||
throws Exception {
|
||||
Parameters parameters = DEFAULT_PARAMETERS.withForceLowestBitrate(true);
|
||||
trackSelector.setParameters(parameters);
|
||||
|
||||
Format lowerBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 15000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
Format higherBitrateFormat =
|
||||
Format.createAudioSampleFormat("audioFormat", MimeTypes.AUDIO_AAC, null, 30000,
|
||||
Format.NO_VALUE, 2, 44100, null, null, 0, null);
|
||||
|
||||
TrackSelectorResult result = trackSelector.selectTracks(
|
||||
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||
singleTrackGroup(lowerBitrateFormat, higherBitrateFormat));
|
||||
|
||||
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(lowerBitrateFormat);
|
||||
}
|
||||
|
||||
private static TrackGroupArray singleTrackGroup(Format... formats) {
|
||||
return new TrackGroupArray(new TrackGroup(formats));
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link RendererCapabilities} that advertises support for all formats of a given type using
|
||||
* a provided support value. For any format that does not have the given track type,
|
||||
* {@link #supportsFormat(Format)} will return {@link #FORMAT_UNSUPPORTED_TYPE}.
|
||||
*/
|
||||
private static final class FakeRendererCapabilities implements RendererCapabilities {
|
||||
|
||||
private final int trackType;
|
||||
private final int supportValue;
|
||||
|
||||
/**
|
||||
* Returns {@link FakeRendererCapabilities} that advertises adaptive support for all
|
||||
* tracks of the given type.
|
||||
*
|
||||
* @param trackType the track type of all formats that this renderer capabilities advertises
|
||||
* support for.
|
||||
*/
|
||||
FakeRendererCapabilities(int trackType) {
|
||||
this(trackType, FORMAT_HANDLED | ADAPTIVE_SEAMLESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link FakeRendererCapabilities} that advertises support level using given value
|
||||
* for all tracks of the given type.
|
||||
*
|
||||
* @param trackType the track type of all formats that this renderer capabilities advertises
|
||||
* support for.
|
||||
* @param supportValue the support level value that will be returned for formats with
|
||||
* the given type.
|
||||
*/
|
||||
FakeRendererCapabilities(int trackType, int supportValue) {
|
||||
this.trackType = trackType;
|
||||
this.supportValue = supportValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackType() {
|
||||
return trackType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int supportsFormat(Format format) throws ExoPlaybackException {
|
||||
return MimeTypes.getTrackType(format.sampleMimeType) == trackType
|
||||
? (supportValue) : FORMAT_UNSUPPORTED_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException {
|
||||
return ADAPTIVE_SEAMLESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link RendererCapabilities} that advertises support for different formats using a mapping
|
||||
* between format ID and format-support value.
|
||||
*/
|
||||
private static final class FakeMappedRendererCapabilities implements RendererCapabilities {
|
||||
|
||||
private final int trackType;
|
||||
private final Map<String, Integer> formatToCapability;
|
||||
|
||||
/**
|
||||
* Returns {@link FakeRendererCapabilities} that advertises support level using the given
|
||||
* mapping between format ID and format-support value.
|
||||
*
|
||||
* @param trackType the track type to be returned for {@link #getTrackType()}
|
||||
* @param formatToCapability a map of (format id, support level) that will be used to return
|
||||
* support level for any given format. For any format that's not in the map,
|
||||
* {@link #supportsFormat(Format)} will return {@link #FORMAT_UNSUPPORTED_TYPE}.
|
||||
*/
|
||||
FakeMappedRendererCapabilities(int trackType, Map<String, Integer> formatToCapability) {
|
||||
this.trackType = trackType;
|
||||
this.formatToCapability = new HashMap<>(formatToCapability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackType() {
|
||||
return trackType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int supportsFormat(Format format) throws ExoPlaybackException {
|
||||
return format.id != null && formatToCapability.containsKey(format.id)
|
||||
? formatToCapability.get(format.id)
|
||||
: FORMAT_UNSUPPORTED_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException {
|
||||
return ADAPTIVE_SEAMLESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user