mirror of
https://github.com/samsonjs/media.git
synced 2026-04-24 14:37:45 +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:
|
||||
* Speed up removal of segmented downloads
|
||||
([#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:
|
||||
* Improve performance of `SimpleCache`.
|
||||
* 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.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
||||
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.source.BehindLiveWindowException;
|
||||
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.AdsMediaSource;
|
||||
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.playlist.DefaultHlsPlaylistParserFactory;
|
||||
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.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||
|
|
@ -472,21 +468,19 @@ public class PlayerActivity extends Activity
|
|||
@SuppressWarnings("unchecked")
|
||||
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
|
||||
@ContentType int type = Util.inferContentType(uri, overrideExtension);
|
||||
List<StreamKey> offlineStreamKeys = getOfflineStreamKeys(uri);
|
||||
switch (type) {
|
||||
case C.TYPE_DASH:
|
||||
return new DashMediaSource.Factory(dataSourceFactory)
|
||||
.setManifestParser(
|
||||
new FilteringManifestParser<>(new DashManifestParser(), getOfflineStreamKeys(uri)))
|
||||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_SS:
|
||||
return new SsMediaSource.Factory(dataSourceFactory)
|
||||
.setManifestParser(
|
||||
new FilteringManifestParser<>(new SsManifestParser(), getOfflineStreamKeys(uri)))
|
||||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(dataSourceFactory)
|
||||
.setPlaylistParserFactory(
|
||||
new DefaultHlsPlaylistParserFactory(getOfflineStreamKeys(uri)))
|
||||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_OTHER:
|
||||
return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
|
|
|
|||
|
|
@ -16,22 +16,27 @@
|
|||
package com.google.android.exoplayer2.offline;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.upstream.ParsingLoadable.Parser;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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> {
|
||||
|
||||
private final Parser<T> parser;
|
||||
private final List<StreamKey> streamKeys;
|
||||
private final Parser<? extends T> parser;
|
||||
@Nullable private final List<StreamKey> streamKeys;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
public FilteringManifestParser(Parser<T> parser, List<StreamKey> streamKeys) {
|
||||
public FilteringManifestParser(Parser<? extends T> parser, @Nullable List<StreamKey> streamKeys) {
|
||||
this.parser = parser;
|
||||
this.streamKeys = streamKeys;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import com.google.android.exoplayer2.ExoPlayer;
|
|||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
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.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFactory;
|
||||
|
|
@ -59,6 +61,7 @@ import java.io.InputStreamReader;
|
|||
import java.nio.charset.Charset;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
|
|
@ -75,15 +78,16 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
public static final class Factory implements AdsMediaSource.MediaSourceFactory {
|
||||
|
||||
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 LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private long livePresentationDelayMs;
|
||||
private boolean livePresentationDelayOverridesManifest;
|
||||
private boolean isCreateCalled;
|
||||
private @Nullable Object tag;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
* Creates a new factory for {@link DashMediaSource}s.
|
||||
|
|
@ -210,6 +214,19 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
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
|
||||
* 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) {
|
||||
Assertions.checkArgument(!manifest.dynamic);
|
||||
isCreateCalled = true;
|
||||
if (streamKeys != null && !streamKeys.isEmpty()) {
|
||||
manifest = manifest.copy(streamKeys);
|
||||
}
|
||||
return new DashMediaSource(
|
||||
manifest,
|
||||
/* manifestUri= */ null,
|
||||
|
|
@ -281,6 +301,9 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
if (manifestParser == null) {
|
||||
manifestParser = new DashManifestParser();
|
||||
}
|
||||
if (streamKeys != null) {
|
||||
manifestParser = new FilteringManifestParser<>(manifestParser, streamKeys);
|
||||
}
|
||||
return new DashMediaSource(
|
||||
/* manifest= */ null,
|
||||
Assertions.checkNotNull(manifestUri),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
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.CompositeSequenceableLoaderFactory;
|
||||
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.hls.playlist.DefaultHlsPlaylistParserFactory;
|
||||
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.HlsPlaylist;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser;
|
||||
|
|
@ -64,12 +66,13 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
|
||||
private HlsExtractorFactory extractorFactory;
|
||||
private HlsPlaylistParserFactory playlistParserFactory;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
private HlsPlaylistTracker.Factory playlistTrackerFactory;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private boolean allowChunklessPreparation;
|
||||
private boolean isCreateCalled;
|
||||
private @Nullable Object tag;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* by calling {@link DefaultHlsPlaylistParserFactory#DefaultHlsPlaylistParserFactory()}.
|
||||
* Sets the factory from which playlist parsers will be obtained. The default value is a {@link
|
||||
* DefaultHlsPlaylistParserFactory}.
|
||||
*
|
||||
* @param playlistParserFactory An {@link HlsPlaylistParserFactory}.
|
||||
* @return This factory, for convenience.
|
||||
|
|
@ -177,6 +180,19 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
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
|
||||
* DefaultHlsPlaylistTracker#FACTORY}.
|
||||
|
|
@ -232,6 +248,10 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
@Override
|
||||
public HlsMediaSource createMediaSource(Uri playlistUri) {
|
||||
isCreateCalled = true;
|
||||
if (streamKeys != null) {
|
||||
playlistParserFactory =
|
||||
new FilteringHlsPlaylistParserFactory(playlistParserFactory, streamKeys);
|
||||
}
|
||||
return new HlsMediaSource(
|
||||
playlistUri,
|
||||
hlsDataSourceFactory,
|
||||
|
|
|
|||
|
|
@ -15,40 +15,19 @@
|
|||
*/
|
||||
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.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Default implementation for {@link 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
|
||||
public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser() {
|
||||
return new FilteringManifestParser<>(new HlsPlaylistParser(), streamKeys);
|
||||
return new HlsPlaylistParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParsingLoadable.Parser<HlsPlaylist> createPlaylistParser(
|
||||
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.ParserException;
|
||||
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.CompositeSequenceableLoaderFactory;
|
||||
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 java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** A SmoothStreaming {@link MediaSource}. */
|
||||
public final class SsMediaSource extends BaseMediaSource
|
||||
|
|
@ -63,14 +66,15 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
public static final class Factory implements AdsMediaSource.MediaSourceFactory {
|
||||
|
||||
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 LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private long livePresentationDelayMs;
|
||||
private boolean isCreateCalled;
|
||||
private @Nullable Object tag;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
* Creates a new factory for {@link SsMediaSource}s.
|
||||
|
|
@ -178,6 +182,19 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
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
|
||||
* 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) {
|
||||
Assertions.checkArgument(!manifest.isLive);
|
||||
isCreateCalled = true;
|
||||
if (streamKeys != null && !streamKeys.isEmpty()) {
|
||||
manifest = manifest.copy(streamKeys);
|
||||
}
|
||||
return new SsMediaSource(
|
||||
manifest,
|
||||
/* manifestUri= */ null,
|
||||
|
|
@ -248,6 +268,9 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
if (manifestParser == null) {
|
||||
manifestParser = new SsManifestParser();
|
||||
}
|
||||
if (streamKeys != null) {
|
||||
manifestParser = new FilteringManifestParser<>(manifestParser, streamKeys);
|
||||
}
|
||||
return new SsMediaSource(
|
||||
/* manifest= */ null,
|
||||
Assertions.checkNotNull(manifestUri),
|
||||
|
|
|
|||
Loading…
Reference in a new issue