mirror of
https://github.com/androidx/media.git
synced 2025-05-05 22:50:57 +08:00
DASH: Output Format before InitializationChunk load completes
This optimization allows a ChunkSampleStream to output track formats as soon as they're parsed during an InitializationChunk load, rather than waiting until after the InitializationChunk load is completed. In DASH VOD, a single InitializationChunk typically loads the moov and sidx atoms in that order. Hence for long form content where the sidx is a non-trivial size, this may result in the track formats being output a non-negligible period of time sooner than was previously the case. This allows downstream renderers to start codec initialization sooner, potentially decreasing startup latency. For a single test stream on a fast & stable network, this pretty consistently reduced elapsed time until both audio and video codecs have been initialized from ~0.5s to ~0.3 seconds on a Galaxy S8. For 5 test runs without and with these patches, the eventTime logged by EventLogger for the second decoder init were: Without (secs): 0.47 0.47 0.45 0.48 0.46 With (secs) : 0.32 0.33 0.34 0.31 0.40 PiperOrigin-RevId: 289845089
This commit is contained in:
parent
7d0f0b69a3
commit
4a5d788fa6
@ -65,11 +65,12 @@
|
|||||||
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.
|
* Startup latency optimizations:
|
||||||
In previous versions, codec initialization would only occur after the network
|
* Reduce startup latency for DASH and SmoothStreaming playbacks by allowing
|
||||||
connection for requesting the first media segment had been established. Codec
|
codec initialization to occur before the network connection for the first
|
||||||
initialization can now occur before this network connection being established,
|
media segment has been established.
|
||||||
reducing startup latency.
|
* Reduce startup latency for on-demand DASH playbacks by allowing codec
|
||||||
|
initialization to occur before the sidx box has been loaded.
|
||||||
|
|
||||||
### 2.11.1 (2019-12-20) ###
|
### 2.11.1 (2019-12-20) ###
|
||||||
|
|
||||||
|
@ -21,7 +21,10 @@ import com.google.android.exoplayer2.source.SampleQueue;
|
|||||||
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider;
|
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
|
|
||||||
/** An output for {@link BaseMediaChunk}s. */
|
/**
|
||||||
|
* A {@link TrackOutputProvider} that provides {@link TrackOutput TrackOutputs} based on a
|
||||||
|
* predefined mapping from track type to output.
|
||||||
|
*/
|
||||||
public final class BaseMediaChunkOutput implements TrackOutputProvider {
|
public final class BaseMediaChunkOutput implements TrackOutputProvider {
|
||||||
|
|
||||||
private static final String TAG = "BaseMediaChunkOutput";
|
private static final String TAG = "BaseMediaChunkOutput";
|
||||||
|
@ -74,7 +74,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
private final List<BaseMediaChunk> readOnlyMediaChunks;
|
private final List<BaseMediaChunk> readOnlyMediaChunks;
|
||||||
private final SampleQueue primarySampleQueue;
|
private final SampleQueue primarySampleQueue;
|
||||||
private final SampleQueue[] embeddedSampleQueues;
|
private final SampleQueue[] embeddedSampleQueues;
|
||||||
private final BaseMediaChunkOutput mediaChunkOutput;
|
private final BaseMediaChunkOutput chunkOutput;
|
||||||
|
|
||||||
private Format primaryDownstreamTrackFormat;
|
private Format primaryDownstreamTrackFormat;
|
||||||
@Nullable private ReleaseCallback<T> releaseCallback;
|
@Nullable private ReleaseCallback<T> releaseCallback;
|
||||||
@ -142,7 +142,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
trackTypes[i + 1] = embeddedTrackTypes[i];
|
trackTypes[i + 1] = embeddedTrackTypes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaChunkOutput = new BaseMediaChunkOutput(trackTypes, sampleQueues);
|
chunkOutput = new BaseMediaChunkOutput(trackTypes, sampleQueues);
|
||||||
pendingResetPositionUs = positionUs;
|
pendingResetPositionUs = positionUs;
|
||||||
lastSeekPositionUs = positionUs;
|
lastSeekPositionUs = positionUs;
|
||||||
}
|
}
|
||||||
@ -554,8 +554,10 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||||||
decodeOnlyUntilPositionUs = resetToMediaChunk ? 0 : pendingResetPositionUs;
|
decodeOnlyUntilPositionUs = resetToMediaChunk ? 0 : pendingResetPositionUs;
|
||||||
pendingResetPositionUs = C.TIME_UNSET;
|
pendingResetPositionUs = C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
mediaChunk.init(mediaChunkOutput);
|
mediaChunk.init(chunkOutput);
|
||||||
mediaChunks.add(mediaChunk);
|
mediaChunks.add(mediaChunk);
|
||||||
|
} else if (loadable instanceof InitializationChunk) {
|
||||||
|
((InitializationChunk) loadable).init(chunkOutput);
|
||||||
}
|
}
|
||||||
long elapsedRealtimeMs =
|
long elapsedRealtimeMs =
|
||||||
loader.startLoading(
|
loader.startLoading(
|
||||||
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
|
|||||||
import com.google.android.exoplayer2.extractor.Extractor;
|
import com.google.android.exoplayer2.extractor.Extractor;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer2.extractor.PositionHolder;
|
import com.google.android.exoplayer2.extractor.PositionHolder;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
@ -144,16 +145,13 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link ChunkExtractorWrapper.TrackOutputProvider} to be used by the wrapped
|
* Returns the {@link TrackOutputProvider} to be used by the wrapped extractor.
|
||||||
* extractor.
|
|
||||||
*
|
*
|
||||||
* @param baseMediaChunkOutput The {@link BaseMediaChunkOutput} most recently passed to {@link
|
* @param baseMediaChunkOutput The {@link BaseMediaChunkOutput} most recently passed to {@link
|
||||||
* #init(BaseMediaChunkOutput)}.
|
* #init(BaseMediaChunkOutput)}.
|
||||||
* @return A {@link ChunkExtractorWrapper.TrackOutputProvider} to be used by the wrapped
|
* @return A {@link TrackOutputProvider} to be used by the wrapped extractor.
|
||||||
* extractor.
|
|
||||||
*/
|
*/
|
||||||
protected ChunkExtractorWrapper.TrackOutputProvider getTrackOutputProvider(
|
protected TrackOutputProvider getTrackOutputProvider(BaseMediaChunkOutput baseMediaChunkOutput) {
|
||||||
BaseMediaChunkOutput baseMediaChunkOutput) {
|
|
||||||
return baseMediaChunkOutput;
|
return baseMediaChunkOutput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,13 @@ import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
|
|||||||
import com.google.android.exoplayer2.extractor.Extractor;
|
import com.google.android.exoplayer2.extractor.Extractor;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer2.extractor.PositionHolder;
|
import com.google.android.exoplayer2.extractor.PositionHolder;
|
||||||
|
import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Chunk} that uses an {@link Extractor} to decode initialization data for single track.
|
* A {@link Chunk} that uses an {@link Extractor} to decode initialization data for single track.
|
||||||
@ -37,6 +39,7 @@ public final class InitializationChunk extends Chunk {
|
|||||||
|
|
||||||
private final ChunkExtractorWrapper extractorWrapper;
|
private final ChunkExtractorWrapper extractorWrapper;
|
||||||
|
|
||||||
|
@MonotonicNonNull private TrackOutputProvider trackOutputProvider;
|
||||||
private long nextLoadPosition;
|
private long nextLoadPosition;
|
||||||
private volatile boolean loadCanceled;
|
private volatile boolean loadCanceled;
|
||||||
|
|
||||||
@ -60,6 +63,17 @@ public final class InitializationChunk extends Chunk {
|
|||||||
this.extractorWrapper = extractorWrapper;
|
this.extractorWrapper = extractorWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the chunk for loading, setting a {@link TrackOutputProvider} for track outputs to
|
||||||
|
* which formats will be written as they are loaded.
|
||||||
|
*
|
||||||
|
* @param trackOutputProvider The {@link TrackOutputProvider} for track outputs to which formats
|
||||||
|
* will be written as they are loaded.
|
||||||
|
*/
|
||||||
|
public void init(TrackOutputProvider trackOutputProvider) {
|
||||||
|
this.trackOutputProvider = trackOutputProvider;
|
||||||
|
}
|
||||||
|
|
||||||
// Loadable implementation.
|
// Loadable implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,9 +86,7 @@ public final class InitializationChunk extends Chunk {
|
|||||||
public void load() throws IOException, InterruptedException {
|
public void load() throws IOException, InterruptedException {
|
||||||
if (nextLoadPosition == 0) {
|
if (nextLoadPosition == 0) {
|
||||||
extractorWrapper.init(
|
extractorWrapper.init(
|
||||||
/* trackOutputProvider= */ null,
|
trackOutputProvider, /* startTimeUs= */ C.TIME_UNSET, /* endTimeUs= */ C.TIME_UNSET);
|
||||||
/* startTimeUs= */ C.TIME_UNSET,
|
|
||||||
/* endTimeUs= */ C.TIME_UNSET);
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Create and open the input.
|
// Create and open the input.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user