ExoPlayer使用CacheDataSource时ClippingConfiguration不生效问题咨询
ExoPlayer ClippingConfiguration 结合缓存不生效问题解决
问题描述
在ExoPlayer中为MediaItem配置了ClippingConfiguration,但使用自定义缓存的ProgressiveMediaSource时裁剪不生效,改用DefaultMediaSourceFactory创建媒体源则正常工作。相关代码如下:
配置MediaItem的代码
val mediaItem: MediaItem = MediaItem.Builder() .setUri(recitationUri) .setMediaId("$surah:${ayah}") .setClippingConfiguration( ClippingConfiguration.Builder() .setStartPositionMs(ayahTiming.start) .setEndPositionMs(ayahTiming.end) .build() ).build() // 裁剪不生效的创建方式 val mediaSourceFactory = ProgressiveMediaSource.Factory(MediaCache.getInstance(this@PlaybackService).cacheFactory) val source = mediaSourceFactory.createMediaSource(mediaItem) // 裁剪生效的创建方式 val source = DefaultMediaSourceFactory(this).createMediaSource(mediaItem)
自定义MediaCache代码
const val CACHE_DIR_NAME = "cached_audio" const val MAX_CACHE_SIZE = 256 * 1024 * 1024L//256MB class MediaCache private constructor(context: Context) { val cacheFactory: CacheDataSource.Factory init { cacheFactory = setupExoPlayerCache(context) } companion object { @Volatile private lateinit var instance: MediaCache fun getInstance(context: Context): MediaCache { synchronized(this) { if (!::instance.isInitialized) { instance = MediaCache(context) } return instance } } } @SuppressLint("UnsafeOptInUsageError") private fun setupExoPlayerCache(context: Context): CacheDataSource.Factory { val cacheEvictor = LeastRecentlyUsedCacheEvictor(MAX_CACHE_SIZE) val databaseProvider = StandaloneDatabaseProvider(context) val cache = SimpleCache( File(context.cacheDir, CACHE_DIR_NAME), cacheEvictor, databaseProvider ) val upstreamFactory = DefaultDataSource.Factory(context) return CacheDataSource.Factory().apply { setCache(cache) setUpstreamDataSourceFactory(upstreamFactory) setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR) } }
原因分析
ProgressiveMediaSource.Factory仅负责创建对应格式的原始媒体源,不会解析MediaItem中的ClippingConfiguration,也不会自动包装ClippingMediaSource,因此裁剪配置无法生效。DefaultMediaSourceFactory内部会自动检查MediaItem的裁剪配置,若存在则自动用ClippingMediaSource包装原始媒体源,同时处理DRM、广告等其他逻辑,所以裁剪功能正常工作。
解决办法
方法一:手动包装ClippingMediaSource
创建ProgressiveMediaSource后,手动用ClippingMediaSource包装,主动应用MediaItem中的裁剪配置:
val mediaSourceFactory = ProgressiveMediaSource.Factory(MediaCache.getInstance(this@PlaybackService).cacheFactory) val originalSource = mediaSourceFactory.createMediaSource(mediaItem) // 确保clippingConfiguration非空后应用裁剪 val clippedSource = mediaItem.clippingConfiguration?.let { ClippingMediaSource( originalSource, it.startPositionMs, it.endPositionMs ) } ?: originalSource
方法二:改用DefaultMediaSourceFactory并配置缓存数据源
保留DefaultMediaSourceFactory的自动处理逻辑,同时将缓存数据源工厂注入,既支持缓存又自动应用裁剪,更符合ExoPlayer设计规范:
val cacheDataSourceFactory = MediaCache.getInstance(this@PlaybackService).cacheFactory val mediaSourceFactory = DefaultMediaSourceFactory(this) .setDataSourceFactory(cacheDataSourceFactory) val source = mediaSourceFactory.createMediaSource(mediaItem)
内容的提问来源于stack exchange,提问作者Hadi Ahmadi
相关产品推荐
相关产品推荐

