[关闭]
@ltlovezh 2021-09-18T16:04:07.000000Z 字数 6448 阅读 1543

HLS M3U8 TS

HLS TS 封装容器


HLS(Http Live Streaming)是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部分,一是M3U8描述文件,二是TS媒体文件。
HLS的优势是可以自适应码率播放,客户端可以根据网速,动态选择合适的一路播放,当网速不好时,可以无缝切换到低码率或者低分辨率的一路继续播放;当网速好时,可以无缝切换到高码率或者高分辨率的一路继续播放,让不同用户都可以享受到最好的观看体检。

M3u8

一级M3U8主要指定了不同码率、分辨率和编码类型的多路二级M3U8,播放端可以根据网速动态选择合适的一路进行播放,甚至在播放中动态切换到另外一路。

  1. #EXTM3U
  2. #EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
  3. http://example.com/low/index.m3u8
  4. #EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720,CODECS="avc1.42e00a,mp4a.40.2"
  5. http://example.com/mid/index.m3u8
  6. #EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1920x1080,CODECS="avc1.42e00a,mp4a.40.2"
  7. http://example.com/high/index.m3u8

二级M3U8主要指定了TS列表,播放端可以按顺序播放TS文件。

  1. #EXTM3U
  2. #EXT-X-VERSION:3
  3. #EXT-X-TARGETDURATION:6
  4. #EXT-X-MEDIA-SEQUENCE:0
  5. #EXTINF:3.375000,
  6. v.f240.ts?start=0&end=1130067&type=mpegts
  7. #EXTINF:1.250000,
  8. v.f240.ts?start=1130068&end=1624131&type=mpegts
  9. #EXTINF:1.750000,
  10. v.f240.ts?start=1624132&end=2118947&type=mpegts
  11. #EXTINF:1.750000,
  12. v.f240.ts?start=2118948&end=2782587&type=mpegts
  13. #EXTINF:2.000000,
  14. v.f240.ts?start=2782588&end=3330983&type=mpegts
  15. #EXTINF:2.000000,
  16. v.f240.ts?start=3330984&end=3852307&type=mpegts
  17. #EXTINF:1.875000,
  18. v.f240.ts?start=3852308&end=4680447&type=mpegts
  19. #EXTINF:3.125000,
  20. v.f240.ts?start=4680448&end=5695083&type=mpegts
  21. #EXTINF:6.000000,
  22. v.f240.ts?start=5695084&end=7813655&type=mpegts
  23. #EXTINF:2.875000,
  24. v.f240.ts?start=7813656&end=8829231&type=mpegts
  25. #EXTINF:5.583333,
  26. v.f240.ts?start=8829232&end=10651327&type=mpegts
  27. #EXTINF:5.458333,
  28. v.f240.ts?start=10651328&end=12483199&type=mpegts
  29. #EXT-X-ENDLIST

#EXTM3U

#EXTM3U是所有M3U8文件必须包含的标签,并且必须在文件第一行。

#EXT-X-VERSION

M3U8文件版本,常见为3。

#EXT-X-KEY

在二级M3U8中,提供了解密媒体文件的必要信息。

  1. #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文件。

#EXT-X-TARGETDURATION

TS文件的最大持续时间,单位秒。该标签一般在二级M3U8文件出现一次。

#EXT-X-MEDIA-SEQUENCE:

指定了二级M3U8文件TS Playlist中第一个TS文件的序号,后续TS文件的序号依次累加。主要作用是多码率切换时,在不同码率的二级M3U8中切换到同一序号的TS文件,例如:当前播放480P分辨率第5个TS文件,因为网速较好,需要切换到720P,那么就可以无缝切换到720P的第6个TS文件继续播放。
一般情况下,仅在二级M3U8文件出现一次,若不出现,则默认为0。

#EXT-X-ALLOW-CATCH

该标签指定是否准许客户端缓存下载的媒体文件用来重播。它可能会出现在M3U8文件的任何地方,但是不能出现两次以上。该标签适用于播放列表中的所有TS分片。其格式如下:

  1. #EXT-X-ALLOW-CACHE:<YES|NO>

#EXTINF

在二级M3U8中,指定了某个TS文件的Duration,以及对应的地址。例如下面的TS分段持续时长为3.375秒,start和end指出该TS地址偏移,即:end - start + 1表示该TS文件的Size。

  1. #EXTINF:3.375000,
  2. v.f240.ts?start=0&end=1130067&type=mpegts

#EXT-X-ENDLIST

表示没有更多TS文件可以播放了,一般情况下,点播存在,直播不存在。该标签可能会出现在播放列表文件的任何地方,但是不能出现两次及以上。

#EXT-X-STREAM-INF

该标签出现在一级M3U8文件中,指定了不同码率、分辨率和编码类型的多路二级M3U8。如下所示:#EXT-X-STREAM-INF标签表示码率为1000000,分辨率为640*360,AVC编码的一路流。

  1. #EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
  2. http://example.com/low/index.m3u8

TS

TS(Transport Stream)是一种音视频封装格式,全称为MPEG2-TS,主要应用于实时传送节目,具有良好的容错能力,要求视频从任一片段都可以独立解码播放。

TS流是由连续的TS包构成,每个TS包固定188字节。TS包从外到里,可以分为3层:

  1. TS层(Transport Stream):装载PAT、PMT等全局控制信息,或者PES拆分后的载荷数据。
  2. PES层(Packet Elementary Stream):在ES基础上添加PES Header,存储DTS、PTS等信息。
  3. ES层(Elementary Stream):音视频裸流数据,视频H264是Annexb格式NALU,音频AAC是ADTS AAC。

TS
TS-Level

TS包包含3块数据,4字节的TS Header、Adaptation区域和有效载荷。TS Header中的adaptation_field_control字段指明了是否包含Adaptation区域,主要作用是TS包不足188字节时,作为填充数据。有效载荷主要是PAT、PMT和PES音视频流。

TS包的最大有效载荷是184字节。

TS Header固定4字节,如下所示:
TS-Header
几个重要字段:

adaptation_field_control指定包含自适应区域,那么4字节的TS Header之后就是Adaptation区域,如下所示:
TS-Adaption
第一个字节指定了后续自适应区域的长度(不包含这一字节本身),所以若包含自适应区域,那么TS包的最大有效载荷是183字节(包含自适应区域,但是长度为0,仅占用一个字节)。

当有效载荷是PAT和PMT时,没有Adaptation区域,不够188字节则在后面直接补0;当有效载荷是音视频流时,通常在第一个和最后一个TS包中包含Adaptation区域,如下所示:
TS-Payload

整个TS流通过PID表示TS包类型,TS的载荷可以是:PAT、PMT、音频流和视频流。解析TS流的步骤如下所示:

  1. 根据PID固定为0,找到PAT,解析PAT获取PMT的PID。
  2. 根据PMT的PID,找到PMT,解析PMT确定音频流和视频的PID。
  3. 根据音视频流的PID,找到音视频TS包。

PAT和PMT是必不可少的全局控制信息,并且至少0.5秒就要插入一次PAT和PMT,保证随时可以播放。

PAT:主要作用是指明PMT的PID值。
PMT:主要作用是指明音视频流的PID值。

PAT

PAT格式如下所示:
PAT
首字节table_id固定为0x00,PAT中最重要的是节目号program_number和PID构成的列表,节目号为0x0001时,其PID表示PMT。

下面是一个包含PAT的TS包的TS Header:

  1. 47 40 00 10 00

TS-Header-Pat
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。
PAT

PMT

PMT格式如下所示:
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:

  1. 47 50 00 10 00

TS-Header-Pmt
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

PES

除了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

下面是PES Header的结构:
PES
前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

我们看一个AAC Packet的前两个TS包,下面是第一个TS包的TS Header:
TS-Header-AAC-Packet
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:
AAC-PES-Header
StreamID为0xC0,表示音频流,且仅包含PTS时间戳,完整AAC Packet的size是2795 - 8 = 2787

下面是一个上述AAC Packet的第二个TS包的TS Header:
TS-Header-AAC-Packet-Follow
adaptation_field_control为1,表示仅包含有效载荷(不包含自适应区域)。

H264 Packet

我们看一个H264 Packet的前两个TS包,下面是第一个TS包的TS Header:
TS-Header-AVC-Packet
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:
AVC-PES-Header
StreamID为0xE0,表示视频流,同时包含PTS和DTS时间戳,PesPacketLength字段为0,表示完整H264 Packet的size已经超出了0xFFFF。

下面是一个上述H264 Packet的第二个TS包的TS Header:
TS-Header-AVC-Packet-Follow
adaptation_field_control为1,表示仅包含有效载荷(不包含自适应区域)。

解封装

解封装时,从payload_unit_start_indicator为1的TS包,到下一个payload_unit_start_indicator为1的前一个TS包,才能拼接成一个完整的AAC Packet或者H264 Packet。

疑问

  1. pts和dts的TimeBase怎么来的?
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注