Skip to content

Commit

Permalink
Wire up experiment to use AdaptiveTrackSelection based selections
Browse files Browse the repository at this point in the history
LegacyVideoTrackSelection is the previous implementation (unchanged).
VideoTrackSelection is rewritten to extend AdaptiveTrackSelection.

An experiment is added to allow use of the new VideoTrackSelection
implementation. It's envisaged that this transition will be more or
less a no-op change. The experiment flag is only in case of bugs
during roll-out, and will be removed with LegacyVideoTrackSelection
upon successful transition.

VideoTrackSelection also implements discard-on-trick-play-exit, which
was a TODO in the previous implementation.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=221153827
  • Loading branch information
ojw28 committed Nov 14, 2018
1 parent f5af6e8 commit c20b157
Showing 1 changed file with 51 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public AdaptiveTrackSelection createTrackSelection(
private final Clock clock;
private final Format[] formats;
private final int[] formatBitrates;
private final int[] estimatedBitrates;
private final int[] trackBitrates;

private TrackBitrateEstimator trackBitrateEstimator;
private float playbackSpeed;
Expand Down Expand Up @@ -338,7 +338,7 @@ public AdaptiveTrackSelection(
trackBitrateEstimator = TrackBitrateEstimator.DEFAULT;
formats = new Format[length];
formatBitrates = new int[length];
estimatedBitrates = new int[length];
trackBitrates = new int[length];
for (int i = 0; i < length; i++) {
@SuppressWarnings("nullness:method.invocation.invalid")
Format format = getFormat(i);
Expand Down Expand Up @@ -380,11 +380,12 @@ public void updateSelectedTrack(
MediaChunkIterator[] mediaChunkIterators) {
long nowMs = clock.elapsedRealtime();

trackBitrateEstimator.getBitrates(formats, queue, mediaChunkIterators, estimatedBitrates);
// Update the estimated track bitrates.
trackBitrateEstimator.getBitrates(formats, queue, mediaChunkIterators, trackBitrates);

// Stash the current selection, then make a new one.
int currentSelectedIndex = selectedIndex;
selectedIndex = determineIdealSelectedIndex(nowMs, estimatedBitrates);
selectedIndex = determineIdealSelectedIndex(nowMs, trackBitrates);
if (selectedIndex == currentSelectedIndex) {
return;
}
Expand Down Expand Up @@ -429,10 +430,10 @@ public int getSelectionReason() {
@Override
public int evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk> queue) {
long nowMs = clock.elapsedRealtime();
if (lastBufferEvaluationMs != C.TIME_UNSET
&& nowMs - lastBufferEvaluationMs < minTimeBetweenBufferReevaluationMs) {
if (!shouldEvaluateQueueSize(nowMs)) {
return queue.size();
}

lastBufferEvaluationMs = nowMs;
if (queue.isEmpty()) {
return 0;
Expand All @@ -443,6 +444,7 @@ public int evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk>
long playoutBufferedDurationBeforeLastChunkUs =
Util.getPlayoutDurationForMediaDuration(
lastChunk.startTimeUs - playbackPositionUs, playbackSpeed);
long minDurationToRetainAfterDiscardUs = getMinDurationToRetainAfterDiscardUs();
if (playoutBufferedDurationBeforeLastChunkUs < minDurationToRetainAfterDiscardUs) {
return queueSize;
}
Expand All @@ -468,19 +470,59 @@ public int evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk>
return queueSize;
}

/**
* Called when updating the selected track to determine whether a candidate track can be selected.
*
* @param format The {@link Format} of the candidate track.
* @param trackBitrate The estimated bitrate of the track. May differ from {@link Format#bitrate}
* if a more accurate estimate of the current track bitrate is available.
* @param playbackSpeed The current playback speed.
* @param effectiveBitrate The bitrate available to this selection.
* @return Whether this {@link Format} can be selected.
*/
@SuppressWarnings("unused")
protected boolean canSelectFormat(
Format format, int trackBitrate, float playbackSpeed, long effectiveBitrate) {
return Math.round(trackBitrate * playbackSpeed) <= effectiveBitrate;
}

/**
* Called from {@link #evaluateQueueSize(long, List)} to determine whether an evaluation should be
* performed.
*
* @param nowMs The current value of {@link Clock#elapsedRealtime()}.
* @return Whether an evaluation should be performed.
*/
protected boolean shouldEvaluateQueueSize(long nowMs) {
return lastBufferEvaluationMs == C.TIME_UNSET
|| nowMs - lastBufferEvaluationMs >= minTimeBetweenBufferReevaluationMs;
}

/**
* Called from {@link #evaluateQueueSize(long, List)} to determine the minimum duration of buffer
* to retain after discarding chunks.
*
* @return The minimum duration of buffer to retain after discarding chunks, in microseconds.
*/
protected long getMinDurationToRetainAfterDiscardUs() {
return minDurationToRetainAfterDiscardUs;
}

/**
* Computes the ideal selected index ignoring buffer health.
*
* @param nowMs The current time in the timebase of {@link Clock#elapsedRealtime()}, or {@link
* Long#MIN_VALUE} to ignore blacklisting.
* @param bitrates Track bitrates.
* @param trackBitrates The estimated track bitrates. May differ from format bitrates if more
* accurate estimates of the current track bitrates are available.
*/
private int determineIdealSelectedIndex(long nowMs, int[] bitrates) {
private int determineIdealSelectedIndex(long nowMs, int[] trackBitrates) {
long effectiveBitrate = (long) (bandwidthMeter.getBitrateEstimate() * bandwidthFraction);
int lowestBitrateNonBlacklistedIndex = 0;
for (int i = 0; i < length; i++) {
if (nowMs == Long.MIN_VALUE || !isBlacklisted(i, nowMs)) {
if (Math.round(bitrates[i] * playbackSpeed) <= effectiveBitrate) {
Format format = getFormat(i);
if (canSelectFormat(format, trackBitrates[i], playbackSpeed, effectiveBitrate)) {
return i;
} else {
lowestBitrateNonBlacklistedIndex = i;
Expand Down

0 comments on commit c20b157

Please sign in to comment.