diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4edc5a5de1..05ff1b9535 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -65,6 +65,11 @@ Matroska or MP4. * Javadocs: Add favicon for easier identification in browser tabs * FMP4: Add support for encrypted AC-4 tracks. +* Reduce startup latency for DASH and SmoothStreaming adaptive playbacks. + In previous versions, codec initialization would only occur after the network + connection for requesting the first media segment had been established. Codec + initialization can now occur before this network connection being established, + reducing startup latency. ### 2.11.1 (2019-12-20) ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java index ba7c0d0d5b..5003208f7b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java @@ -111,22 +111,21 @@ public class ContainerMediaChunk extends BaseMediaChunk { @SuppressWarnings("NonAtomicVolatileUpdate") @Override public final void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); + if (nextLoadPosition == 0) { + // Configure the output and set it as the target for the extractor wrapper. + BaseMediaChunkOutput output = getOutput(); + output.setSampleOffsetUs(sampleOffsetUs); + extractorWrapper.init( + getTrackOutputProvider(output), + clippedStartTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedStartTimeUs - sampleOffsetUs), + clippedEndTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedEndTimeUs - sampleOffsetUs)); + } try { // Create and open the input. - ExtractorInput input = new DefaultExtractorInput(dataSource, - loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); - if (nextLoadPosition == 0) { - // Configure the output and set it as the target for the extractor wrapper. - BaseMediaChunkOutput output = getOutput(); - output.setSampleOffsetUs(sampleOffsetUs); - extractorWrapper.init( - getTrackOutputProvider(output), - clippedStartTimeUs == C.TIME_UNSET - ? C.TIME_UNSET - : (clippedStartTimeUs - sampleOffsetUs), - clippedEndTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedEndTimeUs - sampleOffsetUs)); - } + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); + ExtractorInput input = + new DefaultExtractorInput( + dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); // Load and decode the sample data. try { Extractor extractor = extractorWrapper.extractor; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java index 37c70d5498..892a4f1e32 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java @@ -70,17 +70,18 @@ public final class InitializationChunk extends Chunk { @SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); + if (nextLoadPosition == 0) { + extractorWrapper.init( + /* trackOutputProvider= */ null, + /* startTimeUs= */ C.TIME_UNSET, + /* endTimeUs= */ C.TIME_UNSET); + } try { // Create and open the input. - ExtractorInput input = new DefaultExtractorInput(dataSource, - loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); - if (nextLoadPosition == 0) { - extractorWrapper.init( - /* trackOutputProvider= */ null, - /* startTimeUs= */ C.TIME_UNSET, - /* endTimeUs= */ C.TIME_UNSET); - } + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); + ExtractorInput input = + new DefaultExtractorInput( + dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); // Load and decode the initialization data. try { Extractor extractor = extractorWrapper.extractor; @@ -96,5 +97,4 @@ public final class InitializationChunk extends Chunk { Util.closeQuietly(dataSource); } } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java index d53caf8e10..00d841eee0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java @@ -91,19 +91,19 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { @SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { - DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); + BaseMediaChunkOutput output = getOutput(); + output.setSampleOffsetUs(0); + TrackOutput trackOutput = output.track(0, trackType); + trackOutput.format(sampleFormat); try { // Create and open the input. + DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition); long length = dataSource.open(loadDataSpec); if (length != C.LENGTH_UNSET) { length += nextLoadPosition; } ExtractorInput extractorInput = new DefaultExtractorInput(dataSource, nextLoadPosition, length); - BaseMediaChunkOutput output = getOutput(); - output.setSampleOffsetUs(0); - TrackOutput trackOutput = output.track(0, trackType); - trackOutput.format(sampleFormat); // Load the sample data. int result = 0; while (result != C.RESULT_END_OF_INPUT) { @@ -117,5 +117,4 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { } loadCompleted = true; } - }