HLS全称为HTTP Live Streaming,是苹果公司提出的基于HTTP的流媒体网络传输协议。它的工作原理是把整个媒体流分成一个个小的基于HTTP的媒体分片来下载,每次只下载一些分片。在开始一个流媒体会话时,客户端会下载一个包含媒体分片的索引文件,即extended M3U playlist文件(m3u8),用于寻找可用的媒体分片。
HLS中,索引文件可以嵌套,一般只有一级索引和二级索引;媒体流封分片装格式只支持MPEG-2传输流(ts)、WebVTT [WebVTT]文件或Packed Audio文件。
下图为索引文件(m3u8)和媒体分片(ts)之间的关系图:一级m3u8嵌套二级m3u8,二级m3u8描述ts分片。
1、 服务器将媒体文件转换为m3u8及ts分片;对于直播源,服务器需要实时动态更新。
2、 客户端请求m3u8文件,根据索引获取ts分片;点播与直播服务器不同的地方是, 直播的 m3u8 文件会不断更新,而点播的 m3u8 文件是不会变的,只需要客户端在开始时请求一次即可。
客户端与服务器通过HTTP协议进行交互,以两级m3u8嵌套为例,客户端先GET请求到一级m3u8,一级m3u8里面包含了服务器端可以用于传播的一个或多个不同带宽的URL,这URL可以获取到二级m3u8;二级m3u8包含了多个ts分片的duration及其URL,最后带过这个URL下载ts分片。交互方式如下:
优势:
劣势:
HLS协议很大一部分内容即是对M3U8文本协议的描述。M3U8即播放索引文件,也称为Playlist,是由多个独立行组成的文本文件,必须通过 URI(.m3u8 或 .m3u) 或者 HTTP Content-Type 来识别(application/vnd.apple.mpegurl 或 audio/mpegurl)。
每行由用 \n 或者 \r\n来标识换行。每一行可以是一个URI、空白行或是一个 以# 号开头的字符串。
以 # 开头的是 tag 或者注释,以 #EXT 开头的是 tag, 其余的为注释, 在解析时应该忽略。URI 表示一个ts分片地址或是Playlist地址。URI 可以用绝对地址或者相对地址,如果使用相对地址,那么是相对于当前Playlist的地址。
有些tag带有属性值,多个属性用逗号分隔。
常见的m3u8文件如下所示:
一级m3u8:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=700000
http://gslbserv.itv.cmvideo.cn/index.m3u8?channel-id=bstvod&Contentid=4007432528&authCode=08210410332183529120&stbId=009903FF0002288018189C62AB5407DB&usergroup=g10000000001&userToken=ded7cd85837b64937de618db3e10553310vv
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1300000
http://gslbserv.itv.cmvideo.cn/index.m3u8?channel-id=bstvod&Contentid=4007432527&authCode=08210410332183529120&stbId=009903FF0002288018189C62AB5407DB&usergroup=g10000000001&userToken=ded7cd85837b64937de618db3e10553310vv
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2300000
http://gslbserv.itv.cmvideo.cn/index.m3u8?channel-id=bstvod&Contentid=4007432526&authCode=08210410332183529120&stbId=009903FF0002288018189C62AB5407DB&usergroup=g10000000001&userToken=ded7cd85837b64937de618db3e10553310vv
二级m3u8:
#EXTM3U
#EXT-X-VERSION:1
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:19674922
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:33:40Z
#EXTINF:10,
19674922.ts?
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:33:50Z
#EXTINF:10,
19674923.ts?
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:34:00Z
#EXTINF:10,
19674924.ts?
音视频分离m3u8示例1:
#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="English", \
DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en", \
URI="main/english-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Deutsch", \
DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="de", \
URI="main/german-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Commentary", \
DEFAULT=NO,AUTOSELECT=NO,LANGUAGE="en", \
URI="commentary/audio-only.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS="...",AUDIO="aac"
low/video-only.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS="...",AUDIO="aac"
mid/video-only.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS="...",AUDIO="aac"
hi/video-only.m3u8
音视频分离m3u8示例2:
#EXTM3U
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Main", \
DEFAULT=YES,URI="low/main/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Centerfield", \
DEFAULT=NO,URI="low/centerfield/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Dugout", \
DEFAULT=NO,URI="low/dugout/audio-video.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS="...",VIDEO="low"
low/main/audio-video.m3u8
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Main", \
DEFAULT=YES,URI="mid/main/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Centerfield", \
DEFAULT=NO,URI="mid/centerfield/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Dugout", \
DEFAULT=NO,URI="mid/dugout/audio-video.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS="...",VIDEO="mid"
mid/main/audio-video.m3u8
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Main", \
DEFAULT=YES,URI="hi/main/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Centerfield", \
DEFAULT=NO,URI="hi/centerfield/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Dugout", \
DEFAULT=NO,URI="hi/dugout/audio-video.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS="...",VIDEO="hi"
hi/main/audio-video.m3u8
名词说明:
1、 Media Playlist:携带ts分片url的m3u8;
2、 Master Playlist:一级m3u8;
3、 Media Segment:ts分片
4、 Attribute Lists:属性列表
Attribute Lists :
• 有的 tags 的值带有 Attribute Lists。
• 一个 Attribute List是一个用逗号分隔的 attribute/value 对列表。
• 格式为: AttributeName=AttributeValue。
tag以#EXT开头,主要分为以下几类:
1) Basic Tags
Basic Tags 可以用在 Media Playlist 和 Master Playlist 里面。
• EXTM3U: 必须在文件的第一行, 标识是一个 Extended M3U Playlist 文件。
• EXT-X-VERSION: 表示 Playlist 兼容的版本。
2) Media Segment Tags
每一个 Media Segment 通过一系列的 Media Segment tags 跟一个 URI 来指定。有的 Media Segment tags 只应用于下一个 segment, 有的则是应用所有下面的 segments。
一个 Media Segment tag 只能出现在 Media Playlist 里面。
• EXTINF: 用于指定 Media Segment 的 duration。
• EXT-X-BYTERANGE: 用于指定 URI 的 sub-range。
• EXT-X-DISCONTINUITY: 表示后续分片属性发生变化,如文件格式/编码/序号。
• EXT-X-KEY: 表示Media Segment 已加密,该值用于解密。
• EXT-X-MAP: 表示Media Segment的头部信息,比如PAT/PMT 或者WebVTT头。
• EXT-X-PROGRAM-DATE-TIME: 和 Media Segment 的第一个sample一起来确定时间戳。
3)Media Playlist Tags
Media Playlist tags 描述 Media Playlist 的全局参数。 同样地, Media Playlist tags 只能出现在 Media Playlist 里面。
• EXT-X-TARGETDURATION: 用于指定最大的 Media Segment duration。
• EXT-X-MEDIA-SEQUENCE: 用于指定第一个 Media Segment 的序号。
• EXT-X-DISCONTINUITY-SEQUENCE: 用于不同 Variant Stream 之间同步。
• EXT-X-ENDLIST: 表示Media Playlist结束。
• EXT-X-PLAYLIST-TYPE: 可选, 指定整个 Playlist 的类型。
• EXT-X-I-FRAMES-ONLY: 表示每个 Media Segment 均为I-frame。
4)Master Playlist Tags
Master Playlist tags 定义 Variant Streams, Renditions 和其他显示的全局参数。 Master Playlist tags 只能出现在 Master Playlist 中。
• EXT-X-MEDIA: 用于关联同一个内容的多个 Media Playlist 的多种翻译。
• EXT-X-STREAM-INF:用于指定下级Media Playlist相关属性。
• EXT-X-I-FRAME-STREAM-INF:与EXT-X-STREAM-INF类似,但指向的下级Media Playlist包含Media Segment均为I-frame。
• EXT-X-SESSION-DATA: 可以随意存放一些 session 数据。
5) Media or Master Playlist Tags
这里的 tags 可以出现在 Media Playlist 或者 Master Playlist 中。 但是如果同时出现在同一个 Master Playlist 和 Media Playlist 中时, 必须为相同值。
• EXT-X-INDEPENDENT-SEGMENTS: 表示每个 Media Segment 可以独立解码。
• EXT-X-START: 标识一个优选的点来播放这个 Playlist。
更加详细的描述,请参考HLS官方文档。
#EXTM3U 每个M3U文件第一行必须是这个tag。
#EXTINF
格式:#EXTINF:,
指定每个ts分片的时长,这个仅对其后面的URI有效,每两个媒体段URI间被这个tag分隔开。
表示时长(秒)必须是整数,如果版本在3以上可以是浮点数。
表示该ts分片下载地址
#EXT-X-TARGETDURATION
格式:#EXT-X-TARGETDURATION:
指定最大的媒体段时间长(秒)。#EXTINF中指定的时间长度必须小于或是等于这个最大值。
这个tag在整个PlayList文件中只能出现一次(在嵌套的情况下,一般有真正ts url的m3u8才会出现该tag)。
#EXT-X-MEDIA-SEQUENCE
格式:#EXT-X-MEDIA-SEQUENCE:
表示PlayList中第一个分片开始的序号,其他分片序号按此逐步加1
#EXT-X-ENDLIST 表示PlayList的末尾了,它可以在PlayList中任意位置出现,但是只能出现一个。直播节目不具有此tag,一般用此tag来区分是否为直播节目。
#EXT-X-STREAM-INF 指定一个包含多媒体信息的 media URI 作为PlayList,一般做M3U8的嵌套使用,它只对紧跟后面的URI有效。
格式:
#EXT-X-STREAM-INF:
指定下级m3u8下载地址。
为属性描述
有以下属性:
BANDWIDTH:带宽,必须有。
PROGRAM-ID:该值是一个十进制整数,惟一地标识一个在PlayList文件范围内的特定的描述。一个PlayList 文件中可能包含多个有相同ID的此tag。
CODECS:不是必须的。
RESOLUTION:分辨率。
AUDIO:这个值必须和AUDIO类别的“EXT-X-MEDIA”标签中“GROUP-ID”属性值相匹配。
VIDEO:同上
#EXT-X-MEDIA 被用来在PlayList中表示相同内容的不用语种/译文的版本,比如可以通过使用3个这种tag表示3中不用语音的音频,或者用2个这个tag表示不同角度的video在PlayLists中。
格式:#EXT-X-MEDIA:
为属性描述,包含:URI、TYPE、GROUP-ID、LANGUAGE、NAME、DEFAULT、AUTOSELECT。
URI:如果没有,则表示这个tag描述的可选择版本在主PlayList的EXT-X-STREAM-INF中存在;
TYPE:AUDIO或VIDEO;
GROUP-ID:具有相同ID的MEDIA tag,组成一组样式;
LANGUAGE:确定使用的主要语言
NAME:对当前类型的描述,如果存在LANGUAGE,则改属性必须描述LANGUAGE指定的语言。
DEFAULT:YES或是NO,默认是No,如果是YES,则客户端会以这种选项来播放,除非用户自己进行选择。
AUTOSELECT:YES或是NO,默认是No,如果是YES,则客户端会根据当前播放环境来进行选择(用户没有根据自己偏好进行选择的前提下)。
#EXT-X-PROGRAM-DATE-TIME 将一个绝对时间或是日期和一个媒体段中的第一个sample相关联,只对下一个meida URI有效,格式如下:
#EXT-X-PROGRAM-DATE-TIME:
例如:
#EXT-X-PROGRAM-DATE-TIME:2019-03-26T10:09:10Z
#EXT-X-BYTERANGE 表示媒体段是一个媒体URI资源中的一段,只对其后的media URI有效
格式:#EXT-X-BYTERANGE:[@o]
表示这个区间的大小
[@o]表在URI中的offset;
该tag只在V4及以后的版本生效
#EXT-X-KEY 表示怎么对media segments进行解码。其作用范围是下次该tag出现前的所有media URI
格式:#EXT-X-KEY:
:NONE 或者 AES-128。如果是NONE,则URI以及IV属性必须不存在,如果是AES-128(Advanced Encryption Standard),则URI必须存在,IV可以不存在。对于AES-128的情况,keytag和URI属性共同表示了一个key文件,通过URI可以获得这个key,如果没有IV(Initialization Vector),则使用序列号作为IV进行编解码,将序列号的高位赋到16个字节的buffer中,左边补0;如果有IV,则将改值当成16个字节的16进制数。