下面把 HlsMediaSource(m3u8)/ DashMediaSource(mpd)/ ProgressiveMediaSource(mp4、mkv、ts + Extractors) 的差异讲清楚:协议/容器、能力特性(自适应、直播、低延迟、加密、字幕)、在 ExoPlayer/Media3 里的实现与常见坑,以及选型建议与代码骨架。
一、它们分别是什么?
-
HlsMediaSource(HLS, .m3u8)
Apple 提出的基于 HTTP 分段的自适应流。主清单(master)+ 媒体清单(media),分片通常是 TS 或 fMP4(CMAF) ;天然支持多清晰度、多音轨、字幕、直播窗口与滚动刷新。
-
DashMediaSource(MPEG-DASH, .mpd)
ISO/IEC 标准的自适应流。MPD 清单描述 Period / AdaptationSet / Representation;分片几乎总是 fMP4(CMAF) ;功能表达更丰富(事件流、trick-mode、UTCTiming 等)。
-
ProgressiveMediaSource(渐进式下载,单文件 .mp4/.mkv/.ts)
普通 HTTP 范式:单一文件持续读取(可 Range 断点);没有多码率自适应,也没有清单。快、简单,但弱于前两者的自适应和直播能力。
二、核心能力对比
| 能力 | HLS | DASH | Progressive |
|---|---|---|---|
| 自适应码率(ABR) | ✅(主清单多 variant) | ✅(多 Representation) | ❌(单文件;最多容器内多音轨) |
| 直播(Sliding Window) | ✅ | ✅ | ⚠️ 一般不适合;需切片器/轮播才行 |
| 低延迟 | ✅ LL-HLS(PART/Preload Hint/Chunked CMAF) | ✅ LL-DASH(Chunked CMAF) | ❌ |
| 容器 | TS 或 fMP4(CMAF) | fMP4(CMAF)为主 | MP4/MKV/TS 等 |
| 字幕 | VTT/IMSC1/CEA-608/708、内/外挂 | TTML/IMSC1/WebVTT、内/外挂 | 内嵌轨或外挂(SRT/VTT) |
| DRM | AES-128/ SAMPLE-AES /(Android 端常用 Widevine with CMAF) | CENC(Widevine/PlayReady/ClearKey) | 容器内加密较少见;Exo 支持 ClearKey/Widevine(需封装) |
| 起播时延 | 中 | 中 | 快(取决于 moov 在前“faststart”) |
| 网络/容灾弹性 | 高(可切 variant/备用域名) | 高(可切 Representation/BaseURL) | 低(单 URL) |
| 服务端复杂度 | 低~中(行业最普及) | 中~高(清单更复杂) | 低(直接静态文件) |
三、ExoPlayer/Media3 的实现要点
1) HlsMediaSource
-
PlaylistTracker 定时刷新媒体清单(直播窗口滑动)。
-
支持 TS(TsExtractor)与 fMP4/CMAF(FragmentedMp4Extractor)。
-
参数:
- setAllowChunklessPreparation(true):在有完整清单时,无需预拉第一个分片即可准备,加速起播(限 fMP4/CMAF)。
- LL-HLS:Exo 支持 #EXT-X-PART/chunked transfer,结合 MediaItem.LiveConfiguration(见后述)。
-
元数据:ID3、EXT-X-DISCONTINUITY、PROGRAM-DATE-TIME。
2) DashMediaSource
-
解析 MPD,Period/AdaptationSet/Representation → 轨道选择与 ABR。
-
支持 EventMessage (emsg) 、trick-mode 轨、UTCTiming(校时)。
-
低延迟 DASH:CMAF chunked transfer + 合理 LiveConfiguration。
3) ProgressiveMediaSource
-
通过 Extractor 解析单文件(Mp4Extractor/MkvExtractor/TsExtractor 等)。
-
没有 ABR,但可在容器内选择音轨/字幕。
-
起播快:只要 moov 在前(mp4 “faststart”),seek 也快;否则首帧前可能拉完整 moov。
四、低延迟与直播配置(Media3)
val liveCfg = MediaItem.LiveConfiguration.Builder()
.setMaxPlaybackSpeed(1.02f) // 轻微追赶
.setTargetOffsetMs(3000) // 目标延迟
.setMinOffsetMs(2000) // 下限
.setMaxOffsetMs(5000) // 上限
.build()
val item = MediaItem.Builder()
.setUri(uri)
.setLiveConfiguration(liveCfg) // HLS/DASH 直播/低延迟生效
.build()
低延迟还需要服务端支持(LL-HLS/LL-DASH chunked CMAF),客户端仅能在此基础上优化缓冲。
五、DRM 概览(Android/Exo 常见)
- DASH + CENC(Widevine/PlayReady) :最主流。
- HLS + CMAF + Widevine:越来越常见(多端一致打包)。
- MediaItem.DrmConfiguration 配置即可:
val drmCfg = MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
.setLicenseUri(licenseUrl)
.build()
val item = MediaItem.Builder()
.setUri(uri)
.setDrmConfiguration(drmCfg)
.build()
六、代码骨架(Media3,统一写法)
val player = ExoPlayer.Builder(context).build()
// HLS
val hlsItem = MediaItem.Builder()
.setUri(hlsUri)
.setMimeType(MimeTypes.APPLICATION_M3U8)
.build()
player.setMediaItem(hlsItem)
// DASH
val dashItem = MediaItem.Builder()
.setUri(mpdUri)
.setMimeType(MimeTypes.APPLICATION_MPD)
.build()
player.addMediaItem(dashItem)
// Progressive
val progItem = MediaItem.Builder()
.setUri(mp4Uri)
.setMimeType(MimeTypes.VIDEO_MP4) // 或 VIDEO_MPEG2TS、VIDEO_WEBM 等
.build()
player.addMediaItem(progItem)
player.prepare()
player.play()
自定义工厂:
-
HLS:HlsMediaSource.Factory(dataSourceFactory).setAllowChunklessPreparation(true)
-
DASH:DashMediaSource.Factory(dataSourceFactory)
-
Progressive:ProgressiveMediaSource.Factory(dataSourceFactory)
一般推荐直接用 MediaItem + ExoPlayer 内置 SourceFactory,更简洁。
七、缓存与预缓冲
-
三者都可通过 CacheDataSource + SimpleCache 缓存片段/文件。
-
HLS/DASH:缓存 片段;清单会刷新但占用很小。可做预缓存(选定若干分片提前拉)。
-
Progressive:缓存文件区段;长视频占用大、回收策略要设置好。
-
Key:自定义 CacheKeyFactory,根据 URI+清单信息合成稳定 key,避免同内容多份缓存。
八、常见坑
-
HLS TS 起播慢/seek 慢*
- 优先使用 fMP4/CMAF(chunkless preparation、更好的 index)。
- 合理切片时长(2~6s),LL-HLS 用 PART(0.21s)。
-
DASH 时间轴/校时问题
- 使用 MPD 的 UTCTiming;客户端 LiveConfiguration 调整偏移。
-
Progressive 起播慢
- 确保 mp4 moov 在前(faststart) ;容器优化后起播/seek 都更快。
-
字幕&音轨选择
- HLS/DASH:通过 TrackSelectionParameters.Builder 设置首选语言/角色(commentary、descriptive)。
- Progressive:外挂字幕用 MergingMediaSource(或 MediaItem.SubtitleConfiguration)。
-
DRM 失败
- 证书/License URL、CORS、离线许可(OfflineLicenseHelper)都要对齐;CMAF Widevine 更通用。
-
ABR 抖动
-
调整 DefaultBandwidthMeter、TrackSelectionParameters、LoadControl;对移动网络可加更保守的上切策略。
-
九、如何选型(实战建议)
- 移动端长视频/直播、网络波动明显 → HLS 或 DASH(谁方便就用谁;有 iOS 需求通常统一 HLS/CMAF)。
- 需要低延迟互动直播 → LL-HLS 或 LL-DASH(CMAF) ,客户端设 LiveConfiguration,服务器/打包/CDN 必须支持 chunked。
- 简单点播、成本最低 → Progressive + MP4(faststart) ;不需要多码率。
- 多平台一致打包 → CMAF 一套打包,HLS/DASH 两清单;Android 端都吃得下。
- DRM(Widevine/PlayReady) → DASH+CENC 或 HLS+CMAF+Widevine。
10. 速查总结
-
HLS/DASH = 有清单 + 多码率 + 直播 + 低延迟 + DRM;
-
Progressive = 单文件快启动、实现简单,但没有自适应/直播;
-
Android 端配 ExoPlayer/Media3:用 MediaItem 即可,复杂场景再定制 SourceFactory/LoadControl/TrackSelection。