时间戳的理解
基本概念:
- 采样率
音视频现在采用的数字编码方法,简单说就是把音视频这种波形和图像进行采集,量化,编码,传输,解码。所以采样率就是每秒钟抽取图像或者声波幅度样本的次数。比如音频采样率8k,就是表示把波形进行每秒8000次采样。
我们看到一秒的采样频率其实挺大的,至于这个值是多少合理,其实无论视频还是音频都和人的视觉特征和听觉特征有关系。
对于人的视觉而言,只要1秒钟播放的视频达到25帧以上,我们就看到了连续的图像即为视频。如果低于这个值,我们人眼就能感觉出来卡顿。
对于人的听觉而言,正常的听觉频率范围在20Hz-20kHz,根据奎斯特采样理论,为了保证音频不失真,我们的采样频率应该在40kHz左右。为什么采样率不是越高越好呢,因为采样率越高意味着你传输的数据量越多,这样给编码和传输都带了极大的负担,成本也是个重要考虑因素。
- 帧率
帧率就是每秒显示的帧数,比如30fps就是1秒显示30帧图像。但是对于音频可能理解帧率不太好理解,这有点抽象。对于音频,不同的编码方式比如AAC和mp3分别就规定1024采样sample,mp3每帧为1152采样,如果一个采样用一个字节表示,那就是1024字节AAC编码音频为一帧,1152字节为MP3编码方式的音频一帧。
- 时间戳单位
前面我们提到采样率,感觉到采样率是个很大的单位,一般标准的音频AAC采样率达到了44kHz,视频采样率也规定在90000Hz.所以我们衡量时间的单位不能再是秒,毫秒这种真实的时间单位,我们的单位应该转换为采样率,也就是一个采样的时间为音视频的时间单位,这就是时间戳的真实值。当我们要播放和控制时,我们再将时间戳根据采样率转换为真实的时间即可。
一句话,时间戳不是真实的时间是采样次数。比如时间戳是160,我们不能认为是160秒或者160毫秒,应该是160个采样。要换算真实时间,我们必须知道采样率,比如8000,那么说明1秒被划分成8000分之一,如果你要明确160个采样占用的时间,则160*(1/8000)即可,即20毫秒。
- 时间戳增量
就是一帧图像和另外一帧图像之间的时间戳差值,或者一帧音频和一帧音频的时间戳差值。同理时间戳增量也是采样个数的差值不是真实时间差值,还是要根据采样率才能换算成真实时间。
所以对于视频和音频的时间戳计算要一定明确帧率是多少,采样率是多少。
比如视频而言,帧率25,那么对于90000的采样率来说,一帧占用的采样数就是90000/25也就是3600,说明每帧图像的时间戳增量应该是3600,换算成实际时间就是3600*(1/90000)=0.04秒=40毫秒,这也和1/25=0.04秒=40毫秒一致。
对于AAC音频,一帧1024个采样,采样频率是44kHz,所以一帧的播放时间应该是1024*(1/44100)=0.0232秒=23.22毫秒。
同步方法:
上面说了时间戳重要的功能就是来为了音视频的同步,那么这个时间戳到底是如何让音视频同步的呢?
播放器本地需要建立一个系统时钟,这个时钟一般是根据CPU时间计算出来的,当播放开始时时钟时间为0,时间戳决定了一帧解码和渲染的时刻。当播放开始,时钟时间会进行增加,播放器会用系统时钟和当前视频和音频的时间戳进行比较,如果音视频的时间戳小于当前系统时钟,那么就要理解解码和渲染播放。
可以看到播放能否准确进行需要编码器打的时间戳必须精确,同时播放器端的系统时钟也精确,因为播放时要基于时间戳和这个系统时钟对数据流进行控制,也就是对数据块要根据时间戳来采取不同的处理方法。实际无论编码器还是本地播放器都不能非常精确,所以我们说固定帧率25,也有可能编码器一遍打24帧的现象出现。为了解决这个累计误差问题,一般我们需要在播放端有一套反馈机制,能够消除这种误差。其实,同步是一个动态的过程,是一个有人等待、有人追赶的过程。同步只是暂时的,而不同步才是常态。人们总是在同步的水平线上振荡波动,但不会偏离这条基线太远****。
PTS 和DTS
上面通过介绍基本概念就是为了引出实际使用过程中时间戳的表现形式PTS和DTS.其中DTS就是Decoding Time Stamp即解码时间戳,这个时间戳的意义告诉播放器该在什么时候解码这一帧的数据;
PTS即Presentation TimeStamp即显示时间戳,这个时间戳用来告诉播放器在什么时候显示这一帧的数据。
虽然这两个时间戳都是为了指导播放端的行为,但是他们都是由编码器生成的。正常情况下,我们一般解码出来一帧后,就需要立即进行播放,至于什么时候解码和什么时候播放,这个用一个时间戳来决定就可以,为啥现在引入了两个时间戳?当然这里说的DTS和PTS都是对视频而言的,因为视频而言才会用两个时间戳,音频还是用一个时间戳。换句话说播放器到了音频的时间戳就立即解码和播放,中间也不能有什么延时。视频之所以比较复杂是因为你视频存在三种类型的帧,I P B.
I 帧:帧内编码帧,又称为intra picture.I帧通常是每个GOP的第一个帧,采用的帧内压缩,经过适度压缩,作为随机访问的参考点,可以独立不依赖任何帧进行解码和显示。数据量最大,可以将其看为一张压缩的图像。
P 帧:前向预测编码帧,又称为prdictive frame,通过充分将低于图像序列中前面已经编码帧的时间冗余信息来压缩传输数据的编码图像,其采用了帧间预测技术来进行编码。
B帧:则是双向预测内插编码帧,又称为bi-directionalinterpolated frame,相比较P帧依赖前面的帧还依赖后面的P帧进行利用帧间的
冗余信息来压缩数据。
通过上面的比较,帧的压缩率B帧 > P 帧 > I 帧,数据量则刚好相反。
如果没有B帧,假设传输的视频帧是 I P P P,那我们就根据每个帧的时间戳进行解码和显示即可,因为后面帧的时间戳总是大于前面的时间戳,我们用一个时间戳即可。但是有了B帧则解码和显示变得复杂起来。
\1. 我们实际应该展示帧的顺序是: I B B P 帧解码后的顺序;
\2. 但实际上,这些帧到达后,我们根据I帧和B帧的特点,实际在缓存的顺序为:I P B B;
\3. 实际解码的顺序: 1 4 2 3;
\4. 最终展示的顺序是:1 2 3 4;
即先播放I帧,然后第一个B帧,第二个B帧,最后是P帧。
综上我们看到上面的帧,解码顺序和播放显示顺序是不一致的,为了控制他们到底应该是什么时候解码,什么时候播放,则我们建立了DTS和PTS的概念。注意的是解码后的帧则只有PTS概念,未解码的帧才有DTS和PTS的概念。
对于I帧则PTS=DTS,P帧的PTS > DTS,B帧PTS < DTS。当然这里的大于和小于是相对BP帧而言。时间戳小则意味着先解码或者先显示,值越大意味着后处理。
延迟
延迟:是网络传输中的一个重要指标,测量了数据从一个端点到另外一个端点所需的时间。一般我们用毫秒作为其单位。通常我们也把延迟叫做延时,但是延时有时还会表示数据包发送端到接受端的往返时间。这个往返时间我们可以通过网络监控工具测量,测量数据包的发送时间点和接受到确认的时间点,两者之差就是延时。单向时间就是延迟。
抖动:由于数据包的大小,网络路由的路径选择等众多因素,我们无法保证数据包的延迟时间是一致的,数据包和数据包延迟的差异我们称为抖动。也就是说因为数据包的延时值忽大忽小的现象我们称为是抖动。
关于视频的实时性归纳为三个等级:
伪实时:视频消费延迟超过 3 秒,单向观看实时,通用架构是 CDN + RTMP + HLS,现在基本上所有的直播都是这类技术;
准实时: 视频消费延迟 1 ~ 3 秒,能进行双方互动但互动有障碍。有些直播网站通过 TCP/UDP + FLV 已经实现了这类技术,YY 直播属于这类技术;
真实时:视频消费延迟 < 1秒,平均 500 毫秒。这类技术是真正的实时技术,人和人交谈没有明显延迟感。QQ、微信、Skype 和 WebRTC 等都已经实现了这类技术。
对于严格的音频通话,当延时低于200ms时,就会影响到用户体验。达到400ms对方用户就容易感知出来,1s以上的延迟对于交互式实时直播就不能接受了。
完整直播系统
采集-前处理-编码(A1)——》推流(A2)——》处理转码A3——》CDN路由分发(A4)——》解码-播放-渲染(A5)
处理延时:一般就是路由器要分析数据包头决定这个数据包要送到下一站花费的时间;
排队延时:数据包从进入到路由器的发送队列到被发送之间经过的时间,路由排队算法和网络都会影响这部分延时。
传输延时:将数据包传入到线路花费的时间,跟数据包的大小和带宽有关系。
传播延时:是指数据包第一个bit位从发送端到接收端的时间,其和传输距离和传播速度有关系
设备端的延时:包括数据的采集、前处理、编码、解码、渲染等处理阶段花费的时间。也就是A1和A5花费的时间。
音频部分:
音频从采集后,会经过模数转换,将传统的模拟信号转换成数字信号就会产生延时,一般在10ms级别;采集后,进行编码,采用不同的音频编码器也会产生不同的延时,以Opus为例,延时也在2.5ms-60ms级别
其实对于音视频系统,我们可以将上面讲述的三种延时归纳为下面几种:
设备端的延时:包括数据的采集、前处理、编码、解码、渲染等处理阶段花费的时间。也就是A1和A5花费的时间。
音频部分:
音频从采集后,会经过模数转换,将传统的模拟信号转换成数字信号就会产生延时,一般在10ms级别;采集后,进行编码,采用不同的音频编码器也会产生不同的延时,以Opus为例,延时也在2.5ms-60ms级别。发送前还需要进行3A算法(AEC、ANS、AGC)的处理,又需要十几ms.
视频部分:
从自然采光到成像,取决于CCD和CMOS的成像效率,不过一般也需要几十ms.对采集的RGB数据要进行YUV转换和编码,如果还有B帧会产生比较大的编码延时,紧接着播放端的渲染也是需要一定时间的。
无论音频还是视频,为了防止抖动我们一般会在播放端加上jitter buffer缓存,数据从进入到缓存到出缓存以及当发生丢包时,进行的一些传输算法处理也是需要一定的时间,大概会在几十毫秒到几百毫秒之间。
设备端和服务器的延时:也就是俗称的第一公里和最后一公里的延时,包括了A1到A2推流产生的延时和A5向A4拉流的延时。这里的延时跟设备端距离服务器的物理距离,服务器和设备端的网络运营商,设备的网速和带宽,设备端自己的负载都有密切关系。
服务器之间的延时:包含了音视频数据在网络上进行再次转码、切片、转封装和协议以及分发CDN等花费的时间,包含了A2到A4整个阶段花费的时间。这里要看设备的推流端和播放端是不是在同一个边缘节点,如果属于同一个边缘节点,那延时能小点。国内城市之间的传播延时也在几十毫秒,如果跨洲延时会达到百毫秒以上。
延迟测量:
测试方法1:
让推流端也就是主播端比如手机或者IPC摄像头对着一个在线秒表,然后同时我们用手机或者桌面播放器播放该路视频,然后得到了在线秒表显示的时间,等稳定一段时间后我们将在实际线秒表的时间减去播放器显示的该时间,二者的差值就是当前的系统的延时。每隔一段时间,测试多组,求其平均值就得到了当前负载下的音视频延时。
测试方法2:
在编码端的视频帧前面加上SEI帧,SEI的全称是补充增强信息(Supplemental Enhancement Infomation),提供了一种向视频码流中增加额外私有信息的方法。我们可以隔一段时间就在I帧前面的SPS PPS后面增加SEI帧,私有信息就是这时我们编码器的NTP标准时间,当该SEI帧信息到达播放器端,我们再计算下本地的NTP时间。这样本地的值减去SEI的NTP时间,就是当前系统的延时。前提条件,编码器和播放器进行过NTP校时,保证毫秒级别的时间信息要一致
直播云端定时插入SEI帧(内容:当前NTP时间为14:30,SEI Frame中记录NTP时间14:30)——》用户侧接收到S帧后,记录当前NTP时间:14:32,此时SEI里面记录的NTP时间:14:30,延迟为2秒
注:对于有些播放器如果增加SEI信息,可能会导致播放失败,所以解码前我们可以将使用过的SEI帧丢掉
优化思路1:调整推流端和播放端的缓冲区大小,对于25fps的视频流,如果我们缓存25帧的数据,就会在播放时产生1s的延时。所以我们要动态调整我们的缓冲区,对于推流上行区我们如果带宽不够就会产生网络阻塞,这时发送端的数据就会积累,最终延时不断累加,导致延时变大。我们此时就需要有一套机制来能够预测带宽,降低发送码率,减低当前发送数据量,减少网络阻塞,等网络好的时候再继续增大数据发送量,增大码率。
上面说的这些算法有很多,其中WebRTC方案就采用了GCC算法,还有一些类似BBR的算法来实现上述想法。
对于播放端的缓存,当网络不好产生的延时比较大时,我们需要通过丢帧和加速播放方式快速消耗掉播放缓冲区的数据,从而消除累计的延时。
推流(发送缓冲区)——互联网——分发(服务TCP缓冲区)——互联网——拉流(播放缓冲区)
优化思路2:优化网络传输,如果实时性要求很高的场景,你如果选用基于TCP承载的网络传输协议,无论你怎么优化,也很难降低延时。因为TCP会进行三次握手,而且它会对每一次发送的数据进行确认,还要对丢包进行重传,所以这些限制很不适合降低延时。我们要优化传输协议,我们可以将基于TCP的RTMP、HLS协议切换到基于UDP的RTP、QUIC协议上,或者自己开发基于UDP的私有协议栈,这样我们就可以对一些TCP延时大的功能进行裁剪和修改,对于一些不关重要的数据进行丢弃,优先保障重要数据的传输。其中国内B站、虎牙直播,在线k12教育等都进行了类似的处理;
优化思路3:选择优质的CDN加速服务,保障传输的线路带宽和线路资源,一般都会提供测速选线、动态监测、智能路由等功能。
优化思路4:如果感觉自己的编解码,前期处理等花费时间比较多,我们就需要选择合适的音视频编解码器,进行算法调优降低延时,比如我们在播放端能支持硬解的优先选择硬解否则才选择软解。
案例1:
问题:
将自家消费类摄像头的视频投屏到像Alexa的智能音箱上,当然音箱就是带屏幕那种,类似小度小度。实际测试发现,延时比较大,大概有七八秒钟的样子,但是对于Alexa这种智能音箱也就是播放器,我们能干预的很有限,毕竟推动亚马逊研发给你优化这些都是不太可能的,但是我们想把自家摄像头视频投屏到Alexa后,这样在他们商场上架我们产品可以加快我们的硬件海外出货速度,同时还可以增加我们视频云的套餐订阅量。
措施:
最后我们采取了优化转分发服务器缓存的做法,采取了服务端主动追帧和丢帧的策略使服务器端的缓存能够根据当前网络状态进行自动调节,让Alexa播放器的播放缓存总是处于基本饥饿状态,经过一番优化后,延时从七八秒降低到一二秒,达到了上架IPC摄像头的条件。
所以服务端和播放端的缓存优化是降低延时的一个比较重要手段。
案例2:
一个项目采用了自动切换网络传输协议的措施来降低延时,摄像头的视频一般要推送到云服务器上,然后才能进行大规模的转发和分发。这是因为摄像头毕竟是嵌入式设备,并发量非常有限,能同时推送的视频路数也就一两路,如何想无限制进行分发和允许多客户端同时观看,就需要先让摄像头的视频上云到服务端的流媒体,再进行大规模的分发和转发,这也是视频监控的基本玩法。但是我们摄像头以前只支持TCP长链接方式向服务器推流,这样当网络不好就会丢包重传,延时也逐渐积累增大。甚至网络非常不好时,延时会达到几十秒,用户体验很不好。
措施:
我们流媒体服务端会收集播放器的延时数据和丢包,然后当达到一定条件,我们通过信令服务器进行传输协议切换,重新让摄像头推流。将TCP推流改成UDP推流,我们在流媒体服务器端重新实现组包和增加丢帧策略,降低播放端延时