mirror of
https://github.com/androidx/media.git
synced 2025-05-17 12:39:52 +08:00
Improve MediaPeriodHolder documentation and member access.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=215205796
This commit is contained in:
parent
d97d289b6b
commit
90ca3716aa
@ -993,12 +993,14 @@ import java.util.Collections;
|
|||||||
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
|
MediaPeriodHolder periodHolder = queue.getPlayingPeriod();
|
||||||
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
|
MediaPeriodHolder readingPeriodHolder = queue.getReadingPeriod();
|
||||||
boolean selectionsChangedForReadPeriod = true;
|
boolean selectionsChangedForReadPeriod = true;
|
||||||
|
TrackSelectorResult newTrackSelectorResult = null;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (periodHolder == null || !periodHolder.prepared) {
|
if (periodHolder == null || !periodHolder.prepared) {
|
||||||
// The reselection did not change any prepared periods.
|
// The reselection did not change any prepared periods.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (periodHolder.selectTracks(playbackSpeed, playbackInfo.timeline)) {
|
newTrackSelectorResult = periodHolder.selectTracks(playbackSpeed, playbackInfo.timeline);
|
||||||
|
if (newTrackSelectorResult != null) {
|
||||||
// Selected tracks have changed for this period.
|
// Selected tracks have changed for this period.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1017,7 +1019,7 @@ import java.util.Collections;
|
|||||||
boolean[] streamResetFlags = new boolean[renderers.length];
|
boolean[] streamResetFlags = new boolean[renderers.length];
|
||||||
long periodPositionUs =
|
long periodPositionUs =
|
||||||
playingPeriodHolder.applyTrackSelection(
|
playingPeriodHolder.applyTrackSelection(
|
||||||
playbackInfo.positionUs, recreateStreams, streamResetFlags);
|
newTrackSelectorResult, playbackInfo.positionUs, recreateStreams, streamResetFlags);
|
||||||
if (playbackInfo.playbackState != Player.STATE_ENDED
|
if (playbackInfo.playbackState != Player.STATE_ENDED
|
||||||
&& periodPositionUs != playbackInfo.positionUs) {
|
&& periodPositionUs != playbackInfo.positionUs) {
|
||||||
playbackInfo = playbackInfo.fromNewPosition(playbackInfo.periodId, periodPositionUs,
|
playbackInfo = playbackInfo.fromNewPosition(playbackInfo.periodId, periodPositionUs,
|
||||||
@ -1047,7 +1049,7 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
playbackInfo.copyWithTrackInfo(
|
playbackInfo.copyWithTrackInfo(
|
||||||
playingPeriodHolder.trackGroups, playingPeriodHolder.trackSelectorResult);
|
playingPeriodHolder.getTrackGroups(), playingPeriodHolder.getTrackSelectorResult());
|
||||||
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
|
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
|
||||||
} else {
|
} else {
|
||||||
// Release and re-prepare/buffer periods after the one whose selection changed.
|
// Release and re-prepare/buffer periods after the one whose selection changed.
|
||||||
@ -1056,7 +1058,7 @@ import java.util.Collections;
|
|||||||
long loadingPeriodPositionUs =
|
long loadingPeriodPositionUs =
|
||||||
Math.max(
|
Math.max(
|
||||||
periodHolder.info.startPositionUs, periodHolder.toPeriodTime(rendererPositionUs));
|
periodHolder.info.startPositionUs, periodHolder.toPeriodTime(rendererPositionUs));
|
||||||
periodHolder.applyTrackSelection(loadingPeriodPositionUs, false);
|
periodHolder.applyTrackSelection(newTrackSelectorResult, loadingPeriodPositionUs, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ true);
|
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ true);
|
||||||
@ -1069,13 +1071,11 @@ import java.util.Collections;
|
|||||||
|
|
||||||
private void updateTrackSelectionPlaybackSpeed(float playbackSpeed) {
|
private void updateTrackSelectionPlaybackSpeed(float playbackSpeed) {
|
||||||
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
|
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
|
||||||
while (periodHolder != null) {
|
while (periodHolder != null && periodHolder.prepared) {
|
||||||
if (periodHolder.trackSelectorResult != null) {
|
TrackSelection[] trackSelections = periodHolder.getTrackSelectorResult().selections.getAll();
|
||||||
TrackSelection[] trackSelections = periodHolder.trackSelectorResult.selections.getAll();
|
for (TrackSelection trackSelection : trackSelections) {
|
||||||
for (TrackSelection trackSelection : trackSelections) {
|
if (trackSelection != null) {
|
||||||
if (trackSelection != null) {
|
trackSelection.onPlaybackSpeed(playbackSpeed);
|
||||||
trackSelection.onPlaybackSpeed(playbackSpeed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
periodHolder = periodHolder.getNext();
|
periodHolder = periodHolder.getNext();
|
||||||
@ -1463,9 +1463,9 @@ import java.util.Collections;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackSelectorResult oldTrackSelectorResult = readingPeriodHolder.trackSelectorResult;
|
TrackSelectorResult oldTrackSelectorResult = readingPeriodHolder.getTrackSelectorResult();
|
||||||
readingPeriodHolder = queue.advanceReadingPeriod();
|
readingPeriodHolder = queue.advanceReadingPeriod();
|
||||||
TrackSelectorResult newTrackSelectorResult = readingPeriodHolder.trackSelectorResult;
|
TrackSelectorResult newTrackSelectorResult = readingPeriodHolder.getTrackSelectorResult();
|
||||||
|
|
||||||
boolean initialDiscontinuity =
|
boolean initialDiscontinuity =
|
||||||
readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET;
|
readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET;
|
||||||
@ -1536,7 +1536,7 @@ import java.util.Collections;
|
|||||||
loadingPeriodHolder.handlePrepared(
|
loadingPeriodHolder.handlePrepared(
|
||||||
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
|
mediaClock.getPlaybackParameters().speed, playbackInfo.timeline);
|
||||||
updateLoadControlTrackSelection(
|
updateLoadControlTrackSelection(
|
||||||
loadingPeriodHolder.trackGroups, loadingPeriodHolder.trackSelectorResult);
|
loadingPeriodHolder.getTrackGroups(), loadingPeriodHolder.getTrackSelectorResult());
|
||||||
if (!queue.hasPlayingPeriod()) {
|
if (!queue.hasPlayingPeriod()) {
|
||||||
// This is the first prepared period, so start playing it.
|
// This is the first prepared period, so start playing it.
|
||||||
MediaPeriodHolder playingPeriodHolder = queue.advancePlayingPeriod();
|
MediaPeriodHolder playingPeriodHolder = queue.advancePlayingPeriod();
|
||||||
@ -1596,11 +1596,11 @@ import java.util.Collections;
|
|||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
Renderer renderer = renderers[i];
|
Renderer renderer = renderers[i];
|
||||||
rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED;
|
rendererWasEnabledFlags[i] = renderer.getState() != Renderer.STATE_DISABLED;
|
||||||
if (newPlayingPeriodHolder.trackSelectorResult.isRendererEnabled(i)) {
|
if (newPlayingPeriodHolder.getTrackSelectorResult().isRendererEnabled(i)) {
|
||||||
enabledRendererCount++;
|
enabledRendererCount++;
|
||||||
}
|
}
|
||||||
if (rendererWasEnabledFlags[i]
|
if (rendererWasEnabledFlags[i]
|
||||||
&& (!newPlayingPeriodHolder.trackSelectorResult.isRendererEnabled(i)
|
&& (!newPlayingPeriodHolder.getTrackSelectorResult().isRendererEnabled(i)
|
||||||
|| (renderer.isCurrentStreamFinal()
|
|| (renderer.isCurrentStreamFinal()
|
||||||
&& renderer.getStream() == oldPlayingPeriodHolder.sampleStreams[i]))) {
|
&& renderer.getStream() == oldPlayingPeriodHolder.sampleStreams[i]))) {
|
||||||
// The renderer should be disabled before playing the next period, either because it's not
|
// The renderer should be disabled before playing the next period, either because it's not
|
||||||
@ -1611,7 +1611,8 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
playbackInfo.copyWithTrackInfo(
|
playbackInfo.copyWithTrackInfo(
|
||||||
newPlayingPeriodHolder.trackGroups, newPlayingPeriodHolder.trackSelectorResult);
|
newPlayingPeriodHolder.getTrackGroups(),
|
||||||
|
newPlayingPeriodHolder.getTrackSelectorResult());
|
||||||
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
|
enableRenderers(rendererWasEnabledFlags, enabledRendererCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1621,7 +1622,7 @@ import java.util.Collections;
|
|||||||
int enabledRendererCount = 0;
|
int enabledRendererCount = 0;
|
||||||
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
if (playingPeriodHolder.trackSelectorResult.isRendererEnabled(i)) {
|
if (playingPeriodHolder.getTrackSelectorResult().isRendererEnabled(i)) {
|
||||||
enableRenderer(i, rendererWasEnabledFlags[i], enabledRendererCount++);
|
enableRenderer(i, rendererWasEnabledFlags[i], enabledRendererCount++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1634,10 +1635,10 @@ import java.util.Collections;
|
|||||||
Renderer renderer = renderers[rendererIndex];
|
Renderer renderer = renderers[rendererIndex];
|
||||||
enabledRenderers[enabledRendererIndex] = renderer;
|
enabledRenderers[enabledRendererIndex] = renderer;
|
||||||
if (renderer.getState() == Renderer.STATE_DISABLED) {
|
if (renderer.getState() == Renderer.STATE_DISABLED) {
|
||||||
|
TrackSelectorResult trackSelectorResult = playingPeriodHolder.getTrackSelectorResult();
|
||||||
RendererConfiguration rendererConfiguration =
|
RendererConfiguration rendererConfiguration =
|
||||||
playingPeriodHolder.trackSelectorResult.rendererConfigurations[rendererIndex];
|
trackSelectorResult.rendererConfigurations[rendererIndex];
|
||||||
TrackSelection newSelection = playingPeriodHolder.trackSelectorResult.selections.get(
|
TrackSelection newSelection = trackSelectorResult.selections.get(rendererIndex);
|
||||||
rendererIndex);
|
|
||||||
Format[] formats = getFormats(newSelection);
|
Format[] formats = getFormats(newSelection);
|
||||||
// The renderer needs enabling with its new track selection.
|
// The renderer needs enabling with its new track selection.
|
||||||
boolean playing = playWhenReady && playbackInfo.playbackState == Player.STATE_READY;
|
boolean playing = playWhenReady && playbackInfo.playbackState == Player.STATE_READY;
|
||||||
@ -1674,7 +1675,8 @@ import java.util.Collections;
|
|||||||
&& loadingMediaPeriodHolder != null
|
&& loadingMediaPeriodHolder != null
|
||||||
&& loadingMediaPeriodHolder.prepared) {
|
&& loadingMediaPeriodHolder.prepared) {
|
||||||
updateLoadControlTrackSelection(
|
updateLoadControlTrackSelection(
|
||||||
loadingMediaPeriodHolder.trackGroups, loadingMediaPeriodHolder.trackSelectorResult);
|
loadingMediaPeriodHolder.getTrackGroups(),
|
||||||
|
loadingMediaPeriodHolder.getTrackSelectorResult());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,30 +29,38 @@ 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;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/** Holds a {@link MediaPeriod} with information required to play it as part of a timeline. */
|
/** Holds a {@link MediaPeriod} with information required to play it as part of a timeline. */
|
||||||
/* package */ final class MediaPeriodHolder {
|
/* package */ final class MediaPeriodHolder {
|
||||||
|
|
||||||
private static final String TAG = "MediaPeriodHolder";
|
private static final String TAG = "MediaPeriodHolder";
|
||||||
|
|
||||||
|
/** The {@link MediaPeriod} wrapped by this class. */
|
||||||
public final MediaPeriod mediaPeriod;
|
public final MediaPeriod mediaPeriod;
|
||||||
|
/** The unique timeline period identifier the media period belongs to. */
|
||||||
public final Object uid;
|
public final Object uid;
|
||||||
public final SampleStream[] sampleStreams;
|
/**
|
||||||
public final boolean[] mayRetainStreamFlags;
|
* The sample streams for each renderer associated with this period. May contain null elements.
|
||||||
|
*/
|
||||||
|
public final @NullableType SampleStream[] sampleStreams;
|
||||||
|
|
||||||
|
/** Whether the media period has finished preparing. */
|
||||||
public boolean prepared;
|
public boolean prepared;
|
||||||
|
/** Whether any of the tracks of this media period are enabled. */
|
||||||
public boolean hasEnabledTracks;
|
public boolean hasEnabledTracks;
|
||||||
|
/** {@link MediaPeriodInfo} about this media period. */
|
||||||
public MediaPeriodInfo info;
|
public MediaPeriodInfo info;
|
||||||
public TrackGroupArray trackGroups;
|
|
||||||
public TrackSelectorResult trackSelectorResult;
|
|
||||||
|
|
||||||
|
private final boolean[] mayRetainStreamFlags;
|
||||||
private final RendererCapabilities[] rendererCapabilities;
|
private final RendererCapabilities[] rendererCapabilities;
|
||||||
private final TrackSelector trackSelector;
|
private final TrackSelector trackSelector;
|
||||||
private final MediaSource mediaSource;
|
private final MediaSource mediaSource;
|
||||||
|
|
||||||
private MediaPeriodHolder next;
|
@Nullable private MediaPeriodHolder next;
|
||||||
|
@Nullable private TrackGroupArray trackGroups;
|
||||||
|
@Nullable private TrackSelectorResult trackSelectorResult;
|
||||||
private long rendererPositionOffsetUs;
|
private long rendererPositionOffsetUs;
|
||||||
private TrackSelectorResult periodTrackSelectorResult;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new holder with information required to play it as part of a timeline.
|
* Creates a new holder with information required to play it as part of a timeline.
|
||||||
@ -76,7 +84,7 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
this.rendererPositionOffsetUs = rendererPositionOffsetUs - info.startPositionUs;
|
this.rendererPositionOffsetUs = rendererPositionOffsetUs - info.startPositionUs;
|
||||||
this.trackSelector = trackSelector;
|
this.trackSelector = trackSelector;
|
||||||
this.mediaSource = mediaSource;
|
this.mediaSource = mediaSource;
|
||||||
this.uid = Assertions.checkNotNull(info.id.periodUid);
|
this.uid = info.id.periodUid;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
sampleStreams = new SampleStream[rendererCapabilities.length];
|
sampleStreams = new SampleStream[rendererCapabilities.length];
|
||||||
mayRetainStreamFlags = new boolean[rendererCapabilities.length];
|
mayRetainStreamFlags = new boolean[rendererCapabilities.length];
|
||||||
@ -92,31 +100,38 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
this.mediaPeriod = mediaPeriod;
|
this.mediaPeriod = mediaPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts time relative to the start of the period to the respective renderer time using {@link
|
||||||
|
* #getRendererOffset()}, in microseconds.
|
||||||
|
*/
|
||||||
public long toRendererTime(long periodTimeUs) {
|
public long toRendererTime(long periodTimeUs) {
|
||||||
return periodTimeUs + getRendererOffset();
|
return periodTimeUs + getRendererOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts renderer time to the respective time relative to the start of the period using {@link
|
||||||
|
* #getRendererOffset()}, in microseconds.
|
||||||
|
*/
|
||||||
public long toPeriodTime(long rendererTimeUs) {
|
public long toPeriodTime(long rendererTimeUs) {
|
||||||
return rendererTimeUs - getRendererOffset();
|
return rendererTimeUs - getRendererOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the renderer time of the start of the period, in microseconds. */
|
||||||
public long getRendererOffset() {
|
public long getRendererOffset() {
|
||||||
return rendererPositionOffsetUs;
|
return rendererPositionOffsetUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns start position of period in renderer time. */
|
||||||
public long getStartPositionRendererTime() {
|
public long getStartPositionRendererTime() {
|
||||||
return info.startPositionUs + rendererPositionOffsetUs;
|
return info.startPositionUs + rendererPositionOffsetUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether the period is fully buffered. */
|
||||||
public boolean isFullyBuffered() {
|
public boolean isFullyBuffered() {
|
||||||
return prepared
|
return prepared
|
||||||
&& (!hasEnabledTracks || mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE);
|
&& (!hasEnabledTracks || mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getDurationUs() {
|
|
||||||
return info.durationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the buffered position in microseconds. If the period is buffered to the end then
|
* Returns the buffered position in microseconds. If the period is buffered to the end then
|
||||||
* {@link C#TIME_END_OF_SOURCE} is returned unless {@code convertEosToDuration} is true, in which
|
* {@link C#TIME_END_OF_SOURCE} is returned unless {@code convertEosToDuration} is true, in which
|
||||||
@ -137,65 +152,132 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
: bufferedPositionUs;
|
: bufferedPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next load time relative to the start of the period, or {@link C#TIME_END_OF_SOURCE}
|
||||||
|
* if loading has finished.
|
||||||
|
*/
|
||||||
public long getNextLoadPositionUs() {
|
public long getNextLoadPositionUs() {
|
||||||
return !prepared ? 0 : mediaPeriod.getNextLoadPositionUs();
|
return !prepared ? 0 : mediaPeriod.getNextLoadPositionUs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles period preparation.
|
||||||
|
*
|
||||||
|
* @param playbackSpeed The current playback speed.
|
||||||
|
* @param timeline The current {@link Timeline}.
|
||||||
|
* @throws ExoPlaybackException If an error occurs during track selection.
|
||||||
|
*/
|
||||||
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();
|
||||||
selectTracks(playbackSpeed, timeline);
|
TrackSelectorResult selectorResult =
|
||||||
long newStartPositionUs = applyTrackSelection(info.startPositionUs, false);
|
Assertions.checkNotNull(selectTracks(playbackSpeed, timeline));
|
||||||
|
long newStartPositionUs =
|
||||||
|
applyTrackSelection(
|
||||||
|
selectorResult, info.startPositionUs, /* forceRecreateStreams= */ false);
|
||||||
rendererPositionOffsetUs += info.startPositionUs - newStartPositionUs;
|
rendererPositionOffsetUs += info.startPositionUs - newStartPositionUs;
|
||||||
info = info.copyWithStartPositionUs(newStartPositionUs);
|
info = info.copyWithStartPositionUs(newStartPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reevaluates the buffer of the media period at the given renderer position. Should only be
|
||||||
|
* called if this is the loading media period.
|
||||||
|
*
|
||||||
|
* @param rendererPositionUs The playing position in renderer time, in microseconds.
|
||||||
|
*/
|
||||||
public void reevaluateBuffer(long rendererPositionUs) {
|
public void reevaluateBuffer(long rendererPositionUs) {
|
||||||
|
Assertions.checkState(isLoadingMediaPeriod());
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
mediaPeriod.reevaluateBuffer(toPeriodTime(rendererPositionUs));
|
mediaPeriod.reevaluateBuffer(toPeriodTime(rendererPositionUs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continues loading the media period at the given renderer position. Should only be called if
|
||||||
|
* this is the loading media period.
|
||||||
|
*
|
||||||
|
* @param rendererPositionUs The load position in renderer time, in microseconds.
|
||||||
|
*/
|
||||||
public void continueLoading(long rendererPositionUs) {
|
public void continueLoading(long rendererPositionUs) {
|
||||||
|
Assertions.checkState(isLoadingMediaPeriod());
|
||||||
long loadingPeriodPositionUs = toPeriodTime(rendererPositionUs);
|
long loadingPeriodPositionUs = toPeriodTime(rendererPositionUs);
|
||||||
mediaPeriod.continueLoading(loadingPeriodPositionUs);
|
mediaPeriod.continueLoading(loadingPeriodPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean selectTracks(float playbackSpeed, Timeline timeline) throws ExoPlaybackException {
|
/**
|
||||||
|
* Selects tracks for the period and returns the new result if the selection changed. Must only be
|
||||||
|
* called if {@link #prepared} is {@code true}.
|
||||||
|
*
|
||||||
|
* @param playbackSpeed The current playback speed.
|
||||||
|
* @param timeline The current {@link Timeline}.
|
||||||
|
* @return The {@link TrackSelectorResult} if the result changed. Or null if nothing changed.
|
||||||
|
* @throws ExoPlaybackException If an error occurs during track selection.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public TrackSelectorResult selectTracks(float playbackSpeed, Timeline timeline)
|
||||||
|
throws ExoPlaybackException {
|
||||||
TrackSelectorResult selectorResult =
|
TrackSelectorResult selectorResult =
|
||||||
trackSelector.selectTracks(rendererCapabilities, trackGroups, info.id, timeline);
|
trackSelector.selectTracks(rendererCapabilities, getTrackGroups(), info.id, timeline);
|
||||||
if (selectorResult.isEquivalent(periodTrackSelectorResult)) {
|
if (selectorResult.isEquivalent(trackSelectorResult)) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
trackSelectorResult = selectorResult;
|
for (TrackSelection trackSelection : selectorResult.selections.getAll()) {
|
||||||
for (TrackSelection trackSelection : trackSelectorResult.selections.getAll()) {
|
|
||||||
if (trackSelection != null) {
|
if (trackSelection != null) {
|
||||||
trackSelection.onPlaybackSpeed(playbackSpeed);
|
trackSelection.onPlaybackSpeed(playbackSpeed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return selectorResult;
|
||||||
}
|
|
||||||
|
|
||||||
public long applyTrackSelection(long positionUs, boolean forceRecreateStreams) {
|
|
||||||
return applyTrackSelection(
|
|
||||||
positionUs, forceRecreateStreams, new boolean[rendererCapabilities.length]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a {@link TrackSelectorResult} to the period.
|
||||||
|
*
|
||||||
|
* @param trackSelectorResult The {@link TrackSelectorResult} to apply.
|
||||||
|
* @param positionUs The position relative to the start of the period at which to apply the new
|
||||||
|
* track selections, in microseconds.
|
||||||
|
* @param forceRecreateStreams Whether all streams are forced to be recreated.
|
||||||
|
* @return The actual position relative to the start of the period at which the new track
|
||||||
|
* selections are applied.
|
||||||
|
*/
|
||||||
public long applyTrackSelection(
|
public long applyTrackSelection(
|
||||||
long positionUs, boolean forceRecreateStreams, boolean[] streamResetFlags) {
|
TrackSelectorResult trackSelectorResult, long positionUs, boolean forceRecreateStreams) {
|
||||||
for (int i = 0; i < trackSelectorResult.length; i++) {
|
return applyTrackSelection(
|
||||||
|
trackSelectorResult,
|
||||||
|
positionUs,
|
||||||
|
forceRecreateStreams,
|
||||||
|
new boolean[rendererCapabilities.length]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a {@link TrackSelectorResult} to the period.
|
||||||
|
*
|
||||||
|
* @param newTrackSelectorResult The {@link TrackSelectorResult} to apply.
|
||||||
|
* @param positionUs The position relative to the start of the period at which to apply the new
|
||||||
|
* track selections, in microseconds.
|
||||||
|
* @param forceRecreateStreams Whether all streams are forced to be recreated.
|
||||||
|
* @param streamResetFlags Will be populated to indicate which streams have been reset or were
|
||||||
|
* newly created.
|
||||||
|
* @return The actual position relative to the start of the period at which the new track
|
||||||
|
* selections are applied.
|
||||||
|
*/
|
||||||
|
public long applyTrackSelection(
|
||||||
|
TrackSelectorResult newTrackSelectorResult,
|
||||||
|
long positionUs,
|
||||||
|
boolean forceRecreateStreams,
|
||||||
|
boolean[] streamResetFlags) {
|
||||||
|
for (int i = 0; i < newTrackSelectorResult.length; i++) {
|
||||||
mayRetainStreamFlags[i] =
|
mayRetainStreamFlags[i] =
|
||||||
!forceRecreateStreams && trackSelectorResult.isEquivalent(periodTrackSelectorResult, i);
|
!forceRecreateStreams && newTrackSelectorResult.isEquivalent(trackSelectorResult, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undo the effect of previous call to associate no-sample renderers with empty tracks
|
// Undo the effect of previous call to associate no-sample renderers with empty tracks
|
||||||
// so the mediaPeriod receives back whatever it sent us before.
|
// so the mediaPeriod receives back whatever it sent us before.
|
||||||
disassociateNoSampleRenderersWithEmptySampleStream(sampleStreams);
|
disassociateNoSampleRenderersWithEmptySampleStream(sampleStreams);
|
||||||
disableTrackSelectionsInResult();
|
disableTrackSelectionsInResult();
|
||||||
periodTrackSelectorResult = trackSelectorResult;
|
trackSelectorResult = newTrackSelectorResult;
|
||||||
enableTrackSelectionsInResult();
|
enableTrackSelectionsInResult();
|
||||||
// Disable streams on the period and get new streams for updated/newly-enabled tracks.
|
// Disable streams on the period and get new streams for updated/newly-enabled tracks.
|
||||||
TrackSelectionArray trackSelections = trackSelectorResult.selections;
|
TrackSelectionArray trackSelections = newTrackSelectorResult.selections;
|
||||||
positionUs =
|
positionUs =
|
||||||
mediaPeriod.selectTracks(
|
mediaPeriod.selectTracks(
|
||||||
trackSelections.getAll(),
|
trackSelections.getAll(),
|
||||||
@ -209,7 +291,7 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
hasEnabledTracks = false;
|
hasEnabledTracks = false;
|
||||||
for (int i = 0; i < sampleStreams.length; i++) {
|
for (int i = 0; i < sampleStreams.length; i++) {
|
||||||
if (sampleStreams[i] != null) {
|
if (sampleStreams[i] != null) {
|
||||||
Assertions.checkState(trackSelectorResult.isRendererEnabled(i));
|
Assertions.checkState(newTrackSelectorResult.isRendererEnabled(i));
|
||||||
// hasEnabledTracks should be true only when non-empty streams exists.
|
// hasEnabledTracks should be true only when non-empty streams exists.
|
||||||
if (rendererCapabilities[i].getTrackType() != C.TRACK_TYPE_NONE) {
|
if (rendererCapabilities[i].getTrackType() != C.TRACK_TYPE_NONE) {
|
||||||
hasEnabledTracks = true;
|
hasEnabledTracks = true;
|
||||||
@ -221,9 +303,10 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
return positionUs;
|
return positionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Releases the media period. No other method should be called after the release. */
|
||||||
public void release() {
|
public void release() {
|
||||||
disableTrackSelectionsInResult();
|
disableTrackSelectionsInResult();
|
||||||
periodTrackSelectorResult = null;
|
trackSelectorResult = null;
|
||||||
try {
|
try {
|
||||||
if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) {
|
if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) {
|
||||||
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
|
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
|
||||||
@ -236,6 +319,12 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the next media period holder in the queue.
|
||||||
|
*
|
||||||
|
* @param nextMediaPeriodHolder The next holder, or null if this will be the new loading media
|
||||||
|
* period holder at the end of the queue.
|
||||||
|
*/
|
||||||
public void setNext(@Nullable MediaPeriodHolder nextMediaPeriodHolder) {
|
public void setNext(@Nullable MediaPeriodHolder nextMediaPeriodHolder) {
|
||||||
if (nextMediaPeriodHolder == next) {
|
if (nextMediaPeriodHolder == next) {
|
||||||
return;
|
return;
|
||||||
@ -245,18 +334,39 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
enableTrackSelectionsInResult();
|
enableTrackSelectionsInResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next media period holder in the queue, or null if this is the last media period
|
||||||
|
* (and thus the loading media period).
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public MediaPeriodHolder getNext() {
|
public MediaPeriodHolder getNext() {
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link TrackGroupArray} exposed by this media period. Must only be called if {@link
|
||||||
|
* #prepared} is {@code true}.
|
||||||
|
*/
|
||||||
|
public TrackGroupArray getTrackGroups() {
|
||||||
|
return Assertions.checkNotNull(trackGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link TrackSelectorResult} which is currently applied. Must only be called if
|
||||||
|
* {@link #prepared} is {@code true}.
|
||||||
|
*/
|
||||||
|
public TrackSelectorResult getTrackSelectorResult() {
|
||||||
|
return Assertions.checkNotNull(trackSelectorResult);
|
||||||
|
}
|
||||||
|
|
||||||
private void enableTrackSelectionsInResult() {
|
private void enableTrackSelectionsInResult() {
|
||||||
if (!isLoadingMediaPeriod() || periodTrackSelectorResult == null) {
|
TrackSelectorResult trackSelectorResult = this.trackSelectorResult;
|
||||||
|
if (!isLoadingMediaPeriod() || trackSelectorResult == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < periodTrackSelectorResult.length; i++) {
|
for (int i = 0; i < trackSelectorResult.length; i++) {
|
||||||
boolean rendererEnabled = periodTrackSelectorResult.isRendererEnabled(i);
|
boolean rendererEnabled = trackSelectorResult.isRendererEnabled(i);
|
||||||
TrackSelection trackSelection = periodTrackSelectorResult.selections.get(i);
|
TrackSelection trackSelection = trackSelectorResult.selections.get(i);
|
||||||
if (rendererEnabled && trackSelection != null) {
|
if (rendererEnabled && trackSelection != null) {
|
||||||
trackSelection.enable();
|
trackSelection.enable();
|
||||||
}
|
}
|
||||||
@ -264,12 +374,13 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disableTrackSelectionsInResult() {
|
private void disableTrackSelectionsInResult() {
|
||||||
if (!isLoadingMediaPeriod() || periodTrackSelectorResult == null) {
|
TrackSelectorResult trackSelectorResult = this.trackSelectorResult;
|
||||||
|
if (!isLoadingMediaPeriod() || trackSelectorResult == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < periodTrackSelectorResult.length; i++) {
|
for (int i = 0; i < trackSelectorResult.length; i++) {
|
||||||
boolean rendererEnabled = periodTrackSelectorResult.isRendererEnabled(i);
|
boolean rendererEnabled = trackSelectorResult.isRendererEnabled(i);
|
||||||
TrackSelection trackSelection = periodTrackSelectorResult.selections.get(i);
|
TrackSelection trackSelection = trackSelectorResult.selections.get(i);
|
||||||
if (rendererEnabled && trackSelection != null) {
|
if (rendererEnabled && trackSelection != null) {
|
||||||
trackSelection.disable();
|
trackSelection.disable();
|
||||||
}
|
}
|
||||||
@ -280,7 +391,8 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
* For each renderer of type {@link C#TRACK_TYPE_NONE}, we will remove the dummy {@link
|
* For each renderer of type {@link C#TRACK_TYPE_NONE}, we will remove the dummy {@link
|
||||||
* EmptySampleStream} that was associated with it.
|
* EmptySampleStream} that was associated with it.
|
||||||
*/
|
*/
|
||||||
private void disassociateNoSampleRenderersWithEmptySampleStream(SampleStream[] sampleStreams) {
|
private void disassociateNoSampleRenderersWithEmptySampleStream(
|
||||||
|
@NullableType SampleStream[] sampleStreams) {
|
||||||
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) {
|
||||||
sampleStreams[i] = null;
|
sampleStreams[i] = null;
|
||||||
@ -292,7 +404,9 @@ import com.google.android.exoplayer2.util.Log;
|
|||||||
* For each renderer of type {@link C#TRACK_TYPE_NONE} that was enabled, we will associate it with
|
* For each renderer of type {@link C#TRACK_TYPE_NONE} that was enabled, we will associate it with
|
||||||
* a dummy {@link EmptySampleStream}.
|
* a dummy {@link EmptySampleStream}.
|
||||||
*/
|
*/
|
||||||
private void associateNoSampleRenderersWithEmptySampleStream(SampleStream[] sampleStreams) {
|
private void associateNoSampleRenderersWithEmptySampleStream(
|
||||||
|
@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)) {
|
||||||
|
@ -215,7 +215,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long selectTracks(
|
public long selectTracks(
|
||||||
TrackSelection[] selections,
|
@NullableType TrackSelection[] selections,
|
||||||
boolean[] mayRetainStreamFlags,
|
boolean[] mayRetainStreamFlags,
|
||||||
@NullableType SampleStream[] streams,
|
@NullableType SampleStream[] streams,
|
||||||
boolean[] streamResetFlags,
|
boolean[] streamResetFlags,
|
||||||
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer2.SeekParameters;
|
|||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads media corresponding to a {@link Timeline.Period}, and allows that media to be read. All
|
* Loads media corresponding to a {@link Timeline.Period}, and allows that media to be read. All
|
||||||
@ -108,9 +109,9 @@ public interface MediaPeriod extends SequenceableLoader {
|
|||||||
* @return The actual position at which the tracks were enabled, in microseconds.
|
* @return The actual position at which the tracks were enabled, in microseconds.
|
||||||
*/
|
*/
|
||||||
long selectTracks(
|
long selectTracks(
|
||||||
TrackSelection[] selections,
|
@NullableType TrackSelection[] selections,
|
||||||
boolean[] mayRetainStreamFlags,
|
boolean[] mayRetainStreamFlags,
|
||||||
SampleStream[] streams,
|
@NullableType SampleStream[] streams,
|
||||||
boolean[] streamResetFlags,
|
boolean[] streamResetFlags,
|
||||||
long positionUs);
|
long positionUs);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.trackselection;
|
package com.google.android.exoplayer2.trackselection;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.RendererConfiguration;
|
import com.google.android.exoplayer2.RendererConfiguration;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
@ -70,7 +71,7 @@ public final class TrackSelectorResult {
|
|||||||
* will be returned.
|
* will be returned.
|
||||||
* @return Whether this result is equivalent to {@code other} for all renderers.
|
* @return Whether this result is equivalent to {@code other} for all renderers.
|
||||||
*/
|
*/
|
||||||
public boolean isEquivalent(TrackSelectorResult other) {
|
public boolean isEquivalent(@Nullable TrackSelectorResult other) {
|
||||||
if (other == null || other.selections.length != selections.length) {
|
if (other == null || other.selections.length != selections.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -93,7 +94,7 @@ public final class TrackSelectorResult {
|
|||||||
* @return Whether this result is equivalent to {@code other} for the renderer at the specified
|
* @return Whether this result is equivalent to {@code other} for the renderer at the specified
|
||||||
* index.
|
* index.
|
||||||
*/
|
*/
|
||||||
public boolean isEquivalent(TrackSelectorResult other, int index) {
|
public boolean isEquivalent(@Nullable TrackSelectorResult other, int index) {
|
||||||
if (other == null) {
|
if (other == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user