Commit a6be8eeb by tonihei Committed by kim-vde

Prevent extractor reuse after upstream discard.

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
parent 33af7a45
......@@ -713,6 +713,13 @@ public class SampleQueue implements TrackOutput {
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);
......
......@@ -143,6 +143,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
shouldSpliceIn = !canContinueWithoutSplice;
previousExtractor =
isFollowingChunk
&& !previousChunk.extractorInvalidated
&& previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber
? previousChunk.extractor
: null;
......@@ -224,6 +225,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private volatile boolean loadCanceled;
private boolean loadCompleted;
private ImmutableList<Integer> sampleQueueFirstSampleIndices;
private boolean extractorInvalidated;
private HlsMediaChunk(
HlsExtractorFactory extractorFactory,
......@@ -300,7 +302,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
* @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.
......@@ -309,6 +311,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
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;
......
......@@ -64,6 +64,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
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;
......@@ -833,6 +834,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
Assertions.checkState(removed == loadable);
if (mediaChunks.isEmpty()) {
pendingResetPositionUs = lastSeekPositionUs;
} else {
Iterables.getLast(mediaChunks).invalidateExtractor();
}
}
loadErrorAction = Loader.DONT_RETRY;
......@@ -914,6 +917,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
HlsMediaChunk firstRemovedChunk = discardUpstreamMediaChunksFromIndex(newQueueSize);
if (mediaChunks.isEmpty()) {
pendingResetPositionUs = lastSeekPositionUs;
} else {
Iterables.getLast(mediaChunks).invalidateExtractor();
}
loadingFinished = false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment