HLS+的实现原理

转载请注明出处:https://blog.csdn.net/impingo
项目地址:https://github.com/pingostack/pingos
项目官网:https://pingos.io

HLS+代码实现

项目地址:https://github.com/pingostack/pingos

首屏、稳定(流畅)、低延时的命运三角

这里不对HLS协议做普及,本文假设读者已经对HLS协议有所了解。

常规的hls直播服务采用的是一条直播流对应一个不停更新的m3u8文件,后续所有流的观看者都下载同一份m3u8文件。直播过程中如果存在某一时刻m3u8文件中第一条或前几条TS文件中无关键帧,新参与进来的播放器依旧会把这些无关键帧的TS文件下载下来,但是并不会对视频解码播放,直到新的含有关键帧的TS文件到来。这会造成带宽的浪费,也会造成首屏时间过长的问题。
为了解决首屏过慢的问题,我们可以使每个TS文件都以关键帧开始,这样不管是什么时刻加入进来的终端都能第一时间获取到关键帧。但是CDN系统接入的客户必然比较复杂,推上来的流往往来自各种各样的数据采集端,有些流gop大小相对均匀(这里的gop大小是指gop的可播放时长),有些流gop大小变化较大。当gop大小突然变大时直接造成最新的TS文件迟迟没有生成,播放器下载最新分片可能会不及时导致卡顿。当gop突然变小时造成TS文件生成过快,同时服务器对m3u8文件刷新过快,有可能在播放器下次更新m3u8之前服务器上的m3u8文件已经被更新了数次,导致播放器漏掉某个TS片,同样造成卡顿。这种情况保证了首屏却牺牲了稳定性。
那么为了应对gop大小变化较大的极端情况,我们不能完全依赖gop进行切片,还要控制TS切片的最大和最小时长,切片过长时就强制截断,切片过短时就与下一个gop黏连,强制的截断TS切片就会出现切片首帧不是关键帧的情况,又回到了第一个问题上。同时为了不让延时过大,又要控制TS切片尽量的小,但是TS切片变小意味着终端缓存的切片时长变小,应对网络抖动的能力也就下降。
首屏、稳定(流程)、低延时似乎成了一个无可能的三角形。

寻找解决办法

根据上文的内容可知,一条直播流对应一个m3u8文件,所有播放该流的播放器都要下载同一份m3u8文件。我们做个假设,假设从任何时刻加入进来的播放器拿到的m3u8文件第一条TS记录是关键帧开始的,并且TS切片时长都是以时间为单位均匀地切断,我们讨论一下这时候会发生什么:

首先,每个播放器拿到的第一个TS切片的第一帧都是关键帧,则首屏问题解决。
其次,每个播放器下载到的TS切片都是以时间为单位做均匀切割,则gop不均匀导致的卡顿问题解决。
最后,每个播放器的TS切片大小可以私有定制,网络状态不佳的TS切片大一些,发送给网络状态好的终端是TS切片小一些以降低延时。貌似延时问题也有所改善,同时照顾了不同网络环境下的终端。
有了上面三个条件,比较尖锐的问题貌似得到了解决,下面我们讨论一下可行性。
要实现以上三个条件,必须满足以下两条:
第一、每个客户端看到的m3u8内容是独立的。
第二、每个客户端下载到的ts文件也是独立的。
如果每个客户端看到的m3u8内容是独立的,就不能共用一份m3u8文件(hls源)了,文章开头的架构是无法满足的。下面我们对架构进行一些调整:
在这里插入图片描述
为了说明问题,我把CDN的边缘节点单独画出来,hls协议由CDN边缘节点进行代理,这里已经没有了http加速CDN。

首先看到的是hls协议与rtmp、http-flv复用同一条向上游的回源连接,原有的hls独立的回源带宽被节省了下来。
如果边缘服务器有能力为每个客户端提供不同进度的hls服务,以上的所有问题似乎都迎刃而解。但是我们还有很多问题没有解决,下面我们讨论具体问题。
第一个问题,CDN系统对外暴露的是域名,同一个域名可能对应很多服务器实例,又因为http是短连接,我们如何保证客户端第二次请求的服务器实例与上一次请求的服务器实例是同一个?
第二个问题,服务器如何才能区分不同客户端的http请求?
为了解决这个问题,我们首先需要引入一个“虚拟连接”的概念,同时要客户端每次都向同一个实例IP发送请求。
我们先解释“虚拟连接”:为了让每个客户端拿到不同的m3u8文件,并且能够可持续的更新,服务器需要记录下不同客户端所请求的m3u8文件的状态(进度),网上有人引入uuid来区分不同的客户端请求,为了大家日后看到网上别的文章能够快速理解,这里继续沿用uuid来区别每个客户端的每次会话。如果客户端第一次请求m3u8时,服务器能够给客户端分配一个uuid用来标记这次播放会话,客户端后续的请求都携带上这个uuid,服务器就能够为客户端保持独立的状态了。
“虚拟连接”实现方法有了,如何让客户端每次向同一个实例IP发送请求,这就要用到http协议的重定向功能,当http返回码为302,客户端后续请求会向Location字段里的新url发起请求。Location字段里的url只需要使用ip地址并且包含uuid参数,后续所有的http请求都会向固定的ip地址发送请求,并且会携带uuid参数。
(使用嵌套的m3u8文件(参考hls的多码率实现),也可实现http重定向的功能。)

在这里插入图片描述
第三个问题,独立的TS切片如何解决,为每路请求生成独立的TS文件显然不合适。
这里引入另一个概念——“虚拟切片”,TS数据缓存在服务器的公用buffer中,每路播放会话索要的TS文件都在公用buffer中标记指针位置。通过这种方式可以实现内存的共享,客户端首次请求的TS文件从buffer的后端向前搜索满足长度的第一个关键帧位置,以此保证客户端看到的视频内容尽量及时。
以上是边缘hls方案的主要内容,其中还有许多实现细节没有讨论,欢迎关注日后的更新内容。

QQ交流群:697773082

微信(cczjp1989)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值