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
This commit is contained in:
parent
4b234388c8
commit
7d0f0b69a3
@ -65,6 +65,11 @@
|
|||||||
Matroska or MP4.
|
Matroska or MP4.
|
||||||
* Javadocs: Add favicon for easier identification in browser tabs
|
* Javadocs: Add favicon for easier identification in browser tabs
|
||||||
* FMP4: Add support for encrypted AC-4 tracks.
|
* 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) ###
|
### 2.11.1 (2019-12-20) ###
|
||||||
|
|
||||||
|
@ -111,22 +111,21 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
|||||||
@SuppressWarnings("NonAtomicVolatileUpdate")
|
@SuppressWarnings("NonAtomicVolatileUpdate")
|
||||||
@Override
|
@Override
|
||||||
public final void load() throws IOException, InterruptedException {
|
public final void load() throws IOException, InterruptedException {
|
||||||
DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition);
|
|
||||||
try {
|
|
||||||
// Create and open the input.
|
|
||||||
ExtractorInput input = new DefaultExtractorInput(dataSource,
|
|
||||||
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
|
|
||||||
if (nextLoadPosition == 0) {
|
if (nextLoadPosition == 0) {
|
||||||
// Configure the output and set it as the target for the extractor wrapper.
|
// Configure the output and set it as the target for the extractor wrapper.
|
||||||
BaseMediaChunkOutput output = getOutput();
|
BaseMediaChunkOutput output = getOutput();
|
||||||
output.setSampleOffsetUs(sampleOffsetUs);
|
output.setSampleOffsetUs(sampleOffsetUs);
|
||||||
extractorWrapper.init(
|
extractorWrapper.init(
|
||||||
getTrackOutputProvider(output),
|
getTrackOutputProvider(output),
|
||||||
clippedStartTimeUs == C.TIME_UNSET
|
clippedStartTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedStartTimeUs - sampleOffsetUs),
|
||||||
? C.TIME_UNSET
|
|
||||||
: (clippedStartTimeUs - sampleOffsetUs),
|
|
||||||
clippedEndTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedEndTimeUs - sampleOffsetUs));
|
clippedEndTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedEndTimeUs - sampleOffsetUs));
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
// Create and open the input.
|
||||||
|
DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition);
|
||||||
|
ExtractorInput input =
|
||||||
|
new DefaultExtractorInput(
|
||||||
|
dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
|
||||||
// Load and decode the sample data.
|
// Load and decode the sample data.
|
||||||
try {
|
try {
|
||||||
Extractor extractor = extractorWrapper.extractor;
|
Extractor extractor = extractorWrapper.extractor;
|
||||||
|
@ -70,17 +70,18 @@ public final class InitializationChunk extends Chunk {
|
|||||||
@SuppressWarnings("NonAtomicVolatileUpdate")
|
@SuppressWarnings("NonAtomicVolatileUpdate")
|
||||||
@Override
|
@Override
|
||||||
public void load() throws IOException, InterruptedException {
|
public void load() throws IOException, InterruptedException {
|
||||||
DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition);
|
|
||||||
try {
|
|
||||||
// Create and open the input.
|
|
||||||
ExtractorInput input = new DefaultExtractorInput(dataSource,
|
|
||||||
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
|
|
||||||
if (nextLoadPosition == 0) {
|
if (nextLoadPosition == 0) {
|
||||||
extractorWrapper.init(
|
extractorWrapper.init(
|
||||||
/* trackOutputProvider= */ null,
|
/* trackOutputProvider= */ null,
|
||||||
/* startTimeUs= */ C.TIME_UNSET,
|
/* startTimeUs= */ C.TIME_UNSET,
|
||||||
/* endTimeUs= */ C.TIME_UNSET);
|
/* endTimeUs= */ C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
// Create and open the input.
|
||||||
|
DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition);
|
||||||
|
ExtractorInput input =
|
||||||
|
new DefaultExtractorInput(
|
||||||
|
dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
|
||||||
// Load and decode the initialization data.
|
// Load and decode the initialization data.
|
||||||
try {
|
try {
|
||||||
Extractor extractor = extractorWrapper.extractor;
|
Extractor extractor = extractorWrapper.extractor;
|
||||||
@ -96,5 +97,4 @@ public final class InitializationChunk extends Chunk {
|
|||||||
Util.closeQuietly(dataSource);
|
Util.closeQuietly(dataSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -91,19 +91,19 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
|
|||||||
@SuppressWarnings("NonAtomicVolatileUpdate")
|
@SuppressWarnings("NonAtomicVolatileUpdate")
|
||||||
@Override
|
@Override
|
||||||
public void load() throws IOException, InterruptedException {
|
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 {
|
try {
|
||||||
// Create and open the input.
|
// Create and open the input.
|
||||||
|
DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition);
|
||||||
long length = dataSource.open(loadDataSpec);
|
long length = dataSource.open(loadDataSpec);
|
||||||
if (length != C.LENGTH_UNSET) {
|
if (length != C.LENGTH_UNSET) {
|
||||||
length += nextLoadPosition;
|
length += nextLoadPosition;
|
||||||
}
|
}
|
||||||
ExtractorInput extractorInput =
|
ExtractorInput extractorInput =
|
||||||
new DefaultExtractorInput(dataSource, nextLoadPosition, length);
|
new DefaultExtractorInput(dataSource, nextLoadPosition, length);
|
||||||
BaseMediaChunkOutput output = getOutput();
|
|
||||||
output.setSampleOffsetUs(0);
|
|
||||||
TrackOutput trackOutput = output.track(0, trackType);
|
|
||||||
trackOutput.format(sampleFormat);
|
|
||||||
// Load the sample data.
|
// Load the sample data.
|
||||||
int result = 0;
|
int result = 0;
|
||||||
while (result != C.RESULT_END_OF_INPUT) {
|
while (result != C.RESULT_END_OF_INPUT) {
|
||||||
@ -117,5 +117,4 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
|
|||||||
}
|
}
|
||||||
loadCompleted = true;
|
loadCompleted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user