kopia lustrzana https://github.com/TeamNewPipe/NewPipe
Improve CacheFactory and PlayerDataSource code
rodzic
ef20d9b91a
commit
7ce2250d85
|
@ -3,107 +3,44 @@ package org.schabi.newpipe.player.helper;
|
|||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.FileDataSource;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||
|
||||
import org.schabi.newpipe.player.datasource.YoutubeHttpDataSource;
|
||||
|
||||
/* package-private */ final class CacheFactory implements DataSource.Factory {
|
||||
final class CacheFactory implements DataSource.Factory {
|
||||
private static final int CACHE_FLAGS = CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;
|
||||
|
||||
private final long maxFileSize;
|
||||
private final Context context;
|
||||
private final String userAgent;
|
||||
private final TransferListener transferListener;
|
||||
private final DataSource.Factory upstreamDataSourceFactory;
|
||||
private final SimpleCache simpleCache;
|
||||
private final SimpleCache cache;
|
||||
|
||||
public static class Builder {
|
||||
private final Context context;
|
||||
private final String userAgent;
|
||||
private final TransferListener transferListener;
|
||||
private DataSource.Factory upstreamDataSourceFactory;
|
||||
private SimpleCache simpleCache;
|
||||
|
||||
Builder(@NonNull final Context context,
|
||||
@NonNull final String userAgent,
|
||||
@NonNull final TransferListener transferListener) {
|
||||
this.context = context;
|
||||
this.userAgent = userAgent;
|
||||
this.transferListener = transferListener;
|
||||
}
|
||||
|
||||
public void setUpstreamDataSourceFactory(
|
||||
@Nullable final DataSource.Factory upstreamDataSourceFactory) {
|
||||
this.upstreamDataSourceFactory = upstreamDataSourceFactory;
|
||||
}
|
||||
|
||||
public void setSimpleCache(@NonNull final SimpleCache simpleCache) {
|
||||
this.simpleCache = simpleCache;
|
||||
}
|
||||
|
||||
public CacheFactory build() {
|
||||
if (simpleCache == null) {
|
||||
throw new IllegalStateException("No SimpleCache instance has been specified. "
|
||||
+ "Please specify one with setSimpleCache");
|
||||
}
|
||||
return new CacheFactory(context, userAgent, transferListener, simpleCache,
|
||||
upstreamDataSourceFactory);
|
||||
}
|
||||
}
|
||||
|
||||
private CacheFactory(@NonNull final Context context,
|
||||
@NonNull final String userAgent,
|
||||
@NonNull final TransferListener transferListener,
|
||||
@NonNull final SimpleCache simpleCache,
|
||||
@Nullable final DataSource.Factory upstreamDataSourceFactory) {
|
||||
CacheFactory(final Context context,
|
||||
final TransferListener transferListener,
|
||||
final SimpleCache cache,
|
||||
final DataSource.Factory upstreamDataSourceFactory) {
|
||||
this.context = context;
|
||||
this.userAgent = userAgent;
|
||||
this.transferListener = transferListener;
|
||||
this.simpleCache = simpleCache;
|
||||
this.cache = cache;
|
||||
this.upstreamDataSourceFactory = upstreamDataSourceFactory;
|
||||
|
||||
maxFileSize = PlayerHelper.getPreferredFileSize();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DataSource createDataSource() {
|
||||
|
||||
final DataSource.Factory upstreamDataSourceFactoryToUse;
|
||||
if (upstreamDataSourceFactory == null) {
|
||||
upstreamDataSourceFactoryToUse = new DefaultHttpDataSource.Factory()
|
||||
.setUserAgent(userAgent);
|
||||
} else {
|
||||
if (upstreamDataSourceFactory instanceof DefaultHttpDataSource.Factory) {
|
||||
upstreamDataSourceFactoryToUse =
|
||||
((DefaultHttpDataSource.Factory) upstreamDataSourceFactory)
|
||||
.setUserAgent(userAgent);
|
||||
} else if (upstreamDataSourceFactory instanceof YoutubeHttpDataSource.Factory) {
|
||||
upstreamDataSourceFactoryToUse =
|
||||
((YoutubeHttpDataSource.Factory) upstreamDataSourceFactory)
|
||||
.setUserAgentForNonMobileStreams(userAgent);
|
||||
} else {
|
||||
upstreamDataSourceFactoryToUse = upstreamDataSourceFactory;
|
||||
}
|
||||
}
|
||||
|
||||
final DefaultDataSource dataSource = new DefaultDataSource.Factory(context,
|
||||
upstreamDataSourceFactoryToUse)
|
||||
upstreamDataSourceFactory)
|
||||
.setTransferListener(transferListener)
|
||||
.createDataSource();
|
||||
|
||||
final FileDataSource fileSource = new FileDataSource();
|
||||
final CacheDataSink dataSink = new CacheDataSink(simpleCache, maxFileSize);
|
||||
return new CacheDataSource(simpleCache, dataSource, fileSource, dataSink, CACHE_FLAGS,
|
||||
null);
|
||||
final CacheDataSink dataSink
|
||||
= new CacheDataSink(cache, PlayerHelper.getPreferredFileSize());
|
||||
return new CacheDataSource(cache, dataSource, fileSource, dataSink, CACHE_FLAGS, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package org.schabi.newpipe.player.helper;
|
|||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider;
|
||||
|
@ -31,6 +30,7 @@ import org.schabi.newpipe.player.datasource.YoutubeHttpDataSource;
|
|||
import java.io.File;
|
||||
|
||||
public class PlayerDataSource {
|
||||
public static final String TAG = PlayerDataSource.class.getSimpleName();
|
||||
|
||||
public static final int LIVE_STREAM_EDGE_GAP_MILLIS = 10000;
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class PlayerDataSource {
|
|||
* {@link YoutubeProgressiveDashManifestCreator}, {@link YoutubeOtfDashManifestCreator} and
|
||||
* {@link YoutubePostLiveStreamDvrDashManifestCreator}.
|
||||
*/
|
||||
private static final int MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE = 500;
|
||||
private static final int MAX_MANIFEST_CACHE_SIZE = 500;
|
||||
|
||||
/**
|
||||
* The folder name in which the ExoPlayer cache will be written.
|
||||
|
@ -61,44 +61,53 @@ public class PlayerDataSource {
|
|||
*/
|
||||
private static SimpleCache cache;
|
||||
|
||||
private final int continueLoadingCheckIntervalBytes;
|
||||
private final CacheFactory.Builder cacheDataSourceFactoryBuilder;
|
||||
|
||||
private final int progressiveLoadIntervalBytes;
|
||||
|
||||
// Generic Data Source Factories (without or with cache)
|
||||
private final DataSource.Factory cachelessDataSourceFactory;
|
||||
private final CacheFactory cacheDataSourceFactory;
|
||||
|
||||
public PlayerDataSource(@NonNull final Context context,
|
||||
@NonNull final String userAgent,
|
||||
@NonNull final TransferListener transferListener) {
|
||||
continueLoadingCheckIntervalBytes = PlayerHelper.getProgressiveLoadIntervalBytes(context);
|
||||
final File cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
|
||||
if (!cacheDir.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
cacheDir.mkdir();
|
||||
}
|
||||
// YouTube-specific Data Source Factories (with cache)
|
||||
// They use YoutubeHttpDataSource.Factory, with different parameters each
|
||||
private final CacheFactory ytHlsCacheDataSourceFactory;
|
||||
private final CacheFactory ytDashCacheDataSourceFactory;
|
||||
private final CacheFactory ytProgressiveDashCacheDataSourceFactory;
|
||||
|
||||
if (cache == null) {
|
||||
final LeastRecentlyUsedCacheEvictor evictor
|
||||
= new LeastRecentlyUsedCacheEvictor(PlayerHelper.getPreferredCacheSize());
|
||||
cache = new SimpleCache(cacheDir, evictor, new StandaloneDatabaseProvider(context));
|
||||
Log.d(PlayerDataSource.class.getSimpleName(), "initExoPlayerCache: cacheDir = "
|
||||
+ cacheDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
cacheDataSourceFactoryBuilder = new CacheFactory.Builder(context, userAgent,
|
||||
transferListener);
|
||||
cacheDataSourceFactoryBuilder.setSimpleCache(cache);
|
||||
public PlayerDataSource(final Context context,
|
||||
final String userAgent,
|
||||
final TransferListener transferListener) {
|
||||
|
||||
progressiveLoadIntervalBytes = PlayerHelper.getProgressiveLoadIntervalBytes(context);
|
||||
|
||||
// make sure the static cache was created: needed by CacheFactories below
|
||||
instantiateCacheIfNeeded(context);
|
||||
|
||||
// generic data source factories use DefaultHttpDataSource.Factory
|
||||
cachelessDataSourceFactory = new DefaultDataSource.Factory(context,
|
||||
new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
|
||||
.setTransferListener(transferListener);
|
||||
cacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
|
||||
new DefaultHttpDataSource.Factory().setUserAgent(userAgent));
|
||||
|
||||
YoutubeProgressiveDashManifestCreator.getCache().setMaximumSize(
|
||||
MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE);
|
||||
YoutubeOtfDashManifestCreator.getCache().setMaximumSize(
|
||||
MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE);
|
||||
// YouTube-specific data source factories use getYoutubeHttpDataSourceFactory()
|
||||
ytHlsCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
|
||||
getYoutubeHttpDataSourceFactory(false, false, userAgent));
|
||||
ytDashCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
|
||||
getYoutubeHttpDataSourceFactory(true, true, userAgent));
|
||||
ytProgressiveDashCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
|
||||
getYoutubeHttpDataSourceFactory(false, true, userAgent));
|
||||
|
||||
// set the maximum size to manifest creators
|
||||
YoutubeProgressiveDashManifestCreator.getCache().setMaximumSize(MAX_MANIFEST_CACHE_SIZE);
|
||||
YoutubeOtfDashManifestCreator.getCache().setMaximumSize(MAX_MANIFEST_CACHE_SIZE);
|
||||
YoutubePostLiveStreamDvrDashManifestCreator.getCache().setMaximumSize(
|
||||
MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE);
|
||||
MAX_MANIFEST_CACHE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
//region Live media source factories
|
||||
public SsMediaSource.Factory getLiveSsMediaSourceFactory() {
|
||||
return getSSMediaSourceFactory().setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS);
|
||||
}
|
||||
|
@ -118,26 +127,26 @@ public class PlayerDataSource {
|
|||
getDefaultDashChunkSourceFactory(cachelessDataSourceFactory),
|
||||
cachelessDataSourceFactory);
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
//region Generic media source factories
|
||||
public HlsMediaSource.Factory getHlsMediaSourceFactory(
|
||||
@Nullable final HlsPlaylistParserFactory hlsPlaylistParserFactory) {
|
||||
final HlsMediaSource.Factory factory = new HlsMediaSource.Factory(
|
||||
cacheDataSourceFactoryBuilder.build());
|
||||
if (hlsPlaylistParserFactory != null) {
|
||||
factory.setPlaylistParserFactory(hlsPlaylistParserFactory);
|
||||
}
|
||||
final HlsMediaSource.Factory factory = new HlsMediaSource.Factory(cacheDataSourceFactory);
|
||||
factory.setPlaylistParserFactory(hlsPlaylistParserFactory);
|
||||
return factory;
|
||||
}
|
||||
|
||||
public DashMediaSource.Factory getDashMediaSourceFactory() {
|
||||
return new DashMediaSource.Factory(
|
||||
getDefaultDashChunkSourceFactory(cacheDataSourceFactoryBuilder.build()),
|
||||
cacheDataSourceFactoryBuilder.build());
|
||||
getDefaultDashChunkSourceFactory(cacheDataSourceFactory),
|
||||
cacheDataSourceFactory);
|
||||
}
|
||||
|
||||
public ProgressiveMediaSource.Factory getProgressiveMediaSourceFactory() {
|
||||
return new ProgressiveMediaSource.Factory(cacheDataSourceFactoryBuilder.build())
|
||||
.setContinueLoadingCheckIntervalBytes(continueLoadingCheckIntervalBytes);
|
||||
return new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
|
||||
.setContinueLoadingCheckIntervalBytes(progressiveLoadIntervalBytes);
|
||||
}
|
||||
|
||||
public SsMediaSource.Factory getSSMediaSourceFactory() {
|
||||
|
@ -147,42 +156,57 @@ public class PlayerDataSource {
|
|||
}
|
||||
|
||||
public SingleSampleMediaSource.Factory getSingleSampleMediaSourceFactory() {
|
||||
return new SingleSampleMediaSource.Factory(cacheDataSourceFactoryBuilder.build());
|
||||
return new SingleSampleMediaSource.Factory(cacheDataSourceFactory);
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
//region YouTube media source factories
|
||||
public HlsMediaSource.Factory getYoutubeHlsMediaSourceFactory() {
|
||||
return new HlsMediaSource.Factory(ytHlsCacheDataSourceFactory);
|
||||
}
|
||||
|
||||
public DashMediaSource.Factory getYoutubeDashMediaSourceFactory() {
|
||||
cacheDataSourceFactoryBuilder.setUpstreamDataSourceFactory(
|
||||
getYoutubeHttpDataSourceFactory(true, true));
|
||||
return new DashMediaSource.Factory(
|
||||
getDefaultDashChunkSourceFactory(cacheDataSourceFactoryBuilder.build()),
|
||||
cacheDataSourceFactoryBuilder.build());
|
||||
}
|
||||
|
||||
public HlsMediaSource.Factory getYoutubeHlsMediaSourceFactory() {
|
||||
cacheDataSourceFactoryBuilder.setUpstreamDataSourceFactory(
|
||||
getYoutubeHttpDataSourceFactory(false, false));
|
||||
return new HlsMediaSource.Factory(cacheDataSourceFactoryBuilder.build());
|
||||
getDefaultDashChunkSourceFactory(ytDashCacheDataSourceFactory),
|
||||
ytDashCacheDataSourceFactory);
|
||||
}
|
||||
|
||||
public ProgressiveMediaSource.Factory getYoutubeProgressiveMediaSourceFactory() {
|
||||
cacheDataSourceFactoryBuilder.setUpstreamDataSourceFactory(
|
||||
getYoutubeHttpDataSourceFactory(false, true));
|
||||
return new ProgressiveMediaSource.Factory(cacheDataSourceFactoryBuilder.build())
|
||||
.setContinueLoadingCheckIntervalBytes(continueLoadingCheckIntervalBytes);
|
||||
return new ProgressiveMediaSource.Factory(ytProgressiveDashCacheDataSourceFactory)
|
||||
.setContinueLoadingCheckIntervalBytes(progressiveLoadIntervalBytes);
|
||||
}
|
||||
//endregion
|
||||
|
||||
@NonNull
|
||||
private DefaultDashChunkSource.Factory getDefaultDashChunkSourceFactory(
|
||||
|
||||
//region Static methods
|
||||
private static DefaultDashChunkSource.Factory getDefaultDashChunkSourceFactory(
|
||||
final DataSource.Factory dataSourceFactory) {
|
||||
return new DefaultDashChunkSource.Factory(dataSourceFactory);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private YoutubeHttpDataSource.Factory getYoutubeHttpDataSourceFactory(
|
||||
private static YoutubeHttpDataSource.Factory getYoutubeHttpDataSourceFactory(
|
||||
final boolean rangeParameterEnabled,
|
||||
final boolean rnParameterEnabled) {
|
||||
final boolean rnParameterEnabled,
|
||||
final String userAgent) {
|
||||
return new YoutubeHttpDataSource.Factory()
|
||||
.setRangeParameterEnabled(rangeParameterEnabled)
|
||||
.setRnParameterEnabled(rnParameterEnabled);
|
||||
.setRnParameterEnabled(rnParameterEnabled)
|
||||
.setUserAgentForNonMobileStreams(userAgent);
|
||||
}
|
||||
|
||||
private static void instantiateCacheIfNeeded(final Context context) {
|
||||
if (cache == null) {
|
||||
final File cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
|
||||
Log.d(TAG, "instantiateCacheIfNeeded: cacheDir = " + cacheDir.getAbsolutePath());
|
||||
if (!cacheDir.exists() && !cacheDir.mkdir()) {
|
||||
Log.w(TAG, "instantiateCacheIfNeeded: could not create cache dir");
|
||||
}
|
||||
|
||||
final LeastRecentlyUsedCacheEvictor evictor
|
||||
= new LeastRecentlyUsedCacheEvictor(PlayerHelper.getPreferredCacheSize());
|
||||
cache = new SimpleCache(cacheDir, evictor, new StandaloneDatabaseProvider(context));
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue