基于Android TV Input Framework实现直播时移的ExoPlayer动态更新问题
解决ExoPlayer播放动态更新本地文件的方案
核心原理
ExoPlayer加载本地文件时会一次性解析文件元数据,默认不会自动感知后续的文件内容更新。要实现边下载边播放动态增长的本地文件,核心是让ExoPlayer能持续检测文件变化并刷新数据源。
具体实现方案
1. 自定义DataSource监听文件变化
不要直接使用默认的FileDataSource,而是自定义一个能追踪文件大小变化的数据源,用于判断文件是否有新内容写入:
class DynamicFileDataSource(private val targetFile: File) : FileDataSource() { private var recordedFileSize = 0L override fun open(dataSpec: DataSpec): Long { recordedFileSize = targetFile.length() return super.open(dataSpec) } fun isFileUpdated(): Boolean { val currentSize = targetFile.length() return currentSize > recordedFileSize } }
2. 定时检测并刷新MediaSource
通过协程或Handler定时检查文件状态,当发现文件内容增长时,重新创建MediaSource并通知ExoPlayer加载,同时恢复之前的播放位置:
// 用协程实现定时检测 CoroutineScope(Dispatchers.IO).launch { while (player.isPlaying) { delay(1000) // 每秒检测一次 if (dynamicFileDataSource.isFileUpdated()) { withContext(Dispatchers.Main) { val newMediaSource = ProgressiveMediaSource.Factory { DynamicFileDataSource(targetFile) }.createMediaSource(MediaItem.fromUri(targetFile.toUri())) val currentPos = player.currentPosition player.setMediaSource(newMediaSource) player.prepare() player.seekTo(currentPos) } } } }
3. 进阶:用管道流直接传递实时数据
如果是边下载边写入的场景,也可以跳过本地文件的中间存储,直接将下载的数据流通过管道传递给ExoPlayer,彻底规避文件元数据的限制:
val pipeMediaSource = PipedMediaSource.Factory { // 这里直接返回下载的输入流(需确保流持续输出数据) FileInputStream(targetFile) }.createMediaSource(MediaItem.fromUri(targetFile.toUri())) player.setMediaSource(pipeMediaSource) player.prepare()
关键注意事项
- 文件写入模式:下载时必须以追加模式打开文件(
FileOutputStream(targetFile, true)),避免文件被截断导致ExoPlayer解析失败。 - 播放位置维护:每次刷新MediaSource后,必须记录并恢复当前播放位置,防止播放跳回文件开头。
- 资源清理:停止播放时,要及时取消定时检测的协程/Handler,关闭数据源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者asdf9797
相关产品推荐
相关产品推荐

