今天的内容分为播放器播放流程、直播源流常见问题、直播延迟的产生与处理、WebRTC快直播四个部分。
播放器的播放流程,基本上是推流的逆向过程。推流端基于同一个时钟源进行音频和视频的采集,得到音频帧PCM以及视频帧YUV。由于存在相应的时空信息冗余,需要进行音视频编码,然后进行媒体格式的封装。为了适应网络传输,还要按照流媒体的相关标准协议,进行再次处理,最终得到输出流。播放就是将推流过程反过来,输入流经过流媒体协议解析,然后解封装,得到音频包(比如常见的AAC)以及视频包(比如常见的H.264、H.265),再经过解码得到音频帧PCM和视频帧YUV,最后经过音视频的时钟同步,送到对应播放显示设备输出。
其中解码、音视频同步是影响播放的重要环节,也是容易出现问题的地方。音视频同步主要有三种策略,分别是音频时间优先、视频时间优先、外部时间优先。由于我们的耳朵对音频更为敏感,通常音视频同步默认选择音频时间优先的策略。
随着浏览器的发展,现在H5Web的播放也开始占据相当大的比重。H5的播放主要由video标签以及MSE-API支持。将多媒体内容通过SourceBuffer 输入后,浏览器经过视频及音频的解码,送到音视频设备输出。目前浏览器还没有原生支持H.265的播放,需要通过WASM支持,比如将FFMPEG经过WASM编译,再对视频进行外置解码。浏览器的主要播放过程与客户端的传统播放器类似,但是增加了从FLV/TS流到FMP4的转封装过程。其中比较特殊的地方是音频播放并不完全依靠时间戳,而是内容的连续处理。当出现音频的PTS跳变或者因为传输的原因导致了音频丢帧等情况,播放器需要进行额外的同步处理,否则随着时间推移,可能导致音视频不同步的情况发生。
播放端常见的问题主要集中在播放失败,播放没声音,音画不同步或者画面卡住不动,出现延迟很高等等。造成这些问题的常见原因有几类,这里结合案例展开讲一下。
第一类,时间戳与流畅度不理想
左边这个案例,客户反馈流播放时,有明显的音画不同步。使用ffplay播放流地址,或者将源流经过wget/cu
rl另存为本地文件后,使用ffprobe分析它的音视频时间戳。从图中可以看到,这个音视频的时间戳差距是非常大的。当音视频时间戳差距过大时,播放器有可能会放弃音视频同步,这个例子就是源流的时间戳DTS/PTS不理想导致的不同步。网址:yii666.com
右边的案例则是直播播放频繁卡顿,但是录制的文件播放比较流畅,没有频繁卡顿的现象,只是最后得到的文件播放时长不够。通过分析源流的上行流畅度曲线,发现它在上行的单位时间(比如说5秒内),实际接收到的音视频数据只有3.5秒,媒体内容一直不足,导致播放器没有足够的数据缓冲,引起直播频繁卡顿,最后的录制文件时长不足。其原因通常与网络带宽在受限的情况下,数据产生积压有关。客户端的网络带宽受限,在没有合适的丢帧等策略时,会容易产生这个现象。
第二类,关键帧的间隔设置不合理
比如左边这个案例,部分观众反馈流的播放延迟很高,达到了8-9秒。拉流播放这个客户的流地址时,发现初始下发的音视频内容比较多,再分析客户的源流,发现GOP(关键帧的间隔)有10秒左右的现象。在这个案例中,视频的GOP过大引发CDN下发的缓存过长,播放器缓存过多,导致延迟过大。
右边的案例中,客户原始流地址播放是失败的,但转码流可以正常播放。分析了这个客户的播放文件,发现它下发没有关键帧。其中原因是部分编码器设置时,GOP不合理,出现了全程只有一个关键帧的现象,造成直播无法正常观看。但是转码流经过重新编码之后,关键帧间隔正常,也就可以播放了。
第三类,音视频解码的关键信息缺失或不匹配
当视频解码关键信息缺失或者不匹配时,现象比较明显,主要表现为不能播放或花屏。但当音频解码器信息缺失或者不匹配时,现象则比较隐蔽。比如在左边这个案例中,部分播放器没有声音,但是ffplay播放正常,是有声音的。使用ffplay 播放客户源流时,发现没有显示出音频的profile。常见情况下,源流播放时候会显示音频profile为LC或者HEAAC、HEAACV2(音频编码使用了SBR和PS),同时进一步分析客户的源流日志时,发现源流缺少音频的解码信息。所以造成这个现象的原因就是客户在推送时没有推送音频的解码头,导致有的播放器比如ffplay可以正常播,有的播放器则不能。
右边的例子则与解码关键信息不匹配相关。客户反馈ffplay播放正常,VLC刚开始正常,但后面延迟越来越高。分析后发现客户的源流音频内容实际是是按照44.1Khz进行的编码。但是它的解码信息传递给服务端时,指示为48Khz。客户推流的音视频解码信息不匹配,导致播放产生各种异常。
第四类,音视频内容存在设备兼容性问题
左边的案例中,内容在其他平台,比如说PC、Web、安卓等播放都是正常的,但是在iOS上的HLS流播放不了。使用ffplay 播放客户的源流时,发现客户的源流使用了场编码。场编码主要用于传统的电视直播场景,而苹果手机iOS系统等不支持场编码播放,造成HLS 无法正常观看。其他在iOS上常见的不能兼容的还有自定义SEI不符合标准、profile/level无法兼容等。
右边的案例与音频内容有关。源流在ffplay 、vlc等播放都正常,但在部分移动端上播放没有声音。分析了客户源流的时间戳、帧率、各种解码信息都正常。但将音频内容通过AdobeCC这个工具分析时发现,音频内容的相位是相反的。当采集编码的设备相位调试异常时,会造成音频内容相位相反,部分设备合并声道内容后输出,有可能会出现声音很弱或者没有声音。而声道独立输出的设备,比如耳机就会表现正常。
总结来说,要做到以下几点来尽量避免源流的常见问题:
-
尽量保持源流的时间戳、流畅度正常;
-
设置合理的源流GOP,既不能过大也不能过小。合理的GOP在1-4秒之间;
-
确保音视频的解码信息发送到服务端;
-
避免使用特殊的编码,比如场编码、非标准SEI等等;
当遇到源流问题时,常用的分析工具主要有如下几种:
-
ffmpeg、ffplay、ffprobe套装,主要用来分析解码,时间戳等相关内容;
-
使用elecard analyzer辅助分析264内容,类似SEI的相关内容;
-
使用AdobeCC分析音频内容,判断是否有相位相反,或者音频没有能量基本处于静音状态等问题。
直播延迟的产生与从推流到云端再到观众的整个环境有关。推流端经过采集、预处理然后再编码,推到云端进行接入。之后云端经过媒体处理再进行CDN的分发与传输。最后在观众端经过解码、后处理播放出来。延迟主要来自链路中的数据堆积,推流、传输、下行播放,都有可能会产生数据堆积,也就都有可能产生延迟。
实践中,影响延迟的主要因素有如下几个方面:
-
上行编码参数的选择;
-
音视频时间传输是否选择了交织;
-
链路传输、线路相关的延迟,以及TCP可靠协议带来的延迟;
-
GOP的大小;
-
下行播放抗抖动缓冲的能力。
常见的协议,比如说RTMP、HTTP-FLV基本上可以做到延迟2-3秒之内。HLS的延迟大概在6-20秒左右,这个值主要依赖于GOP的大小,切片的大小以及切片的数目
直播延迟的常见测量方式有两种。第一种是端到端的播放对比,比如说在推流端,推流采集网页时间,然后在播放端通过对比直接可以得到延迟(这里是一个WebRTC播放的例子,可以看到延迟在500毫秒以内)。这种端到端的播放对比,需要有一个良好的低延迟播放器。如果手头暂时没有的话,ffplay配合-fflags nobuffer可以简单用下。第二种是在推流端中插入自定义的SEI内容,通过携带本地时间戳进行粗略估算。比如说发送端,将本地时间戳以json 的形式放进SEI里,播放端解析到这个SEI后,获取本地时间与json中的时间戳进行比较,得到端到端的链路延迟。这种方法要求两端之间的本地机器时钟不能差异太大。
实践中影响延迟的这几个主要因素中常见的首先是推流端上行编码参数的选择,如果是采用软编码,比如X264,一些参数的设置会影响到它的延迟,比如说rclookahead 与frame threads的数目,还有是否使用B帧以及B帧的数目。随着编码预设preset的增加,从veryfast、faster、fast 到medium ,lookahead的数目从10-40帧不等,以常见的推流编码帧数(FPS15)为例,会导致的延迟额外增加从660ms对应增加至2300ms。这个就是为了提高图像质量、编码速度导致引入的额外延迟。
第二个影响延迟的因素是音视频交织同步,即使用ffmpeg时,音视频交织同步等待会导致额外的延迟。比如说视频的时间戳t1、t2、t3与音频的时间戳,t0、t1、t2并不完全一致时,存在缓冲区的重排,在等待过程中,会产生额外的延迟。
第三个是网络传输本身存在时延RTT。例如测试ping www.qcloud.com的结果,平均时延大概在30-40毫秒之间。在海外,部分地区网络设施较差,这个时延可能会到100-200毫秒。另外现在传统的推流直播主要基于TCP的可靠传输协议,在ACK弱网丢失的时候,容易造成延迟的扩大。例如客户端发送了一段数据之后,等待服务器和ACK,如果超时200毫秒还没收到,那么下一次客户端会进行重试。但是如果下一次的ACK再次丢失,超时时间有可能会扩大到400毫秒。如此累加,整体的延时会变得不可控。
影响延迟的第四个因素,是GOP的大小。播放器在接入CDN时,CDN通常会从最近的GOP下发数据。GOP的设置会影响播放器接入初始发送的数据量。比如播放端连接到CDN节点时,CDN的缓存目前有8秒,那么CDN将这8秒发送给播放端之后,就会产生初始的8秒延迟。
最后一个因素是网络抖动,导致缓冲累积。当网络抖动时,容易出现数据的波峰波谷,播放器会出现数据累积。假设在单位时间5秒内,由于网络卡顿,只收到了2秒的音视频内容。那么播放器有可能在播完这2秒后,就会卡住,等收到后面的8秒内容之后,再按照正常的节奏去播放,也就产生了额外的3秒延迟。如果这个延迟得不到有效的处理,那么随着时间的累积,抖动次数的变多,延迟也会越来越长。
这里为大家介绍一些降低延迟的可选方法:在常用的OBS的推流软件中,可以将编码tune设置为zerolantency,此时它的rclookahead 基本上为0,也没有frame threads,也不使用B帧,延迟比较低。还可以将GOP设置在合理范围,比如两秒,CDN节点下发的缓冲较少,有利于播放器降低延迟。此外还可以为播放器主动增加追帧的能力,主动去丢帧或者是采用soundtouch等快速播放,来降低延迟。如果是H5的Web播放器,适当控制playbackrate的属性,也可以有类似的效果。同时推荐使用一些成熟的播放器,比如说腾讯云视立方的SDK。针对推流接入如果有条件可以采用HTTPDNS获取最佳的调度节点,避免localDNS干扰。最后还可以考虑采用其他的非TCP上行协议,例如SRT等推流。具体的OBS及视立方设置。。
传统的直播,延迟经过一定优化能够低至2-3秒就很不错了。如果想进一步优化延迟,要做到毫秒级别,完全放弃缓冲区,或是将缓冲区控制的特别小,很有可能会导致卡顿率的大幅上升。
而快直播基于WebRTC低延迟技术打造,能够在保证卡顿的同时将延迟降低至毫秒级,满足了对延迟性能要求更高的场景需求,比如在线教育、体育赛事直播、在线答题等。同时它兼容了标准直播,包括推流、转码、录制、截图、鉴黄、播放等全功能,支持客户从现有的标准直播业务平滑迁移。客户既可以选用WebRTC接入,也可以使用传统的RTMP方式,基本上不修改用户的使用习惯。在播放端,快直播使用WebRTC来获得毫秒级的低延迟,同时抗卡顿的效果。
WebRTC快直播和普通直播相比到底做了哪些内容,或者是具有什么样的优势,使得它在延迟降低的同时,卡顿率又不上升呢?普通直播的主要问题首先是基于TCP的可靠数据传输,存在ACK延迟确认、弱网数据积压等。另外普通直播的播放-传输-网络三部分相互割裂,对于缓存的调整没有联动,因此过于降低缓存会造成卡顿率上升。
而WebRTC快直播基于UDP+NACK,可以实现快速重传。当RTT较长时,快直播可以提高FEC的冗余,使得不需要借助重传,直接通过冗余的数据包就可以进行恢复。另外通过带宽估计算法动态调整jitterbuffer,使得缓冲更适应当前网络的状态。同时快直播通过pacer机制降低对网络带宽的压力,比如在发送I帧时,快直播能够对I帧进行分片传输,避免因I帧数据内容较大引起网络抖动丢包,使得网络发送的更为平滑。最后,快直播会对传送媒体的优先级进行区别处理,例如音频优先、视频I帧、P帧、B帧分级丢帧,在网络带宽有限时优先丢弃一些没有参考的B帧,通过降低数据发送量,来避免网络带宽的压力。
上图是快直播与标准直播在推流端参数相同的情况下(1280x720,15FPS,1800Kbps),主播端无损网络,客户端设置不同弱网的对比结果。在丢包30%的情况下,FLV帧率只有10帧,而快直播还有14帧。丢包50%的情况下,FLV只有2帧,快直播仍能保持13帧水平。整体对比来看,快直播在网络抗性以及延迟等方面都具有相当大的优势。