12. 流媒体协议支持:HTTP Live Streaming (HLS)、MPEG-DASH、RTSP协议栈解析

流媒体协议这块,说实话是Stagefright里最让我头疼又最兴奋的部分。为什么?因为你要面对的不是一个协议,而是三个完全不同的“祖宗”——HLS、DASH、RTSP。每个都有自己的脾气,每个都有一堆坑等着你踩。

我个人习惯把这三者分成两类:基于HTTP的(HLS和DASH)和基于RTP的(RTSP)。前者走的是“下载-播放”模式,后者走的是“实时流”模式。你想想看,这两者的设计哲学完全不同,但Stagefright硬是把它们整合到了一套框架里。

12.1 HLS:苹果的“封闭”标准

HLS(HTTP Live Streaming)是苹果搞出来的。我记得2010年左右第一次接触它时,心里还在嘀咕:这玩意儿不就是把视频切成小段,然后用一个m3u8文件索引一下吗?后来才发现,事情远没那么简单。

HLS的核心是m3u8播放列表。这个列表有两种:

  • 主播放列表(Master Playlist):包含多个不同码率的流,供客户端自适应选择
  • 媒体播放列表(Media Playlist):包含实际的TS或fMP4片段列表

在Stagefright里,HLS的解析流程大致是这样的:

// 伪代码:HLS解析核心流程
HLSDataSource::parsePlaylist() {
    // 1. 下载m3u8文件
    // 2. 解析标签(#EXTINF, #EXT-X-STREAM-INF等)
    // 3. 构建片段列表
    // 4. 根据带宽和分辨率选择最佳流
    // 5. 开始下载并解码第一个片段
}

关键点:HLS的#EXT-X-DISCONTINUITY标签是个大坑。它表示前后片段可能编码参数不同,比如分辨率变了、采样率变了。如果你不处理这个,播放器会直接崩掉。

我曾经在一个项目中遇到这样的问题:用户上传的视频,前10秒是720p,后面突然变成了480p,而且音频采样率从44100变成了48000。播放器直接花屏加无声。后来我加了个discontinuity检测逻辑,每次遇到这个标签就重新初始化解码器,问题才解决。

12.2 MPEG-DASH:开放但复杂

DASH(Dynamic Adaptive Streaming over HTTP)是MPEG推出的标准,说白了就是HLS的“官方版”。它用MPD(Media Presentation Description)文件来描述流媒体内容,格式是XML。

DASH比HLS灵活得多,但也复杂得多。一个MPD文件可以包含:

  • Period:时间段,每个Period可以有不同的编码参数
  • AdaptationSet:自适应集,比如视频流、音频流、字幕流
  • Representation:具体码率的流,包含带宽、分辨率等信息
  • Segment:实际的媒体片段

在Stagefright里,DASH的解析是通过DashPlayerMPDParser完成的。我记得有一次调试一个DASH直播流,发现MPD文件里minimumUpdatePeriod设成了0,结果播放器不停地重新下载MPD,导致卡顿。后来我加了个缓存机制,才搞定。

小技巧:DASH的SegmentTimeline模式比SegmentTemplate模式更精确,但解析起来也更复杂。如果你遇到时间戳不对齐的问题,多半是这里出的错。

12.3 RTSP:实时流的“老大哥”

RTSP(Real Time Streaming Protocol)是这三个里最“古老”的。它不像HLS和DASH那样走HTTP下载,而是走RTP/UDP实时传输。说白了,RTSP是控制协议,真正传数据的是RTP。

RTSP的典型流程是:

  1. DESCRIBE:客户端请求媒体描述(SDP)
  2. SETUP:建立传输通道(RTP端口)
  3. PLAY:开始播放
  4. PAUSE/TEARDOWN:暂停/停止

在Stagefright里,RTSP的支持是通过ARTSPControllerARTPConnection实现的。嗯,这里要注意:RTSP的NAT穿透是个大问题。我曾经在一个项目中,用户在内网用RTSP看监控,结果视频流死活出不来。后来发现是RTP端口被防火墙封了,改成了TCP隧道才解决。

警告:RTSP的Transport头里,interleaved模式(RTP over RTSP)虽然能解决NAT问题,但会增加延迟。如果你做的是低延迟场景(比如无人机图传),建议还是用UDP。

12.4 协议栈对比:一张表说清楚

特性 HLS MPEG-DASH RTSP
传输协议 HTTP HTTP RTP/UDP
描述文件 m3u8 MPD (XML) SDP
自适应码率 支持 支持 不支持(需扩展)
延迟 高(10-30秒) 中(5-15秒) 低(1-3秒)
复杂度
Stagefright组件 HLSDataSource DashPlayer ARTSPController

12.5 核心逻辑:一张SVG图

下面这张图展示了Stagefright里三个协议栈的核心流程。我特意把HLS和DASH归为“HTTP下载”类,RTSP归为“RTP实时”类,这样你一眼就能看出它们的区别。

Stagefright 流媒体协议栈核心流程 流媒体输入 HTTP 下载类(HLS / DASH) RTP 实时类(RTSP) HLSDataSource / DashPlayer 解析 m3u8 / MPD,下载片段 ARTSPController SDP解析,RTP通道建立 MediaCodec 解码 MediaCodec 解码 音视频输出

12.6 避坑指南:我踩过的那些坑

做流媒体协议支持这几年,我踩过的坑能写一本书。这里挑几个典型的:

  • HLS的#EXT-X-KEY:加密的HLS流,密钥获取失败会导致播放黑屏。我曾经遇到一个CDN配置问题,密钥URL返回了404,排查了整整两天。
  • DASH的SegmentBase:有些DASH流用SegmentBase而不是SegmentList,这意味着整个视频只有一个大文件,需要靠indexRange来定位。如果你解析错了,播放器会直接跳到错误位置。
  • RTSP的Keep-Alive:RTSP连接如果长时间不发送OPTIONS请求,服务器会断开。我见过一个项目,播放器在后台挂了一夜,第二天早上起来发现流断了,就是因为没有做心跳检测。

总结一下:HLS和DASH适合点播和直播,RTSP适合低延迟场景。在Stagefright里,这三者的实现路径完全不同,但最终都汇聚到MediaCodec解码。理解它们的差异,你就能在项目中做出正确的选择。

公众号:蓝海资料掘金营,微信deep3321