一、如何判断当前的网络状况
可以以发送一帧视频数据的时间为依据,判断当前网络拥塞情况。
网络中出现丢包和抖动,导致接收端接收数据超时,会激发发送端数据重传,重传机制本身挤占网络带宽,导致sendbuffer中的数据进一步发送失败,致使sendbuffer中的数据不断增多,达到上溢的警戒线,此时应用层函数下发数据到sendbuffer就不会瞬间完成,而是会等待sendbuffer中的数据低于警戒线,再将数据下发。因此可以根据应用层函数写数据到sendbuffer的时间来判断网络的拥塞情况。
可以实时监控直播网络状况,当网络带宽变差时,推流端会迅速地逐级降低视频的帧率、码率、分辨率,以保证推流视频的流畅。而当网络恢复良好时,在确保流畅的前提下,推流端会逐渐提升视频的帧率、码率、分辨率,提升直播视频的清晰度。
二、弱网情况下的一些优化
1. 根据网络状况动态调整视频的帧率、分辨率,使占用的网络带宽更低;
2. 当网络状况不好时,选择性的丢弃参考帧(不丢I帧和音频帧);
3. 选择更高编码压缩率的编码格式(如H.265)。
三、推流端自适应码率
直播推流端实时根据主播所处的网络环境,调整主播的视频码率。在推流过程中,我们可以根据当时主播的网络状况,测算出网络出口带宽是多少,进而和编码器产生的数据量进行比较:如果网络出口带宽大于编码器产生的数据量,则可以提高视频质量(增大编码器的码率设置,同时增大视频的fps以达到更加流畅的效果);如果网络出口带宽和编码器产生的数据量相近,那么视频质量可不做任何改变;如果小于,那就要降低视频质量,以使得主播可以流畅的进行直播。由于整个流的码率中视频轨码率达90%以上,所以只处理视频一般就能满足大部分场景。
1. 网络带宽监测模块
网络上行带宽成为发送码率,编码器编码出来的码率成为压缩码率。实际的监测过程应该是一个窗口时间段的平均码率(一般为3~10s)。
2. 码率调整策略
我们的目的就是按照发送码率反馈给编码器来调整压缩码率。一般会使用几个窗口时间长度的发送平均码率去设置知道编码器改变码率。但是这种策略只能作为将码率的条件,因为这种统计方式统计出来的发送码率不可能会大于压缩码率。因此,如果想要做到升码率,就需要在策略中加上当前H264队列大小的变化趋势,比如队列大小哦啊一直在0和1之间进行变化,则代表编码器编码出来的视频帧,Publisher模块就立马将他发送出去,这时我们就可以尝试去上升码率;比如如果队列编码趋势在队列大小的10%~70%范围内徘徊,则代表有网络抖动发生,可以暂时不做处理(也就是说升码率同时也要看当前视频buffer的大小)。
3. 实时改变编码器的码率
ios和android的硬解分别有相应的接口可以实时改变码率。而FFmpeg的libx264可以通过x264_encoder_reconfig函数实时改变码率。
总结,对于直播场景,采用qos策略,动态调整编码参数,包括帧率,码率,分辨率,缓冲区。当直播出现卡顿,采用快降慢升的策略,当网络波动比较厉害,这样可以避免编码参数频繁的来回调整,造成恶性循环。当进行编码参数调整时,一般是根据分辨率把码率,帧率分成几个档次,然后在根据一定时间段内的统计数据,在这几组参数集合之间进行来回切换,确保音视频流畅的同时,尽量提高图像质量。
五、GOP(Group of pictures)
GOP的长度就是指2个I帧之间的帧数(通常也称为“关键帧间隔”)。
GOP 长度越小,直播内容延时越小,GOP 长度越大,直播内容延时越大;
GOP 越长,越有利于减少视频码率,降低其所需要消耗的存储和带宽。
六、播放体验
两个问题:
1. 至少一个 GOP 的直播内容延时不可避免;
2. 如果 GOP 尚未生成完毕时进行播放,会遇到黑屏(或是花屏)。
针对第一个问题,其实很好解决,推流端编码器或直播服务器将 GOP 长度设置的足够低(比如 0.5s 或是 1s, 不影响编码画质的前提下),播放画面与现场画面的时间差将会越低。
针对第二个问题,单纯修改播放器业务逻辑也解决不了问题。有一种办法是即修改直播服务器,也修改客户端播放器行为逻辑,实现 “双 I 帧交替秒开优化”。
七、双 I 帧交替秒开优化
修改直播服务器由缓存一个 GOP 为缓存一个 I 帧,快速下发给播放器;
修改客户端播放器行为,当遇到一个 I 帧后立即渲染显示,达到秒开,并且是“首帧秒开”;
为了防止时间差内首次播放请求没有遇到 I 帧播放会出现花屏,直播服务器与客户端播放器建立连接后,将缓存的 I 帧快速下发,将第二个 I 帧之前的非 I 帧全部丢弃,直到第二个 I 帧之后传输正常的 GOP。这样,通过 “双 I 帧交替秒开优化”,即可以减少一个 GOP 的直播内容延时,又可以避免黑屏或花屏达到播放请求一次性秒开。