天天看点

HLS协议

HTTP Live Streaming(HLS实时流)大白话理解:其实就是规定一种封装和传输方式。以我的理解来说,首先原始数据经过音频/视频编码后,变成编码完的裸数据,再按照一定的标准进行封装(比如hls中规定了索引文件m3u和切片ts的不同封装标准),然后基于HTTP协议进行传输(传输过程中,主要对服务端和客户端进行了一些规定,要求按照标准来生成hls和应用hls)。

先来看一个别人写的文档——(Apple官网的文档那也是相当古老的)

1.这个里面讲了一些基本点,比较古老 HTTP Live Streaming (HLS) - 概念

2.这个里面更多提到了HLS包含的分片,支持的格式,以及对索引文件的每个标签做了详细解释。 HLS协议概述

一、基本介绍

一些知识点:

  • 由Apple提出和开发,但并不是仅仅使用在ios系统上,目前在各种终端均得到了支持。
  • 虽然是实时流,但可以用于直播(live)和点播(vod)场景,点播就是在索引文件结束处有一个#EXT-X-ENDLIST标志。
  • 点播只需要请求一次索引文件(包含切片名称的那个索引文件),而直播场景下,服务器会不断产生新的切片,所以播放端也要间隙性地刷新索引文件。播放器一般是根据EXT-X-MEDIA-SEQUENCE,可能还会结合列表中ts片的数目,判断m3u8是否更新,然后决定是否需要请求新的m3u8。
  • 播放器拿到索引列表后,一般是根据m3u8中的#EXT-X-TARGETDURATION, 比如间隔1/2(或1/3)的EXT-X-TARGETDURATION请求下一片ts。播放器不同,策略也不同,这个是工业场景比较重要的播放优化点。
  • 服务端可以采用软编或硬编来生成hls。目前Apple官方文档提到,他们默认的Server端编码方式是HEVC(H.265),貌似在哪儿看到硬编码会使用H.265,软编码更多人使用H.264。反正国内很多互联网公司生成hls流时会更多使用H.264。(更奇怪的是,在Apple官网的问答模块,他们却只字未提H.265)
  • 至于生成的hls流中,使用的视频压缩标准可以是H.265或者H.264,音频压缩标准可以是AAC或者AC-3。
  • HLS是支持动态码率(即码率自适应)的,但这个动态码率仅限于不同的ts分片之间。(在编码中途,不要修改视频编码器的设置,比如视频大小或者编码解码器类型。如果避免不了,那修改动作必须发生在一个片段边界。并且需要在之后相连的片段上用 EXT-X-DISCONTINUITY进行标记。)(客户端和分发的服务端能根据网络环境自适应地请求和发送不同码率的分片。比如服务端对同一音视频内容缓存了多个不同码率的分片,客户端接收速度较慢,则发送码率较低的分片;反之则发送码率较高的分片但这依赖服务端生成"主-从"形式的动态索引结构。具体见前面引用的第1篇文章。)
  • 索引文件可能以.m3u8/.m3u为标记结束,其中.m3u一般用于mp3音频流的索引。索引文件的格式参考前面引用的文章或Apple官网。用于动态切换码率的主-从形式的动态索引结构,可以使用Apple官网提供的variantplaylistcreator生成。无论是点播还是直播场景,都可以使用动态索引结构。(值得注意的是,在国内互联网公司使用hls的场景中,为了降低服务端生成/存储/分发流的负载,或者由于客户端对动态切换码率适配不够,通常并没有使用这个功能。)
  • 虽然我们常见的hls流中,包含音视频媒体数据的切片都是ts文件(MPEG-2 Transport Streams),但实际上hls流中还可以支持fMP4文件和纯音频文件(Packed Audio),WebVTT,具体见前面引用的第2篇文章。

二、某些知识点重点介绍

动态切换码率(码率自适应)

背景:Apple官方的设备都是支持动态切换码率的,这除了对切片器有要求外,更多的是对播放终端的适配性要求。但国内使用hls流播放的场景,通常并不是这样,因为我们同样的流,可能在PC端,web端,Android端和ios端都要播放,播放器可能使用的是自己开发的或第三方SDK,不能很好地适配码率切换这个功能。

这方面的文章不算特别多,这里简单写下我的理解。

由于没有找到比较官方的翻译,这里我们暂时定义结构图中的Index file为主索引文件,Alternate index file为动态索引文件。

  • 1)这两者都是.m3u8格式;
  • 2)主索引文件只需下载一次,但直播场景下动态索引文件需要下载多次,主索引文件负责给出各个动态索引文件的参数和地址,动态索引文件负责给出具体的ts分片信息;
  • 3)位于索引结构中(主索引文件列表中有顺序的)的第一个索引关联着客户端默认使用的流,但客户端可以根据网络环境随时动态切换到其他流;
  • 4)不同流应使用同样的音频文件;
  • 5)通常而言,如果条件允许,应尽可能编码足够多的不同码率的流来适应不同网络环境(以保证流畅播放);
  • 6)建议在动态索引文件命名时加上路径/码率等一些有区别性的字段;
  • 7)同一视频内容的不同码率流,虽然分辨率不同,但应保持宽高比一致;
  • 8)动态索引文件中EXT-X-STREAM-INF内的RESOLUTION字段应尽可能标出,以协助客户端根据需要切换合适的流;
  • 9)如果将同一视频内容的不同码率流存储在不同服务器上,那么这些流除了可供动态切换码率以外,还能作为某一路流请求失败的备份流。比如见示例,ALPHA和BETA服务器上的流其实内容和码率都一致,仅为备份使用。
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=200000, RESOLUTION=720x480
http://ALPHA.mycompany.com/lo/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=200000, RESOLUTION=720x480
http://BETA.mycompany.com/lo/prog_index.m3u8
 
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=1920x1080
http://ALPHA.mycompany.com/md/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=1920x1080
http://BETA.mycompany.com/md/prog_index.m3u8
复制代码
           
  • 10)动态索引文件中可以指定编码方式,如下面示例中的CODECS属性,但是要记得用双引号。
#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
复制代码
           
  • 11)如果在多个动态索引文件中,包含了一个音频流,那么可以在主索引文件中指定,如下所示:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=1920x1080
mid_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=150000, RESOLUTION=720x480
3g_video_index.M3U8
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=64000, CODECS="mp4a.40.5"
aacaudio_index.M3U8
复制代码
           
  • 12)主索引文件中列出来的动态索引文件路径,可以是绝对路径,也可以是相对路径。以上第一个示例为绝对路径,第二、三个示例为相对路径。

音频流或静态图流

  • 1)创建音频流,在切片时加入-audio-only的命令即可
  • 2)创建静态图流,如以下示例,-meta-file为指定的静态图片,-meta-type=picture为固定的命令。
mediafilesegmenter -f /Dir/outputFile -a --meta-file=poster.jpg --meta-type=picture track01.mp3
复制代码
           

三、改进HLS技术

相较于其他媒体传输协议,hls虽然有一些自己的优势,但也有很显而易见的劣势。(具体见不同音视频传输协议的对比)那商业场景中使用hls作为传输协议时,如果尽可能去避免它的劣势呢?

  • 1).改进hls中http请求无状态的特性,用以有效区分不同的播放端,保证及时定位排查问题——可以通过在ts分片的URL中添加sessionId或者uuid之类的东东,来区分不同的连接。
  • 2).改进hls中延时较高的问题——HLS在直播场景中,相对于其他流媒体协议而言,延时一般在10s~35s左右,非常高。

    HLS 理论上延时=1个切片的时长+ 0-1个td(td是EXT-X-TARGETDURATION,可简单理解为播放器取片的间隔时间) + 0-n个启动切片(苹果官方建议是请求到3个片之后才开始播放) + 播放器最开始请求的片的网络延时(网络连接耗时)。

    改进hls直播延时需要从延时构成上逐一突破:1.服务端编码和切片模块生成切片文件的耗时(这个可以从提高服务端性能,缩短切片文件时长和大小来做);2.播放器取片间隔时长(仍旧是切片文件大小);3.客户端启动切片个数(这个可以在客户端做优化,尽可能启动播放前下载较少的切片,同时保证音视频的同步);4.客户端下载和解码耗时(这部分主要是网络连接的优化以及客户端解码器的优化)

  • 3).P2P传输——这是比较进阶的技术支持,在客户端的各个节点间完成。要保证切片文件比较小(由于P2P传输是不可靠的,太大的切片文件会导致大量传输失败和重传,造成整个P2P网络严重的资源浪费)。此外仍旧不太适用于实时性要求很高的无延时P2P,如上文3.2中所述,hls协议中的延时来自于各个环节,如果单个切片文件时长要求控制在几十毫秒,实现难度极其高。