-Modified adaptive track selection to upgrade with 1 second of buffer.

-Modified dynamic track updates to seek to default time instead of clamping to 0 time when negative progress is reached.
This commit is contained in:
John Zhen Mo 2018-04-02 16:07:43 -07:00
parent de534b58c5
commit 238bff1fee
2 changed files with 54 additions and 28 deletions

View File

@ -46,7 +46,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -125,7 +125,6 @@ public abstract class BasePlayer implements
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f}; protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f};
protected static final float[] PLAYBACK_PITCHES = {0.8f, 0.9f, 0.95f, 1f, 1.05f, 1.1f, 1.2f};
protected PlayQueue playQueue; protected PlayQueue playQueue;
protected PlayQueueAdapter playQueueAdapter; protected PlayQueueAdapter playQueueAdapter;
@ -141,10 +140,11 @@ public abstract class BasePlayer implements
// Player // Player
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
protected final static int FAST_FORWARD_REWIND_AMOUNT = 10000; // 10 Seconds protected final static int FAST_FORWARD_REWIND_AMOUNT_MILLIS = 10000; // 10 Seconds
protected final static int PLAY_PREV_ACTIVATION_LIMIT = 5000; // 5 seconds protected final static int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds
protected final static int PROGRESS_LOOP_INTERVAL = 500; protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
protected final static int RECOVERY_SKIP_THRESHOLD = 3000; // 3 seconds protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
protected final static int SHORT_LIVESTREAM_CHUNK_LENGTH_MILLIS = 60000; // 1 minute
protected CustomTrackSelector trackSelector; protected CustomTrackSelector trackSelector;
protected PlayerDataSource dataSource; protected PlayerDataSource dataSource;
@ -192,8 +192,8 @@ public abstract class BasePlayer implements
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter); dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
final AdaptiveTrackSelection.Factory trackSelectionFactory = final TrackSelection.Factory trackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter); PlayerHelper.getQualitySelector(context, bandwidthMeter);
trackSelector = new CustomTrackSelector(trackSelectionFactory); trackSelector = new CustomTrackSelector(trackSelectionFactory);
final LoadControl loadControl = new LoadController(context); final LoadControl loadControl = new LoadController(context);
@ -519,15 +519,16 @@ public abstract class BasePlayer implements
} }
public void triggerProgressUpdate() { public void triggerProgressUpdate() {
if (simpleExoPlayer == null) return;
onUpdateProgress( onUpdateProgress(
(int) simpleExoPlayer.getCurrentPosition(), Math.max((int) simpleExoPlayer.getCurrentPosition(), 0),
(int) simpleExoPlayer.getDuration(), (int) simpleExoPlayer.getDuration(),
simpleExoPlayer.getBufferedPercentage() simpleExoPlayer.getBufferedPercentage()
); );
} }
private Disposable getProgressReactor() { private Disposable getProgressReactor() {
return Observable.interval(PROGRESS_LOOP_INTERVAL, TimeUnit.MILLISECONDS) return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(ignored -> triggerProgressUpdate()); .subscribe(ignored -> triggerProgressUpdate());
} }
@ -554,8 +555,8 @@ public abstract class BasePlayer implements
// Ensure dynamic/livestream timeline changes does not cause negative position // Ensure dynamic/livestream timeline changes does not cause negative position
if (isPlaylistStable && !isCurrentWindowValid() && !isSynchronizing) { if (isPlaylistStable && !isCurrentWindowValid() && !isSynchronizing) {
if (DEBUG) Log.d(TAG, "Playback - negative time position reached, " + if (DEBUG) Log.d(TAG, "Playback - negative time position reached, " +
"clamping position to 0ms."); "clamping to default position.");
seekTo(/*clampToTime=*/0); seekToDefault();
} }
break; break;
} }
@ -703,11 +704,7 @@ public abstract class BasePlayer implements
private void processSourceError(final IOException error) { private void processSourceError(final IOException error) {
if (simpleExoPlayer == null || playQueue == null) return; if (simpleExoPlayer == null || playQueue == null) return;
setRecovery();
if (simpleExoPlayer.getCurrentPosition() <
simpleExoPlayer.getDuration() - RECOVERY_SKIP_THRESHOLD) {
setRecovery();
}
final Throwable cause = error.getCause(); final Throwable cause = error.getCause();
if (cause instanceof BehindLiveWindowException) { if (cause instanceof BehindLiveWindowException) {
@ -972,22 +969,22 @@ public abstract class BasePlayer implements
public void onFastRewind() { public void onFastRewind() {
if (DEBUG) Log.d(TAG, "onFastRewind() called"); if (DEBUG) Log.d(TAG, "onFastRewind() called");
seekBy(-FAST_FORWARD_REWIND_AMOUNT); seekBy(-FAST_FORWARD_REWIND_AMOUNT_MILLIS);
} }
public void onFastForward() { public void onFastForward() {
if (DEBUG) Log.d(TAG, "onFastForward() called"); if (DEBUG) Log.d(TAG, "onFastForward() called");
seekBy(FAST_FORWARD_REWIND_AMOUNT); seekBy(FAST_FORWARD_REWIND_AMOUNT_MILLIS);
} }
public void onPlayPrevious() { public void onPlayPrevious() {
if (simpleExoPlayer == null || playQueue == null) return; if (simpleExoPlayer == null || playQueue == null) return;
if (DEBUG) Log.d(TAG, "onPlayPrevious() called"); if (DEBUG) Log.d(TAG, "onPlayPrevious() called");
/* If current playback has run for PLAY_PREV_ACTIVATION_LIMIT milliseconds, /* If current playback has run for PLAY_PREV_ACTIVATION_LIMIT_MILLIS milliseconds,
* restart current track. Also restart the track if the current track * restart current track. Also restart the track if the current track
* is the first in a queue.*/ * is the first in a queue.*/
if (simpleExoPlayer.getCurrentPosition() > PLAY_PREV_ACTIVATION_LIMIT || if (simpleExoPlayer.getCurrentPosition() > PLAY_PREV_ACTIVATION_LIMIT_MILLIS ||
playQueue.getIndex() == 0) { playQueue.getIndex() == 0) {
seekToDefault(); seekToDefault();
playQueue.offsetIndex(0); playQueue.offsetIndex(0);
@ -1036,8 +1033,27 @@ public abstract class BasePlayer implements
&& simpleExoPlayer.getCurrentPosition() >= 0; && simpleExoPlayer.getCurrentPosition() >= 0;
} }
/**
* Seeks to the default position of the currently playing
* {@link com.google.android.exoplayer2.Timeline.Window}. Does nothing if the
* {@link #simpleExoPlayer} is not initialized.
* <br><br>
* If the current window is non-live, then this will seek to the start of the window.
* If the window is live but has a buffer length greater than
* {@link #SHORT_LIVESTREAM_CHUNK_LENGTH_MILLIS}, then this will seek to the default
* live edge position through {@link SimpleExoPlayer#seekToDefaultPosition}.
* Otherwise, this will seek to the maximum position possible for the current buffer
* given by {@link SimpleExoPlayer#getDuration}.
*
* @see SimpleExoPlayer#seekToDefaultPosition
* */
public void seekToDefault() { public void seekToDefault() {
if (simpleExoPlayer != null) simpleExoPlayer.seekToDefaultPosition(); if (simpleExoPlayer == null) return;
if (isLive() && simpleExoPlayer.getDuration() < SHORT_LIVESTREAM_CHUNK_LENGTH_MILLIS) {
simpleExoPlayer.seekTo(simpleExoPlayer.getDuration());
} else {
simpleExoPlayer.seekToDefaultPosition();
}
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -1078,9 +1094,9 @@ public abstract class BasePlayer implements
private void savePlaybackState() { private void savePlaybackState() {
if (simpleExoPlayer == null || currentInfo == null) return; if (simpleExoPlayer == null || currentInfo == null) return;
if (simpleExoPlayer.getCurrentPosition() > RECOVERY_SKIP_THRESHOLD && if (simpleExoPlayer.getCurrentPosition() > RECOVERY_SKIP_THRESHOLD_MILLIS &&
simpleExoPlayer.getCurrentPosition() < simpleExoPlayer.getCurrentPosition() <
simpleExoPlayer.getDuration() - RECOVERY_SKIP_THRESHOLD) { simpleExoPlayer.getDuration() - RECOVERY_SKIP_THRESHOLD_MILLIS) {
savePlaybackState(currentInfo, simpleExoPlayer.getCurrentPosition()); savePlaybackState(currentInfo, simpleExoPlayer.getCurrentPosition());
} }
} }
@ -1165,10 +1181,6 @@ public abstract class BasePlayer implements
setPlaybackParameters(speed, getPlaybackPitch()); setPlaybackParameters(speed, getPlaybackPitch());
} }
public void setPlaybackPitch(float pitch) {
setPlaybackParameters(getPlaybackSpeed(), pitch);
}
public PlaybackParameters getPlaybackParameters() { public PlaybackParameters getPlaybackParameters() {
final PlaybackParameters defaultParameters = new PlaybackParameters(1f, 1f); final PlaybackParameters defaultParameters = new PlaybackParameters(1f, 1f);
if (simpleExoPlayer == null) return defaultParameters; if (simpleExoPlayer == null) return defaultParameters;

View File

@ -7,7 +7,11 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
@ -203,6 +207,16 @@ public class PlayerHelper {
return 60000; return 60000;
} }
public static TrackSelection.Factory getQualitySelector(@NonNull final Context context,
@NonNull final BandwidthMeter meter) {
return new AdaptiveTrackSelection.Factory(meter,
AdaptiveTrackSelection.DEFAULT_MAX_INITIAL_BITRATE,
/*bufferDurationRequiredForQualityIncrease=*/1000,
AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS,
AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS,
AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION);
}
public static boolean isUsingDSP(@NonNull final Context context) { public static boolean isUsingDSP(@NonNull final Context context) {
return true; return true;
} }