mirror of
https://github.com/androidx/media.git
synced 2025-05-11 09:39:52 +08:00
Partially revert "Tell LoadControl whether playback can start"
- Renderers becoming ready is asynchronous, so the change wasn't well thought through :(. - This will bring back the possibility of getting stuck in the buffering-but-not-loading anything state. This will need to be addressed in a future CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=183646837
This commit is contained in:
parent
d32181e4e9
commit
e26dc3990d
@ -214,8 +214,7 @@ public class DefaultLoadControl implements LoadControl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldContinueLoading(
|
||||
boolean canStartPlayback, long bufferedDurationUs, float playbackSpeed) {
|
||||
public boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed) {
|
||||
boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >= targetBufferSize;
|
||||
boolean wasBuffering = isBuffering;
|
||||
if (prioritizeTimeOverSizeThresholds) {
|
||||
@ -230,9 +229,6 @@ public class DefaultLoadControl implements LoadControl {
|
||||
&& (bufferedDurationUs < minBufferUs // below low watermark
|
||||
|| (bufferedDurationUs <= maxBufferUs && isBuffering)); // between watermarks
|
||||
}
|
||||
if (!isBuffering && !canStartPlayback && !targetBufferSizeReached) {
|
||||
isBuffering = true;
|
||||
}
|
||||
if (priorityTaskManager != null && isBuffering != wasBuffering) {
|
||||
if (isBuffering) {
|
||||
priorityTaskManager.add(C.PRIORITY_PLAYBACK);
|
||||
|
@ -117,8 +117,7 @@ import java.util.Collections;
|
||||
private boolean released;
|
||||
private boolean playWhenReady;
|
||||
private boolean rebuffering;
|
||||
private boolean renderersReadyOrEnded;
|
||||
private @Player.RepeatMode int repeatMode;
|
||||
@Player.RepeatMode private int repeatMode;
|
||||
private boolean shuffleModeEnabled;
|
||||
|
||||
private int pendingPrepareCount;
|
||||
@ -554,8 +553,6 @@ import java.util.Collections;
|
||||
}
|
||||
renderersReadyOrEnded = renderersReadyOrEnded && rendererReadyOrEnded;
|
||||
}
|
||||
|
||||
this.renderersReadyOrEnded = renderersReadyOrEnded;
|
||||
if (!renderersReadyOrEnded) {
|
||||
maybeThrowPeriodPrepareError();
|
||||
}
|
||||
@ -567,25 +564,14 @@ import java.util.Collections;
|
||||
&& playingPeriodHolder.info.isFinal) {
|
||||
setState(Player.STATE_ENDED);
|
||||
stopRenderers();
|
||||
} else if (playbackInfo.playbackState == Player.STATE_BUFFERING) {
|
||||
boolean shouldStartPlayback = isReady();
|
||||
if (shouldStartPlayback && playbackInfo.isLoading && enabledRenderers.length != 0) {
|
||||
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
||||
long bufferedPositionUs = loadingHolder.getBufferedPositionUs(!loadingHolder.info.isFinal);
|
||||
shouldStartPlayback =
|
||||
bufferedPositionUs == C.TIME_END_OF_SOURCE
|
||||
|| loadControl.shouldStartPlayback(
|
||||
bufferedPositionUs - loadingHolder.toPeriodTime(rendererPositionUs),
|
||||
mediaClock.getPlaybackParameters().speed,
|
||||
rebuffering);
|
||||
}
|
||||
if (shouldStartPlayback) {
|
||||
} else if (playbackInfo.playbackState == Player.STATE_BUFFERING
|
||||
&& shouldTransitionToReadyState(renderersReadyOrEnded)) {
|
||||
setState(Player.STATE_READY);
|
||||
if (playWhenReady) {
|
||||
startRenderers();
|
||||
}
|
||||
}
|
||||
} else if (playbackInfo.playbackState == Player.STATE_READY && !isReady()) {
|
||||
} else if (playbackInfo.playbackState == Player.STATE_READY
|
||||
&& !(enabledRenderers.length == 0 ? isTimelineReady() : renderersReadyOrEnded)) {
|
||||
rebuffering = playWhenReady;
|
||||
setState(Player.STATE_BUFFERING);
|
||||
stopRenderers();
|
||||
@ -694,7 +680,6 @@ import java.util.Collections;
|
||||
throws ExoPlaybackException {
|
||||
stopRenderers();
|
||||
rebuffering = false;
|
||||
renderersReadyOrEnded = false;
|
||||
setState(Player.STATE_BUFFERING);
|
||||
|
||||
// Clear the timeline, but keep the requested period if it is already prepared.
|
||||
@ -736,8 +721,8 @@ import java.util.Collections;
|
||||
return periodPositionUs;
|
||||
}
|
||||
|
||||
private boolean shouldKeepPeriodHolder(MediaPeriodId seekPeriodId, long positionUs,
|
||||
MediaPeriodHolder holder) {
|
||||
private boolean shouldKeepPeriodHolder(
|
||||
MediaPeriodId seekPeriodId, long positionUs, MediaPeriodHolder holder) {
|
||||
if (seekPeriodId.equals(holder.info.id) && holder.prepared) {
|
||||
playbackInfo.timeline.getPeriod(holder.info.id.periodIndex, period);
|
||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
||||
@ -802,7 +787,6 @@ import java.util.Collections;
|
||||
boolean releaseMediaSource, boolean resetPosition, boolean resetState) {
|
||||
handler.removeMessages(MSG_DO_SOME_WORK);
|
||||
rebuffering = false;
|
||||
renderersReadyOrEnded = false;
|
||||
mediaClock.stop();
|
||||
rendererPositionUs = RENDERER_TIMESTAMP_OFFSET_US;
|
||||
for (Renderer renderer : enabledRenderers) {
|
||||
@ -1115,11 +1099,30 @@ import java.util.Collections;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReady() {
|
||||
if (enabledRenderers.length != 0) {
|
||||
return renderersReadyOrEnded;
|
||||
private boolean shouldTransitionToReadyState(boolean renderersReadyOrEnded) {
|
||||
if (enabledRenderers.length == 0) {
|
||||
// If there are no enabled renderers, determine whether we're ready based on the timeline.
|
||||
return isTimelineReady();
|
||||
}
|
||||
// Determine whether we're ready based on the timeline.
|
||||
if (!renderersReadyOrEnded) {
|
||||
return false;
|
||||
}
|
||||
if (!playbackInfo.isLoading) {
|
||||
// Renderers are ready and we're not loading. Transition to ready, since the alternative is
|
||||
// getting stuck waiting for additional media that's not being loaded.
|
||||
return true;
|
||||
}
|
||||
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
|
||||
MediaPeriodHolder loadingHolder = queue.getLoadingPeriod();
|
||||
long bufferedPositionUs = loadingHolder.getBufferedPositionUs(!loadingHolder.info.isFinal);
|
||||
return bufferedPositionUs == C.TIME_END_OF_SOURCE
|
||||
|| loadControl.shouldStartPlayback(
|
||||
bufferedPositionUs - loadingHolder.toPeriodTime(rendererPositionUs),
|
||||
mediaClock.getPlaybackParameters().speed,
|
||||
rebuffering);
|
||||
}
|
||||
|
||||
private boolean isTimelineReady() {
|
||||
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
||||
long playingPeriodDurationUs = playingPeriodHolder.info.durationUs;
|
||||
return playingPeriodDurationUs == C.TIME_UNSET
|
||||
@ -1312,8 +1315,8 @@ import java.util.Collections;
|
||||
* @return The index in the new timeline of the first subsequent period, or {@link C#INDEX_UNSET}
|
||||
* if no such period was found.
|
||||
*/
|
||||
private int resolveSubsequentPeriod(int oldPeriodIndex, Timeline oldTimeline,
|
||||
Timeline newTimeline) {
|
||||
private int resolveSubsequentPeriod(
|
||||
int oldPeriodIndex, Timeline oldTimeline, Timeline newTimeline) {
|
||||
int newPeriodIndex = C.INDEX_UNSET;
|
||||
int maxIterations = oldTimeline.getPeriodCount();
|
||||
for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) {
|
||||
@ -1391,8 +1394,8 @@ import java.util.Collections;
|
||||
* Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the
|
||||
* current timeline.
|
||||
*/
|
||||
private Pair<Integer, Long> getPeriodPosition(Timeline timeline, int windowIndex,
|
||||
long windowPositionUs) {
|
||||
private Pair<Integer, Long> getPeriodPosition(
|
||||
Timeline timeline, int windowIndex, long windowPositionUs) {
|
||||
return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
||||
}
|
||||
|
||||
@ -1576,15 +1579,11 @@ import java.util.Collections;
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
boolean canStartPlayback = playbackInfo.playbackState == Player.STATE_READY || isReady();
|
||||
long bufferedDurationUs =
|
||||
nextLoadPositionUs - loadingPeriodHolder.toPeriodTime(rendererPositionUs);
|
||||
boolean continueLoading =
|
||||
loadControl.shouldContinueLoading(
|
||||
canStartPlayback, bufferedDurationUs, mediaClock.getPlaybackParameters().speed);
|
||||
if (!canStartPlayback && !continueLoading) {
|
||||
throw new StuckBufferingException();
|
||||
}
|
||||
bufferedDurationUs, mediaClock.getPlaybackParameters().speed);
|
||||
setIsLoading(continueLoading);
|
||||
if (continueLoading) {
|
||||
loadingPeriodHolder.continueLoading(rendererPositionUs);
|
||||
@ -1632,8 +1631,9 @@ import java.util.Collections;
|
||||
}
|
||||
}
|
||||
|
||||
private void enableRenderer(int rendererIndex, boolean wasRendererEnabled,
|
||||
int enabledRendererIndex) throws ExoPlaybackException {
|
||||
private void enableRenderer(
|
||||
int rendererIndex, boolean wasRendererEnabled, int enabledRendererIndex)
|
||||
throws ExoPlaybackException {
|
||||
MediaPeriodHolder playingPeriodHolder = queue.getPlayingPeriod();
|
||||
Renderer renderer = renderers[rendererIndex];
|
||||
enabledRenderers[enabledRendererIndex] = renderer;
|
||||
|
@ -90,17 +90,11 @@ public interface LoadControl {
|
||||
/**
|
||||
* Called by the player to determine whether it should continue to load the source.
|
||||
*
|
||||
* @param canStartPlayback Whether the player has the minimum amount of data necessary to start
|
||||
* playback. If {@code false}, this method must return {@code true} or playback will fail.
|
||||
* Hence {@code true} should be returned in this case, unless some hard upper limit (e.g. on
|
||||
* the amount of memory that the control will permit to be allocated) has been exceeded.
|
||||
* Always true if playback is currently started.
|
||||
* @param bufferedDurationUs The duration of media that's currently buffered.
|
||||
* @param playbackSpeed The current playback speed.
|
||||
* @return Whether the loading should continue.
|
||||
*/
|
||||
boolean shouldContinueLoading(
|
||||
boolean canStartPlayback, long bufferedDurationUs, float playbackSpeed);
|
||||
boolean shouldContinueLoading(long bufferedDurationUs, float playbackSpeed);
|
||||
|
||||
/**
|
||||
* Called repeatedly by the player when it's loading the source, has yet to start playback, and
|
||||
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
/**
|
||||
* Thrown when the player is stuck in a state where it has insufficient media to start playback, but
|
||||
* its {@link LoadControl} is indicating that no further media should be loaded.
|
||||
*/
|
||||
public final class StuckBufferingException extends IllegalStateException {}
|
Loading…
x
Reference in New Issue
Block a user