Использование кеша в ExoPlayer

Я ищу любой пример реализации кеша в ExoPlayer.

ExoPlayer имеет в своей библиотеке различные классы, относящиеся к кешу, и Google объясняет в этом видео, что мы можем реализовать его с классом CacheDataSource, но Google не предоставляет никакой демонстрации в теме. К сожалению, это довольно сложно использовать, поэтому в настоящее время я ищу примеры (без успеха в Google).

Кто-нибудь преуспеет или имеет какую-либо информацию, которая поможет? Спасибо.

Ответ 1

Вот решение для ExoPlayer 2. +

Создайте собственный источник данных кеша factory

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

Это работает очень хорошо.

Ответ 3

Я реализовал его так, как в построителе рендеринга

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

В документации Exoplayer указан класс DashDownloader и приведен пример кода для этого типа источника. (Нажмите [Рамки], чтобы вернуться к навигации по документации. Мне пришлось удалить ее, чтобы получить глубокую ссылку.)

Ответ 5

По умолчанию ExoPlayer не кэширует медиа (видео, аудио и т.д.). Например, если вы хотите воспроизвести видеофайл онлайн, каждый раз, когда ExoPlayer будет открывать соединение, читайте данные, а затем воспроизводите их.

К счастью, он предоставляет нам некоторые интерфейсы и классы реализации для поддержки кэширования мультимедиа в нашем приложении.

Вы можете написать свой собственный кеш, который реализует данные интерфейсы из ExoPlayer. Для простоты я покажу вам, как включить кэш с помощью классов реализации.

Шаг 1: Укажите папку, содержащую ваши медиа файлы. В Android для более мелкой папки кэша (менее 1 МБ) вы должны использовать getCacheDir, в противном случае вы можете указать предпочитаемую папку кэша, например, getFileDir.

Шаг 2: Укажите размер папки кеша и политики, когда размер будет достигнут. Есть 2 API

  • NoOpCacheEvictor, который никогда не удаляет/удаляет файлы кэша. В зависимости от расположения вашей папки кэша, если она находится во внутренней памяти, папка будет удалена, когда пользователи очистят данные приложения или удалят приложение.
  • LeastRecentlyUsedCacheEvictor, который сначала будет удалять/удалять наименее недавно использованные файлы кэша. Например, если размер вашего кэша составляет 10 МБ, то при достижении этого размера он автоматически найдет и удалит файлы, которые использовались не так давно.

Положите это вместе

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)

Ответ 6

В дополнение к ответу Бао Ле, здесь можно использовать версию CacheDataSourceFactory Kotlin, в которой хранится один экземпляр 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)
    }
}