diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/BundledHlsMediaChunkExtractor.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/BundledHlsMediaChunkExtractor.java index 4fd77135ab..c5a496c60d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/BundledHlsMediaChunkExtractor.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/BundledHlsMediaChunkExtractor.java @@ -27,6 +27,7 @@ import com.google.android.exoplayer2.extractor.ts.Ac3Extractor; import com.google.android.exoplayer2.extractor.ts.Ac4Extractor; import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; import com.google.android.exoplayer2.extractor.ts.TsExtractor; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.TimestampAdjuster; import java.io.IOException; @@ -75,11 +76,13 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract } @Override - public HlsMediaChunkExtractor reuseOrRecreate() { - if (extractor instanceof TsExtractor || extractor instanceof FragmentedMp4Extractor) { - // We can reuse this instance. - return this; - } + public boolean isReusable() { + return extractor instanceof TsExtractor || extractor instanceof FragmentedMp4Extractor; + } + + @Override + public HlsMediaChunkExtractor recreate() { + Assertions.checkState(!isReusable()); Extractor newExtractorInstance; if (extractor instanceof WebvttExtractor) { newExtractorInstance = new WebvttExtractor(masterPlaylistFormat.language, timestampAdjuster); @@ -93,7 +96,7 @@ public final class BundledHlsMediaChunkExtractor implements HlsMediaChunkExtract newExtractorInstance = new Mp3Extractor(); } else { throw new IllegalStateException( - "Unexpected previousExtractor type: " + extractor.getClass().getSimpleName()); + "Unexpected extractor type for recreation: " + extractor.getClass().getSimpleName()); } return new BundledHlsMediaChunkExtractor( newExtractorInstance, masterPlaylistFormat, timestampAdjuster); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 3dec4fafd9..687f7f8ccb 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -134,10 +134,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; boolean shouldSpliceIn; ImmutableMap sampleQueueDiscardFromIndices = ImmutableMap.of(); if (previousChunk != null) { + boolean isFollowingChunk = + playlistUrl.equals(previousChunk.playlistUrl) && previousChunk.loadCompleted; id3Decoder = previousChunk.id3Decoder; scratchId3Data = previousChunk.scratchId3Data; boolean canContinueWithoutSplice = - (playlistUrl.equals(previousChunk.playlistUrl) && previousChunk.loadCompleted) + isFollowingChunk || (mediaPlaylist.hasIndependentSegments && segmentStartTimeInPeriodUs >= previousChunk.endTimeUs); shouldSpliceIn = !canContinueWithoutSplice; @@ -145,8 +147,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; sampleQueueDiscardFromIndices = previousChunk.sampleQueueDiscardFromIndices; } previousExtractor = - previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber - && !shouldSpliceIn + isFollowingChunk + && previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber ? previousChunk.extractor : null; } else { @@ -334,9 +336,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; public void load() throws IOException { // output == null means init() hasn't been called. Assertions.checkNotNull(output); - if (extractor == null && previousExtractor != null) { - extractor = previousExtractor.reuseOrRecreate(); - initDataLoadRequired = extractor != previousExtractor; + if (extractor == null && previousExtractor != null && previousExtractor.isReusable()) { + extractor = previousExtractor; + initDataLoadRequired = false; } maybeLoadInitData(); if (!loadCanceled) { @@ -426,13 +428,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; extractorInput.resetPeekPosition(); extractor = - extractorFactory.createExtractor( - dataSpec.uri, - trackFormat, - muxedCaptionFormats, - timestampAdjuster, - dataSource.getResponseHeaders(), - extractorInput); + previousExtractor != null + ? previousExtractor.recreate() + : extractorFactory.createExtractor( + dataSpec.uri, + trackFormat, + muxedCaptionFormats, + timestampAdjuster, + dataSource.getResponseHeaders(), + extractorInput); if (extractor.isPackedAudioExtractor()) { output.setSampleOffsetUs( id3Timestamp != C.TIME_UNSET diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunkExtractor.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunkExtractor.java index 55f69b7e6c..0ca5c5d0ad 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunkExtractor.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunkExtractor.java @@ -51,9 +51,12 @@ public interface HlsMediaChunkExtractor { /** Returns whether this is a packed audio extractor, as defined in RFC 8216, Section 3.4. */ boolean isPackedAudioExtractor(); + /** Returns whether this instance can be used for extracting multiple continuous segments. */ + boolean isReusable(); + /** - * If this instance can be used for extracting multiple continuous segments, returns itself. - * Otherwise, returns a new instance for extracting the same type of media. + * Returns a new instance for extracting the same type of media as this one. Can only be called on + * instances that are not {@link #isReusable() reusable}. */ - HlsMediaChunkExtractor reuseOrRecreate(); + HlsMediaChunkExtractor recreate(); }