TrackSelection.Factory clean-up.

We currently have two factory methods where it is completely unclear which one needs
to be overridden.

This change deprecates the old one, adds a Util method to easily map back from the new
to the old behaviour, and updates all implementations of the now deprecated method in
our code.

PiperOrigin-RevId: 224303560
This commit is contained in:
tonihei 2018-12-06 10:54:45 +00:00 committed by Andrew Lewis
parent 9a5096ee64
commit 5776bed190
9 changed files with 151 additions and 101 deletions

View file

@ -5,10 +5,13 @@
* Support for playing spherical videos on Daydream.
* Improve decoder re-use between playbacks. TODO: Write and link a blog post
here ([#2826](https://github.com/google/ExoPlayer/issues/2826)).
* Add options for controlling audio track selections to `DefaultTrackSelector`
([#3314](https://github.com/google/ExoPlayer/issues/3314)).
* Track selection:
* Add options for controlling audio track selections to `DefaultTrackSelector`
([#3314](https://github.com/google/ExoPlayer/issues/3314)).
* Update `TrackSelection.Factory` interface to support creating all track
selections together.
* Do not retry failed loads whose error is `FileNotFoundException`.
* Prevent Cea608Decoder from generating Subtitles with null Cues list
* Prevent Cea608Decoder from generating Subtitles with null Cues list.
* Caching: Cache data with unknown length by default. The previous flag to opt
in to this behavior (`DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH`) has been
replaced with an opt out flag (`DataSpec.FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN`).

View file

@ -227,8 +227,36 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
}
@Override
public AdaptiveTrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
public @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
AdaptiveTrackSelection adaptiveSelection = null;
int totalFixedBandwidth = 0;
for (int i = 0; i < definitions.length; i++) {
Definition definition = definitions[i];
if (definition == null) {
continue;
}
if (definition.tracks.length > 1) {
adaptiveSelection =
createAdaptiveTrackSelection(definition.group, bandwidthMeter, definition.tracks);
selections[i] = adaptiveSelection;
} else {
selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]);
int trackBitrate = definition.group.getFormat(definition.tracks[0]).bitrate;
if (trackBitrate != Format.NO_VALUE) {
totalFixedBandwidth += trackBitrate;
}
}
}
if (blockFixedTrackSelectionBandwidth && adaptiveSelection != null) {
adaptiveSelection.experimental_setNonAllocatableBandwidth(totalFixedBandwidth);
}
return selections;
}
private AdaptiveTrackSelection createAdaptiveTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int[] tracks) {
if (this.bandwidthMeter != null) {
bandwidthMeter = this.bandwidthMeter;
}
@ -246,34 +274,6 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
adaptiveTrackSelection.experimental_setTrackBitrateEstimator(trackBitrateEstimator);
return adaptiveTrackSelection;
}
@Override
public @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
AdaptiveTrackSelection adaptiveSelection = null;
int totalFixedBandwidth = 0;
for (int i = 0; i < definitions.length; i++) {
Definition definition = definitions[i];
if (definition == null) {
continue;
}
if (definition.tracks.length > 1) {
selections[i] = createTrackSelection(definition.group, bandwidthMeter, definition.tracks);
adaptiveSelection = (AdaptiveTrackSelection) selections[i];
} else {
selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]);
int trackBitrate = definition.group.getFormat(definition.tracks[0]).bitrate;
if (trackBitrate != Format.NO_VALUE) {
totalFixedBandwidth += trackBitrate;
}
}
}
if (blockFixedTrackSelectionBandwidth && adaptiveSelection != null) {
adaptiveSelection.experimental_setNonAllocatableBandwidth(totalFixedBandwidth);
}
return selections;
}
}
public static final int DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS = 10000;

View file

@ -24,12 +24,14 @@ import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.trackselection.TrackSelection.Definition;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* Builder for a {@link TrackSelection.Factory} and {@link LoadControl} that implement buffer size
@ -273,19 +275,22 @@ public final class BufferSizeAdaptationBuilder {
TrackSelection.Factory trackSelectionFactory =
new TrackSelection.Factory() {
@Override
public TrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
return new BufferSizeAdaptiveTrackSelection(
group,
tracks,
bandwidthMeter,
minBufferMs,
maxBufferMs,
hysteresisBufferMs,
startUpBandwidthFraction,
startUpMinBufferForQualityIncreaseMs,
dynamicFormatFilter,
clock);
public @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
return TrackSelectionUtil.createTrackSelectionsForDefinitions(
definitions,
definition ->
new BufferSizeAdaptiveTrackSelection(
definition.group,
definition.tracks,
bandwidthMeter,
minBufferMs,
maxBufferMs,
hysteresisBufferMs,
startUpBandwidthFraction,
startUpMinBufferForQualityIncreaseMs,
dynamicFormatFilter,
clock));
}
};

View file

@ -21,8 +21,8 @@ import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* A {@link TrackSelection} consisting of a single track.
@ -56,10 +56,12 @@ public final class FixedTrackSelection extends BaseTrackSelection {
}
@Override
public FixedTrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
Assertions.checkArgument(tracks.length == 1);
return new FixedTrackSelection(group, tracks[0], reason, data);
public @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
return TrackSelectionUtil.createTrackSelectionsForDefinitions(
definitions,
definition ->
new FixedTrackSelection(definition.group, definition.tracks[0], reason, data));
}
}

View file

@ -24,6 +24,7 @@ import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import java.util.List;
import java.util.Random;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* A {@link TrackSelection} whose selected track is updated randomly.
@ -49,9 +50,11 @@ public final class RandomTrackSelection extends BaseTrackSelection {
}
@Override
public RandomTrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
return new RandomTrackSelection(group, tracks, random);
public @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
return TrackSelectionUtil.createTrackSelectionsForDefinitions(
definitions,
definition -> new RandomTrackSelection(definition.group, definition.tracks, random));
}
}

View file

@ -21,8 +21,8 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.trackselection.TrackSelectionUtil.AdaptiveTrackSelectionFactory;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
@ -61,42 +61,31 @@ public interface TrackSelection {
interface Factory {
/**
* Creates a new selection.
*
* @param group The {@link TrackGroup}. Must not be null.
* @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks.
* @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be
* null or empty. May be in any order.
* @return The created selection.
* @deprecated Implement {@link #createTrackSelections(Definition[], BandwidthMeter)} instead.
* Calling {@link TrackSelectionUtil#createTrackSelectionsForDefinitions(Definition[],
* AdaptiveTrackSelectionFactory)} helps to create a single adaptive track selection in the
* same way as using this deprecated method.
*/
TrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks);
@Deprecated
default TrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
throw new UnsupportedOperationException();
}
/**
* Creates a new selection for each {@link Definition}.
*
* @param definitions A {@link Definition} array. May include null values.
* @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks.
* @return The created selections. For null entries in {@code definitions} returns null values.
* @return The created selections. Must have the same length as {@code definitions} and may
* include null values.
*/
@SuppressWarnings("deprecation")
default @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
boolean createdAdaptiveTrackSelection = false;
for (int i = 0; i < definitions.length; i++) {
Definition definition = definitions[i];
if (definition == null) {
continue;
}
if (definition.tracks.length > 1) {
Assertions.checkState(!createdAdaptiveTrackSelection);
createdAdaptiveTrackSelection = true;
selections[i] = createTrackSelection(definition.group, bandwidthMeter, definition.tracks);
} else {
selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]);
}
}
return selections;
return TrackSelectionUtil.createTrackSelectionsForDefinitions(
definitions,
definition -> createTrackSelection(definition.group, bandwidthMeter, definition.tracks));
}
}

View file

@ -22,15 +22,59 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.source.chunk.MediaChunkListIterator;
import com.google.android.exoplayer2.trackselection.TrackSelection.Definition;
import com.google.android.exoplayer2.util.Assertions;
import java.util.Arrays;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** Track selection related utility methods. */
public final class TrackSelectionUtil {
private TrackSelectionUtil() {}
/** Functional interface to create a single adaptive track selection. */
public interface AdaptiveTrackSelectionFactory {
/**
* Creates an adaptive track selection for the provided track selection definition.
*
* @param trackSelectionDefinition A {@link Definition} for the track selection.
* @return The created track selection.
*/
TrackSelection createAdaptiveTrackSelection(Definition trackSelectionDefinition);
}
/**
* Creates track selections for an array of track selection definitions, with at most one
* multi-track adaptive selection.
*
* @param definitions The list of track selection {@link Definition definitions}. May include null
* values.
* @param adaptiveTrackSelectionFactory A factory for the multi-track adaptive track selection.
* @return The array of created track selection. For null entries in {@code definitions} returns
* null values.
*/
public static @NullableType TrackSelection[] createTrackSelectionsForDefinitions(
@NullableType Definition[] definitions,
AdaptiveTrackSelectionFactory adaptiveTrackSelectionFactory) {
TrackSelection[] selections = new TrackSelection[definitions.length];
boolean createdAdaptiveTrackSelection = false;
for (int i = 0; i < definitions.length; i++) {
Definition definition = definitions[i];
if (definition == null) {
continue;
}
if (definition.tracks.length > 1 && !createdAdaptiveTrackSelection) {
createdAdaptiveTrackSelection = true;
selections[i] = adaptiveTrackSelectionFactory.createAdaptiveTrackSelection(definition);
} else {
selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]);
}
}
return selections;
}
/**
* Returns average bitrate for chunks in bits per second. Chunks are included in average until
* {@code maxDurationMs} or the first unknown length chunk.

View file

@ -32,6 +32,7 @@ import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.testutil.FakeClock;
import com.google.android.exoplayer2.testutil.FakeMediaChunk;
import com.google.android.exoplayer2.trackselection.TrackSelection.Definition;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes;
import java.util.ArrayList;
@ -66,15 +67,20 @@ public final class AdaptiveTrackSelectionTest {
}
@Test
@SuppressWarnings("deprecation")
public void testFactoryUsesInitiallyProvidedBandwidthMeter() {
BandwidthMeter initialBandwidthMeter = mock(BandwidthMeter.class);
BandwidthMeter injectedBandwidthMeter = mock(BandwidthMeter.class);
Format format = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240);
@SuppressWarnings("deprecation")
AdaptiveTrackSelection adaptiveTrackSelection =
Format format1 = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240);
Format format2 = videoFormat(/* bitrate= */ 1000, /* width= */ 640, /* height= */ 480);
TrackSelection[] trackSelections =
new AdaptiveTrackSelection.Factory(initialBandwidthMeter)
.createTrackSelection(new TrackGroup(format), injectedBandwidthMeter, /* tracks= */ 0);
adaptiveTrackSelection.updateSelectedTrack(
.createTrackSelections(
new Definition[] {
new Definition(new TrackGroup(format1, format2), /* tracks= */ 0, 1)
},
injectedBandwidthMeter);
trackSelections[0].updateSelectedTrack(
/* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0,
/* availableDurationUs= */ C.TIME_UNSET,

View file

@ -79,8 +79,19 @@ public class FakeTrackSelector extends DefaultTrackSelector {
}
@Override
public TrackSelection createTrackSelection(
TrackGroup trackGroup, BandwidthMeter bandwidthMeter, int... tracks) {
public TrackSelection[] createTrackSelections(
TrackSelection.Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
for (int i = 0; i < definitions.length; i++) {
TrackSelection.Definition definition = definitions[i];
if (definition != null) {
selections[i] = createTrackSelection(definition.group);
}
}
return selections;
}
private TrackSelection createTrackSelection(TrackGroup trackGroup) {
if (mayReuseTrackSelection) {
for (FakeTrackSelection trackSelection : trackSelections) {
if (trackSelection.getTrackGroup().equals(trackGroup)) {
@ -92,18 +103,5 @@ public class FakeTrackSelector extends DefaultTrackSelector {
trackSelections.add(trackSelection);
return trackSelection;
}
@Override
public TrackSelection[] createTrackSelections(
TrackSelection.Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length];
for (int i = 0; i < definitions.length; i++) {
TrackSelection.Definition definition = definitions[i];
if (definition != null) {
selections[i] = createTrackSelection(definition.group, bandwidthMeter, definition.tracks);
}
}
return selections;
}
}
}