最近有空,准备将常用流媒体协议整理成一系列博客文章。前面已经完成了一篇MPEG-DASH概述。本篇来整理一下HTTP Live Streaming,也就是我们常说的HLS。
HLS是苹果公司提出的基于HTTP的流媒体网络传输协议。类似于MPEG-DASH,但是HLS更加简洁,它的基本原理也是服务端把文件或媒体流按照不同的码率切分成一个个小片段进行传输,客户端在播放码流时,可以根据自身的带宽及性能限制,在同一视频内容的不同码率的备用源中,选择合适码率的码流进行下载播放。在传输会话开始时,客户端首先需要下载描述不同码流元数据的M3U8索引文件(类似于DASH中的MPD文件)。
与基于UDP的RTP协议不同,HLS请求仅使用HTTP传输,因此可以穿过任何允许HTTP数据通过的防火墙或代理服务器。这也便于使用传统的HTTP服务器作为源,并广泛使用基于HTTP的内容分发网络来传输媒体流。
虽然HLS有上述优势,但也同时存在延迟过大的劣势。采用HLS直播的视频流延时一般在10秒以上,使用推荐配置时延迟大概在30s,而RTMP直播的延迟最低可达到3、4秒,因此,在对实时性要求较高的场合,如互动直播,就要慎用HLS了。
HLS的格式可简单归结如下:
网络协议: HTTP;
封装格式: MEPG-2 TS;
编码格式: 视频编码格式为H.264,音频编码格式为MP3、AAC、AC-3或EC-3;
索引文件: M3U8。
需要说明的是,目前已有厂家实现了H.265的HLS编码。在封装层面,除了MPEG-2 TS封装外,在WWDC2016上,苹果宣布了HLS对分段MP4(fMP4)文件字节寻址的支持,为HLS向MPEG-DASH的兼容提供了可能。根据媒体流的生成及流向,HLS的结构可划分为如下几个部分(本图来自苹果官网):
上图中,Audio/Video inputs视频源可以是任意格式,可以是离线文件或实时码流;Server接收到视频源后,Media encoder将源视频转码成HLS支持的编码格式和封装格式,根据需求可输出多个码率分别送至Stream segmenter,在segmenter中被切分成指定大小或时间长度的TS切片,并生成索引文件M3U8;Distribution是一个HTTP文件服务器,负责将流媒体文件推送出去或响应客户端的请求。客户端只要访问一级M3U8文件路径就能自动播放HLS视频流了。
那么,M3U8到底是个什么文件呢?
M3U8文件其实就是以UTF-8编码的M3U文件,该文件本身不能播放,只是用于存放待播放视频流的基本信息。下图表示了M3U8文件的结构。
HLS有两级索引,第一级索引存放的是不同码率的HLS源的M3U8地址,也就是二级索引文件的地址;第二级索引则记录了同一码率下TS切片序列的下载地址。客户端获取一级M3U8文件后,根据自己的带宽,去下载相应码率的二级索引文件,然后再按二级索引文件的切片顺序下载并播放TS文件序列。
一个典型的一级索引文件如下:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=720x480
mid_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=800000, RESOLUTION=1280x720
wifi_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=3000000, CODECS="avc1.4d001e,mp4a.40.5", RESOLUTION=1920x1080
h264main_heaac_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=64000, CODECS="mp4a.40.5"
aacaudio_index.M3U8
#EXTM3U: 格式标签,标明该文件是一个Extended M3U播放列表文件,必须存在于一二级列表的第一行。
#EXT-X-STREAM-INF:特定流标签,指示了该流的格式信息:PROGRAM-ID节目ID,一般不用考虑;BANDWIDTH:指定流的带宽;RESOLUTION:视频分辨率;如果存在音频分级,则需指定音频的编码格式CODECS,如上例中的最后两项;#EXT-X-STREAM-INF下面紧接的一行,如mid_video_index.m3u8则是对应流的二级索引文件地址,通过下载该二级索引文件,便可得到媒体切片的信息。
二级索引文件格式如下:
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXTINF:9.009,
http://media.example.com/first.ts
#EXTINF:9.009,
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
#EXT-X-ENDLIST
仍然是以#EXTM3U开头。
#EXT-X-TARGETDURATION: 表示切片的最大时长,单位是秒。#EXT-X-TARGETDURATION:10表示列表中表示的每个切片时长不超过10秒。
#EXT-X-VERSION:表示协议兼容性版本。
#EXTINF:切片的实际时长,若要求取整,则其数值不能大于EXT-X-TARGETDURATION的值。
http://media.example.com/first.ts:对应的切片文件(路径),可以是绝对路径,也可以是相对路径。
#EXT-X-ENDLIST:表示整个码流的结束,不再向后附加新的切片列表。
#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
#EXT-X-MEDIA-SEQUENCE:媒体序列号,表示出现在当前M3U8文件中的第一个Segment的序列号。
Live形式的M3U8一般用于直播,列表中的文件数有限制,推荐配置中是3个,服务端会实时更新该列表,删除最开始的Segment,并向后面添加新生成的Segment。因此,这种模式下,当网络带宽不足时,客户端来不及下载新的M3U8和对应的切片文件,会导致切片丢失,播放卡顿。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:7794
#EXT-X-TARGETDURATION:15
#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"
#EXTINF:2.833,
http://media.example.com/fileSequence52-A.ts
#EXTINF:15.0,
http://media.example.com/fileSequence52-B.ts
#EXTINF:13.333,
http://media.example.com/fileSequence52-C.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=53"
#EXTINF:15.0,
http://media.example.com/fileSequence53-A.ts
HLS可以被加密。客户端通过读取M3U8文件中的#EXT-X_KEY标签可以获取解密的密钥。
EXT-X-KEY指示的密钥信息作用于当前EXT-X-KEY标签至下一个EXT-X-KEY标签(若没有下一个,则到最后一个Segment)之间的所有Segments。METHOD指示加密算法,可用的取值有NONE、AES-128和SAMPLE-AES,NONE表示不加密。URI指示获取密钥的路径,该项不可省略,除非METHOD为NONE。
时间关系,先写这么多,想了解更多详细内容,请参考:
draft-pantos-http-live-streaming
Frequently Asked Questions
HLS维基百科