Allow more flexible loading strategy when loading multiple sub streams.

Currently for a DASH ChunkSource that consists of multiple sub-streams, we
always use a CompositeSequenceableLoader, which only allows the furthest behind
loader or any loader that are behind current playback position to continue
loading.
This changes allow clients to have more flexibility when deciding the loading
strategy:
- They can construct a different kind of composite SequenceableLoader from
the sub-loaders, and use it by injecting a different CompositeSequeableLoaderFactory accordingly.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176363870
This commit is contained in:
hoangtc 2017-11-20 08:22:19 -08:00 committed by Oliver Woodman
parent e45907193c
commit 0de57cbfae
12 changed files with 244 additions and 52 deletions

View File

@ -2,8 +2,12 @@
### dev-v2 (not yet released) ### ### dev-v2 (not yet released) ###
* Add Builder to ExtractorMediaSource, HlsMediaSource, SsMediaSource, * Allow more flexible loading strategy when playing media containing multiple
DashMediaSource, SingleSampleMediaSource. sub-streams, by allowing injection of custom `CompositeSequenceableLoader`
factories through `DashMediaSource.Builder`, `HlsMediaSource.Builder`,
`SsMediaSource.Builder`, and `MergingMediaSource`.
* Add Builder to `ExtractorMediaSource`, `HlsMediaSource`, `SsMediaSource`,
`DashMediaSource`, `SingleSampleMediaSource`.
* DASH: * DASH:
* Support in-MPD EventStream. * Support in-MPD EventStream.
* Allow a back-buffer of media to be retained behind the current playback * Allow a back-buffer of media to be retained behind the current playback

View File

@ -20,9 +20,9 @@ import com.google.android.exoplayer2.C;
/** /**
* A {@link SequenceableLoader} that encapsulates multiple other {@link SequenceableLoader}s. * A {@link SequenceableLoader} that encapsulates multiple other {@link SequenceableLoader}s.
*/ */
public final class CompositeSequenceableLoader implements SequenceableLoader { public class CompositeSequenceableLoader implements SequenceableLoader {
private final SequenceableLoader[] loaders; protected final SequenceableLoader[] loaders;
public CompositeSequenceableLoader(SequenceableLoader[] loaders) { public CompositeSequenceableLoader(SequenceableLoader[] loaders) {
this.loaders = loaders; this.loaders = loaders;
@ -53,7 +53,7 @@ public final class CompositeSequenceableLoader implements SequenceableLoader {
} }
@Override @Override
public final boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
boolean madeProgress = false; boolean madeProgress = false;
boolean madeProgressThisIteration; boolean madeProgressThisIteration;
do { do {

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source;
/**
* A factory to create composite {@link SequenceableLoader}s.
*/
public interface CompositeSequenceableLoaderFactory {
/**
* Creates a composite {@link SequenceableLoader}.
*
* @param loaders The sub-loaders that make up the {@link SequenceableLoader} to be built.
* @return A composite {@link SequenceableLoader} that comprises the given loaders.
*/
SequenceableLoader createCompositeSequenceableLoader(SequenceableLoader... loaders);
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.source;
/**
* Default implementation of {@link CompositeSequenceableLoaderFactory}.
*/
public final class DefaultCompositeSequenceableLoaderFactory
implements CompositeSequenceableLoaderFactory {
@Override
public SequenceableLoader createCompositeSequenceableLoader(SequenceableLoader... loaders) {
return new CompositeSequenceableLoader(loaders);
}
}

View File

@ -30,15 +30,18 @@ import java.util.IdentityHashMap;
public final MediaPeriod[] periods; public final MediaPeriod[] periods;
private final IdentityHashMap<SampleStream, Integer> streamPeriodIndices; private final IdentityHashMap<SampleStream, Integer> streamPeriodIndices;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private Callback callback; private Callback callback;
private int pendingChildPrepareCount; private int pendingChildPrepareCount;
private TrackGroupArray trackGroups; private TrackGroupArray trackGroups;
private MediaPeriod[] enabledPeriods; private MediaPeriod[] enabledPeriods;
private SequenceableLoader sequenceableLoader; private SequenceableLoader compositeSequenceableLoader;
public MergingMediaPeriod(MediaPeriod... periods) { public MergingMediaPeriod(CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
MediaPeriod... periods) {
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
this.periods = periods; this.periods = periods;
streamPeriodIndices = new IdentityHashMap<>(); streamPeriodIndices = new IdentityHashMap<>();
} }
@ -124,7 +127,8 @@ import java.util.IdentityHashMap;
// Update the local state. // Update the local state.
enabledPeriods = new MediaPeriod[enabledPeriodsList.size()]; enabledPeriods = new MediaPeriod[enabledPeriodsList.size()];
enabledPeriodsList.toArray(enabledPeriods); enabledPeriodsList.toArray(enabledPeriods);
sequenceableLoader = new CompositeSequenceableLoader(enabledPeriods); compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(enabledPeriods);
return positionUs; return positionUs;
} }
@ -137,12 +141,12 @@ import java.util.IdentityHashMap;
@Override @Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return compositeSequenceableLoader.continueLoading(positionUs);
} }
@Override @Override
public long getNextLoadPositionUs() { public long getNextLoadPositionUs() {
return sequenceableLoader.getNextLoadPositionUs(); return compositeSequenceableLoader.getNextLoadPositionUs();
} }
@Override @Override
@ -168,7 +172,7 @@ import java.util.IdentityHashMap;
@Override @Override
public long getBufferedPositionUs() { public long getBufferedPositionUs() {
return sequenceableLoader.getBufferedPositionUs(); return compositeSequenceableLoader.getBufferedPositionUs();
} }
@Override @Override

View File

@ -74,6 +74,7 @@ public final class MergingMediaSource implements MediaSource {
private final MediaSource[] mediaSources; private final MediaSource[] mediaSources;
private final ArrayList<MediaSource> pendingTimelineSources; private final ArrayList<MediaSource> pendingTimelineSources;
private final Timeline.Window window; private final Timeline.Window window;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private Listener listener; private Listener listener;
private Timeline primaryTimeline; private Timeline primaryTimeline;
@ -85,7 +86,19 @@ public final class MergingMediaSource implements MediaSource {
* @param mediaSources The {@link MediaSource}s to merge. * @param mediaSources The {@link MediaSource}s to merge.
*/ */
public MergingMediaSource(MediaSource... mediaSources) { public MergingMediaSource(MediaSource... mediaSources) {
this(new DefaultCompositeSequenceableLoaderFactory(), mediaSources);
}
/**
* @param compositeSequenceableLoaderFactory A factory to create composite
* {@link SequenceableLoader}s for when this media source loads data from multiple streams
* (video, audio etc...).
* @param mediaSources The {@link MediaSource}s to merge.
*/
public MergingMediaSource(CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
MediaSource... mediaSources) {
this.mediaSources = mediaSources; this.mediaSources = mediaSources;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
pendingTimelineSources = new ArrayList<>(Arrays.asList(mediaSources)); pendingTimelineSources = new ArrayList<>(Arrays.asList(mediaSources));
window = new Timeline.Window(); window = new Timeline.Window();
periodCount = PERIOD_COUNT_UNSET; periodCount = PERIOD_COUNT_UNSET;
@ -121,7 +134,7 @@ public final class MergingMediaSource implements MediaSource {
for (int i = 0; i < periods.length; i++) { for (int i = 0; i < periods.length; i++) {
periods[i] = mediaSources[i].createPeriod(id, allocator); periods[i] = mediaSources[i].createPeriod(id, allocator);
} }
return new MergingMediaPeriod(periods); return new MergingMediaPeriod(compositeSequenceableLoaderFactory, periods);
} }
@Override @Override

View File

@ -21,7 +21,7 @@ import android.util.SparseIntArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoader; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.EmptySampleStream; import com.google.android.exoplayer2.source.EmptySampleStream;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
@ -64,19 +64,21 @@ import java.util.Map;
private final Allocator allocator; private final Allocator allocator;
private final TrackGroupArray trackGroups; private final TrackGroupArray trackGroups;
private final TrackGroupInfo[] trackGroupInfos; private final TrackGroupInfo[] trackGroupInfos;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private Callback callback; private Callback callback;
private ChunkSampleStream<DashChunkSource>[] sampleStreams; private ChunkSampleStream<DashChunkSource>[] sampleStreams;
private EventSampleStream[] eventSampleStreams; private EventSampleStream[] eventSampleStreams;
private CompositeSequenceableLoader sequenceableLoader; private SequenceableLoader compositeSequenceableLoader;
private DashManifest manifest; private DashManifest manifest;
private int periodIndex; private int periodIndex;
private List<EventStream> eventStreams; private List<EventStream> eventStreams;
public DashMediaPeriod(int id, DashManifest manifest, int periodIndex, public DashMediaPeriod(int id, DashManifest manifest, int periodIndex,
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
EventDispatcher eventDispatcher, long elapsedRealtimeOffset, EventDispatcher eventDispatcher, long elapsedRealtimeOffset,
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) { LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
this.id = id; this.id = id;
this.manifest = manifest; this.manifest = manifest;
this.periodIndex = periodIndex; this.periodIndex = periodIndex;
@ -86,9 +88,11 @@ import java.util.Map;
this.elapsedRealtimeOffset = elapsedRealtimeOffset; this.elapsedRealtimeOffset = elapsedRealtimeOffset;
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
this.allocator = allocator; this.allocator = allocator;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
sampleStreams = newSampleStreamArray(0); sampleStreams = newSampleStreamArray(0);
eventSampleStreams = new EventSampleStream[0]; eventSampleStreams = new EventSampleStream[0];
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams); compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
Period period = manifest.getPeriod(periodIndex); Period period = manifest.getPeriod(periodIndex);
eventStreams = period.eventStreams; eventStreams = period.eventStreams;
Pair<TrackGroupArray, TrackGroupInfo[]> result = buildTrackGroups(period.adaptationSets, Pair<TrackGroupArray, TrackGroupInfo[]> result = buildTrackGroups(period.adaptationSets,
@ -163,7 +167,8 @@ import java.util.Map;
primarySampleStreams.values().toArray(sampleStreams); primarySampleStreams.values().toArray(sampleStreams);
eventSampleStreams = new EventSampleStream[eventSampleStreamList.size()]; eventSampleStreams = new EventSampleStream[eventSampleStreamList.size()];
eventSampleStreamList.toArray(eventSampleStreams); eventSampleStreamList.toArray(eventSampleStreams);
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams); compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
return positionUs; return positionUs;
} }
@ -267,12 +272,12 @@ import java.util.Map;
@Override @Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return compositeSequenceableLoader.continueLoading(positionUs);
} }
@Override @Override
public long getNextLoadPositionUs() { public long getNextLoadPositionUs() {
return sequenceableLoader.getNextLoadPositionUs(); return compositeSequenceableLoader.getNextLoadPositionUs();
} }
@Override @Override
@ -282,7 +287,7 @@ import java.util.Map;
@Override @Override
public long getBufferedPositionUs() { public long getBufferedPositionUs() {
return sequenceableLoader.getBufferedPositionUs(); return compositeSequenceableLoader.getBufferedPositionUs();
} }
@Override @Override

View File

@ -28,8 +28,11 @@ import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SequenceableLoader;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest; import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement; import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement;
@ -71,6 +74,7 @@ public final class DashMediaSource implements MediaSource {
private ParsingLoadable.Parser<? extends DashManifest> manifestParser; private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
private AdaptiveMediaSourceEventListener eventListener; private AdaptiveMediaSourceEventListener eventListener;
private Handler eventHandler; private Handler eventHandler;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private int minLoadableRetryCount; private int minLoadableRetryCount;
private long livePresentationDelayMs; private long livePresentationDelayMs;
@ -171,6 +175,22 @@ public final class DashMediaSource implements MediaSource {
return this; return this;
} }
/**
* Sets the factory to create composite {@link SequenceableLoader}s for when this media source
* loads data from multiple streams (video, audio etc...). The default is an instance of
* {@link DefaultCompositeSequenceableLoaderFactory}.
*
* @param compositeSequenceableLoaderFactory A factory to create composite
* {@link SequenceableLoader}s for when this media source loads data from multiple streams
* (video, audio etc...).
* @return This builder.
*/
public Builder setCompositeSequenceableLoaderFactory(
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
return this;
}
/** /**
* Builds a new {@link DashMediaSource} using the current parameters. * Builds a new {@link DashMediaSource} using the current parameters.
* <p> * <p>
@ -186,9 +206,12 @@ public final class DashMediaSource implements MediaSource {
if (loadableManifestUri && manifestParser == null) { if (loadableManifestUri && manifestParser == null) {
manifestParser = new DashManifestParser(); manifestParser = new DashManifestParser();
} }
if (compositeSequenceableLoaderFactory == null) {
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
}
return new DashMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser, return new DashMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser,
chunkSourceFactory, minLoadableRetryCount, livePresentationDelayMs, eventHandler, chunkSourceFactory, compositeSequenceableLoaderFactory, minLoadableRetryCount,
eventListener); livePresentationDelayMs, eventHandler, eventListener);
} }
} }
@ -226,6 +249,7 @@ public final class DashMediaSource implements MediaSource {
private final boolean sideloadedManifest; private final boolean sideloadedManifest;
private final DataSource.Factory manifestDataSourceFactory; private final DataSource.Factory manifestDataSourceFactory;
private final DashChunkSource.Factory chunkSourceFactory; private final DashChunkSource.Factory chunkSourceFactory;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final long livePresentationDelayMs; private final long livePresentationDelayMs;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
@ -280,7 +304,8 @@ public final class DashMediaSource implements MediaSource {
public DashMediaSource(DashManifest manifest, DashChunkSource.Factory chunkSourceFactory, public DashMediaSource(DashManifest manifest, DashChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, Handler eventHandler, AdaptiveMediaSourceEventListener int minLoadableRetryCount, Handler eventHandler, AdaptiveMediaSourceEventListener
eventListener) { eventListener) {
this(manifest, null, null, null, chunkSourceFactory, minLoadableRetryCount, this(manifest, null, null, null, chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS, eventHandler, eventListener); DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS, eventHandler, eventListener);
} }
@ -356,14 +381,16 @@ public final class DashMediaSource implements MediaSource {
long livePresentationDelayMs, Handler eventHandler, long livePresentationDelayMs, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory, this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory,
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener); new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
livePresentationDelayMs, eventHandler, eventListener);
} }
private DashMediaSource(DashManifest manifest, Uri manifestUri, private DashMediaSource(DashManifest manifest, Uri manifestUri,
DataSource.Factory manifestDataSourceFactory, DataSource.Factory manifestDataSourceFactory,
ParsingLoadable.Parser<? extends DashManifest> manifestParser, ParsingLoadable.Parser<? extends DashManifest> manifestParser,
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, DashChunkSource.Factory chunkSourceFactory,
long livePresentationDelayMs, Handler eventHandler, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount, long livePresentationDelayMs, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
this.manifest = manifest; this.manifest = manifest;
this.manifestUri = manifestUri; this.manifestUri = manifestUri;
@ -372,6 +399,7 @@ public final class DashMediaSource implements MediaSource {
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.livePresentationDelayMs = livePresentationDelayMs; this.livePresentationDelayMs = livePresentationDelayMs;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
sideloadedManifest = manifest != null; sideloadedManifest = manifest != null;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
manifestUriLock = new Object(); manifestUriLock = new Object();
@ -438,7 +466,7 @@ public final class DashMediaSource implements MediaSource {
manifest.getPeriod(periodIndex).startMs); manifest.getPeriod(periodIndex).startMs);
DashMediaPeriod mediaPeriod = new DashMediaPeriod(firstPeriodId + periodIndex, manifest, DashMediaPeriod mediaPeriod = new DashMediaPeriod(firstPeriodId + periodIndex, manifest,
periodIndex, chunkSourceFactory, minLoadableRetryCount, periodEventDispatcher, periodIndex, chunkSourceFactory, minLoadableRetryCount, periodEventDispatcher,
elapsedRealtimeOffsetMs, loaderErrorThrower, allocator); elapsedRealtimeOffsetMs, loaderErrorThrower, allocator, compositeSequenceableLoaderFactory);
periodsById.put(mediaPeriod.id, mediaPeriod); periodsById.put(mediaPeriod.id, mediaPeriod);
return mediaPeriod; return mediaPeriod;
} }

View File

@ -20,9 +20,10 @@ import android.text.TextUtils;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoader; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.source.SequenceableLoader;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
@ -53,23 +54,26 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
private final IdentityHashMap<SampleStream, Integer> streamWrapperIndices; private final IdentityHashMap<SampleStream, Integer> streamWrapperIndices;
private final TimestampAdjusterProvider timestampAdjusterProvider; private final TimestampAdjusterProvider timestampAdjusterProvider;
private final Handler continueLoadingHandler; private final Handler continueLoadingHandler;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private Callback callback; private Callback callback;
private int pendingPrepareCount; private int pendingPrepareCount;
private TrackGroupArray trackGroups; private TrackGroupArray trackGroups;
private HlsSampleStreamWrapper[] sampleStreamWrappers; private HlsSampleStreamWrapper[] sampleStreamWrappers;
private HlsSampleStreamWrapper[] enabledSampleStreamWrappers; private HlsSampleStreamWrapper[] enabledSampleStreamWrappers;
private CompositeSequenceableLoader sequenceableLoader; private SequenceableLoader compositeSequenceableLoader;
public HlsMediaPeriod(HlsExtractorFactory extractorFactory, HlsPlaylistTracker playlistTracker, public HlsMediaPeriod(HlsExtractorFactory extractorFactory, HlsPlaylistTracker playlistTracker,
HlsDataSourceFactory dataSourceFactory, int minLoadableRetryCount, HlsDataSourceFactory dataSourceFactory, int minLoadableRetryCount,
EventDispatcher eventDispatcher, Allocator allocator) { EventDispatcher eventDispatcher, Allocator allocator,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
this.extractorFactory = extractorFactory; this.extractorFactory = extractorFactory;
this.playlistTracker = playlistTracker; this.playlistTracker = playlistTracker;
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.allocator = allocator; this.allocator = allocator;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
streamWrapperIndices = new IdentityHashMap<>(); streamWrapperIndices = new IdentityHashMap<>();
timestampAdjusterProvider = new TimestampAdjusterProvider(); timestampAdjusterProvider = new TimestampAdjusterProvider();
continueLoadingHandler = new Handler(); continueLoadingHandler = new Handler();
@ -178,7 +182,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
// Update the local state. // Update the local state.
enabledSampleStreamWrappers = Arrays.copyOf(newEnabledSampleStreamWrappers, enabledSampleStreamWrappers = Arrays.copyOf(newEnabledSampleStreamWrappers,
newEnabledSampleStreamWrapperCount); newEnabledSampleStreamWrapperCount);
sequenceableLoader = new CompositeSequenceableLoader(enabledSampleStreamWrappers); compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(
enabledSampleStreamWrappers);
return positionUs; return positionUs;
} }
@ -191,12 +197,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
@Override @Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return compositeSequenceableLoader.continueLoading(positionUs);
} }
@Override @Override
public long getNextLoadPositionUs() { public long getNextLoadPositionUs() {
return sequenceableLoader.getNextLoadPositionUs(); return compositeSequenceableLoader.getNextLoadPositionUs();
} }
@Override @Override
@ -206,7 +212,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
@Override @Override
public long getBufferedPositionUs() { public long getBufferedPositionUs() {
return sequenceableLoader.getBufferedPositionUs(); return compositeSequenceableLoader.getBufferedPositionUs();
} }
@Override @Override

View File

@ -23,8 +23,11 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SequenceableLoader;
import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist;
@ -59,6 +62,8 @@ public final class HlsMediaSource implements MediaSource,
private ParsingLoadable.Parser<HlsPlaylist> playlistParser; private ParsingLoadable.Parser<HlsPlaylist> playlistParser;
private AdaptiveMediaSourceEventListener eventListener; private AdaptiveMediaSourceEventListener eventListener;
private Handler eventHandler; private Handler eventHandler;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private int minLoadableRetryCount; private int minLoadableRetryCount;
private boolean isBuildCalled; private boolean isBuildCalled;
@ -150,6 +155,22 @@ public final class HlsMediaSource implements MediaSource,
return this; return this;
} }
/**
* Sets the factory to create composite {@link SequenceableLoader}s for when this media source
* loads data from multiple streams (video, audio etc...). The default is an instance of
* {@link DefaultCompositeSequenceableLoaderFactory}.
*
* @param compositeSequenceableLoaderFactory A factory to create composite
* {@link SequenceableLoader}s for when this media source loads data from multiple streams
* (video, audio etc...).
* @return This builder.
*/
public Builder setCompositeSequenceableLoaderFactory(
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
return this;
}
/** /**
* Builds a new {@link HlsMediaSource} using the current parameters. * Builds a new {@link HlsMediaSource} using the current parameters.
* <p> * <p>
@ -167,8 +188,12 @@ public final class HlsMediaSource implements MediaSource,
if (playlistParser == null) { if (playlistParser == null) {
playlistParser = new HlsPlaylistParser(); playlistParser = new HlsPlaylistParser();
} }
if (compositeSequenceableLoaderFactory == null) {
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
}
return new HlsMediaSource(manifestUri, hlsDataSourceFactory, extractorFactory, return new HlsMediaSource(manifestUri, hlsDataSourceFactory, extractorFactory,
minLoadableRetryCount, eventHandler, eventListener, playlistParser); compositeSequenceableLoaderFactory, minLoadableRetryCount, eventHandler, eventListener,
playlistParser);
} }
} }
@ -181,6 +206,7 @@ public final class HlsMediaSource implements MediaSource,
private final HlsExtractorFactory extractorFactory; private final HlsExtractorFactory extractorFactory;
private final Uri manifestUri; private final Uri manifestUri;
private final HlsDataSourceFactory dataSourceFactory; private final HlsDataSourceFactory dataSourceFactory;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final ParsingLoadable.Parser<HlsPlaylist> playlistParser; private final ParsingLoadable.Parser<HlsPlaylist> playlistParser;
@ -242,11 +268,23 @@ public final class HlsMediaSource implements MediaSource,
HlsExtractorFactory extractorFactory, int minLoadableRetryCount, Handler eventHandler, HlsExtractorFactory extractorFactory, int minLoadableRetryCount, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener, AdaptiveMediaSourceEventListener eventListener,
ParsingLoadable.Parser<HlsPlaylist> playlistParser) { ParsingLoadable.Parser<HlsPlaylist> playlistParser) {
this(manifestUri, dataSourceFactory, extractorFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount, eventHandler,
eventListener, playlistParser);
}
private HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory,
HlsExtractorFactory extractorFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener,
ParsingLoadable.Parser<HlsPlaylist> playlistParser) {
this.manifestUri = manifestUri; this.manifestUri = manifestUri;
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.extractorFactory = extractorFactory; this.extractorFactory = extractorFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.playlistParser = playlistParser; this.playlistParser = playlistParser;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
} }
@ -268,7 +306,7 @@ public final class HlsMediaSource implements MediaSource,
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
Assertions.checkArgument(id.periodIndex == 0); Assertions.checkArgument(id.periodIndex == 0);
return new HlsMediaPeriod(extractorFactory, playlistTracker, dataSourceFactory, return new HlsMediaPeriod(extractorFactory, playlistTracker, dataSourceFactory,
minLoadableRetryCount, eventDispatcher, allocator); minLoadableRetryCount, eventDispatcher, allocator, compositeSequenceableLoaderFactory);
} }
@Override @Override

View File

@ -19,7 +19,7 @@ import android.util.Base64;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoader; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.source.SequenceableLoader; import com.google.android.exoplayer2.source.SequenceableLoader;
@ -49,13 +49,15 @@ import java.util.ArrayList;
private final Allocator allocator; private final Allocator allocator;
private final TrackGroupArray trackGroups; private final TrackGroupArray trackGroups;
private final TrackEncryptionBox[] trackEncryptionBoxes; private final TrackEncryptionBox[] trackEncryptionBoxes;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private Callback callback; private Callback callback;
private SsManifest manifest; private SsManifest manifest;
private ChunkSampleStream<SsChunkSource>[] sampleStreams; private ChunkSampleStream<SsChunkSource>[] sampleStreams;
private CompositeSequenceableLoader sequenceableLoader; private SequenceableLoader compositeSequenceableLoader;
public SsMediaPeriod(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, public SsMediaPeriod(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount, EventDispatcher eventDispatcher, int minLoadableRetryCount, EventDispatcher eventDispatcher,
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) { LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) {
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
@ -63,6 +65,7 @@ import java.util.ArrayList;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.allocator = allocator; this.allocator = allocator;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
trackGroups = buildTrackGroups(manifest); trackGroups = buildTrackGroups(manifest);
ProtectionElement protectionElement = manifest.protectionElement; ProtectionElement protectionElement = manifest.protectionElement;
@ -76,7 +79,8 @@ import java.util.ArrayList;
} }
this.manifest = manifest; this.manifest = manifest;
sampleStreams = newSampleStreamArray(0); sampleStreams = newSampleStreamArray(0);
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams); compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
} }
public void updateManifest(SsManifest manifest) { public void updateManifest(SsManifest manifest) {
@ -133,7 +137,8 @@ import java.util.ArrayList;
} }
sampleStreams = newSampleStreamArray(sampleStreamsList.size()); sampleStreams = newSampleStreamArray(sampleStreamsList.size());
sampleStreamsList.toArray(sampleStreams); sampleStreamsList.toArray(sampleStreams);
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams); compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
return positionUs; return positionUs;
} }
@ -146,12 +151,12 @@ import java.util.ArrayList;
@Override @Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return compositeSequenceableLoader.continueLoading(positionUs);
} }
@Override @Override
public long getNextLoadPositionUs() { public long getNextLoadPositionUs() {
return sequenceableLoader.getNextLoadPositionUs(); return compositeSequenceableLoader.getNextLoadPositionUs();
} }
@Override @Override
@ -161,7 +166,7 @@ import java.util.ArrayList;
@Override @Override
public long getBufferedPositionUs() { public long getBufferedPositionUs() {
return sequenceableLoader.getBufferedPositionUs(); return compositeSequenceableLoader.getBufferedPositionUs();
} }
@Override @Override

View File

@ -26,8 +26,11 @@ import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SequenceableLoader;
import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement; import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement;
@ -65,6 +68,7 @@ public final class SsMediaSource implements MediaSource,
private ParsingLoadable.Parser<? extends SsManifest> manifestParser; private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
private AdaptiveMediaSourceEventListener eventListener; private AdaptiveMediaSourceEventListener eventListener;
private Handler eventHandler; private Handler eventHandler;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private int minLoadableRetryCount; private int minLoadableRetryCount;
private long livePresentationDelayMs; private long livePresentationDelayMs;
@ -162,6 +166,22 @@ public final class SsMediaSource implements MediaSource,
return this; return this;
} }
/**
* Sets the factory to create composite {@link SequenceableLoader}s for when this media source
* loads data from multiple streams (video, audio etc...). The default is an instance of
* {@link DefaultCompositeSequenceableLoaderFactory}.
*
* @param compositeSequenceableLoaderFactory A factory to create composite
* {@link SequenceableLoader}s for when this media source loads data from multiple streams
* (video, audio etc...).
* @return This builder.
*/
public Builder setCompositeSequenceableLoaderFactory(
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
return this;
}
/** /**
* Builds a new {@link SsMediaSource} using the current parameters. * Builds a new {@link SsMediaSource} using the current parameters.
* <p> * <p>
@ -177,9 +197,12 @@ public final class SsMediaSource implements MediaSource,
if (loadableManifestUri && manifestParser == null) { if (loadableManifestUri && manifestParser == null) {
manifestParser = new SsManifestParser(); manifestParser = new SsManifestParser();
} }
if (compositeSequenceableLoaderFactory == null) {
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
}
return new SsMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser, return new SsMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser,
chunkSourceFactory, minLoadableRetryCount, livePresentationDelayMs, eventHandler, chunkSourceFactory, compositeSequenceableLoaderFactory, minLoadableRetryCount,
eventListener); livePresentationDelayMs, eventHandler, eventListener);
} }
} }
@ -206,6 +229,7 @@ public final class SsMediaSource implements MediaSource,
private final Uri manifestUri; private final Uri manifestUri;
private final DataSource.Factory manifestDataSourceFactory; private final DataSource.Factory manifestDataSourceFactory;
private final SsChunkSource.Factory chunkSourceFactory; private final SsChunkSource.Factory chunkSourceFactory;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final int minLoadableRetryCount; private final int minLoadableRetryCount;
private final long livePresentationDelayMs; private final long livePresentationDelayMs;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
@ -252,7 +276,8 @@ public final class SsMediaSource implements MediaSource,
public SsMediaSource(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory, public SsMediaSource(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory,
int minLoadableRetryCount, Handler eventHandler, int minLoadableRetryCount, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
this(manifest, null, null, null, chunkSourceFactory, minLoadableRetryCount, this(manifest, null, null, null, chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
DEFAULT_LIVE_PRESENTATION_DELAY_MS, eventHandler, eventListener); DEFAULT_LIVE_PRESENTATION_DELAY_MS, eventHandler, eventListener);
} }
@ -324,14 +349,16 @@ public final class SsMediaSource implements MediaSource,
long livePresentationDelayMs, Handler eventHandler, long livePresentationDelayMs, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory, this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory,
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener); new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
livePresentationDelayMs, eventHandler, eventListener);
} }
private SsMediaSource(SsManifest manifest, Uri manifestUri, private SsMediaSource(SsManifest manifest, Uri manifestUri,
DataSource.Factory manifestDataSourceFactory, DataSource.Factory manifestDataSourceFactory,
ParsingLoadable.Parser<? extends SsManifest> manifestParser, ParsingLoadable.Parser<? extends SsManifest> manifestParser,
SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount, SsChunkSource.Factory chunkSourceFactory,
long livePresentationDelayMs, Handler eventHandler, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
int minLoadableRetryCount, long livePresentationDelayMs, Handler eventHandler,
AdaptiveMediaSourceEventListener eventListener) { AdaptiveMediaSourceEventListener eventListener) {
Assertions.checkState(manifest == null || !manifest.isLive); Assertions.checkState(manifest == null || !manifest.isLive);
this.manifest = manifest; this.manifest = manifest;
@ -341,6 +368,7 @@ public final class SsMediaSource implements MediaSource,
this.manifestDataSourceFactory = manifestDataSourceFactory; this.manifestDataSourceFactory = manifestDataSourceFactory;
this.manifestParser = manifestParser; this.manifestParser = manifestParser;
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
this.livePresentationDelayMs = livePresentationDelayMs; this.livePresentationDelayMs = livePresentationDelayMs;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener); this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
@ -372,8 +400,9 @@ public final class SsMediaSource implements MediaSource,
@Override @Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
Assertions.checkArgument(id.periodIndex == 0); Assertions.checkArgument(id.periodIndex == 0);
SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory, minLoadableRetryCount, SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory,
eventDispatcher, manifestLoaderErrorThrower, allocator); compositeSequenceableLoaderFactory, minLoadableRetryCount, eventDispatcher,
manifestLoaderErrorThrower, allocator);
mediaPeriods.add(period); mediaPeriods.add(period);
return period; return period;
} }