@ltlovezh
2021-09-18T16:04:07.000000Z
字数 6448
阅读 1583
HLS
TS
封装容器
HLS(Http Live Streaming)是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部分,一是M3U8描述文件,二是TS媒体文件。
HLS的优势是可以自适应码率播放,客户端可以根据网速,动态选择合适的一路播放,当网速不好时,可以无缝切换到低码率或者低分辨率的一路继续播放;当网速好时,可以无缝切换到高码率或者高分辨率的一路继续播放,让不同用户都可以享受到最好的观看体检。
一级M3U8主要指定了不同码率、分辨率和编码类型的多路二级M3U8,播放端可以根据网速动态选择合适的一路进行播放,甚至在播放中动态切换到另外一路。
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1920x1080,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/high/index.m3u8
二级M3U8主要指定了TS列表,播放端可以按顺序播放TS文件。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:3.375000,
v.f240.ts?start=0&end=1130067&type=mpegts
#EXTINF:1.250000,
v.f240.ts?start=1130068&end=1624131&type=mpegts
#EXTINF:1.750000,
v.f240.ts?start=1624132&end=2118947&type=mpegts
#EXTINF:1.750000,
v.f240.ts?start=2118948&end=2782587&type=mpegts
#EXTINF:2.000000,
v.f240.ts?start=2782588&end=3330983&type=mpegts
#EXTINF:2.000000,
v.f240.ts?start=3330984&end=3852307&type=mpegts
#EXTINF:1.875000,
v.f240.ts?start=3852308&end=4680447&type=mpegts
#EXTINF:3.125000,
v.f240.ts?start=4680448&end=5695083&type=mpegts
#EXTINF:6.000000,
v.f240.ts?start=5695084&end=7813655&type=mpegts
#EXTINF:2.875000,
v.f240.ts?start=7813656&end=8829231&type=mpegts
#EXTINF:5.583333,
v.f240.ts?start=8829232&end=10651327&type=mpegts
#EXTINF:5.458333,
v.f240.ts?start=10651328&end=12483199&type=mpegts
#EXT-X-ENDLIST
#EXTM3U
是所有M3U8文件必须包含的标签,并且必须在文件第一行。
M3U8文件版本,常见为3。
在二级M3U8中,提供了解密媒体文件的必要信息。
#EXT-X-KEY:METHOD=<method> [,URI=<uri>][,IV=<iv>]
Method指定了加解密方法,包含三种取值:NONE(未加密)、AES-128和SAMPLE-AES。
URI指定了获取解密key的地址,可以获取到解密Key。对于IV属性,如果存在,则指定了使用密钥的初始化向量,将该值当成16字节的16进制数,如果没有IV(Initialization Vector),则使用序列号作为IV进行编解码,将序列号的高位赋值到16字节的buffer中。
若指定了加解密方法,那么下载完整个TS文件之后,必现先解密,才能去解封装TS文件。
TS文件的最大持续时间,单位秒。该标签一般在二级M3U8文件出现一次。
指定了二级M3U8文件TS Playlist中第一个TS文件的序号,后续TS文件的序号依次累加。主要作用是多码率切换时,在不同码率的二级M3U8中切换到同一序号的TS文件,例如:当前播放480P分辨率第5个TS文件,因为网速较好,需要切换到720P,那么就可以无缝切换到720P的第6个TS文件继续播放。
一般情况下,仅在二级M3U8文件出现一次,若不出现,则默认为0。
该标签指定是否准许客户端缓存下载的媒体文件用来重播。它可能会出现在M3U8文件的任何地方,但是不能出现两次以上。该标签适用于播放列表中的所有TS分片。其格式如下:
#EXT-X-ALLOW-CACHE:<YES|NO>
在二级M3U8中,指定了某个TS文件的Duration,以及对应的地址。例如下面的TS分段持续时长为3.375秒,start和end指出该TS地址偏移,即:end - start + 1
表示该TS文件的Size。
#EXTINF:3.375000,
v.f240.ts?start=0&end=1130067&type=mpegts
表示没有更多TS文件可以播放了,一般情况下,点播存在,直播不存在。该标签可能会出现在播放列表文件的任何地方,但是不能出现两次及以上。
该标签出现在一级M3U8文件中,指定了不同码率、分辨率和编码类型的多路二级M3U8。如下所示:#EXT-X-STREAM-INF
标签表示码率为1000000,分辨率为640*360,AVC编码的一路流。
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/low/index.m3u8
TS(Transport Stream)是一种音视频封装格式,全称为MPEG2-TS,主要应用于实时传送节目,具有良好的容错能力,要求视频从任一片段都可以独立解码播放。
TS流是由连续的TS包构成,每个TS包固定188字节。TS包从外到里,可以分为3层:
TS包包含3块数据,4字节的TS Header、Adaptation区域和有效载荷。TS Header中的adaptation_field_control
字段指明了是否包含Adaptation区域,主要作用是TS包不足188字节时,作为填充数据。有效载荷主要是PAT、PMT和PES音视频流。
TS包的最大有效载荷是184字节。
TS Header固定4字节,如下所示:
几个重要字段:
若adaptation_field_control
指定包含自适应区域,那么4字节的TS Header之后就是Adaptation区域,如下所示:
第一个字节指定了后续自适应区域的长度(不包含这一字节本身),所以若包含自适应区域,那么TS包的最大有效载荷是183字节(包含自适应区域,但是长度为0,仅占用一个字节)。
当有效载荷是PAT和PMT时,没有Adaptation区域,不够188字节则在后面直接补0;当有效载荷是音视频流时,通常在第一个和最后一个TS包中包含Adaptation区域,如下所示:
整个TS流通过PID表示TS包类型,TS的载荷可以是:PAT、PMT、音频流和视频流。解析TS流的步骤如下所示:
PAT和PMT是必不可少的全局控制信息,并且至少0.5秒就要插入一次PAT和PMT,保证随时可以播放。
PAT:主要作用是指明PMT的PID值。
PMT:主要作用是指明音视频流的PID值。
PAT格式如下所示:
首字节table_id固定为0x00,PAT中最重要的是节目号program_number和PID构成的列表,节目号为0x0001时,其PID表示PMT。
下面是一个包含PAT的TS包的TS Header:
47 40 00 10 00
TS Header第一个字节固定为0x47
,表示同步字节。PID为0,表示该TS包装载的是PAT,adaptation_field_control
为1,表示无自适应区域。
除了4字节的TS Header,因为
adaptation_field_control
为1且是PAT,所以还要跳过1字节才是PAT。
下面👇是PAT内容:只包含一个PMT,且其PID为4096。
PMT格式如下所示:
首字节table_id固定为0x02,PMT中最重要的是流类型stream_type和PID构成的列表,表示音视频流的PID。stream_type为0x1B,表示H264编码的视频流;stream_type为0x0F,表示AAC编码的音频流;stream_type为0x03,表示MP3。
下面是一个包含PMT的TS包的TS Header:
47 50 00 10 00
TS Header第一个字节固定为0x47
,表示同步字节。PID为4096,表示该TS包装载的是PMT,adaptation_field_control
为1,表示无自适应区域。
除了4字节的TS Header,因为
adaptation_field_control
为1且是PMT,所以还要跳过1字节才是PMT。
下面👇是PMT内容:包含一个H264视频(PID为256),一个AAC音频(PID为257)。
除了PAT和PMT,TS包的Payload就是音视频数据了。因为一个TS包只有188字节,而音视频裸数据可能更大,所以一般一个音视频Packet,需要划分为多个TS包传输。
这种情况下,第一个TS包的TS Header中payload_unit_start_indicator
为1,表示是一个音视频Packet的第一个TS包,同属于一个音视频Packet的后续TS包的TS Header中payload_unit_start_indicator
就为0了。
payload_unit_start_indicator
为1的TS包不仅包含了音视频Packet的第一份数据,还在TS Header后包含了PES Header,主要指定了一个完整音视频Packet的Size、PTS和DTS等信息。
下面是PES Header的结构:
前3字节是固定的0x000001开始码,第四字节StreamID表示是音频流(0xC0)还是视频流(0xE0)。第五六两字节PesPacketLength表示一个完整音视频Packet的Size(多个TS包拼接后的完整Packet的Size) + 8(音频)或者13(视频)[因为PesPacketLength还包含了PES Header中PesPacketLength后面的剩余数据,这部分数据在音频流上是8字节(不包含DTS),在视频流上是13字节]。后面的tag还指出了是仅包含PTS(音频流)还是同时包含PTS和DTS(视频流)。最后,5字节表示PTS,5字节表示DTS(视频流)。
PES Header之后就是H264的Annexb NALU或者ADTS AAC了。
我们看一个AAC Packet的前两个TS包,下面是第一个TS包的TS Header:
PID是257,表示音频流;payload_unit_start_indicator
为1,表示AAC Packet的首个TS包;adaptation_field_control
为3,表示既包含自适应区域,也包含有效载荷,并且指出了自适应区域占1字节,即TS Header + 自适应区域总共占了6字节,那剩下的182字节就是PES Header + ADTS AAC了。
下面是紧接着的PES Header:
StreamID为0xC0,表示音频流,且仅包含PTS时间戳,完整AAC Packet的size是2795 - 8 = 2787
下面是一个上述AAC Packet的第二个TS包的TS Header:
adaptation_field_control
为1,表示仅包含有效载荷(不包含自适应区域)。
我们看一个H264 Packet的前两个TS包,下面是第一个TS包的TS Header:
PID是256,表示视频流;payload_unit_start_indicator
为1,表示H264 Packet的首个TS包;adaptation_field_control
为3,表示既包含自适应区域,也包含有效载荷,并且指出了自适应区域占7字节,即TS Header + 自适应区域总共占了12字节,那剩下的176字节就是PES Header + Annexb NALU了。
下面是紧接着的PES Header:
StreamID为0xE0,表示视频流,同时包含PTS和DTS时间戳,PesPacketLength字段为0,表示完整H264 Packet的size已经超出了0xFFFF。
下面是一个上述H264 Packet的第二个TS包的TS Header:
adaptation_field_control
为1,表示仅包含有效载荷(不包含自适应区域)。
解封装时,从payload_unit_start_indicator
为1的TS包,到下一个payload_unit_start_indicator
为1的前一个TS包,才能拼接成一个完整的AAC Packet或者H264 Packet。