Add simplified adaptive media source stream key filter to factory classes.

This change only simplifies the API by using the ManifestParser internally.

PiperOrigin-RevId: 225516193
This commit is contained in:
tonihei 2018-12-14 11:16:33 +00:00 committed by Oliver Woodman
parent 845f54a467
commit 173ddd6ee7
8 changed files with 147 additions and 46 deletions

View file

@ -15,6 +15,8 @@
* Offline: * Offline:
* Speed up removal of segmented downloads * Speed up removal of segmented downloads
([#5136](https://github.com/google/ExoPlayer/issues/5136)). ([#5136](https://github.com/google/ExoPlayer/issues/5136)).
* Add `setStreamKeys` method to factories of DASH, SmoothStreaming and HLS
media sources to simplify filtering by downloaded streams.
* Caching: * Caching:
* Improve performance of `SimpleCache`. * Improve performance of `SimpleCache`.
* Cache data with unknown length by default. The previous flag to opt in to * Cache data with unknown length by default. The previous flag to opt in to

View file

@ -48,7 +48,6 @@ import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.UnsupportedDrmException; import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.offline.FilteringManifestParser;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
@ -58,11 +57,8 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdsLoader; import com.google.android.exoplayer2.source.ads.AdsLoader;
import com.google.android.exoplayer2.source.ads.AdsMediaSource; import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource; import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
import com.google.android.exoplayer2.source.hls.HlsMediaSource; import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistParserFactory;
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
@ -472,21 +468,19 @@ public class PlayerActivity extends Activity
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) { private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
@ContentType int type = Util.inferContentType(uri, overrideExtension); @ContentType int type = Util.inferContentType(uri, overrideExtension);
List<StreamKey> offlineStreamKeys = getOfflineStreamKeys(uri);
switch (type) { switch (type) {
case C.TYPE_DASH: case C.TYPE_DASH:
return new DashMediaSource.Factory(dataSourceFactory) return new DashMediaSource.Factory(dataSourceFactory)
.setManifestParser( .setStreamKeys(offlineStreamKeys)
new FilteringManifestParser<>(new DashManifestParser(), getOfflineStreamKeys(uri)))
.createMediaSource(uri); .createMediaSource(uri);
case C.TYPE_SS: case C.TYPE_SS:
return new SsMediaSource.Factory(dataSourceFactory) return new SsMediaSource.Factory(dataSourceFactory)
.setManifestParser( .setStreamKeys(offlineStreamKeys)
new FilteringManifestParser<>(new SsManifestParser(), getOfflineStreamKeys(uri)))
.createMediaSource(uri); .createMediaSource(uri);
case C.TYPE_HLS: case C.TYPE_HLS:
return new HlsMediaSource.Factory(dataSourceFactory) return new HlsMediaSource.Factory(dataSourceFactory)
.setPlaylistParserFactory( .setStreamKeys(offlineStreamKeys)
new DefaultHlsPlaylistParserFactory(getOfflineStreamKeys(uri)))
.createMediaSource(uri); .createMediaSource(uri);
case C.TYPE_OTHER: case C.TYPE_OTHER:
return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri); return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);

View file

@ -16,22 +16,27 @@
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser; import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
/** A manifest parser that includes only the streams identified by the given stream keys. */ /**
* A manifest parser that includes only the streams identified by the given stream keys.
*
* @param <T> The {@link FilterableManifest} type.
*/
public final class FilteringManifestParser<T extends FilterableManifest<T>> implements Parser<T> { public final class FilteringManifestParser<T extends FilterableManifest<T>> implements Parser<T> {
private final Parser<T> parser; private final Parser<? extends T> parser;
private final List<StreamKey> streamKeys; @Nullable private final List<StreamKey> streamKeys;
/** /**
* @param parser A parser for the manifest that will be filtered. * @param parser A parser for the manifest that will be filtered.
* @param streamKeys The stream keys. If null or empty then filtering will not occur. * @param streamKeys The stream keys. If null or empty then filtering will not occur.
*/ */
public FilteringManifestParser(Parser<T> parser, List<StreamKey> streamKeys) { public FilteringManifestParser(Parser<? extends T> parser, @Nullable List<StreamKey> streamKeys) {
this.parser = parser; this.parser = parser;
this.streamKeys = streamKeys; this.streamKeys = streamKeys;
} }

View file

@ -26,6 +26,8 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.offline.FilteringManifestParser;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
@ -59,6 +61,7 @@ import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -75,15 +78,16 @@ public final class DashMediaSource extends BaseMediaSource {
public static final class Factory implements AdsMediaSource.MediaSourceFactory { public static final class Factory implements AdsMediaSource.MediaSourceFactory {
private final DashChunkSource.Factory chunkSourceFactory; private final DashChunkSource.Factory chunkSourceFactory;
private final @Nullable DataSource.Factory manifestDataSourceFactory; @Nullable private final DataSource.Factory manifestDataSourceFactory;
private @Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser; @Nullable private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
@Nullable private List<StreamKey> streamKeys;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private long livePresentationDelayMs; private long livePresentationDelayMs;
private boolean livePresentationDelayOverridesManifest; private boolean livePresentationDelayOverridesManifest;
private boolean isCreateCalled; private boolean isCreateCalled;
private @Nullable Object tag; @Nullable private Object tag;
/** /**
* Creates a new factory for {@link DashMediaSource}s. * Creates a new factory for {@link DashMediaSource}s.
@ -210,6 +214,19 @@ public final class DashMediaSource extends BaseMediaSource {
return this; return this;
} }
/**
* Sets a list of {@link StreamKey stream keys} by which the manifest is filtered.
*
* @param streamKeys A list of {@link StreamKey stream keys}.
* @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called.
*/
public Factory setStreamKeys(List<StreamKey> streamKeys) {
Assertions.checkState(!isCreateCalled);
this.streamKeys = streamKeys;
return this;
}
/** /**
* Sets the factory to create composite {@link SequenceableLoader}s for when this media source * 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 * loads data from multiple streams (video, audio etc...). The default is an instance of {@link
@ -240,6 +257,9 @@ public final class DashMediaSource extends BaseMediaSource {
public DashMediaSource createMediaSource(DashManifest manifest) { public DashMediaSource createMediaSource(DashManifest manifest) {
Assertions.checkArgument(!manifest.dynamic); Assertions.checkArgument(!manifest.dynamic);
isCreateCalled = true; isCreateCalled = true;
if (streamKeys != null && !streamKeys.isEmpty()) {
manifest = manifest.copy(streamKeys);
}
return new DashMediaSource( return new DashMediaSource(
manifest, manifest,
/* manifestUri= */ null, /* manifestUri= */ null,
@ -281,6 +301,9 @@ public final class DashMediaSource extends BaseMediaSource {
if (manifestParser == null) { if (manifestParser == null) {
manifestParser = new DashManifestParser(); manifestParser = new DashManifestParser();
} }
if (streamKeys != null) {
manifestParser = new FilteringManifestParser<>(manifestParser, streamKeys);
}
return new DashMediaSource( return new DashMediaSource(
/* manifest= */ null, /* manifest= */ null,
Assertions.checkNotNull(manifestUri), Assertions.checkNotNull(manifestUri),

View file

@ -22,6 +22,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; 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.offline.StreamKey;
import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
@ -34,6 +35,7 @@ import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import com.google.android.exoplayer2.source.ads.AdsMediaSource; import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistParserFactory; import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistParserFactory;
import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistTracker; import com.google.android.exoplayer2.source.hls.playlist.DefaultHlsPlaylistTracker;
import com.google.android.exoplayer2.source.hls.playlist.FilteringHlsPlaylistParserFactory;
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;
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser;
@ -64,12 +66,13 @@ public final class HlsMediaSource extends BaseMediaSource
private HlsExtractorFactory extractorFactory; private HlsExtractorFactory extractorFactory;
private HlsPlaylistParserFactory playlistParserFactory; private HlsPlaylistParserFactory playlistParserFactory;
@Nullable private List<StreamKey> streamKeys;
private HlsPlaylistTracker.Factory playlistTrackerFactory; private HlsPlaylistTracker.Factory playlistTrackerFactory;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private boolean allowChunklessPreparation; private boolean allowChunklessPreparation;
private boolean isCreateCalled; private boolean isCreateCalled;
private @Nullable Object tag; @Nullable private Object tag;
/** /**
* Creates a new factory for {@link HlsMediaSource}s. * Creates a new factory for {@link HlsMediaSource}s.
@ -164,8 +167,8 @@ public final class HlsMediaSource extends BaseMediaSource
} }
/** /**
* Sets the factory from which playlist parsers will be obtained. The default value is created * Sets the factory from which playlist parsers will be obtained. The default value is a {@link
* by calling {@link DefaultHlsPlaylistParserFactory#DefaultHlsPlaylistParserFactory()}. * DefaultHlsPlaylistParserFactory}.
* *
* @param playlistParserFactory An {@link HlsPlaylistParserFactory}. * @param playlistParserFactory An {@link HlsPlaylistParserFactory}.
* @return This factory, for convenience. * @return This factory, for convenience.
@ -177,6 +180,19 @@ public final class HlsMediaSource extends BaseMediaSource
return this; return this;
} }
/**
* Sets a list of {@link StreamKey stream keys} by which the playlists are filtered.
*
* @param streamKeys A list of {@link StreamKey stream keys}.
* @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called.
*/
public Factory setStreamKeys(List<StreamKey> streamKeys) {
Assertions.checkState(!isCreateCalled);
this.streamKeys = streamKeys;
return this;
}
/** /**
* Sets the {@link HlsPlaylistTracker} factory. The default value is {@link * Sets the {@link HlsPlaylistTracker} factory. The default value is {@link
* DefaultHlsPlaylistTracker#FACTORY}. * DefaultHlsPlaylistTracker#FACTORY}.
@ -232,6 +248,10 @@ public final class HlsMediaSource extends BaseMediaSource
@Override @Override
public HlsMediaSource createMediaSource(Uri playlistUri) { public HlsMediaSource createMediaSource(Uri playlistUri) {
isCreateCalled = true; isCreateCalled = true;
if (streamKeys != null) {
playlistParserFactory =
new FilteringHlsPlaylistParserFactory(playlistParserFactory, streamKeys);
}
return new HlsMediaSource( return new HlsMediaSource(
playlistUri, playlistUri,
hlsDataSourceFactory, hlsDataSourceFactory,

View file

@ -15,40 +15,19 @@
*/ */
package com.google.android.exoplayer2.source.hls.playlist; package com.google.android.exoplayer2.source.hls.playlist;
import com.google.android.exoplayer2.offline.FilteringManifestParser;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.upstream.ParsingLoadable; import com.google.android.exoplayer2.upstream.ParsingLoadable;
import java.util.Collections;
import java.util.List;
/** Default implementation for {@link HlsPlaylistParserFactory}. */ /** Default implementation for {@link HlsPlaylistParserFactory}. */
public final class DefaultHlsPlaylistParserFactory implements HlsPlaylistParserFactory { public final class DefaultHlsPlaylistParserFactory implements HlsPlaylistParserFactory {
private final List<StreamKey> streamKeys;
/** Creates an instance that does not filter any parsing results. */
public DefaultHlsPlaylistParserFactory() {
this(Collections.emptyList());
}
/**
* Creates an instance that filters the parsing results using the given {@code streamKeys}.
*
* @param streamKeys See {@link
* FilteringManifestParser#FilteringManifestParser(ParsingLoadable.Parser, List)}.
*/
public DefaultHlsPlaylistParserFactory(List<StreamKey> streamKeys) {
this.streamKeys = streamKeys;
}
@Override @Override
public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser() { public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser() {
return new FilteringManifestParser<>(new HlsPlaylistParser(), streamKeys); return new HlsPlaylistParser();
} }
@Override @Override
public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser( public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser(
HlsMasterPlaylist masterPlaylist) { HlsMasterPlaylist masterPlaylist) {
return new FilteringManifestParser<>(new HlsPlaylistParser(masterPlaylist), streamKeys); return new HlsPlaylistParser(masterPlaylist);
} }
} }

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 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.hls.playlist;
import com.google.android.exoplayer2.offline.FilteringManifestParser;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import java.util.List;
/**
* A {@link HlsPlaylistParserFactory} that includes only the streams identified by the given stream
* keys.
*/
public final class FilteringHlsPlaylistParserFactory implements HlsPlaylistParserFactory {
private final HlsPlaylistParserFactory hlsPlaylistParserFactory;
private final List<StreamKey> streamKeys;
/**
* @param hlsPlaylistParserFactory A factory for the parsers of the playlists which will be
* filtered.
* @param streamKeys The stream keys. If null or empty then filtering will not occur.
*/
public FilteringHlsPlaylistParserFactory(
HlsPlaylistParserFactory hlsPlaylistParserFactory, List<StreamKey> streamKeys) {
this.hlsPlaylistParserFactory = hlsPlaylistParserFactory;
this.streamKeys = streamKeys;
}
@Override
public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser() {
return new FilteringManifestParser<>(
hlsPlaylistParserFactory.createPlaylistParser(), streamKeys);
}
@Override
public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser(
HlsMasterPlaylist masterPlaylist) {
return new FilteringManifestParser<>(
hlsPlaylistParserFactory.createPlaylistParser(masterPlaylist), streamKeys);
}
}

View file

@ -24,6 +24,8 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.offline.FilteringManifestParser;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory; import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
@ -50,6 +52,7 @@ import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
/** A SmoothStreaming {@link MediaSource}. */ /** A SmoothStreaming {@link MediaSource}. */
public final class SsMediaSource extends BaseMediaSource public final class SsMediaSource extends BaseMediaSource
@ -63,14 +66,15 @@ public final class SsMediaSource extends BaseMediaSource
public static final class Factory implements AdsMediaSource.MediaSourceFactory { public static final class Factory implements AdsMediaSource.MediaSourceFactory {
private final SsChunkSource.Factory chunkSourceFactory; private final SsChunkSource.Factory chunkSourceFactory;
private final @Nullable DataSource.Factory manifestDataSourceFactory; @Nullable private final DataSource.Factory manifestDataSourceFactory;
private @Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser; @Nullable private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
@Nullable private List<StreamKey> streamKeys;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private long livePresentationDelayMs; private long livePresentationDelayMs;
private boolean isCreateCalled; private boolean isCreateCalled;
private @Nullable Object tag; @Nullable private Object tag;
/** /**
* Creates a new factory for {@link SsMediaSource}s. * Creates a new factory for {@link SsMediaSource}s.
@ -178,6 +182,19 @@ public final class SsMediaSource extends BaseMediaSource
return this; return this;
} }
/**
* Sets a list of {@link StreamKey stream keys} by which the manifest is filtered.
*
* @param streamKeys A list of {@link StreamKey stream keys}.
* @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called.
*/
public Factory setStreamKeys(List<StreamKey> streamKeys) {
Assertions.checkState(!isCreateCalled);
this.streamKeys = streamKeys;
return this;
}
/** /**
* Sets the factory to create composite {@link SequenceableLoader}s for when this media source * 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 * loads data from multiple streams (video, audio etc.). The default is an instance of {@link
@ -208,6 +225,9 @@ public final class SsMediaSource extends BaseMediaSource
public SsMediaSource createMediaSource(SsManifest manifest) { public SsMediaSource createMediaSource(SsManifest manifest) {
Assertions.checkArgument(!manifest.isLive); Assertions.checkArgument(!manifest.isLive);
isCreateCalled = true; isCreateCalled = true;
if (streamKeys != null && !streamKeys.isEmpty()) {
manifest = manifest.copy(streamKeys);
}
return new SsMediaSource( return new SsMediaSource(
manifest, manifest,
/* manifestUri= */ null, /* manifestUri= */ null,
@ -248,6 +268,9 @@ public final class SsMediaSource extends BaseMediaSource
if (manifestParser == null) { if (manifestParser == null) {
manifestParser = new SsManifestParser(); manifestParser = new SsManifestParser();
} }
if (streamKeys != null) {
manifestParser = new FilteringManifestParser<>(manifestParser, streamKeys);
}
return new SsMediaSource( return new SsMediaSource(
/* manifest= */ null, /* manifest= */ null,
Assertions.checkNotNull(manifestUri), Assertions.checkNotNull(manifestUri),