我正在寻找在ExoPlayer中实现缓存的任何示例。
ExoPlayer在其库中有关于缓存的不同类,Google在此video中解释我们可以使用CacheDataSource类实现它,但Google并没有提供任何演示。不幸的是,这似乎相当复杂,所以我目前正在寻找示例(在Google上没有成功)。
有没有人成功或有任何有用的信息?感谢。
答案 0 :(得分:27)
以下是ExoPlayer 2的解决方案。+
创建自定义缓存数据源工厂
class CacheDataSourceFactory implements DataSource.Factory {
private final Context context;
private final DefaultDataSourceFactory defaultDatasourceFactory;
private final long maxFileSize, maxCacheSize;
CacheDataSourceFactory(Context context, long maxCacheSize, long maxFileSize) {
super();
this.context = context;
this.maxCacheSize = maxCacheSize;
this.maxFileSize = maxFileSize;
String userAgent = Util.getUserAgent(context, context.getString(R.string.app_name));
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
defaultDatasourceFactory = new DefaultDataSourceFactory(this.context,
bandwidthMeter,
new DefaultHttpDataSourceFactory(userAgent, bandwidthMeter));
}
@Override
public DataSource createDataSource() {
LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media"), evictor);
return new CacheDataSource(simpleCache, defaultDatasourceFactory.createDataSource(),
new FileDataSource(), new CacheDataSink(simpleCache, maxFileSize),
CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR, null);
}
}
玩家
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
MediaSource audioSource = new ExtractorMediaSource(Uri.parse(url),
new CacheDataSourceFactory(context, 100 * 1024 * 1024, 5 * 1024 * 1024), new DefaultExtractorsFactory(), null, null);
exoPlayer.setPlayWhenReady(true);
exoPlayer.prepare(audioSource);
效果很好。
答案 1 :(得分:6)
默认情况下,ExoPlayer不缓存媒体(视频,音频等)。例如,如果您要播放在线视频文件,则ExoPlayer每次打开连接时,先读取数据然后播放。
幸运的是,它为我们提供了一些接口和实现类,以支持我们应用程序中的缓存媒体。
您可以编写自己的缓存,以实现ExoPlayer中的给定接口。为简单起见,我将指导您如何使用实现类启用缓存。
步骤1:指定一个包含媒体文件的文件夹,在Android中,对于较小的缓存文件夹(小于1MB),您应该使用getCacheDir,否则可以指定自己喜欢的缓存文件夹,例如getFileDir。
步骤2:指定缓存文件夹的大小,并指定达到该大小时的策略。有2个API
放在一起
val renderersFactory = DefaultRenderersFactory(context.applicationContext)
val trackSelector = DefaultTrackSelector()
val loadControl = DefaultLoadControl()
val player = ExoPlayerFactory.newSimpleInstance(context, renderersFactory, trackSelector, loadControl)
player.addListener(this)
// Specify cache folder, my cache folder named media which is inside getCacheDir.
val cacheFolder = File(context.cacheDir, "media")
// Specify cache size and removing policies
val cacheEvictor = LeastRecentlyUsedCacheEvictor(1 * 1024 * 1024) // My cache size will be 1MB and it will automatically remove least recently used files if the size is reached out.
// Build cache
val cache = SimpleCache(cacheFolder, cacheEvictor)
// Build data source factory with cache enabled, if data is available in cache it will return immediately, otherwise it will open a new connection to get the data.
val cacheDataSourceFactory = CacheDataSourceFactory(cache, DefaultHttpDataSourceFactory("ExoplayerDemo"))
val uri = Uri.parse("Put your media url here")
val mediaSource = ExtractorMediaSource.Factory(cacheDataSourceFactory).createMediaSource(uri)
player.prepare(mediaSource)
答案 2 :(得分:5)
这是一个用OkHttp替换演示数据源的示例,默认是没有缓存 https://github.com/b95505017/ExoPlayer/commit/ebfdda8e7848a2e2e275f5c0525f614b56ef43a6 https://github.com/b95505017/ExoPlayer/tree/okhttp_http_data_source 因此,您只需要正确配置OkHttp缓存并缓存请求。
答案 3 :(得分:2)
我在渲染器构建器
中实现了这个private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
private static final int BUFFER_SEGMENT_COUNT = 160;
final String userAgent = Util.getUserAgent(mContext, appName);
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
final Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);*
Cache cache = new SimpleCache(context.getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 10));
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
CacheDataSource cacheDataSource = new CacheDataSource(cache, dataSource, false, false);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri
, cacheDataSource
, allocator
, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE
, new Mp4Extractor());
答案 4 :(得分:0)
Exoplayer的文档列表为class DashDownloader,并具有用于该类型源的一些示例代码。 (单击[框架]返回文档导航。我必须将其删除才能获得深层链接。)
答案 5 :(得分:0)
除了Bao Le的答案之外,这里还准备使用Kotlin版本的CacheDataSourceFactory
,该版本保留SimpleCache
的一个实例,以解决多个Cache对象写入同一目录的问题。
class CacheDataSourceFactory(private val context: Context,
private val maxCacheSize: Long,
private val maxFileSize: Long) : DataSource.Factory {
private val defaultDatasourceFactory: DefaultDataSourceFactory
private val simpleCache: SimpleCache by lazy {
val evictor = LeastRecentlyUsedCacheEvictor(maxCacheSize)
SimpleCache(File(context.cacheDir, "media"), evictor)
}
init {
val userAgent = Util.getUserAgent(context, context.packageName)
val bandwidthMeter = DefaultBandwidthMeter()
defaultDatasourceFactory = DefaultDataSourceFactory(context,
bandwidthMeter,
DefaultHttpDataSourceFactory(userAgent, bandwidthMeter))
}
override fun createDataSource(): DataSource {
return CacheDataSource(simpleCache,
defaultDatasourceFactory.createDataSource(),
FileDataSource(),
CacheDataSink(simpleCache, maxFileSize),
CacheDataSource.FLAG_BLOCK_ON_CACHE or CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR,
null)
}
}
答案 6 :(得分:0)
这是我在Kotlin的样本(项目here可用):
completed: Bool
答案 7 :(得分:0)
要解决多个视频或多个进程尝试访问同一缓存的问题,您需要一个真正的Singleton。一种可靠的方法是这样:
object VideoCache {
private var sDownloadCache: SimpleCache? = null
private const val maxCacheSize: Long = 100 * 1024 * 1024
fun getInstance(context: Context): SimpleCache {
val evictor = LeastRecentlyUsedCacheEvictor(maxCacheSize)
if (sDownloadCache == null) sDownloadCache = SimpleCache(File(context.cacheDir, "koko-media"), evictor)
return sDownloadCache as SimpleCache
}
}
您现在可以使用:
private val simpleCache: SimpleCache by lazy {
VideoCache.getInstance(context)
}
答案 8 :(得分:0)
我在这里回答了类似的问题:https://stackoverflow.com/a/58678192/2029134
基本上,我使用这个库:https://github.com/danikula/AndroidVideoCache 从URL缓存文件 然后将其放入ExoPlayer。
这是示例代码:
String mediaURL = "https://my_cool_vid.com/vi.mp4";
SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(getContext());
HttpProxyCacheServer proxyServer = HttpProxyCacheServer.Builder(getContext()).maxCacheSize(1024 * 1024 * 1024).build();
String proxyURL = proxyServer.getProxyUrl(mediaURL);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(),
Util.getUserAgent(getContext(), getActivity().getApplicationContext().getPackageName()));
exoPlayer.prepare(new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(proxyURL)););
希望有帮助。
答案 9 :(得分:-1)
SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media/"+id), evictor);
此处,id
必须是唯一的。