Skip to content

Commit

Permalink
Prevent extractor reuse after upstream discard.
Browse files Browse the repository at this point in the history
After discarding upstream we shouldn't reuse the extractor from the
(newly) last media chunk because the extractor may have been reused
already by the discarded chunks.

Also add an assertion to SampleQueue that prevents the hard-to-detect
failure mode of overlapping sample byte ranges.

Issue: #7690
PiperOrigin-RevId: 324785093
  • Loading branch information
tonihei authored and kim-vde committed Aug 7, 2020
1 parent 33af7a4 commit a6be8ee
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,13 @@ private synchronized void commitSample(
long offset,
int size,
@Nullable CryptoData cryptoData) {
if (length > 0) {
// Ensure sample data doesn't overlap.
int previousSampleRelativeIndex = getRelativeIndex(length - 1);
checkArgument(
offsets[previousSampleRelativeIndex] + sizes[previousSampleRelativeIndex] <= offset);
}

isLastSampleQueued = (sampleFlags & C.BUFFER_FLAG_LAST_SAMPLE) != 0;
largestQueuedTimestampUs = max(largestQueuedTimestampUs, timeUs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public static HlsMediaChunk createInstance(
shouldSpliceIn = !canContinueWithoutSplice;
previousExtractor =
isFollowingChunk
&& !previousChunk.extractorInvalidated
&& previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber
? previousChunk.extractor
: null;
Expand Down Expand Up @@ -224,6 +225,7 @@ public static HlsMediaChunk createInstance(
private volatile boolean loadCanceled;
private boolean loadCompleted;
private ImmutableList<Integer> sampleQueueFirstSampleIndices;
private boolean extractorInvalidated;

private HlsMediaChunk(
HlsExtractorFactory extractorFactory,
Expand Down Expand Up @@ -300,7 +302,7 @@ public void init(HlsSampleStreamWrapper output, ImmutableList<Integer> sampleQue
* @param sampleQueueIndex The index of the sample queue in the output.
* @return The first sample index of this chunk in the specified sample queue.
*/
int getFirstSampleIndex(int sampleQueueIndex) {
public int getFirstSampleIndex(int sampleQueueIndex) {
Assertions.checkState(!shouldSpliceIn);
if (sampleQueueIndex >= sampleQueueFirstSampleIndices.size()) {
// The sample queue was created by this chunk or a later chunk.
Expand All @@ -309,6 +311,11 @@ int getFirstSampleIndex(int sampleQueueIndex) {
return sampleQueueFirstSampleIndices.get(sampleQueueIndex);
}

/** Prevents the extractor from being reused by a following media chunk. */
public void invalidateExtractor() {
extractorInvalidated = true;
}

@Override
public boolean isLoadCompleted() {
return loadCompleted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -833,6 +834,8 @@ public LoadErrorAction onLoadError(
Assertions.checkState(removed == loadable);
if (mediaChunks.isEmpty()) {
pendingResetPositionUs = lastSeekPositionUs;
} else {
Iterables.getLast(mediaChunks).invalidateExtractor();
}
}
loadErrorAction = Loader.DONT_RETRY;
Expand Down Expand Up @@ -914,6 +917,8 @@ private void discardUpstream(int preferredQueueSize) {
HlsMediaChunk firstRemovedChunk = discardUpstreamMediaChunksFromIndex(newQueueSize);
if (mediaChunks.isEmpty()) {
pendingResetPositionUs = lastSeekPositionUs;
} else {
Iterables.getLast(mediaChunks).invalidateExtractor();
}
loadingFinished = false;

Expand Down

0 comments on commit a6be8ee

Please sign in to comment.