HlsMediaSource、DashMediaSource、 ProgressiveMediaSource差异详解

124 阅读4分钟

下面把 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 断点);没有多码率自适应,也没有清单。快、简单,但弱于前两者的自适应和直播能力。

二、核心能力对比

能力HLSDASHProgressive
自适应码率(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)
DRMAES-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,避免同内容多份缓存。

八、常见坑

  1. HLS TS 起播慢/seek 慢*

    • 优先使用 fMP4/CMAF(chunkless preparation、更好的 index)。
    • 合理切片时长(2~6s),LL-HLS 用 PART(0.21s)。
  2. DASH 时间轴/校时问题

    • 使用 MPD 的 UTCTiming;客户端 LiveConfiguration 调整偏移。
  3. Progressive 起播慢

    • 确保 mp4 moov 在前(faststart) ;容器优化后起播/seek 都更快。
  4. 字幕&音轨选择

    • HLS/DASH:通过 TrackSelectionParameters.Builder 设置首选语言/角色(commentary、descriptive)。
    • Progressive:外挂字幕用 MergingMediaSource(或 MediaItem.SubtitleConfiguration)。
  5. DRM 失败

    • 证书/License URL、CORS、离线许可(OfflineLicenseHelper)都要对齐;CMAF Widevine 更通用。
  6. 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。