如何为ExoPlayer配置多类型DataSource.Factory适配多种媒体?
解决ExoPlayer多类型媒体兼容问题
要同时适配流式MP4、本地混淆MP4、流式/本地HLS/DASH,核心是做一个数据源工厂分发器,根据媒体的具体特征(类型、存储方式)自动选择对应的DataSource.Factory,下面是具体实现方案:
步骤1:实现本地混淆MP4的解密数据源工厂
先针对本地混淆MP4实现自定义的解密数据源工厂,假设你已经有了处理解密逻辑的EncryptedFileDataSource:
class EncryptedFileDataSourceFactory : DataSource.Factory { override fun createDataSource(): DataSource { return EncryptedFileDataSource() // 你的自定义解密数据源,负责读取并解密混淆MP4 } }
步骤2:实现数据源工厂分发器
这个分发器会根据请求的Uri特征,判断该用哪种数据源工厂:
class MediaDataSourceFactory( private val cacheFactory: DataSource.Factory, private val encryptedFactory: DataSource.Factory ) : DataSource.Factory { override fun createDataSource(): DataSource { return object : DataSource { private var delegateDataSource: DataSource? = null override fun open(dataSpec: DataSpec): Long { val uri = dataSpec.uri // 根据Uri特征判断是否为本地混淆MP4,可根据实际业务调整判断逻辑 val isEncryptedLocalMp4 = when { // 示例1:通过自定义scheme识别,比如uri为"encrypted:///sdcard/xxx.enc.mp4" uri.scheme == "encrypted" -> true // 示例2:通过本地文件后缀识别,比如".enc.mp4"结尾的本地文件 uri.scheme == "file" && uri.path?.endsWith(".enc.mp4") == true -> true else -> false } // 选择对应的数据源 delegateDataSource = if (isEncryptedLocalMp4) { encryptedFactory.createDataSource() } else { cacheFactory.createDataSource() } return delegateDataSource!!.open(dataSpec) } override fun read(buffer: ByteArray, offset: Int, length: Int): Int { return delegateDataSource!!.read(buffer, offset, length) } override fun close() { delegateDataSource?.close() } override fun getUri(): Uri? { return delegateDataSource?.uri } override fun getResponseHeaders(): MutableMap<String, MutableList<String>> { return delegateDataSource?.responseHeaders ?: mutableMapOf() } } } }
步骤3:重构ExoPlayer初始化代码
将分发器作为统一的数据源工厂传入ExoPlayer:
val cacheFactory = CacheDataSource.Factory() .setCache(cache) .setUpstreamDataSourceFactory(httpFactory) .setCacheWriteDataSinkFactory(null) .setCacheReadDataSourceFactory(FileDataSource.Factory()) .setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR) // 初始化自定义解密数据源工厂 val encryptedFactory = EncryptedFileDataSourceFactory() // 初始化数据源分发器 val mediaDataSourceFactory = MediaDataSourceFactory(cacheFactory, encryptedFactory) 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(mediaDataSourceFactory) // 设置分发器作为统一数据源 ) .setAudioAttributes(audioAttributes, true) .build()
关键细节说明
- 判断逻辑灵活调整:你可以根据业务需求修改
isEncryptedLocalMp4的判断规则,比如用文件路径前缀、Uri参数、业务标记等方式识别本地混淆MP4。 - CacheDataSource的复用:原有的
cacheFactory已经能覆盖流式MP4、流式HLS/DASH(缓存未命中时自动用OkHttpDataSource拉取)、本地缓存的HLS/DASH(读取缓存文件),无需额外修改。 - 自定义DataSource注意事项:确保
EncryptedFileDataSource正确实现ExoPlayer的DataSource接口,处理好文件读取、解密逻辑及异常捕获。
内容的提问来源于stack exchange,提问作者Vinnie
相关产品推荐
相关产品推荐

