Remove nullablity of track groups and selections in MediaPeriodHolder.

These values can easily default to the empty track group and the empty
selection. As a result we can remove restrictions about not calling
holder.getTrackGroups before the period finished preparation.

PiperOrigin-RevId: 261280927
This commit is contained in:
tonihei 2019-08-02 09:28:17 +01:00 committed by Oliver Woodman
parent 5eab519925
commit 0887ab059c
5 changed files with 49 additions and 42 deletions

View file

@ -1108,7 +1108,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
return; return;
} }
newTrackSelectorResult = periodHolder.selectTracks(playbackSpeed, playbackInfo.timeline); newTrackSelectorResult = periodHolder.selectTracks(playbackSpeed, playbackInfo.timeline);
if (newTrackSelectorResult != null) { if (!newTrackSelectorResult.isEquivalent(periodHolder.getTrackSelectorResult())) {
// Selected tracks have changed for this period. // Selected tracks have changed for this period.
break; break;
} }
@ -1197,13 +1197,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void notifyTrackSelectionDiscontinuity() { private void notifyTrackSelectionDiscontinuity() {
MediaPeriodHolder periodHolder = queue.getFrontPeriod(); MediaPeriodHolder periodHolder = queue.getFrontPeriod();
while (periodHolder != null) { while (periodHolder != null) {
TrackSelectorResult trackSelectorResult = periodHolder.getTrackSelectorResult(); TrackSelection[] trackSelections = periodHolder.getTrackSelectorResult().selections.getAll();
if (trackSelectorResult != null) { for (TrackSelection trackSelection : trackSelections) {
TrackSelection[] trackSelections = trackSelectorResult.selections.getAll(); if (trackSelection != null) {
for (TrackSelection trackSelection : trackSelections) { trackSelection.onDiscontinuity();
if (trackSelection != null) {
trackSelection.onDiscontinuity();
}
} }
} }
periodHolder = periodHolder.getNext(); periodHolder = periodHolder.getNext();
@ -1506,7 +1503,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
} else { } else {
MediaPeriod mediaPeriod = MediaPeriod mediaPeriod =
queue.enqueueNextMediaPeriod( queue.enqueueNextMediaPeriod(
rendererCapabilities, trackSelector, loadControl.getAllocator(), mediaSource, info); rendererCapabilities,
trackSelector,
loadControl.getAllocator(),
mediaSource,
info,
emptyTrackSelectorResult);
mediaPeriod.prepare(this, info.startPositionUs); mediaPeriod.prepare(this, info.startPositionUs);
setIsLoading(true); setIsLoading(true);
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false); handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false);

View file

@ -59,8 +59,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
private final MediaSource mediaSource; private final MediaSource mediaSource;
@Nullable private MediaPeriodHolder next; @Nullable private MediaPeriodHolder next;
@Nullable private TrackGroupArray trackGroups; private TrackGroupArray trackGroups;
@Nullable private TrackSelectorResult trackSelectorResult; private TrackSelectorResult trackSelectorResult;
private long rendererPositionOffsetUs; private long rendererPositionOffsetUs;
/** /**
@ -72,6 +72,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
* @param allocator The allocator. * @param allocator The allocator.
* @param mediaSource The media source that produced the media period. * @param mediaSource The media source that produced the media period.
* @param info Information used to identify this media period in its timeline period. * @param info Information used to identify this media period in its timeline period.
* @param emptyTrackSelectorResult A {@link TrackSelectorResult} with empty selections for each
* renderer.
*/ */
public MediaPeriodHolder( public MediaPeriodHolder(
RendererCapabilities[] rendererCapabilities, RendererCapabilities[] rendererCapabilities,
@ -79,13 +81,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
TrackSelector trackSelector, TrackSelector trackSelector,
Allocator allocator, Allocator allocator,
MediaSource mediaSource, MediaSource mediaSource,
MediaPeriodInfo info) { MediaPeriodInfo info,
TrackSelectorResult emptyTrackSelectorResult) {
this.rendererCapabilities = rendererCapabilities; this.rendererCapabilities = rendererCapabilities;
this.rendererPositionOffsetUs = rendererPositionOffsetUs; this.rendererPositionOffsetUs = rendererPositionOffsetUs;
this.trackSelector = trackSelector; this.trackSelector = trackSelector;
this.mediaSource = mediaSource; this.mediaSource = mediaSource;
this.uid = info.id.periodUid; this.uid = info.id.periodUid;
this.info = info; this.info = info;
this.trackGroups = TrackGroupArray.EMPTY;
this.trackSelectorResult = emptyTrackSelectorResult;
sampleStreams = new SampleStream[rendererCapabilities.length]; sampleStreams = new SampleStream[rendererCapabilities.length];
mayRetainStreamFlags = new boolean[rendererCapabilities.length]; mayRetainStreamFlags = new boolean[rendererCapabilities.length];
mediaPeriod = mediaPeriod =
@ -167,8 +172,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
public void handlePrepared(float playbackSpeed, Timeline timeline) throws ExoPlaybackException { public void handlePrepared(float playbackSpeed, Timeline timeline) throws ExoPlaybackException {
prepared = true; prepared = true;
trackGroups = mediaPeriod.getTrackGroups(); trackGroups = mediaPeriod.getTrackGroups();
TrackSelectorResult selectorResult = TrackSelectorResult selectorResult = selectTracks(playbackSpeed, timeline);
Assertions.checkNotNull(selectTracks(playbackSpeed, timeline));
long newStartPositionUs = long newStartPositionUs =
applyTrackSelection( applyTrackSelection(
selectorResult, info.startPositionUs, /* forceRecreateStreams= */ false); selectorResult, info.startPositionUs, /* forceRecreateStreams= */ false);
@ -202,22 +206,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
} }
/** /**
* Selects tracks for the period and returns the new result if the selection changed. Must only be * Selects tracks for the period. Must only be called if {@link #prepared} is {@code true}.
* called if {@link #prepared} is {@code true}. *
* <p>The new track selection needs to be applied with {@link
* #applyTrackSelection(TrackSelectorResult, long, boolean)} before taking effect.
* *
* @param playbackSpeed The current playback speed. * @param playbackSpeed The current playback speed.
* @param timeline The current {@link Timeline}. * @param timeline The current {@link Timeline}.
* @return The {@link TrackSelectorResult} if the result changed. Or null if nothing changed. * @return The {@link TrackSelectorResult}.
* @throws ExoPlaybackException If an error occurs during track selection. * @throws ExoPlaybackException If an error occurs during track selection.
*/ */
@Nullable
public TrackSelectorResult selectTracks(float playbackSpeed, Timeline timeline) public TrackSelectorResult selectTracks(float playbackSpeed, Timeline timeline)
throws ExoPlaybackException { throws ExoPlaybackException {
TrackSelectorResult selectorResult = TrackSelectorResult selectorResult =
trackSelector.selectTracks(rendererCapabilities, getTrackGroups(), info.id, timeline); trackSelector.selectTracks(rendererCapabilities, getTrackGroups(), info.id, timeline);
if (selectorResult.isEquivalent(trackSelectorResult)) {
return null;
}
for (TrackSelection trackSelection : selectorResult.selections.getAll()) { for (TrackSelection trackSelection : selectorResult.selections.getAll()) {
if (trackSelection != null) { if (trackSelection != null) {
trackSelection.onPlaybackSpeed(playbackSpeed); trackSelection.onPlaybackSpeed(playbackSpeed);
@ -303,7 +305,6 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
/** Releases the media period. No other method should be called after the release. */ /** Releases the media period. No other method should be called after the release. */
public void release() { public void release() {
disableTrackSelectionsInResult(); disableTrackSelectionsInResult();
trackSelectorResult = null;
releaseMediaPeriod(info.endPositionUs, mediaSource, mediaPeriod); releaseMediaPeriod(info.endPositionUs, mediaSource, mediaPeriod);
} }
@ -331,25 +332,18 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
return next; return next;
} }
/** /** Returns the {@link TrackGroupArray} exposed by this media period. */
* Returns the {@link TrackGroupArray} exposed by this media period. Must only be called if {@link
* #prepared} is {@code true}.
*/
public TrackGroupArray getTrackGroups() { public TrackGroupArray getTrackGroups() {
return Assertions.checkNotNull(trackGroups); return trackGroups;
} }
/** /** Returns the {@link TrackSelectorResult} which is currently applied. */
* Returns the {@link TrackSelectorResult} which is currently applied. Must only be called if
* {@link #prepared} is {@code true}.
*/
public TrackSelectorResult getTrackSelectorResult() { public TrackSelectorResult getTrackSelectorResult() {
return Assertions.checkNotNull(trackSelectorResult); return trackSelectorResult;
} }
private void enableTrackSelectionsInResult() { private void enableTrackSelectionsInResult() {
TrackSelectorResult trackSelectorResult = this.trackSelectorResult; if (!isLoadingMediaPeriod()) {
if (!isLoadingMediaPeriod() || trackSelectorResult == null) {
return; return;
} }
for (int i = 0; i < trackSelectorResult.length; i++) { for (int i = 0; i < trackSelectorResult.length; i++) {
@ -362,8 +356,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
} }
private void disableTrackSelectionsInResult() { private void disableTrackSelectionsInResult() {
TrackSelectorResult trackSelectorResult = this.trackSelectorResult; if (!isLoadingMediaPeriod()) {
if (!isLoadingMediaPeriod() || trackSelectorResult == null) {
return; return;
} }
for (int i = 0; i < trackSelectorResult.length; i++) { for (int i = 0; i < trackSelectorResult.length; i++) {
@ -394,7 +387,6 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
*/ */
private void associateNoSampleRenderersWithEmptySampleStream( private void associateNoSampleRenderersWithEmptySampleStream(
@NullableType SampleStream[] sampleStreams) { @NullableType SampleStream[] sampleStreams) {
TrackSelectorResult trackSelectorResult = Assertions.checkNotNull(this.trackSelectorResult);
for (int i = 0; i < rendererCapabilities.length; i++) { for (int i = 0; i < rendererCapabilities.length; i++) {
if (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE if (rendererCapabilities[i].getTrackType() == C.TRACK_TYPE_NONE
&& trackSelectorResult.isRendererEnabled(i)) { && trackSelectorResult.isRendererEnabled(i)) {

View file

@ -22,6 +22,7 @@ import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -135,13 +136,16 @@ import com.google.android.exoplayer2.util.Assertions;
* @param allocator The allocator. * @param allocator The allocator.
* @param mediaSource The media source that produced the media period. * @param mediaSource The media source that produced the media period.
* @param info Information used to identify this media period in its timeline period. * @param info Information used to identify this media period in its timeline period.
* @param emptyTrackSelectorResult A {@link TrackSelectorResult} with empty selections for each
* renderer.
*/ */
public MediaPeriod enqueueNextMediaPeriod( public MediaPeriod enqueueNextMediaPeriod(
RendererCapabilities[] rendererCapabilities, RendererCapabilities[] rendererCapabilities,
TrackSelector trackSelector, TrackSelector trackSelector,
Allocator allocator, Allocator allocator,
MediaSource mediaSource, MediaSource mediaSource,
MediaPeriodInfo info) { MediaPeriodInfo info,
TrackSelectorResult emptyTrackSelectorResult) {
long rendererPositionOffsetUs = long rendererPositionOffsetUs =
loading == null loading == null
? (info.id.isAd() && info.contentPositionUs != C.TIME_UNSET ? (info.id.isAd() && info.contentPositionUs != C.TIME_UNSET
@ -155,7 +159,8 @@ import com.google.android.exoplayer2.util.Assertions;
trackSelector, trackSelector,
allocator, allocator,
mediaSource, mediaSource,
info); info,
emptyTrackSelectorResult);
if (loading != null) { if (loading != null) {
Assertions.checkState(hasPlayingPeriod()); Assertions.checkState(hasPlayingPeriod());
loading.setNext(newPeriodHolder); loading.setNext(newPeriodHolder);

View file

@ -85,8 +85,8 @@ public final class TrackSelectorResult {
/** /**
* Returns whether this result is equivalent to {@code other} for the renderer at the given index. * Returns whether this result is equivalent to {@code other} for the renderer at the given index.
* The results are equivalent if they have equal renderersEnabled array, track selections, and * The results are equivalent if they have equal track selections and configurations for the
* configurations for the renderer. * renderer.
* *
* @param other The other {@link TrackSelectorResult}. May be null, in which case {@code false} * @param other The other {@link TrackSelectorResult}. May be null, in which case {@code false}
* will be returned. * will be returned.

View file

@ -26,7 +26,9 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline; import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -381,7 +383,13 @@ public final class MediaPeriodQueueTest {
private void enqueueNext() { private void enqueueNext() {
mediaPeriodQueue.enqueueNextMediaPeriod( mediaPeriodQueue.enqueueNextMediaPeriod(
rendererCapabilities, trackSelector, allocator, mediaSource, getNextMediaPeriodInfo()); rendererCapabilities,
trackSelector,
allocator,
mediaSource,
getNextMediaPeriodInfo(),
new TrackSelectorResult(
new RendererConfiguration[0], new TrackSelection[0], /* info= */ null));
} }
private MediaPeriodInfo getNextMediaPeriodInfo() { private MediaPeriodInfo getNextMediaPeriodInfo() {