From 6d8588fcead11b39d8e559687e69658a459b037d Mon Sep 17 00:00:00 2001 From: Steve Mayhew Date: Fri, 10 Dec 2021 15:32:09 -0800 Subject: [PATCH] Timestamp init wait occurs after dataSource.open() Opening the `DataSource` is one of the longer operations in the `Loader` sequence, as it requires a round trip to the origin server. This change allows all the potential `Loader` threads to perform this operation before one of them is forced to wait on shared TimestampAdjuster initialization. Also, the initialization segment load will never produce media samples, so there is no need for it to wait for `TimestampAdjuster` initialization. --- .../exoplayer2/source/hls/HlsMediaChunk.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) 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 e405bfc374..e59f503793 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 @@ -423,19 +423,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; // initDataLoadRequired => initDataSource != null && initDataSpec != null Assertions.checkNotNull(initDataSource); Assertions.checkNotNull(initDataSpec); - feedDataToExtractor(initDataSource, initDataSpec, initSegmentEncrypted); + feedDataToExtractor(initDataSource, initDataSpec, initSegmentEncrypted, false); nextLoadPosition = 0; initDataLoadRequired = false; } @RequiresNonNull("output") private void loadMedia() throws IOException { - try { - timestampAdjuster.sharedInitializeOrWait(isMasterTimestampSource, startTimeUs); - } catch (InterruptedException e) { - throw new InterruptedIOException(); - } - feedDataToExtractor(dataSource, dataSpec, mediaSegmentEncrypted); + feedDataToExtractor(dataSource, dataSpec, mediaSegmentEncrypted, true); } /** @@ -445,7 +440,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; */ @RequiresNonNull("output") private void feedDataToExtractor( - DataSource dataSource, DataSpec dataSpec, boolean dataIsEncrypted) throws IOException { + DataSource dataSource, DataSpec dataSpec, boolean dataIsEncrypted, boolean initializeTimestampAdjuster) throws IOException { // If we previously fed part of this chunk to the extractor, we need to skip it this time. For // encrypted content we need to skip the data by reading it through the source, so as to ensure // correct decryption of the remainder of the chunk. For clear content, we can request the @@ -460,7 +455,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; skipLoadedBytes = false; } try { - ExtractorInput input = prepareExtraction(dataSource, loadDataSpec); + ExtractorInput input = prepareExtraction(dataSource, loadDataSpec, initializeTimestampAdjuster); if (skipLoadedBytes) { input.skipFully(nextLoadPosition); } @@ -484,9 +479,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @RequiresNonNull("output") @EnsuresNonNull("extractor") - private DefaultExtractorInput prepareExtraction(DataSource dataSource, DataSpec dataSpec) + private DefaultExtractorInput prepareExtraction(DataSource dataSource, + DataSpec dataSpec, + boolean initializeTimestampAdjuster) throws IOException { long bytesToRead = dataSource.open(dataSpec); + if (initializeTimestampAdjuster) { + try { + timestampAdjuster.sharedInitializeOrWait(isMasterTimestampSource, startTimeUs); + } catch (InterruptedException e) { + throw new InterruptedIOException(); + } + } DefaultExtractorInput extractorInput = new DefaultExtractorInput(dataSource, dataSpec.position, bytesToRead);