ExoPlayer 与 Media3
问题
ExoPlayer 的架构是什么?Media3 有什么变化?
答案
ExoPlayer 架构
Media3 基本使用
// Media3 = ExoPlayer + MediaSession + UI 统一到 androidx.media3
val player = ExoPlayer.Builder(context)
.setTrackSelector(DefaultTrackSelector(context).apply {
setParameters(buildUponParameters().setMaxVideoSizeSd())
})
.setLoadControl(DefaultLoadControl.Builder()
.setBufferDurationsMs(
/* minBuffer */ 15_000,
/* maxBuffer */ 50_000,
/* playbackBuffer */ 2_500,
/* rebuffer */ 5_000
).build()
)
.build()
// 设置媒体源
val mediaItem = MediaItem.fromUri("https://example.com/video.m3u8")
player.setMediaItem(mediaItem)
player.prepare()
player.play()
// 绑定到 PlayerView
binding.playerView.player = player
生命周期管理
class VideoPlayerActivity : AppCompatActivity() {
private var player: ExoPlayer? = null
override fun onStart() {
super.onStart()
initializePlayer()
}
override fun onStop() {
super.onStop()
releasePlayer()
}
private fun releasePlayer() {
player?.let {
// 保存播放位置以便恢复
playbackPosition = it.currentPosition
currentItem = it.currentMediaItemIndex
it.release()
}
player = null
}
}
ExoPlayer vs MediaPlayer
| 维度 | ExoPlayer / Media3 | MediaPlayer |
|---|---|---|
| 格式支持 | HLS/DASH/SmoothStreaming/MP4 | MP4/MP3/基础格式 |
| 自适应码率 | ✅ | ❌ |
| DRM | ✅ Widevine | 有限 |
| 字幕 | SRT/WebVTT/TTML | 有限 |
| 自定义能力 | 高(组件可替换) | 低 |
| 维护 | Google 活跃维护 | 基本停滞 |
常见面试问题
Q1: ExoPlayer 的缓冲策略是什么?
答案:
ExoPlayer 通过 LoadControl 控制缓冲。DefaultLoadControl 有四个关键参数:
- minBufferMs(15s):最小缓冲时长,缓冲低于此值时继续加载
- maxBufferMs(50s):最大缓冲时长,达到后停止加载
- bufferForPlaybackMs(2.5s):初次播放前需要缓冲的时长
- bufferForPlaybackAfterRebufferMs(5s):卡顿后重新播放需要的缓冲时长
可以根据场景调整:短视频可缩短 buffer,长视频/直播可适当增大。
Q2: 如何实现视频列表的预加载?
答案:
使用 ExoPlayer 的预缓存能力:
- 全局共享缓存:使用
SimpleCache配置磁盘缓存目录 - 预加载:为即将可见的视频提前创建
MediaSource并调用preload() - 复用 Player:列表中复用同一个 ExoPlayer 实例,切换
MediaItem而非创建新 Player
或使用 CacheDataSource.Factory 配合 ProgressiveMediaSource,让已缓存的数据直接从本地读取。