mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-12-23 08:30:44 +00:00
Improve CacheFactory and PlayerDataSource code
This commit is contained in:
parent
ef20d9b91a
commit
7ce2250d85
@ -3,107 +3,44 @@ package org.schabi.newpipe.player.helper;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSource;
|
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.FileDataSource;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
|
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
|
||||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
|
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
|
||||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||||
|
|
||||||
import org.schabi.newpipe.player.datasource.YoutubeHttpDataSource;
|
final class CacheFactory implements DataSource.Factory {
|
||||||
|
|
||||||
/* package-private */ final class CacheFactory implements DataSource.Factory {
|
|
||||||
private static final int CACHE_FLAGS = CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;
|
private static final int CACHE_FLAGS = CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;
|
||||||
|
|
||||||
private final long maxFileSize;
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final String userAgent;
|
|
||||||
private final TransferListener transferListener;
|
private final TransferListener transferListener;
|
||||||
private final DataSource.Factory upstreamDataSourceFactory;
|
private final DataSource.Factory upstreamDataSourceFactory;
|
||||||
private final SimpleCache simpleCache;
|
private final SimpleCache cache;
|
||||||
|
|
||||||
public static class Builder {
|
CacheFactory(final Context context,
|
||||||
private final Context context;
|
final TransferListener transferListener,
|
||||||
private final String userAgent;
|
final SimpleCache cache,
|
||||||
private final TransferListener transferListener;
|
final DataSource.Factory upstreamDataSourceFactory) {
|
||||||
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) {
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.userAgent = userAgent;
|
|
||||||
this.transferListener = transferListener;
|
this.transferListener = transferListener;
|
||||||
this.simpleCache = simpleCache;
|
this.cache = cache;
|
||||||
this.upstreamDataSourceFactory = upstreamDataSourceFactory;
|
this.upstreamDataSourceFactory = upstreamDataSourceFactory;
|
||||||
|
|
||||||
maxFileSize = PlayerHelper.getPreferredFileSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public DataSource createDataSource() {
|
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,
|
final DefaultDataSource dataSource = new DefaultDataSource.Factory(context,
|
||||||
upstreamDataSourceFactoryToUse)
|
upstreamDataSourceFactory)
|
||||||
.setTransferListener(transferListener)
|
.setTransferListener(transferListener)
|
||||||
.createDataSource();
|
.createDataSource();
|
||||||
|
|
||||||
final FileDataSource fileSource = new FileDataSource();
|
final FileDataSource fileSource = new FileDataSource();
|
||||||
final CacheDataSink dataSink = new CacheDataSink(simpleCache, maxFileSize);
|
final CacheDataSink dataSink
|
||||||
return new CacheDataSource(simpleCache, dataSource, fileSource, dataSink, CACHE_FLAGS,
|
= new CacheDataSink(cache, PlayerHelper.getPreferredFileSize());
|
||||||
null);
|
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.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider;
|
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider;
|
||||||
@ -31,6 +30,7 @@ import org.schabi.newpipe.player.datasource.YoutubeHttpDataSource;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class PlayerDataSource {
|
public class PlayerDataSource {
|
||||||
|
public static final String TAG = PlayerDataSource.class.getSimpleName();
|
||||||
|
|
||||||
public static final int LIVE_STREAM_EDGE_GAP_MILLIS = 10000;
|
public static final int LIVE_STREAM_EDGE_GAP_MILLIS = 10000;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public class PlayerDataSource {
|
|||||||
* {@link YoutubeProgressiveDashManifestCreator}, {@link YoutubeOtfDashManifestCreator} and
|
* {@link YoutubeProgressiveDashManifestCreator}, {@link YoutubeOtfDashManifestCreator} and
|
||||||
* {@link YoutubePostLiveStreamDvrDashManifestCreator}.
|
* {@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.
|
* The folder name in which the ExoPlayer cache will be written.
|
||||||
@ -61,44 +61,53 @@ public class PlayerDataSource {
|
|||||||
*/
|
*/
|
||||||
private static SimpleCache cache;
|
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 DataSource.Factory cachelessDataSourceFactory;
|
||||||
|
private final CacheFactory cacheDataSourceFactory;
|
||||||
|
|
||||||
public PlayerDataSource(@NonNull final Context context,
|
// YouTube-specific Data Source Factories (with cache)
|
||||||
@NonNull final String userAgent,
|
// They use YoutubeHttpDataSource.Factory, with different parameters each
|
||||||
@NonNull final TransferListener transferListener) {
|
private final CacheFactory ytHlsCacheDataSourceFactory;
|
||||||
continueLoadingCheckIntervalBytes = PlayerHelper.getProgressiveLoadIntervalBytes(context);
|
private final CacheFactory ytDashCacheDataSourceFactory;
|
||||||
final File cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
|
private final CacheFactory ytProgressiveDashCacheDataSourceFactory;
|
||||||
if (!cacheDir.exists()) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
cacheDir.mkdir();
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
public PlayerDataSource(final Context context,
|
||||||
transferListener);
|
final String userAgent,
|
||||||
cacheDataSourceFactoryBuilder.setSimpleCache(cache);
|
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,
|
cachelessDataSourceFactory = new DefaultDataSource.Factory(context,
|
||||||
new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
|
new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
|
||||||
.setTransferListener(transferListener);
|
.setTransferListener(transferListener);
|
||||||
|
cacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
|
||||||
|
new DefaultHttpDataSource.Factory().setUserAgent(userAgent));
|
||||||
|
|
||||||
YoutubeProgressiveDashManifestCreator.getCache().setMaximumSize(
|
// YouTube-specific data source factories use getYoutubeHttpDataSourceFactory()
|
||||||
MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE);
|
ytHlsCacheDataSourceFactory = new CacheFactory(context, transferListener, cache,
|
||||||
YoutubeOtfDashManifestCreator.getCache().setMaximumSize(
|
getYoutubeHttpDataSourceFactory(false, false, userAgent));
|
||||||
MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE);
|
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(
|
YoutubePostLiveStreamDvrDashManifestCreator.getCache().setMaximumSize(
|
||||||
MAXIMUM_SIZE_CACHED_GENERATED_MANIFESTS_PER_CACHE);
|
MAX_MANIFEST_CACHE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//region Live media source factories
|
||||||
public SsMediaSource.Factory getLiveSsMediaSourceFactory() {
|
public SsMediaSource.Factory getLiveSsMediaSourceFactory() {
|
||||||
return getSSMediaSourceFactory().setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS);
|
return getSSMediaSourceFactory().setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS);
|
||||||
}
|
}
|
||||||
@ -118,26 +127,26 @@ public class PlayerDataSource {
|
|||||||
getDefaultDashChunkSourceFactory(cachelessDataSourceFactory),
|
getDefaultDashChunkSourceFactory(cachelessDataSourceFactory),
|
||||||
cachelessDataSourceFactory);
|
cachelessDataSourceFactory);
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
//region Generic media source factories
|
||||||
public HlsMediaSource.Factory getHlsMediaSourceFactory(
|
public HlsMediaSource.Factory getHlsMediaSourceFactory(
|
||||||
@Nullable final HlsPlaylistParserFactory hlsPlaylistParserFactory) {
|
@Nullable final HlsPlaylistParserFactory hlsPlaylistParserFactory) {
|
||||||
final HlsMediaSource.Factory factory = new HlsMediaSource.Factory(
|
final HlsMediaSource.Factory factory = new HlsMediaSource.Factory(cacheDataSourceFactory);
|
||||||
cacheDataSourceFactoryBuilder.build());
|
factory.setPlaylistParserFactory(hlsPlaylistParserFactory);
|
||||||
if (hlsPlaylistParserFactory != null) {
|
|
||||||
factory.setPlaylistParserFactory(hlsPlaylistParserFactory);
|
|
||||||
}
|
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DashMediaSource.Factory getDashMediaSourceFactory() {
|
public DashMediaSource.Factory getDashMediaSourceFactory() {
|
||||||
return new DashMediaSource.Factory(
|
return new DashMediaSource.Factory(
|
||||||
getDefaultDashChunkSourceFactory(cacheDataSourceFactoryBuilder.build()),
|
getDefaultDashChunkSourceFactory(cacheDataSourceFactory),
|
||||||
cacheDataSourceFactoryBuilder.build());
|
cacheDataSourceFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgressiveMediaSource.Factory getProgressiveMediaSourceFactory() {
|
public ProgressiveMediaSource.Factory getProgressiveMediaSourceFactory() {
|
||||||
return new ProgressiveMediaSource.Factory(cacheDataSourceFactoryBuilder.build())
|
return new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
|
||||||
.setContinueLoadingCheckIntervalBytes(continueLoadingCheckIntervalBytes);
|
.setContinueLoadingCheckIntervalBytes(progressiveLoadIntervalBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SsMediaSource.Factory getSSMediaSourceFactory() {
|
public SsMediaSource.Factory getSSMediaSourceFactory() {
|
||||||
@ -147,42 +156,57 @@ public class PlayerDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SingleSampleMediaSource.Factory getSingleSampleMediaSourceFactory() {
|
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() {
|
public DashMediaSource.Factory getYoutubeDashMediaSourceFactory() {
|
||||||
cacheDataSourceFactoryBuilder.setUpstreamDataSourceFactory(
|
|
||||||
getYoutubeHttpDataSourceFactory(true, true));
|
|
||||||
return new DashMediaSource.Factory(
|
return new DashMediaSource.Factory(
|
||||||
getDefaultDashChunkSourceFactory(cacheDataSourceFactoryBuilder.build()),
|
getDefaultDashChunkSourceFactory(ytDashCacheDataSourceFactory),
|
||||||
cacheDataSourceFactoryBuilder.build());
|
ytDashCacheDataSourceFactory);
|
||||||
}
|
|
||||||
|
|
||||||
public HlsMediaSource.Factory getYoutubeHlsMediaSourceFactory() {
|
|
||||||
cacheDataSourceFactoryBuilder.setUpstreamDataSourceFactory(
|
|
||||||
getYoutubeHttpDataSourceFactory(false, false));
|
|
||||||
return new HlsMediaSource.Factory(cacheDataSourceFactoryBuilder.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgressiveMediaSource.Factory getYoutubeProgressiveMediaSourceFactory() {
|
public ProgressiveMediaSource.Factory getYoutubeProgressiveMediaSourceFactory() {
|
||||||
cacheDataSourceFactoryBuilder.setUpstreamDataSourceFactory(
|
return new ProgressiveMediaSource.Factory(ytProgressiveDashCacheDataSourceFactory)
|
||||||
getYoutubeHttpDataSourceFactory(false, true));
|
.setContinueLoadingCheckIntervalBytes(progressiveLoadIntervalBytes);
|
||||||
return new ProgressiveMediaSource.Factory(cacheDataSourceFactoryBuilder.build())
|
|
||||||
.setContinueLoadingCheckIntervalBytes(continueLoadingCheckIntervalBytes);
|
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private DefaultDashChunkSource.Factory getDefaultDashChunkSourceFactory(
|
//region Static methods
|
||||||
|
private static DefaultDashChunkSource.Factory getDefaultDashChunkSourceFactory(
|
||||||
final DataSource.Factory dataSourceFactory) {
|
final DataSource.Factory dataSourceFactory) {
|
||||||
return new DefaultDashChunkSource.Factory(dataSourceFactory);
|
return new DefaultDashChunkSource.Factory(dataSourceFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private static YoutubeHttpDataSource.Factory getYoutubeHttpDataSourceFactory(
|
||||||
private YoutubeHttpDataSource.Factory getYoutubeHttpDataSourceFactory(
|
|
||||||
final boolean rangeParameterEnabled,
|
final boolean rangeParameterEnabled,
|
||||||
final boolean rnParameterEnabled) {
|
final boolean rnParameterEnabled,
|
||||||
|
final String userAgent) {
|
||||||
return new YoutubeHttpDataSource.Factory()
|
return new YoutubeHttpDataSource.Factory()
|
||||||
.setRangeParameterEnabled(rangeParameterEnabled)
|
.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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user