Commit 5776bed1 by tonihei Committed by Andrew Lewis

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
parent 9a5096ee
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
* Support for playing spherical videos on Daydream. * Support for playing spherical videos on Daydream.
* Improve decoder re-use between playbacks. TODO: Write and link a blog post * Improve decoder re-use between playbacks. TODO: Write and link a blog post
here ([#2826](https://github.com/google/ExoPlayer/issues/2826)). here ([#2826](https://github.com/google/ExoPlayer/issues/2826)).
* Add options for controlling audio track selections to `DefaultTrackSelector` * Track selection:
([#3314](https://github.com/google/ExoPlayer/issues/3314)). * 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`. * 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 * 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 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`). replaced with an opt out flag (`DataSpec.FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN`).
......
...@@ -227,27 +227,6 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { ...@@ -227,27 +227,6 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
} }
@Override @Override
public AdaptiveTrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
if (this.bandwidthMeter != null) {
bandwidthMeter = this.bandwidthMeter;
}
AdaptiveTrackSelection adaptiveTrackSelection =
new AdaptiveTrackSelection(
group,
tracks,
new DefaultBandwidthProvider(bandwidthMeter, bandwidthFraction),
minDurationForQualityIncreaseMs,
maxDurationForQualityDecreaseMs,
minDurationToRetainAfterDiscardMs,
bufferedFractionToLiveEdgeForQualityIncrease,
minTimeBetweenBufferReevaluationMs,
clock);
adaptiveTrackSelection.experimental_setTrackBitrateEstimator(trackBitrateEstimator);
return adaptiveTrackSelection;
}
@Override
public @NullableType TrackSelection[] createTrackSelections( public @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) { @NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length]; TrackSelection[] selections = new TrackSelection[definitions.length];
...@@ -259,8 +238,9 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { ...@@ -259,8 +238,9 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
continue; continue;
} }
if (definition.tracks.length > 1) { if (definition.tracks.length > 1) {
selections[i] = createTrackSelection(definition.group, bandwidthMeter, definition.tracks); adaptiveSelection =
adaptiveSelection = (AdaptiveTrackSelection) selections[i]; createAdaptiveTrackSelection(definition.group, bandwidthMeter, definition.tracks);
selections[i] = adaptiveSelection;
} else { } else {
selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]); selections[i] = new FixedTrackSelection(definition.group, definition.tracks[0]);
int trackBitrate = definition.group.getFormat(definition.tracks[0]).bitrate; int trackBitrate = definition.group.getFormat(definition.tracks[0]).bitrate;
...@@ -274,6 +254,26 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { ...@@ -274,6 +254,26 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
} }
return selections; return selections;
} }
private AdaptiveTrackSelection createAdaptiveTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int[] tracks) {
if (this.bandwidthMeter != null) {
bandwidthMeter = this.bandwidthMeter;
}
AdaptiveTrackSelection adaptiveTrackSelection =
new AdaptiveTrackSelection(
group,
tracks,
new DefaultBandwidthProvider(bandwidthMeter, bandwidthFraction),
minDurationForQualityIncreaseMs,
maxDurationForQualityDecreaseMs,
minDurationToRetainAfterDiscardMs,
bufferedFractionToLiveEdgeForQualityIncrease,
minTimeBetweenBufferReevaluationMs,
clock);
adaptiveTrackSelection.experimental_setTrackBitrateEstimator(trackBitrateEstimator);
return adaptiveTrackSelection;
}
} }
public static final int DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS = 10000; public static final int DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS = 10000;
......
...@@ -24,12 +24,14 @@ import com.google.android.exoplayer2.LoadControl; ...@@ -24,12 +24,14 @@ import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk; import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; 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.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultAllocator; import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.PriorityTaskManager; import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** /**
* Builder for a {@link TrackSelection.Factory} and {@link LoadControl} that implement buffer size * Builder for a {@link TrackSelection.Factory} and {@link LoadControl} that implement buffer size
...@@ -273,19 +275,22 @@ public final class BufferSizeAdaptationBuilder { ...@@ -273,19 +275,22 @@ public final class BufferSizeAdaptationBuilder {
TrackSelection.Factory trackSelectionFactory = TrackSelection.Factory trackSelectionFactory =
new TrackSelection.Factory() { new TrackSelection.Factory() {
@Override @Override
public TrackSelection createTrackSelection( public @NullableType TrackSelection[] createTrackSelections(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) { @NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
return new BufferSizeAdaptiveTrackSelection( return TrackSelectionUtil.createTrackSelectionsForDefinitions(
group, definitions,
tracks, definition ->
bandwidthMeter, new BufferSizeAdaptiveTrackSelection(
minBufferMs, definition.group,
maxBufferMs, definition.tracks,
hysteresisBufferMs, bandwidthMeter,
startUpBandwidthFraction, minBufferMs,
startUpMinBufferForQualityIncreaseMs, maxBufferMs,
dynamicFormatFilter, hysteresisBufferMs,
clock); startUpBandwidthFraction,
startUpMinBufferForQualityIncreaseMs,
dynamicFormatFilter,
clock));
} }
}; };
......
...@@ -21,8 +21,8 @@ import com.google.android.exoplayer2.source.TrackGroup; ...@@ -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.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** /**
* A {@link TrackSelection} consisting of a single track. * A {@link TrackSelection} consisting of a single track.
...@@ -56,10 +56,12 @@ public final class FixedTrackSelection extends BaseTrackSelection { ...@@ -56,10 +56,12 @@ public final class FixedTrackSelection extends BaseTrackSelection {
} }
@Override @Override
public FixedTrackSelection createTrackSelection( public @NullableType TrackSelection[] createTrackSelections(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) { @NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
Assertions.checkArgument(tracks.length == 1); return TrackSelectionUtil.createTrackSelectionsForDefinitions(
return new FixedTrackSelection(group, tracks[0], reason, data); definitions,
definition ->
new FixedTrackSelection(definition.group, definition.tracks[0], reason, data));
} }
} }
......
...@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; ...@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** /**
* A {@link TrackSelection} whose selected track is updated randomly. * A {@link TrackSelection} whose selected track is updated randomly.
...@@ -49,9 +50,11 @@ public final class RandomTrackSelection extends BaseTrackSelection { ...@@ -49,9 +50,11 @@ public final class RandomTrackSelection extends BaseTrackSelection {
} }
@Override @Override
public RandomTrackSelection createTrackSelection( public @NullableType TrackSelection[] createTrackSelections(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) { @NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
return new RandomTrackSelection(group, tracks, random); return TrackSelectionUtil.createTrackSelectionsForDefinitions(
definitions,
definition -> new RandomTrackSelection(definition.group, definition.tracks, random));
} }
} }
......
...@@ -21,8 +21,8 @@ import com.google.android.exoplayer2.Format; ...@@ -21,8 +21,8 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk; import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; 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.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.compatqual.NullableType;
...@@ -61,42 +61,31 @@ public interface TrackSelection { ...@@ -61,42 +61,31 @@ public interface TrackSelection {
interface Factory { interface Factory {
/** /**
* Creates a new selection. * @deprecated Implement {@link #createTrackSelections(Definition[], BandwidthMeter)} instead.
* * Calling {@link TrackSelectionUtil#createTrackSelectionsForDefinitions(Definition[],
* @param group The {@link TrackGroup}. Must not be null. * AdaptiveTrackSelectionFactory)} helps to create a single adaptive track selection in the
* @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks. * same way as using this deprecated method.
* @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.
*/ */
TrackSelection createTrackSelection( @Deprecated
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks); default TrackSelection createTrackSelection(
TrackGroup group, BandwidthMeter bandwidthMeter, int... tracks) {
throw new UnsupportedOperationException();
}
/** /**
* Creates a new selection for each {@link Definition}. * Creates a new selection for each {@link Definition}.
* *
* @param definitions A {@link Definition} array. May include null values. * @param definitions A {@link Definition} array. May include null values.
* @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks. * @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( default @NullableType TrackSelection[] createTrackSelections(
@NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) { @NullableType Definition[] definitions, BandwidthMeter bandwidthMeter) {
TrackSelection[] selections = new TrackSelection[definitions.length]; return TrackSelectionUtil.createTrackSelectionsForDefinitions(
boolean createdAdaptiveTrackSelection = false; definitions,
for (int i = 0; i < definitions.length; i++) { definition -> createTrackSelection(definition.group, bandwidthMeter, definition.tracks));
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;
} }
} }
......
...@@ -22,15 +22,59 @@ import com.google.android.exoplayer2.Format; ...@@ -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.MediaChunk;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.source.chunk.MediaChunkListIterator; import com.google.android.exoplayer2.source.chunk.MediaChunkListIterator;
import com.google.android.exoplayer2.trackselection.TrackSelection.Definition;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** Track selection related utility methods. */ /** Track selection related utility methods. */
public final class TrackSelectionUtil { public final class TrackSelectionUtil {
private 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 * Returns average bitrate for chunks in bits per second. Chunks are included in average until
* {@code maxDurationMs} or the first unknown length chunk. * {@code maxDurationMs} or the first unknown length chunk.
......
...@@ -32,6 +32,7 @@ import com.google.android.exoplayer2.source.TrackGroup; ...@@ -32,6 +32,7 @@ import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; import com.google.android.exoplayer2.source.chunk.MediaChunkIterator;
import com.google.android.exoplayer2.testutil.FakeClock; import com.google.android.exoplayer2.testutil.FakeClock;
import com.google.android.exoplayer2.testutil.FakeMediaChunk; 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.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -66,15 +67,20 @@ public final class AdaptiveTrackSelectionTest { ...@@ -66,15 +67,20 @@ public final class AdaptiveTrackSelectionTest {
} }
@Test @Test
@SuppressWarnings("deprecation")
public void testFactoryUsesInitiallyProvidedBandwidthMeter() { public void testFactoryUsesInitiallyProvidedBandwidthMeter() {
BandwidthMeter initialBandwidthMeter = mock(BandwidthMeter.class); BandwidthMeter initialBandwidthMeter = mock(BandwidthMeter.class);
BandwidthMeter injectedBandwidthMeter = mock(BandwidthMeter.class); BandwidthMeter injectedBandwidthMeter = mock(BandwidthMeter.class);
Format format = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240); Format format1 = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240);
@SuppressWarnings("deprecation") Format format2 = videoFormat(/* bitrate= */ 1000, /* width= */ 640, /* height= */ 480);
AdaptiveTrackSelection adaptiveTrackSelection = TrackSelection[] trackSelections =
new AdaptiveTrackSelection.Factory(initialBandwidthMeter) new AdaptiveTrackSelection.Factory(initialBandwidthMeter)
.createTrackSelection(new TrackGroup(format), injectedBandwidthMeter, /* tracks= */ 0); .createTrackSelections(
adaptiveTrackSelection.updateSelectedTrack( new Definition[] {
new Definition(new TrackGroup(format1, format2), /* tracks= */ 0, 1)
},
injectedBandwidthMeter);
trackSelections[0].updateSelectedTrack(
/* playbackPositionUs= */ 0, /* playbackPositionUs= */ 0,
/* bufferedDurationUs= */ 0, /* bufferedDurationUs= */ 0,
/* availableDurationUs= */ C.TIME_UNSET, /* availableDurationUs= */ C.TIME_UNSET,
......
...@@ -79,8 +79,19 @@ public class FakeTrackSelector extends DefaultTrackSelector { ...@@ -79,8 +79,19 @@ public class FakeTrackSelector extends DefaultTrackSelector {
} }
@Override @Override
public TrackSelection createTrackSelection( public TrackSelection[] createTrackSelections(
TrackGroup trackGroup, BandwidthMeter bandwidthMeter, int... tracks) { 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) { if (mayReuseTrackSelection) {
for (FakeTrackSelection trackSelection : trackSelections) { for (FakeTrackSelection trackSelection : trackSelections) {
if (trackSelection.getTrackGroup().equals(trackGroup)) { if (trackSelection.getTrackGroup().equals(trackGroup)) {
...@@ -92,18 +103,5 @@ public class FakeTrackSelector extends DefaultTrackSelector { ...@@ -92,18 +103,5 @@ public class FakeTrackSelector extends DefaultTrackSelector {
trackSelections.add(trackSelection); trackSelections.add(trackSelection);
return 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;
}
} }
} }
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