Clean up chunked Sample/Chunk sources.

- Remove need for SampleSources to ref ChunkSources.
- Correctly propagate errors loading manifests through
  ChunkSource components.
- Fix some misc warnings.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=123732918
This commit is contained in:
olly 2016-06-01 03:07:37 -07:00 committed by Oliver Woodman
parent 7aae5805b8
commit 7f70ee911b
8 changed files with 108 additions and 95 deletions

View File

@ -239,12 +239,12 @@ import java.util.concurrent.atomic.AtomicInteger;
return false;
}
} catch (ExoPlaybackException e) {
Log.e(TAG, "Internal track renderer error.", e);
Log.e(TAG, "Renderer error.", e);
eventHandler.obtainMessage(MSG_ERROR, e).sendToTarget();
stopInternal();
return true;
} catch (IOException e) {
Log.e(TAG, "Source track renderer error.", e);
Log.e(TAG, "Source error.", e);
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForSource(e)).sendToTarget();
stopInternal();
return true;

View File

@ -84,4 +84,11 @@ public interface ChunkSource {
*/
boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e);
/**
* Releases the source.
* <p>
* This method should be called when the source is no longer required.
*/
void release();
}

View File

@ -37,10 +37,11 @@ import java.util.List;
/**
* A {@link TrackStream} that loads media in {@link Chunk}s, obtained from a {@link ChunkSource}.
*/
public class ChunkTrackStream implements TrackStream, Loader.Callback<Chunk> {
public class ChunkTrackStream<T extends ChunkSource> implements TrackStream,
Loader.Callback<Chunk> {
private final Loader loader;
private final ChunkSource chunkSource;
private final T chunkSource;
private final int minLoadableRetryCount;
private final LinkedList<BaseMediaChunk> mediaChunks;
private final List<BaseMediaChunk> readOnlyMediaChunks;
@ -72,7 +73,7 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback<Chunk> {
* @param minLoadableRetryCount The minimum number of times that the source should retry a load
* before propagating an error.
*/
public ChunkTrackStream(ChunkSource chunkSource, LoadControl loadControl,
public ChunkTrackStream(T chunkSource, LoadControl loadControl,
int bufferSizeContribution, long positionUs, Handler eventHandler,
ChunkTrackStreamEventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
this.chunkSource = chunkSource;
@ -109,6 +110,15 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback<Chunk> {
}
}
/**
* Returns the {@link ChunkSource} used by this stream.
*
* @return The {@link ChunkSource}.
*/
public T getChunkSource() {
return chunkSource;
}
/**
* Returns an estimate of the position up to which data is buffered.
*
@ -160,6 +170,7 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback<Chunk> {
* This method should be called when the stream is no longer required.
*/
public void release() {
chunkSource.release();
loadControl.unregister(this);
if (loader.isLoading()) {
loader.cancelLoading();
@ -181,8 +192,10 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback<Chunk> {
@Override
public void maybeThrowError() throws IOException {
loader.maybeThrowError();
if (!loader.isLoading()) {
chunkSource.maybeThrowError();
}
}
@Override
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {

View File

@ -42,6 +42,7 @@ import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
import com.google.android.exoplayer.extractor.mp4.FragmentedMp4Extractor;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
@ -56,6 +57,7 @@ import java.util.List;
*/
public class DashChunkSource implements ChunkSource {
private final Loader manifestLoader;
private final int adaptationSetIndex;
private final TrackGroup trackGroup;
private final RepresentationHolder[] representationHolders;
@ -72,6 +74,7 @@ public class DashChunkSource implements ChunkSource {
private IOException fatalError;
/**
* @param manifestLoader The {@link Loader} being used to load manifests.
* @param manifest The initial manifest.
* @param adaptationSetIndex The index of the adaptation set in the manifest.
* @param trackGroup The track group corresponding to the adaptation set.
@ -82,9 +85,10 @@ public class DashChunkSource implements ChunkSource {
* server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified
* as the server's unix time minus the local elapsed time. It unknown, set to 0.
*/
public DashChunkSource(MediaPresentationDescription manifest, int adaptationSetIndex,
TrackGroup trackGroup, int[] tracks, DataSource dataSource,
public DashChunkSource(Loader manifestLoader, MediaPresentationDescription manifest,
int adaptationSetIndex, TrackGroup trackGroup, int[] tracks, DataSource dataSource,
FormatEvaluator adaptiveFormatEvaluator, long elapsedRealtimeOffsetMs) {
this.manifestLoader = manifestLoader;
this.manifest = manifest;
this.adaptationSetIndex = adaptationSetIndex;
this.trackGroup = trackGroup;
@ -131,18 +135,14 @@ public class DashChunkSource implements ChunkSource {
}
}
public void release() {
if (adaptiveFormatEvaluator != null) {
adaptiveFormatEvaluator.disable();
}
}
// ChunkSource implementation.
@Override
public void maybeThrowError() throws IOException {
if (fatalError != null) {
throw fatalError;
} else {
manifestLoader.maybeThrowError();
}
}
@ -273,6 +273,13 @@ public class DashChunkSource implements ChunkSource {
return false;
}
@Override
public void release() {
if (adaptiveFormatEvaluator != null) {
adaptiveFormatEvaluator.disable();
}
}
// Private methods.
private long getNowUnixTimeUs() {

View File

@ -47,7 +47,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
import java.io.BufferedReader;
import java.io.IOException;
@ -93,9 +92,7 @@ public final class DashSampleSource implements SampleSource {
private int[] trackGroupAdaptationSetIndices;
private boolean pendingReset;
private long lastSeekPositionUs;
private DashChunkSource[] chunkSources;
private ChunkTrackStream[] trackStreams;
private ChunkTrackStream<DashChunkSource>[] trackStreams;
public DashSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler,
@ -110,8 +107,7 @@ public final class DashSampleSource implements SampleSource {
dataSource = dataSourceFactory.createDataSource();
manifestParser = new MediaPresentationDescriptionParser();
manifestCallback = new ManifestCallback();
chunkSources = new DashChunkSource[0];
trackStreams = new ChunkTrackStream[0];
trackStreams = newTrackStreamArray(0);
}
@Override
@ -140,18 +136,15 @@ public final class DashSampleSource implements SampleSource {
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
List<TrackSelection> newSelections, long positionUs) {
int newEnabledSourceCount = trackStreams.length + newSelections.size() - oldStreams.size();
DashChunkSource[] newChunkSources = new DashChunkSource[newEnabledSourceCount];
ChunkTrackStream[] newTrackStreams = new ChunkTrackStream[newEnabledSourceCount];
ChunkTrackStream<DashChunkSource>[] newTrackStreams =
newTrackStreamArray(newEnabledSourceCount);
int newEnabledSourceIndex = 0;
// Iterate over currently enabled streams, either releasing them or adding them to the new list.
for (int i = 0; i < trackStreams.length; i++) {
ChunkTrackStream trackStream = trackStreams[i];
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
if (oldStreams.contains(trackStream)) {
chunkSources[i].release();
trackStream.release();
} else {
newChunkSources[newEnabledSourceIndex] = chunkSources[i];
newTrackStreams[newEnabledSourceIndex++] = trackStream;
}
}
@ -159,14 +152,11 @@ public final class DashSampleSource implements SampleSource {
// Instantiate and return new streams.
TrackStream[] streamsToReturn = new TrackStream[newSelections.size()];
for (int i = 0; i < newSelections.size(); i++) {
Pair<DashChunkSource, ChunkTrackStream> trackComponents =
buildTrackStream(newSelections.get(i), positionUs);
newChunkSources[newEnabledSourceIndex] = trackComponents.first;
newTrackStreams[newEnabledSourceIndex++] = trackComponents.second;
streamsToReturn[i] = trackComponents.second;
newTrackStreams[newEnabledSourceIndex] = buildTrackStream(newSelections.get(i), positionUs);
streamsToReturn[i] = newTrackStreams[newEnabledSourceIndex];
newEnabledSourceIndex++;
}
chunkSources = newChunkSources;
trackStreams = newTrackStreams;
return streamsToReturn;
}
@ -187,7 +177,7 @@ public final class DashSampleSource implements SampleSource {
startLoadingManifest();
}
}
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
trackStream.continueBuffering(positionUs);
}
}
@ -196,7 +186,7 @@ public final class DashSampleSource implements SampleSource {
public long readReset() {
if (pendingReset) {
pendingReset = false;
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
trackStream.setReadingEnabled(true);
}
return lastSeekPositionUs;
@ -207,7 +197,7 @@ public final class DashSampleSource implements SampleSource {
@Override
public long getBufferedPositionUs() {
long bufferedPositionUs = Long.MAX_VALUE;
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
long rendererBufferedPositionUs = trackStream.getBufferedPositionUs();
if (rendererBufferedPositionUs != C.END_OF_SOURCE_US) {
bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs);
@ -220,7 +210,7 @@ public final class DashSampleSource implements SampleSource {
public void seekToUs(long positionUs) {
lastSeekPositionUs = positionUs;
pendingReset = true;
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
trackStream.setReadingEnabled(false);
trackStream.seekToUs(positionUs);
}
@ -229,10 +219,7 @@ public final class DashSampleSource implements SampleSource {
@Override
public void release() {
loader.release();
for (DashChunkSource chunkSource : chunkSources) {
chunkSource.release();
}
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
trackStream.release();
}
}
@ -254,8 +241,8 @@ public final class DashSampleSource implements SampleSource {
prepared = true;
}
} else {
for (DashChunkSource chunkSource : chunkSources) {
chunkSource.updateManifest(manifest);
for (ChunkTrackStream<DashChunkSource> trackStream : trackStreams) {
trackStream.getChunkSource().updateManifest(manifest);
}
}
}
@ -337,7 +324,7 @@ public final class DashSampleSource implements SampleSource {
trackGroups = new TrackGroupArray(trackGroupArray);
}
private Pair<DashChunkSource, ChunkTrackStream> buildTrackStream(TrackSelection selection,
private ChunkTrackStream<DashChunkSource> buildTrackStream(TrackSelection selection,
long positionUs) {
int[] selectedTracks = selection.getTracks();
FormatEvaluator adaptiveEvaluator = selectedTracks.length > 1
@ -348,14 +335,17 @@ public final class DashSampleSource implements SampleSource {
int adaptationSetType = adaptationSet.type;
int bufferSize = Util.getDefaultBufferSize(adaptationSetType);
DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
DashChunkSource chunkSource = new DashChunkSource(manifest, adaptationSetIndex,
DashChunkSource chunkSource = new DashChunkSource(loader, manifest, adaptationSetIndex,
trackGroups.get(selection.group), selectedTracks, dataSource, adaptiveEvaluator,
elapsedRealtimeOffset);
ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize,
positionUs, eventHandler, eventListener, adaptationSetType, MIN_LOADABLE_RETRY_COUNT);
return Pair.create(chunkSource, trackStream);
return new ChunkTrackStream<>(chunkSource, loadControl, bufferSize, positionUs, eventHandler,
eventListener, adaptationSetType, MIN_LOADABLE_RETRY_COUNT);
}
@SuppressWarnings("unchecked")
private static ChunkTrackStream<DashChunkSource>[] newTrackStreamArray(int length) {
return new ChunkTrackStream[length];
}
private final class ManifestCallback implements
Loader.Callback<UriLoadable<MediaPresentationDescription>> {

View File

@ -93,7 +93,7 @@ import java.util.List;
* @param bufferSizeContribution The contribution of this source to the media buffer, in bytes.
* @param muxedAudioFormat If HLS master playlist indicates that the stream contains muxed audio,
* this is the audio {@link Format} as defined by the playlist.
* @param muxedAudioFormat If HLS master playlist indicates that the stream contains muxed
* @param muxedCaptionFormat If HLS master playlist indicates that the stream contains muxed
* captions, this is the audio {@link Format} as defined by the playlist.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.

View File

@ -34,6 +34,7 @@ import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.Loader;
import android.net.Uri;
import android.text.TextUtils;
@ -47,6 +48,7 @@ import java.util.List;
*/
public class SmoothStreamingChunkSource implements ChunkSource {
private final Loader manifestLoader;
private final int elementIndex;
private final TrackGroup trackGroup;
private final ChunkExtractorWrapper[] extractorWrappers;
@ -63,6 +65,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
private IOException fatalError;
/**
* @param manifestLoader The {@link Loader} being used to load manifests.
* @param manifest The initial manifest.
* @param elementIndex The index of the stream element in the manifest.
* @param trackGroup The track group corresponding to the stream element.
@ -71,9 +74,10 @@ public class SmoothStreamingChunkSource implements ChunkSource {
* @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats.
* @param trackEncryptionBoxes Track encryption boxes for the stream.
*/
public SmoothStreamingChunkSource(SmoothStreamingManifest manifest, int elementIndex,
TrackGroup trackGroup, int[] tracks, DataSource dataSource,
public SmoothStreamingChunkSource(Loader manifestLoader, SmoothStreamingManifest manifest,
int elementIndex, TrackGroup trackGroup, int[] tracks, DataSource dataSource,
FormatEvaluator adaptiveFormatEvaluator, TrackEncryptionBox[] trackEncryptionBoxes) {
this.manifestLoader = manifestLoader;
this.manifest = manifest;
this.elementIndex = elementIndex;
this.trackGroup = trackGroup;
@ -135,18 +139,14 @@ public class SmoothStreamingChunkSource implements ChunkSource {
return needManifestRefresh;
}
public void release() {
if (adaptiveFormatEvaluator != null) {
adaptiveFormatEvaluator.disable();
}
}
// ChunkSource implementation.
@Override
public void maybeThrowError() throws IOException {
if (fatalError != null) {
throw fatalError;
} else {
manifestLoader.maybeThrowError();
}
}
@ -233,6 +233,13 @@ public class SmoothStreamingChunkSource implements ChunkSource {
return false;
}
@Override
public void release() {
if (adaptiveFormatEvaluator != null) {
adaptiveFormatEvaluator.disable();
}
}
// Private methods.
/**

View File

@ -44,7 +44,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Base64;
import android.util.Pair;
import java.io.IOException;
import java.util.Arrays;
@ -85,8 +84,7 @@ public final class SmoothStreamingSampleSource implements SampleSource,
private boolean pendingReset;
private long lastSeekPositionUs;
private SmoothStreamingChunkSource[] chunkSources;
private ChunkTrackStream[] trackStreams;
private ChunkTrackStream<SmoothStreamingChunkSource>[] trackStreams;
public SmoothStreamingSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory,
BandwidthMeter bandwidthMeter, Handler eventHandler,
@ -97,11 +95,8 @@ public final class SmoothStreamingSampleSource implements SampleSource,
this.bandwidthMeter = bandwidthMeter;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
loadControl = new DefaultLoadControl(new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE));
chunkSources = new SmoothStreamingChunkSource[0];
trackStreams = new ChunkTrackStream[0];
trackStreams = newTrackStreamArray(0);
manifestDataSource = dataSourceFactory.createDataSource();
manifestParser = new SmoothStreamingManifestParser();
manifestLoader = new Loader("Loader:Manifest");
@ -133,19 +128,15 @@ public final class SmoothStreamingSampleSource implements SampleSource,
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
List<TrackSelection> newSelections, long positionUs) {
int newEnabledSourceCount = trackStreams.length + newSelections.size() - oldStreams.size();
SmoothStreamingChunkSource[] newChunkSources =
new SmoothStreamingChunkSource[newEnabledSourceCount];
ChunkTrackStream[] newTrackStreams = new ChunkTrackStream[newEnabledSourceCount];
ChunkTrackStream<SmoothStreamingChunkSource>[] newTrackStreams =
newTrackStreamArray(newEnabledSourceCount);
int newEnabledSourceIndex = 0;
// Iterate over currently enabled streams, either releasing them or adding them to the new list.
for (int i = 0; i < trackStreams.length; i++) {
ChunkTrackStream trackStream = trackStreams[i];
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
if (oldStreams.contains(trackStream)) {
chunkSources[i].release();
trackStream.release();
} else {
newChunkSources[newEnabledSourceIndex] = chunkSources[i];
newTrackStreams[newEnabledSourceIndex++] = trackStream;
}
}
@ -153,14 +144,11 @@ public final class SmoothStreamingSampleSource implements SampleSource,
// Instantiate and return new streams.
TrackStream[] streamsToReturn = new TrackStream[newSelections.size()];
for (int i = 0; i < newSelections.size(); i++) {
Pair<SmoothStreamingChunkSource, ChunkTrackStream> trackComponents =
buildTrackStream(newSelections.get(i), positionUs);
newChunkSources[newEnabledSourceIndex] = trackComponents.first;
newTrackStreams[newEnabledSourceIndex++] = trackComponents.second;
streamsToReturn[i] = trackComponents.second;
newTrackStreams[newEnabledSourceIndex] = buildTrackStream(newSelections.get(i), positionUs);
streamsToReturn[i] = newTrackStreams[newEnabledSourceIndex];
newEnabledSourceIndex++;
}
chunkSources = newChunkSources;
trackStreams = newTrackStreams;
return streamsToReturn;
}
@ -170,15 +158,15 @@ public final class SmoothStreamingSampleSource implements SampleSource,
if (manifest.isLive) {
if (!manifestLoader.isLoading() && SystemClock.elapsedRealtime()
> manifestLoadTimestamp + MINIMUM_MANIFEST_REFRESH_PERIOD_MS) {
for (SmoothStreamingChunkSource chunkSource : chunkSources) {
if (chunkSource.needManifestRefresh()) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
if (trackStream.getChunkSource().needManifestRefresh()) {
startLoadingManifest();
break;
}
}
}
}
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.continueBuffering(positionUs);
}
}
@ -187,7 +175,7 @@ public final class SmoothStreamingSampleSource implements SampleSource,
public long readReset() {
if (pendingReset) {
pendingReset = false;
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.setReadingEnabled(true);
}
return lastSeekPositionUs;
@ -198,7 +186,7 @@ public final class SmoothStreamingSampleSource implements SampleSource,
@Override
public long getBufferedPositionUs() {
long bufferedPositionUs = Long.MAX_VALUE;
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
long rendererBufferedPositionUs = trackStream.getBufferedPositionUs();
if (rendererBufferedPositionUs != C.END_OF_SOURCE_US) {
bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs);
@ -211,7 +199,7 @@ public final class SmoothStreamingSampleSource implements SampleSource,
public void seekToUs(long positionUs) {
lastSeekPositionUs = positionUs;
pendingReset = true;
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.setReadingEnabled(false);
trackStream.seekToUs(positionUs);
}
@ -220,10 +208,7 @@ public final class SmoothStreamingSampleSource implements SampleSource,
@Override
public void release() {
manifestLoader.release();
for (SmoothStreamingChunkSource chunkSource : chunkSources) {
chunkSource.release();
}
for (ChunkTrackStream trackStream : trackStreams) {
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.release();
}
}
@ -245,8 +230,8 @@ public final class SmoothStreamingSampleSource implements SampleSource,
}
prepared = true;
} else {
for (SmoothStreamingChunkSource chunkSource : chunkSources) {
chunkSource.updateManifest(manifest);
for (ChunkTrackStream<SmoothStreamingChunkSource> trackStream : trackStreams) {
trackStream.getChunkSource().updateManifest(manifest);
}
}
}
@ -291,8 +276,8 @@ public final class SmoothStreamingSampleSource implements SampleSource,
trackGroups = new TrackGroupArray(trackGroupArray);
}
private Pair<SmoothStreamingChunkSource, ChunkTrackStream> buildTrackStream(
TrackSelection selection, long positionUs) {
private ChunkTrackStream<SmoothStreamingChunkSource> buildTrackStream(TrackSelection selection,
long positionUs) {
int[] selectedTracks = selection.getTracks();
FormatEvaluator adaptiveEvaluator = selectedTracks.length > 1
? new AdaptiveEvaluator(bandwidthMeter) : null;
@ -301,12 +286,16 @@ public final class SmoothStreamingSampleSource implements SampleSource,
int streamElementType = streamElement.type;
int bufferSize = Util.getDefaultBufferSize(streamElementType);
DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
SmoothStreamingChunkSource chunkSource = new SmoothStreamingChunkSource(manifest,
streamElementIndex, trackGroups.get(selection.group), selectedTracks, dataSource,
SmoothStreamingChunkSource chunkSource = new SmoothStreamingChunkSource(manifestLoader,
manifest, streamElementIndex, trackGroups.get(selection.group), selectedTracks, dataSource,
adaptiveEvaluator, trackEncryptionBoxes);
ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize,
positionUs, eventHandler, eventListener, streamElementType, MIN_LOADABLE_RETRY_COUNT);
return Pair.create(chunkSource, trackStream);
return new ChunkTrackStream<>(chunkSource, loadControl, bufferSize, positionUs, eventHandler,
eventListener, streamElementType, MIN_LOADABLE_RETRY_COUNT);
}
@SuppressWarnings("unchecked")
private static ChunkTrackStream<SmoothStreamingChunkSource>[] newTrackStreamArray(int length) {
return new ChunkTrackStream[length];
}
private static byte[] getProtectionElementKeyId(byte[] initData) {