我的应用程序支持多种不同类型的媒体;流式传输和下载。问题是,我有多个 DataSourceFactories 来支持每种媒体类型以及它们正在流式传输或下载的事实。
例如
对于 HLS 和 DASH 来说,情况还不错。我可以传递 CacheDataSource 并将其设置为 MediaSourceFactory 中的数据源。如果缓存未命中,它将去命中上游数据源,即 OkHttpDataSource。
对于 MP4 来说事情变得更加复杂。
现在,我的代码如下所示:
val cacheFactory = CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(httpFactory)
.setCacheWriteDataSinkFactory(null)
.setCacheReadDataSourceFactory(FileDataSource.Factory())
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
val audioAttributes = AudioAttributes.Builder()
.setUsage(C.USAGE_MEDIA)
.setContentType(C.AUDIO_CONTENT_TYPE_SPEECH)
.build()
return ExoPlayer.Builder(context, DefaultRenderersFactory(context))
.setMediaSourceFactory(
DefaultMediaSourceFactory(context)
.setDrmSessionManagerProvider { drmSessionManager }
.setDataSourceFactory(cacheFactory)
)
正如我所说,这对于 HLS 和 DASH 来说效果很好,因为它们都使用相同的缓存和上游数据源。它也适用于流式传输 MP4,因为 DefaultMediaSourceFactory 支持开箱即用。但它不适用于下载的 MP4,因为它有自定义数据源。
有什么方法可以让这些一起工作吗?
好吧,我想我已经成功了。我最终创建了自己的
MediaSource.Factory
自定义实现。根据我获得的内容类型,我会遵循适当的MediaSource.Factory
。我的实现看起来像这样......
class CustomMediaSourceFactory @Inject constructor(
@Named("hls") private val hlsFactory: DataSource.Factory,
private val dashStreamingFactory: DashMediaSource.Factory,
@Named("mp4") private val mp4DataSourceFactory: DataSource.Factory,
private val adaptiveStreamDownloadSource: AdaptiveStreamDownloadSource,
@Named("adaptiveStreamDownloadInternalDataSource") private val adaptiveStreamDownloadDataSource: CacheDataSource.Factory,
private val dashMediaSourceProvider: DashMediaSourceProvider,
private val extractorsFactory: ExtractorsFactory,
private val loadErrorHandlingPolicy: LoadErrorHandlingPolicy
) : MediaSource.Factory {
private val hlsStreamingFactory: HlsMediaSource.Factory by lazy(LazyThreadSafetyMode.NONE) {
HlsMediaSource.Factory(hlsFactory)
.setAllowChunklessPreparation(true)
.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
}
private val mp4Factory: ProgressiveMediaSource.Factory by lazy(LazyThreadSafetyMode.NONE) {
ProgressiveMediaSource.Factory(mp4DataSourceFactory, extractorsFactory)
.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
}
private var drmSessionManagerProvider: DrmSessionManagerProvider? = null
override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider): MediaSource.Factory {
this.drmSessionManagerProvider = drmSessionManagerProvider
return this
}
override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy): MediaSource.Factory {
return this
}
override fun getSupportedTypes(): IntArray = intArrayOf(
CONTENT_TYPE_DASH,
CONTENT_TYPE_HLS,
CONTENT_TYPE_OTHER
)
override fun createMediaSource(mediaItem: MediaItem): MediaSource {
val type = Util.inferContentTypeForUriAndMimeType(
mediaItem.localConfiguration!!.uri, mediaItem.localConfiguration!!.mimeType)
return when (type) {
CONTENT_TYPE_OTHER -> mp4Factory.createMediaSource(mediaItem)
CONTENT_TYPE_HLS -> handleAdaptiveMediaSourceCreation(mediaItem, hlsStreamingFactory)
CONTENT_TYPE_DASH -> handleAdaptiveMediaSourceCreation(mediaItem, dashStreamingFactory)
else -> throw IllegalArgumentException("MediaItem must be one of type DASH, HLS or MP4")
}
}
我希望这可以帮助其他面临类似问题的人。