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:
parent
e45907193c
commit
0de57cbfae
@ -2,8 +2,12 @@
|
||||
|
||||
### dev-v2 (not yet released) ###
|
||||
|
||||
* Add Builder to ExtractorMediaSource, HlsMediaSource, SsMediaSource,
|
||||
DashMediaSource, SingleSampleMediaSource.
|
||||
* Allow more flexible loading strategy when playing media containing multiple
|
||||
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:
|
||||
* Support in-MPD EventStream.
|
||||
* Allow a back-buffer of media to be retained behind the current playback
|
||||
|
@ -20,9 +20,9 @@ import com.google.android.exoplayer2.C;
|
||||
/**
|
||||
* 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) {
|
||||
this.loaders = loaders;
|
||||
@ -53,7 +53,7 @@ public final class CompositeSequenceableLoader implements SequenceableLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean continueLoading(long positionUs) {
|
||||
public boolean continueLoading(long positionUs) {
|
||||
boolean madeProgress = false;
|
||||
boolean madeProgressThisIteration;
|
||||
do {
|
||||
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -30,15 +30,18 @@ import java.util.IdentityHashMap;
|
||||
public final MediaPeriod[] periods;
|
||||
|
||||
private final IdentityHashMap<SampleStream, Integer> streamPeriodIndices;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private Callback callback;
|
||||
private int pendingChildPrepareCount;
|
||||
private TrackGroupArray trackGroups;
|
||||
|
||||
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;
|
||||
streamPeriodIndices = new IdentityHashMap<>();
|
||||
}
|
||||
@ -124,7 +127,8 @@ import java.util.IdentityHashMap;
|
||||
// Update the local state.
|
||||
enabledPeriods = new MediaPeriod[enabledPeriodsList.size()];
|
||||
enabledPeriodsList.toArray(enabledPeriods);
|
||||
sequenceableLoader = new CompositeSequenceableLoader(enabledPeriods);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(enabledPeriods);
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
@ -137,12 +141,12 @@ import java.util.IdentityHashMap;
|
||||
|
||||
@Override
|
||||
public boolean continueLoading(long positionUs) {
|
||||
return sequenceableLoader.continueLoading(positionUs);
|
||||
return compositeSequenceableLoader.continueLoading(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextLoadPositionUs() {
|
||||
return sequenceableLoader.getNextLoadPositionUs();
|
||||
return compositeSequenceableLoader.getNextLoadPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,7 +172,7 @@ import java.util.IdentityHashMap;
|
||||
|
||||
@Override
|
||||
public long getBufferedPositionUs() {
|
||||
return sequenceableLoader.getBufferedPositionUs();
|
||||
return compositeSequenceableLoader.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,6 +74,7 @@ public final class MergingMediaSource implements MediaSource {
|
||||
private final MediaSource[] mediaSources;
|
||||
private final ArrayList<MediaSource> pendingTimelineSources;
|
||||
private final Timeline.Window window;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private Listener listener;
|
||||
private Timeline primaryTimeline;
|
||||
@ -85,7 +86,19 @@ public final class MergingMediaSource implements MediaSource {
|
||||
* @param mediaSources The {@link MediaSource}s to merge.
|
||||
*/
|
||||
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.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
pendingTimelineSources = new ArrayList<>(Arrays.asList(mediaSources));
|
||||
window = new Timeline.Window();
|
||||
periodCount = PERIOD_COUNT_UNSET;
|
||||
@ -121,7 +134,7 @@ public final class MergingMediaSource implements MediaSource {
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
periods[i] = mediaSources[i].createPeriod(id, allocator);
|
||||
}
|
||||
return new MergingMediaPeriod(periods);
|
||||
return new MergingMediaPeriod(compositeSequenceableLoaderFactory, periods);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,7 +21,7 @@ import android.util.SparseIntArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
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.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
@ -64,11 +64,12 @@ import java.util.Map;
|
||||
private final Allocator allocator;
|
||||
private final TrackGroupArray trackGroups;
|
||||
private final TrackGroupInfo[] trackGroupInfos;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private Callback callback;
|
||||
private ChunkSampleStream<DashChunkSource>[] sampleStreams;
|
||||
private EventSampleStream[] eventSampleStreams;
|
||||
private CompositeSequenceableLoader sequenceableLoader;
|
||||
private SequenceableLoader compositeSequenceableLoader;
|
||||
private DashManifest manifest;
|
||||
private int periodIndex;
|
||||
private List<EventStream> eventStreams;
|
||||
@ -76,7 +77,8 @@ import java.util.Map;
|
||||
public DashMediaPeriod(int id, DashManifest manifest, int periodIndex,
|
||||
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
|
||||
EventDispatcher eventDispatcher, long elapsedRealtimeOffset,
|
||||
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) {
|
||||
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
this.id = id;
|
||||
this.manifest = manifest;
|
||||
this.periodIndex = periodIndex;
|
||||
@ -86,9 +88,11 @@ import java.util.Map;
|
||||
this.elapsedRealtimeOffset = elapsedRealtimeOffset;
|
||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||
this.allocator = allocator;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
sampleStreams = newSampleStreamArray(0);
|
||||
eventSampleStreams = new EventSampleStream[0];
|
||||
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
|
||||
Period period = manifest.getPeriod(periodIndex);
|
||||
eventStreams = period.eventStreams;
|
||||
Pair<TrackGroupArray, TrackGroupInfo[]> result = buildTrackGroups(period.adaptationSets,
|
||||
@ -163,7 +167,8 @@ import java.util.Map;
|
||||
primarySampleStreams.values().toArray(sampleStreams);
|
||||
eventSampleStreams = new EventSampleStream[eventSampleStreamList.size()];
|
||||
eventSampleStreamList.toArray(eventSampleStreams);
|
||||
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
@ -267,12 +272,12 @@ import java.util.Map;
|
||||
|
||||
@Override
|
||||
public boolean continueLoading(long positionUs) {
|
||||
return sequenceableLoader.continueLoading(positionUs);
|
||||
return compositeSequenceableLoader.continueLoading(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextLoadPositionUs() {
|
||||
return sequenceableLoader.getNextLoadPositionUs();
|
||||
return compositeSequenceableLoader.getNextLoadPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -282,7 +287,7 @@ import java.util.Map;
|
||||
|
||||
@Override
|
||||
public long getBufferedPositionUs() {
|
||||
return sequenceableLoader.getBufferedPositionUs();
|
||||
return compositeSequenceableLoader.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,8 +28,11 @@ import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
|
||||
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.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.DashManifestParser;
|
||||
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 AdaptiveMediaSourceEventListener eventListener;
|
||||
private Handler eventHandler;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private int minLoadableRetryCount;
|
||||
private long livePresentationDelayMs;
|
||||
@ -171,6 +175,22 @@ public final class DashMediaSource implements MediaSource {
|
||||
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.
|
||||
* <p>
|
||||
@ -186,9 +206,12 @@ public final class DashMediaSource implements MediaSource {
|
||||
if (loadableManifestUri && manifestParser == null) {
|
||||
manifestParser = new DashManifestParser();
|
||||
}
|
||||
if (compositeSequenceableLoaderFactory == null) {
|
||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||
}
|
||||
return new DashMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser,
|
||||
chunkSourceFactory, minLoadableRetryCount, livePresentationDelayMs, eventHandler,
|
||||
eventListener);
|
||||
chunkSourceFactory, compositeSequenceableLoaderFactory, minLoadableRetryCount,
|
||||
livePresentationDelayMs, eventHandler, eventListener);
|
||||
}
|
||||
|
||||
}
|
||||
@ -226,6 +249,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
private final boolean sideloadedManifest;
|
||||
private final DataSource.Factory manifestDataSourceFactory;
|
||||
private final DashChunkSource.Factory chunkSourceFactory;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final int minLoadableRetryCount;
|
||||
private final long livePresentationDelayMs;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
@ -280,7 +304,8 @@ public final class DashMediaSource implements MediaSource {
|
||||
public DashMediaSource(DashManifest manifest, DashChunkSource.Factory chunkSourceFactory,
|
||||
int minLoadableRetryCount, Handler eventHandler, AdaptiveMediaSourceEventListener
|
||||
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);
|
||||
}
|
||||
|
||||
@ -356,14 +381,16 @@ public final class DashMediaSource implements MediaSource {
|
||||
long livePresentationDelayMs, Handler eventHandler,
|
||||
AdaptiveMediaSourceEventListener eventListener) {
|
||||
this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory,
|
||||
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener);
|
||||
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
|
||||
livePresentationDelayMs, eventHandler, eventListener);
|
||||
}
|
||||
|
||||
private DashMediaSource(DashManifest manifest, Uri manifestUri,
|
||||
DataSource.Factory manifestDataSourceFactory,
|
||||
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
|
||||
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
|
||||
long livePresentationDelayMs, Handler eventHandler,
|
||||
DashChunkSource.Factory chunkSourceFactory,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
int minLoadableRetryCount, long livePresentationDelayMs, Handler eventHandler,
|
||||
AdaptiveMediaSourceEventListener eventListener) {
|
||||
this.manifest = manifest;
|
||||
this.manifestUri = manifestUri;
|
||||
@ -372,6 +399,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
sideloadedManifest = manifest != null;
|
||||
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||
manifestUriLock = new Object();
|
||||
@ -438,7 +466,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
manifest.getPeriod(periodIndex).startMs);
|
||||
DashMediaPeriod mediaPeriod = new DashMediaPeriod(firstPeriodId + periodIndex, manifest,
|
||||
periodIndex, chunkSourceFactory, minLoadableRetryCount, periodEventDispatcher,
|
||||
elapsedRealtimeOffsetMs, loaderErrorThrower, allocator);
|
||||
elapsedRealtimeOffsetMs, loaderErrorThrower, allocator, compositeSequenceableLoaderFactory);
|
||||
periodsById.put(mediaPeriod.id, mediaPeriod);
|
||||
return mediaPeriod;
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ import android.text.TextUtils;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
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.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
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 TimestampAdjusterProvider timestampAdjusterProvider;
|
||||
private final Handler continueLoadingHandler;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private Callback callback;
|
||||
private int pendingPrepareCount;
|
||||
private TrackGroupArray trackGroups;
|
||||
private HlsSampleStreamWrapper[] sampleStreamWrappers;
|
||||
private HlsSampleStreamWrapper[] enabledSampleStreamWrappers;
|
||||
private CompositeSequenceableLoader sequenceableLoader;
|
||||
private SequenceableLoader compositeSequenceableLoader;
|
||||
|
||||
public HlsMediaPeriod(HlsExtractorFactory extractorFactory, HlsPlaylistTracker playlistTracker,
|
||||
HlsDataSourceFactory dataSourceFactory, int minLoadableRetryCount,
|
||||
EventDispatcher eventDispatcher, Allocator allocator) {
|
||||
EventDispatcher eventDispatcher, Allocator allocator,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
this.extractorFactory = extractorFactory;
|
||||
this.playlistTracker = playlistTracker;
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.allocator = allocator;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
streamWrapperIndices = new IdentityHashMap<>();
|
||||
timestampAdjusterProvider = new TimestampAdjusterProvider();
|
||||
continueLoadingHandler = new Handler();
|
||||
@ -178,7 +182,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
// Update the local state.
|
||||
enabledSampleStreamWrappers = Arrays.copyOf(newEnabledSampleStreamWrappers,
|
||||
newEnabledSampleStreamWrapperCount);
|
||||
sequenceableLoader = new CompositeSequenceableLoader(enabledSampleStreamWrappers);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(
|
||||
enabledSampleStreamWrappers);
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
@ -191,12 +197,12 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
|
||||
@Override
|
||||
public boolean continueLoading(long positionUs) {
|
||||
return sequenceableLoader.continueLoading(positionUs);
|
||||
return compositeSequenceableLoader.continueLoading(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextLoadPositionUs() {
|
||||
return sequenceableLoader.getNextLoadPositionUs();
|
||||
return compositeSequenceableLoader.getNextLoadPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -206,7 +212,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
|
||||
@Override
|
||||
public long getBufferedPositionUs() {
|
||||
return sequenceableLoader.getBufferedPositionUs();
|
||||
return compositeSequenceableLoader.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,8 +23,11 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
|
||||
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.MediaSource;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.SinglePeriodTimeline;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
|
||||
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 AdaptiveMediaSourceEventListener eventListener;
|
||||
private Handler eventHandler;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private int minLoadableRetryCount;
|
||||
private boolean isBuildCalled;
|
||||
|
||||
@ -150,6 +155,22 @@ public final class HlsMediaSource implements MediaSource,
|
||||
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.
|
||||
* <p>
|
||||
@ -167,8 +188,12 @@ public final class HlsMediaSource implements MediaSource,
|
||||
if (playlistParser == null) {
|
||||
playlistParser = new HlsPlaylistParser();
|
||||
}
|
||||
if (compositeSequenceableLoaderFactory == null) {
|
||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||
}
|
||||
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 Uri manifestUri;
|
||||
private final HlsDataSourceFactory dataSourceFactory;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final int minLoadableRetryCount;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final ParsingLoadable.Parser<HlsPlaylist> playlistParser;
|
||||
@ -242,11 +268,23 @@ public final class HlsMediaSource implements MediaSource,
|
||||
HlsExtractorFactory extractorFactory, int minLoadableRetryCount, Handler eventHandler,
|
||||
AdaptiveMediaSourceEventListener eventListener,
|
||||
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.dataSourceFactory = dataSourceFactory;
|
||||
this.extractorFactory = extractorFactory;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.playlistParser = playlistParser;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||
}
|
||||
|
||||
@ -268,7 +306,7 @@ public final class HlsMediaSource implements MediaSource,
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
Assertions.checkArgument(id.periodIndex == 0);
|
||||
return new HlsMediaPeriod(extractorFactory, playlistTracker, dataSourceFactory,
|
||||
minLoadableRetryCount, eventDispatcher, allocator);
|
||||
minLoadableRetryCount, eventDispatcher, allocator, compositeSequenceableLoaderFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,7 @@ import android.util.Base64;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox;
|
||||
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.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
@ -49,13 +49,15 @@ import java.util.ArrayList;
|
||||
private final Allocator allocator;
|
||||
private final TrackGroupArray trackGroups;
|
||||
private final TrackEncryptionBox[] trackEncryptionBoxes;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private Callback callback;
|
||||
private SsManifest manifest;
|
||||
private ChunkSampleStream<SsChunkSource>[] sampleStreams;
|
||||
private CompositeSequenceableLoader sequenceableLoader;
|
||||
private SequenceableLoader compositeSequenceableLoader;
|
||||
|
||||
public SsMediaPeriod(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
int minLoadableRetryCount, EventDispatcher eventDispatcher,
|
||||
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) {
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
@ -63,6 +65,7 @@ import java.util.ArrayList;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.allocator = allocator;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
|
||||
trackGroups = buildTrackGroups(manifest);
|
||||
ProtectionElement protectionElement = manifest.protectionElement;
|
||||
@ -76,7 +79,8 @@ import java.util.ArrayList;
|
||||
}
|
||||
this.manifest = manifest;
|
||||
sampleStreams = newSampleStreamArray(0);
|
||||
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
|
||||
}
|
||||
|
||||
public void updateManifest(SsManifest manifest) {
|
||||
@ -133,7 +137,8 @@ import java.util.ArrayList;
|
||||
}
|
||||
sampleStreams = newSampleStreamArray(sampleStreamsList.size());
|
||||
sampleStreamsList.toArray(sampleStreams);
|
||||
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
|
||||
return positionUs;
|
||||
}
|
||||
|
||||
@ -146,12 +151,12 @@ import java.util.ArrayList;
|
||||
|
||||
@Override
|
||||
public boolean continueLoading(long positionUs) {
|
||||
return sequenceableLoader.continueLoading(positionUs);
|
||||
return compositeSequenceableLoader.continueLoading(positionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextLoadPositionUs() {
|
||||
return sequenceableLoader.getNextLoadPositionUs();
|
||||
return compositeSequenceableLoader.getNextLoadPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,7 +166,7 @@ import java.util.ArrayList;
|
||||
|
||||
@Override
|
||||
public long getBufferedPositionUs() {
|
||||
return sequenceableLoader.getBufferedPositionUs();
|
||||
return compositeSequenceableLoader.getBufferedPositionUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,8 +26,11 @@ import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
|
||||
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.MediaSource;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
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.StreamElement;
|
||||
@ -65,6 +68,7 @@ public final class SsMediaSource implements MediaSource,
|
||||
private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||
private AdaptiveMediaSourceEventListener eventListener;
|
||||
private Handler eventHandler;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private int minLoadableRetryCount;
|
||||
private long livePresentationDelayMs;
|
||||
@ -162,6 +166,22 @@ public final class SsMediaSource implements MediaSource,
|
||||
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.
|
||||
* <p>
|
||||
@ -177,9 +197,12 @@ public final class SsMediaSource implements MediaSource,
|
||||
if (loadableManifestUri && manifestParser == null) {
|
||||
manifestParser = new SsManifestParser();
|
||||
}
|
||||
if (compositeSequenceableLoaderFactory == null) {
|
||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||
}
|
||||
return new SsMediaSource(manifest, manifestUri, manifestDataSourceFactory, manifestParser,
|
||||
chunkSourceFactory, minLoadableRetryCount, livePresentationDelayMs, eventHandler,
|
||||
eventListener);
|
||||
chunkSourceFactory, compositeSequenceableLoaderFactory, minLoadableRetryCount,
|
||||
livePresentationDelayMs, eventHandler, eventListener);
|
||||
}
|
||||
|
||||
}
|
||||
@ -206,6 +229,7 @@ public final class SsMediaSource implements MediaSource,
|
||||
private final Uri manifestUri;
|
||||
private final DataSource.Factory manifestDataSourceFactory;
|
||||
private final SsChunkSource.Factory chunkSourceFactory;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final int minLoadableRetryCount;
|
||||
private final long livePresentationDelayMs;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
@ -252,7 +276,8 @@ public final class SsMediaSource implements MediaSource,
|
||||
public SsMediaSource(SsManifest manifest, SsChunkSource.Factory chunkSourceFactory,
|
||||
int minLoadableRetryCount, Handler eventHandler,
|
||||
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);
|
||||
}
|
||||
|
||||
@ -324,14 +349,16 @@ public final class SsMediaSource implements MediaSource,
|
||||
long livePresentationDelayMs, Handler eventHandler,
|
||||
AdaptiveMediaSourceEventListener eventListener) {
|
||||
this(null, manifestUri, manifestDataSourceFactory, manifestParser, chunkSourceFactory,
|
||||
minLoadableRetryCount, livePresentationDelayMs, eventHandler, eventListener);
|
||||
new DefaultCompositeSequenceableLoaderFactory(), minLoadableRetryCount,
|
||||
livePresentationDelayMs, eventHandler, eventListener);
|
||||
}
|
||||
|
||||
private SsMediaSource(SsManifest manifest, Uri manifestUri,
|
||||
DataSource.Factory manifestDataSourceFactory,
|
||||
ParsingLoadable.Parser<? extends SsManifest> manifestParser,
|
||||
SsChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
|
||||
long livePresentationDelayMs, Handler eventHandler,
|
||||
SsChunkSource.Factory chunkSourceFactory,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
int minLoadableRetryCount, long livePresentationDelayMs, Handler eventHandler,
|
||||
AdaptiveMediaSourceEventListener eventListener) {
|
||||
Assertions.checkState(manifest == null || !manifest.isLive);
|
||||
this.manifest = manifest;
|
||||
@ -341,6 +368,7 @@ public final class SsMediaSource implements MediaSource,
|
||||
this.manifestDataSourceFactory = manifestDataSourceFactory;
|
||||
this.manifestParser = manifestParser;
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||
@ -372,8 +400,9 @@ public final class SsMediaSource implements MediaSource,
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
Assertions.checkArgument(id.periodIndex == 0);
|
||||
SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory, minLoadableRetryCount,
|
||||
eventDispatcher, manifestLoaderErrorThrower, allocator);
|
||||
SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory,
|
||||
compositeSequenceableLoaderFactory, minLoadableRetryCount, eventDispatcher,
|
||||
manifestLoaderErrorThrower, allocator);
|
||||
mediaPeriods.add(period);
|
||||
return period;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user