直播背后的原理是?初识视频流协议 HLS 和 RTMP

3,098 阅读6分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

image.png

背景

当每天看抖音漂亮小姐姐的时候,我只知道开心的滑屏幕、点❤️,但没有想到哪天突然开始做直播相关业务的时候,一脸懵逼,两眼汪汪。

到处都是各种专业术语,完全找不到本。救救俺,我只想单纯的看看漂亮妹子。

哭过之后,理智告诉自己,万物皆协议,互联网构建在一系列协议之上,直播也一样。稍微搜了下资料,发现主要就两个视频流协议 HLS 和 RTMP。

HTTP Live Streaming (HLS)

HTTP Live Streaming 简称为 HLS, 是一个基于 HTTP 的视频流协议,由 APPLE 公司提出和实现。苹果公司的很多产品都支持 HLS 协议,譬如 Mac OS 上的 QuickTime、Safari 以及 iOS 上的 Safari。苹果 2009 年提出该协议,HLS 是 iOS 设备默认要求的视频流标准。安卓也支持HLS,见文章 Guide to Mobile Video Streaming with HLS

Since then, Android has added support, as have most other platforms.

HLS 因为以下几个原因比较受欢迎。

  • HLS 几乎可随处播放。  几个大平台 web、mobile、tv 基本都有免费的HLS 播放器支持。
  • 苹果 要求 HLS。 如果你想在 iOS 设备直播,逃不了的。
  • HLS 相对简单。  它使用了普遍且已经存储的视频格式(MP4 或 TS,伴随着 H.264 和 AAC 等编解码器), 另外附加了一个丑陋但人类可读的文本格式(m3u8).
  • 它通过 HTTP 工作。  不需要跑特殊的服务(不像老旧校风派的 RTMP 协议或者新潮的 WebRTC 协议). HLS 可以方便的透过防火墙或者代理服务器,而且可以很方便的利用 CDN 进行分发加速,并且客户端实现起来也很方便。

原理

HLS 协议基于 HTTP,而一个提供 HLS 的服务器需要做两件事:

  • 编码: 以 H.264 格式对图像进行编码,以 MP3 或者 HE-AAC 对声音进行编码,最终打包到 MPEG-2 TS(Transport Stream)容器之中;
  • 分割: 把编码好的 TS 文件等长切分成后缀为 ts 的小文件,并生成一个 .m3u8 的纯文本索引文件

HLS 把整个流分成一个个小的基于 HTTP 的文件来下载,每次只下载一些。HLS 协议由三部分组成:HTTP、M3U8、TS。这三部分中,HTTP 是传输协议,M3U8 是索引文件,TS 是音视频的媒体信息。

浏览器使用的是 m3u8 文件。在 HTML5 页面上使用 HLS 非常简单,直接

<video src="example.m3u8" controls></video>

或者

<video controls>
    <source src="example.m3u8"></source>
</video>

HLS的index文件就是m3u8的文件,先下载一级index file(master_playlist.m3u8),它里面记录了二级索引文件的地址(Alternate-A、Alternate-B、Alternate-C)的地址,然后客户端再去下载二级索引文件,二级索引文件中又记录了TS文件的下载地址,这样客户端就可以按顺序下载TS视频文件并连续播放。

image.png

一个典型的一级索引 m3u8 文件格式如下:

#EXTM3U

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2000000,CODECS="mp4a.40.2, avc1.4d401f"
skiing-720p.m3u8

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=375000,CODECS="mp4a.40.2, avc1.4d4015"
skiing-360p.m3u8

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=750000,CODECS="mp4a.40.2, avc1.4d401e"
skiing-480p.m3u8

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3500000,CODECS="mp4a.40.2, avc1.4d401e"
skiing-1080p.m3u8

详细介绍如下:

  • bandwidth指定视频流的比特率
  • PROGRAM-ID无用无需关注,
  • 每一个#EXT-X-STREAM-INF的下一行是二级index文件的路径,可以用相对路径也可以用绝对路径。例子中用的是相对路径。

一级索引 m3u8 文件中记录了不同比特率视频流的二级index文件路径,客户端可以自己判断自己的现行网络带宽,来决定播放哪一个视频流。也可以在网络带宽变化的时候平滑切换到和带宽匹配的视频流。

一个二级索引文件格式内容如下 (skiing-480p.m3u8):

#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.97667,
file000.ts
#EXTINF:9.97667,
file001.ts
#EXTINF:9.97667,
file002.ts
#EXTINF:9.97667,
file003.ts
#EXTINF:9.97667,
file004.ts

可以简单的认为二级 m3u8 就是包含多个 ts 文件的播放列表。播放器按顺序逐个播放,全部放完再请求一下 m3u8 文件,获得包含最新 ts 文件的播放列表继续播,周而复始。整个直播过程就是依靠一个不断更新的 m3u8 和一堆小的 ts 文件组成,m3u8 必须动态更新,ts 可以走 CDN。

整体架构

HLS的架构分为三部分:Server,CDN,Client 。即服务器、分发组件和客户端。架构图如下:

image.png

HLS 缺点

HLS 不是万能的,它也有一个致命的弱点:延迟现象非常明显。如果每个 ts 按照 5 秒来切分,一个 m3u8 放 6 个 ts 索引,那么至少就会带来 30 秒的延迟。如果减少每个 ts 的长度,减少 m3u8 中的索引数,延时确实会减少,但会带来更频繁的缓冲,对服务端的请求压力也会成倍增加。所以只能根据实际情况找到一个折中的点。

另外一点, HLS 基于短连接 HTTP,HTTP 是基于 TCP 的,这就意味着 HLS 需要不断地与服务器建立连接,TCP 每次建立连接时的三次握手、慢启动过程、断开连接时的四次挥手都会产生消耗。

Real Time Messaging Protocol (RTMP)

Real Time Messaging Protocol(简称 RTMP)是 Macromedia 开发的一套视频直播协议,现在属于 Adobe。

协议基于 TCP,是一个协议族,包括 RTMP 基本协议及 RTMPT/RTMPS/RTMPE 等多种变种。RTMP 是一种设计用来进行实时数据通信的网络协议,主要用来在 Flash/AIR 平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。

无法支持移动端 WEB 播放是它的硬伤。虽然无法在iOS的H5页面播放,但是iOS原生应用可以写解码去解析的。浏览器端,HTML5 video标签无法播放 RTMP 协议的视频,可以通过 video.js 来实现。

其主要优点:

  • 实时性非常好,延时较小,通常为 1-3s
  • 基于 TCP 长连接,不需要多次建连。

HLS 和 RTMP 对比

image.png

整体直播方案

如上所见,两个协议各有所长,所以实际项目中需要自己抉择到底采用哪种方案。直播整体架构如下。

image.png

参考致谢