重点模块梳理NetEQ等
1. NetEQ
先盗两张图,兄台写得实在是好
NetEQ有两大核心技术点。一是计算当前网络延时和抖动缓冲延时的算法。要根据网络延时、抖动缓冲延时和其他因素决定信号处理命令,信号处理命令对了能提高音质,相反则会降低音质,所以说信号处理命令的决策非常关键。二是各种信号处理算法,主要有加速(accelerate)、减速(preemptive expand)、丢包补偿(PLC)、融合(merge)和背景噪声生成(BNG)。
2. JitterBuffer
- 第一次接收到一个视频包,从freeframes队列中弹出一个空frame块,用来放置这个包。
- 之后每次接收到一个RTP包,根据时间戳在incompleteframes和decodableframes中寻找,看是否已经接收到过相同时间戳的包,如果找到,则弹出该frame块,否则,从freeframes弹出一个空frame。
- 根据包的序列号,找到应该插入frame的位置,并更新state。其中state有empty、incomplete、decodable和complete,empty为没有数据的状态,incomplete为至少有一个包的状态,decodable为可解码状态,complete为这一帧所有数据都已经到齐。decodable会根据decode_error_mode 有不同的规则,QOS的不同策略会设置不同的decode_error_mode ,包含kNoErrors、kSelectiveErrors以及kWithErrors。decode_error_mode 就决定了解码线程从buffer中取出来的帧是否包含错误,即当前帧是否有丢包。
- 根据不同的state将frame帧 push回到队列中去。其中state为incomplete时,push到incompleteframes队列,decodable和complete状态的frame,push回到decodableframes队列中。
- freeframes队列有初始size,freeframes队列为空时,会增加队列size,但有最大值。也会定期从incompleteframes和decodable队列中清除一些过时的frame,push到freeframes队列。
- 解码线程取出frame,解码完成之后,push回freeframes队列。
jitterbuffer与QOS策略联系紧密,比如,incompleteframes和decodable队列清除一些frame之后,需要FIR(关键帧请求),根据包序号检测到丢包之后要NACK(丢包重传)等。
jitter主要根据当前帧的大小和延时评估出jitter delay,再结合decode delay、render delay以及音视频同步延时,得到render time,来控制平稳的渲染视频帧。
frameDelayMS指的是一帧数据因为分包和网络传输所造成的延时总和,帧间延迟。具体如下图,即RTP1和RTP2到达Receiver的时间差。
incompleteFrame指是否为完整的帧,
UpdateEstimate为根据这三个参数来更新jitterdelay的模块,这个模块为核心模块,其中会用到卡尔曼滤波对帧间延迟进行滤波。
JitterDelay = theta[0] * (MaxFS – AvgFS) + [noiseStdDevs * sqrt(varNoise) – noiseStdDevOffset]其中theta[0]是信道传输速率的倒数,MaxFS是自会话开始以来所收到的最大帧大小,AvgFS表示平均帧大小。noiseStdDevs表示噪声系数2.33,varNoise表示噪声方差,noiseStdDevOffset是噪声扣除常数30。UpdateEstimate会不断地对varNoise等进行更新。
在得到jitterdelay之后,通过jitterdelay+ decodedelay + renderdelay,再确保大于音视频同步的延时,加上当前系统时间得到rendertime,这样就可以控制播放时间。控制播放,也就间接控制了buffer的大小。