Android 在ExoPlayer中使用缓存

Android 在ExoPlayer中使用缓存,android,caching,media,exoplayer,Android,Caching,Media,Exoplayer,我正在寻找在ExoPlayer中实现缓存的任何示例 ExoPlayer在其库中有不同的关于缓存的类,Google在本文中解释说,我们可以用CacheDataSource类实现它,但Google没有提供任何关于它的演示。不幸的是,这似乎很复杂的使用,所以我目前正在寻找的例子(没有成功的谷歌) 有没有人成功了,或者有什么信息可以帮助你?谢谢。我已经在渲染器生成器中这样实现了它 private static final int BUFFER_SEGMENT_SIZE = 64 * 1024; priv

我正在寻找在ExoPlayer中实现缓存的任何示例

ExoPlayer在其库中有不同的关于缓存的类,Google在本文中解释说,我们可以用CacheDataSource类实现它,但Google没有提供任何关于它的演示。不幸的是,这似乎很复杂的使用,所以我目前正在寻找的例子(没有成功的谷歌)


有没有人成功了,或者有什么信息可以帮助你?谢谢。

我已经在渲染器生成器中这样实现了它

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());

下面是一个用OkHttp替换演示数据源的示例,默认为无缓存
因此,您只需要正确配置OkHttp缓存,请求应该被缓存。

以下是ExoPlayer 2的解决方案+

创建自定义缓存数据源工厂

public class CacheDataSourceFactory implements DataSource.Factory {
    private final Context context;
    private final DefaultDataSourceFactory defaultDatasourceFactory;
    private final long maxFileSize, maxCacheSize;

    public 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);

它工作得很好。

Exoplayer的文档列表是最新的,并且有一些用于该类型源代码的示例代码。(单击[Frames]返回文档导航。我必须删除它才能获得深层链接。)

默认情况下,ExoPlayer不缓存媒体(视频、音频等)。例如,如果您想播放在线视频文件,每次ExoPlayer都会打开连接,读取数据,然后播放

幸运的是,它为我们提供了一些接口和实现类来支持在我们的应用程序中缓存媒体

您可以编写自己的缓存,实现ExoPlayer中给定的接口。为了简单起见,我将指导您如何使用实现类启用缓存

步骤1:指定一个包含媒体文件的文件夹,在Android中,对于较小的缓存文件夹(小于1MB),您应该使用,否则您可以指定首选缓存文件夹,例如

步骤2:指定缓存文件夹的大小,以及达到该大小时的策略。有两个API

  • 不会逐出/删除缓存文件。根据缓存文件夹的位置,如果它位于内部存储器中,则当用户清除应用程序数据或卸载应用程序时,该文件夹将被删除
  • 这将首先逐出/删除最近使用最少的缓存文件。例如,如果缓存大小为10MB,当达到该大小时,它将自动查找并删除最近使用最少的文件
把它放在一起

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)

除了Bao Le的答案之外,这里还准备使用Kotlin版本的
CacheDataSourceFactory
,它保留了一个
SimpleCache
实例,以解决多个缓存对象写入同一目录的问题

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)
    }
}

以下是我在Kotlin的示例(项目可用):


要解决多个视频或进程试图访问同一缓存的问题,您需要一个真正的单例。一个可靠的方法是这样做:

对象视频缓存{
私有变量sDownloadCache:SimpleCache?=null
private const val maxCacheSize:Long=100*1024*1024
fun getInstance(上下文:context):SimpleCache{
val executer=leastRecentlyUsedCacheExecuter(maxCacheSize)
如果(sDownloadCache==null)sDownloadCache=SimpleCache(文件(context.cacheDir,“koko媒体”),则逐出器
将sDownloadCache作为SimpleCache返回
}
}
您现在可以使用:

private val simpleCache:lazy的simpleCache{
VideoCache.getInstance(上下文)
}

我在这里回答了类似的问题:

基本上,我使用这个库: 从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)););
希望有帮助

SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media/"+id), evictor);

在这里,
id
必须是唯一的

看这个文件显然我看了。。。不,显然还不可能实现它。那太糟糕了。。。分享你的代码到目前为止你都做了些什么很遗憾,但目前缓存只能与DASH一起使用。此代码编译并运行,但似乎没有在指定的缓存文件夹中写入任何视频。它对你有用吗?它是否在没有internet连接的情况下从缓存播放?如能提供更深入的信息,将不胜感激。ThanksAlso添加了这段代码,但如上所述,它看起来并没有缓存任何东西。这里有什么我们遗漏的吗?根据这个答案只对破折号流有效。对于MP4文件,OkHttpDataSource似乎产生了很好的效果(根据该线程上的人员)。我从exoplayer 2.2.0演示应用程序中获得了OkHttpDataSource。你能分享一些配置OkHttp缓存的链接吗?这个解决方案的问题是,如果我使用它缓存和播放多个视频,多个播放器可能播放相同的数据(即,对于不同的uri,似乎从缓存返回相同的数据流)。使用默认的ExtractorDiaSource时不会发生此问题。视频的uri是唯一的解决方案:保留SimpleCache的共享实例,而不是在createDataSource中创建它。否则,多个缓存对象将写入相同的文件,导致troublethnx。它可以工作,但有加密缓存的解决方案吗?它支持磁盘缓存吗??还是仅在内存缓存中?@Bao Le,此实现的预期行为应该是缓存流的视频播放也应该在脱机状态下进行,对吗?但我无法在网络断开时播放,尽管它是缓存流。很明显,视频播放将仅在在线模式下播放吗?还是我遗漏了什么?这篇文章看起来不像是试图回答这个问题。这里的每一篇文章都是为了明确回答这个问题;如果你有批评或需要澄清问题或其他答案,你可以(像这一个)直接在它下面。请删除此答案并创建评论或新问题。请看:我当然想帮助回答最初的问题。AFAIR提到的DashDownloader类是我解决缓存问题的方法,因为我需要完全缓存一组媒体文件。由于有些人可能出于同样的原因来到这里,你可能想收回否决票;谢谢,我是Extra的执行官
SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media/"+id), evictor);