HLS
全称是 HTTP Live Streaming
,是一个由 Apple
公司提出的基于 HTTP
的媒体流传输协议,用于实时音视频流的传输。目前 HLS
协议被广泛的应用于视频点播和直播领域。
概述
原理介绍
通过将整条流切割成一个小的可以通过 HTTP
下载的媒体文件,然后提供一个配套的媒体列表文件,提供给客户端,让客户端顺序地拉取这些媒体文件播放,来实现看上去是在播放一条流的效果。由于传输层协议只需要标准的 HTTP
协议,HLS 可以方便的透过防火墙或者代理服务器,而且可以很方便的利用 CDN 进行分发加速,并且客户端实现起来也很方便.
整体架构
HLS
的架构分为三部分:Server,CDN,Client 。即服务器、分发组件和客户端。
下面是 HLS
整体架构图:
HLS 整体架构图
服务器用于接收媒体输入流,对它们进行编码,封装成适合于分发的格式,然后准备进行分发。
分发组件为标准的 Web 服务器。它们用于接收客户端请求,传递处理过的媒体,把资源和客户端联系起来。
客户端软件决定请求何种合适的媒体,下载这些资源,然后把它们重新组装成用户可以观看的连续流。
HLS 协议分析
HLS Playlist
其实,HLS
协议的主要内容是关于 M3U8
这个文本协议的,其实生成与解析都非常简单。为了更加直接地说明这一点,我下面举两个简单的例子:
【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~
简单的 Media Playlist
:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:2680
#EXTINF:7.975,
https://priv.example.com/fileSequence2680.ts
#EXTINF:7.941,
https://priv.example.com/fileSequence2681.ts
#EXTINF:7.975,
https://priv.example.com/fileSequence2682.ts
包含多种比特率的 Master Playlist
:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1280000
http://example.com/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2560000
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7680000
http://example.com/hi.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS="mp4a.40.5"
http://example.com/audio-only.m3u8
-
HLS
通过URI(RFC3986)
指向的一个Playlist
来表示一个媒体流 -
一个
Playlist
可以是一个Media Playlist
或者Master Playlist
, 使用UTF-8
编码的文本文件,包含一些URI
跟描述性的tags
-
一个
Media Playlist
包含一个Media Segments
列表,当顺序播放时,能播放整个完整的流 -
要想播放这个
Playlist
, 客户端需要首先下载他,然后播放里面的每一个Media Segment
-
更加复杂的情况是,
Playlist
是一个Master Playlist
, 包含一个Variant Stream
集合,通常每个Variant Stream
里面是同一个流的多个不同版本 (如:分辨率,码率不同) -
一个
Playlist
文件必须通过URI(.m3u8 或 m3u)
或者HTTP Content-Type
来识别 (application/vnd.apple.mpegurl
或audio/mpegurl
) -
换行符可以用
\n
或者\r\n
-
以
#
开头的是tag
或者注释,以#EXT
开头的是tag
, 其余的为注释,在解析时应该忽略 -
Playlist
里面的URI
可以用绝对地址或者相对地址,如果使用相对地址,那么是相对于Playlist
文件的地址
HLS Media Segments
-
每一个
Media Segment
通过一个URI
指定,可能包含一个byte range
-
每一个
Media Segment
的duration
通过EXTINF
tag
指定 -
每一个
Media Segment
有一个唯一的整数Media Segment Number
-
有些媒体格式需要一个
format-specific sequence
来初始化一个parser
, 在Media Segment
被parse
之前。这个字段叫做Media Initialization Section
, 通过EXT-X-MAP
tag
来指定。支持的Media Segment
格式
HLS TAGS
-
Basic Tags: 用在Media Playlist和Master Playlist里面
-
EXTM3U
: 必须在文件的第一行,标识是一个Extended M3U Playlist
文件 -
EXT-X-VERSION
: 表示Playlist
兼容的版本
-
-
Media Segment Tags: 只能出现在Media Playlist里面
-
EXTINF
: 用于指定Media Segment
的duration
-
EXT-X-BYTERANGE
: 用于指定URI
的sub-range
-
EXT-X-DISCONTINUITY
: 表示不连续 -
EXT-X-KEY
: 表示Media Segment
已加密,该值用于解密 -
EXT-X-MAP
: 用于指定Media Initialization Section
-
EXT-X-PROGRAM-DATE-TIME
: 和Media Segment
的第一个sample
一起来确定时间戳 -
EXT-X-DATERANGE
: 将一个时间范围和一组属性键值对结合到一起
-
-
Media Playlist tags: 只能出现在Media Playlist里面
-
EXT-X-TARGETDURATION
: 用于指定最大的Media Segment duration
-
EXT-X-MEDIA-SEQUENCE
: 用于指定第一个Media Segment
的Media Sequence Number
-
EXT-X-DISCONTINUITY-SEQUENCE
: 用于不同Variant Stream
之间同步 -
EXT-X-ENDLIST
: 表示结束 -
EXT-X-PLAYLIST-TYPE
: 可选,指定整个Playlist
的类型 -
EXT-X-I-FRAMES-ONLY
: 表示每个Media Segment
描述一个单一的I-frame
-
-
Master Playlist tags: 只能出现在Master Playlist中
-
EXT-X-MEDIA
: 用于关联同一个内容的多个Media Playlist
的多种renditions
-
EXT-X-STREAM-INF
: 用于指定一个Variant Stream
-
EXT-X-I-FRAME-STREAM-INF
: 用于指定一个Media Playlist
包含媒体的I-frames
-
EXT-X-SESSION-DATA
: 存放一些session
数据 -
EXT-X-SESSION-KEY
: 用于解密
-
-
Media or Master Playlist Tags: 可以出现在Media Playlist或者Master Playlist中,但是如果同时出现在同一个Master Playlist和Media Playlist中时,必须为相同值
-
EXT-X-INDEPENDENT-SEGMENTS
: 表示每个Media Segment
可以独立解码 -
EXT-X-START
: 标识一个优选的点来播放这个Playlist
-
HLS 播放
播放未加密 HLS
我们通过 VLC
播放器播放苹果官方提供的一个例子:http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
,并使用 Wirshark
对其中交互进行抓包。
GET /iphone/samples/bipbop/gear1/prog_index.m3u8 HTTP/1.1
Host: devimages.apple.com
Accept: */*
Accept-Language: zh_CN
User-Agent: VLC/3.0.8 LibVLC/3.0.8
Range: bytes=0-
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: audio/x-mpegurl
ETag: "50117c8233644c19b5ab49551b72507f:1239907352"
Last-Modified: Thu, 16 Apr 2009 18:42:32 GMT
Server: AkamaiNetStorage
Date: Sun, 22 Nov 2020 15:01:49 GMT
Content-Range: bytes 0-7018/7019
Content-Length: 7019
X-Cache: TCP_MEM_HIT from a184-26-91-45.deploy.akamaitechnologies.com (AkamaiGHost/10.2.0.2-31441410) (-)
Connection: keep-alive
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10, no desc
fileSequence0.ts
#EXTINF:10, no desc
fileSequence1.ts
#EXTINF:10, no desc
fileSequence2.ts
#EXTINF:10, no desc
......
#EXTINF:1, no desc
fileSequence180.ts
#EXT-X-ENDLIST
我们可以看到返回的 M3U8
里面他有一个一个 ts
视频片段,这个一个一个视频片段就是我们需要的播放的视频片段。
#EXTINF` 表示每个 `ts` 切片视频文件的时长。 `#EXT-X-TARGETDURATION` 指定当前视频流中的切片文件的最大时长,也就是说这些 `ts` 切片的时长不能大于 `#EXT-X-TARGETDURATION` 的值。 `#EXT-X-MEDIA-SEQUENCE` 第一个 `ts` 分片的序列号 `#EXT-X-ENDLIST` 这个表示视频结束,有这个标志同时也说明当前的流是一个非直播流。 `#EXT-X-PLAYLIST-TYPE:VOD` 的意思是当前的视频流并不是一个直播流,而是点播流,换句话说就是该视频的全部的 `ts` 文件已经被生成好了 `#EXT-X-ALLOW-CACHE` 是否允许 `cache
播放加密 HLS
HLS 协议总结
优点
-
客户端支持简单,只需要支持
HTTP
请求即可,HTTP
协议无状态,只需要按顺序下载媒体片段即可。 -
使用
HTTP
协议网络兼容性好,HTTP
数据包也可以方便地通过防火墙或者代理服务器,CDN
支持良好。 -
Apple
的全系列产品支持,不需要安装任何插件就可以原生支持播放HLS
, 目前Android
也加入了对HLS
的支持。 -
自带多码率自适应机制。
缺点
-
相比
RTMP
这类长连接协议,延时较高,难以用到互动直播场景。 -
对于点播服务来说,由于
TS
切片通常较小,海量碎片在文件分发,一致性缓存,存储等方面都有较大挑战。
改进
-
由于客户端每次请求
TS
或M3U8
有可能一个新的连接请求,无法有效的标识客户端,一旦出现问题,基本无法有效的定位问题。 -
一般工业级的服务器都会对传统的
HLS
做一些改进,常见优化是对每个M3U8
文件增加Session
来标识一条HLS
连接。 -
不管通过哪种方式,最终我们都能通过一个唯一的
id
来标识一条流,这样在排查问题时就可以根据这个id
来定位播放过程中的问题。