mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
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:
parent
845f54a467
commit
173ddd6ee7
8 changed files with 147 additions and 46 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue