Allow HlsSampleStreamWrapper to cancel partial media chunk loads

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=213439145
This commit is contained in:
aquilescanta 2018-09-18 06:24:37 -07:00 committed by Oliver Woodman
parent decbb33490
commit db33b3bbd1
4 changed files with 35 additions and 23 deletions

View file

@ -223,9 +223,6 @@ import java.util.List;
* started, the value will be the starting position in the period minus the duration of any
* media in previous periods still to be played.
* @param loadPositionUs The current load position relative to the period start in microseconds.
* If {@code queue} is empty, this is the starting position from which chunks should be
* provided. Else it's equal to {@link HlsMediaChunk#endTimeUs} of the last chunk in the
* {@code queue}.
* @param queue The queue of buffered {@link HlsMediaChunk}s.
* @param out A holder to populate.
*/
@ -237,12 +234,12 @@ import java.util.List;
long bufferedDurationUs = loadPositionUs - playbackPositionUs;
long timeToLiveEdgeUs = resolveTimeToLiveEdgeUs(playbackPositionUs);
if (previous != null && !independentSegments) {
// Unless segments are known to be independent, switching variant will require downloading
// overlapping segments. Hence we will subtract previous chunk's duration from buffered
// Unless segments are known to be independent, switching variant requires downloading
// overlapping segments. Hence we subtract the previous segment's duration from the buffered
// duration.
// This may affect the live-streaming adaptive track selection logic, when we are comparing
// buffered duration to time to live edge to decide whether to switch. Therefore,
// we will subtract this same amount from timeToLiveEdgeUs as well.
// This may affect the live-streaming adaptive track selection logic, when we compare the
// buffered duration to time-to-live-edge to decide whether to switch. Therefore, we subtract
// the duration of the last loaded segment from timeToLiveEdgeUs as well.
long subtractedDurationUs = previous.getDurationUs();
bufferedDurationUs = Math.max(0, bufferedDurationUs - subtractedDurationUs);
if (timeToLiveEdgeUs != C.TIME_UNSET) {
@ -420,7 +417,7 @@ import java.util.List;
}
/**
* Returns list of {@link MediaChunkIterator}s for upcoming media chunks.
* Returns an array of {@link MediaChunkIterator}s for upcoming media chunks.
*
* @param previous The previous media chunk. May be null.
* @param loadPositionUs The position at which the iterators will start.
@ -458,6 +455,18 @@ import java.util.List;
// Private methods.
/**
* Returns the media sequence number of the segment to load next in {@code mediaPlaylist}.
*
* @param previous The last (at least partially) loaded segment.
* @param switchingVariant Whether the segment to load is not preceded by a segment in the same
* variant.
* @param mediaPlaylist The media playlist to which the segment to load belongs.
* @param startOfPlaylistInPeriodUs The start of {@code mediaPlaylist} relative to the period
* start in microseconds.
* @param loadPositionUs The current load position relative to the period start in microseconds.
* @return The media sequence of the segment to load.
*/
private long getChunkMediaSequence(
@Nullable HlsMediaChunk previous,
boolean switchingVariant,
@ -480,6 +489,8 @@ import java.util.List;
/* stayInBounds= */ !playlistTracker.isLive() || previous == null)
+ mediaPlaylist.mediaSequence;
}
// We ignore the case of previous not having loaded completely, in which case we load the next
// segment.
return previous.getNextChunkIndex();
}

View file

@ -152,7 +152,7 @@ import java.util.concurrent.atomic.AtomicInteger;
if (previousChunk != null) {
id3Decoder = previousChunk.id3Decoder;
id3Data = previousChunk.id3Data;
shouldSpliceIn = previousChunk.hlsUrl != hlsUrl;
shouldSpliceIn = previousChunk.hlsUrl != hlsUrl || !previousChunk.loadCompleted;
previousExtractor = previousChunk.discontinuitySequenceNumber != discontinuitySequenceNumber
|| shouldSpliceIn ? null : previousChunk.extractor;
} else {

View file

@ -460,9 +460,7 @@ import java.util.List;
&& finishedReadingChunk(mediaChunks.get(discardToMediaChunkIndex))) {
discardToMediaChunkIndex++;
}
if (discardToMediaChunkIndex > 0) {
Util.removeRange(mediaChunks, 0, discardToMediaChunkIndex);
}
Util.removeRange(mediaChunks, 0, discardToMediaChunkIndex);
HlsMediaChunk currentChunk = mediaChunks.get(0);
Format trackFormat = currentChunk.trackFormat;
if (!trackFormat.equals(downstreamTrackFormat)) {
@ -554,7 +552,11 @@ import java.util.List;
loadPositionUs = pendingResetPositionUs;
} else {
chunkQueue = readOnlyMediaChunks;
loadPositionUs = getLastMediaChunk().endTimeUs;
HlsMediaChunk lastMediaChunk = getLastMediaChunk();
loadPositionUs =
lastMediaChunk.isLoadCompleted()
? lastMediaChunk.endTimeUs
: Math.max(lastSeekPositionUs, lastMediaChunk.startTimeUs);
}
chunkSource.getNextChunk(positionUs, loadPositionUs, chunkQueue, nextChunkHolder);
boolean endOfStream = nextChunkHolder.endOfStream;
@ -666,17 +668,15 @@ import java.util.List;
boolean blacklistSucceeded = false;
LoadErrorAction loadErrorAction;
if (!isMediaChunk || bytesLoaded == 0) {
long blacklistDurationMs =
loadErrorHandlingPolicy.getBlacklistDurationMsFor(
loadable.type, loadDurationMs, error, errorCount);
if (blacklistDurationMs != C.TIME_UNSET) {
blacklistSucceeded = chunkSource.maybeBlacklistTrack(loadable, blacklistDurationMs);
}
long blacklistDurationMs =
loadErrorHandlingPolicy.getBlacklistDurationMsFor(
loadable.type, loadDurationMs, error, errorCount);
if (blacklistDurationMs != C.TIME_UNSET) {
blacklistSucceeded = chunkSource.maybeBlacklistTrack(loadable, blacklistDurationMs);
}
if (blacklistSucceeded) {
if (isMediaChunk) {
if (isMediaChunk && bytesLoaded == 0) {
HlsMediaChunk removed = mediaChunks.remove(mediaChunks.size() - 1);
Assertions.checkState(removed == loadable);
if (mediaChunks.isEmpty()) {
@ -707,7 +707,7 @@ import java.util.List;
loadable.endTimeUs,
elapsedRealtimeMs,
loadDurationMs,
loadable.bytesLoaded(),
bytesLoaded,
error,
/* wasCanceled= */ !loadErrorAction.isRetry());

View file

@ -33,6 +33,7 @@ android {
dependencies {
androidTestImplementation 'androidx.test:rules:' + testRunnerVersion
androidTestImplementation 'androidx.test:runner:' + testRunnerVersion
androidTestImplementation 'com.android.support:support-annotations:' + supportLibraryVersion
androidTestImplementation project(modulePrefix + 'library-core')
androidTestImplementation project(modulePrefix + 'library-dash')
androidTestImplementation project(modulePrefix + 'library-hls')