Commit 12451027 by olly Committed by Oliver Woodman

Optimize chunks to init their outputs before opening the DataSource

The current order of operations means that the Format is only passed
to the chunk's output after the DataSource has been opened. This
means that establishing the network connection and the downstream
renderers initializing their codecs are effectively serialized to
occur one after the other.

In the new order, the Format is passed to the chunk's output before
the DataSource has been opened. This allows the downstream renderers
to initialize their codecs in parallel with the network connection
being established, and hence latency at the start of playback is
reduced.

PiperOrigin-RevId: 289841854
parent 771aa328
......@@ -38,6 +38,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) ###
......
......@@ -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;
......
......@@ -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);
}
}
}
......@@ -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;
}
}
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