一、jitter buffer 介绍
二、jitter 估计
三、buffer 处理 rtp 包逻辑
四、接收和解码流程
五、FrameBuffer 类介绍
/*
********************************************************************************
一、jitter buffer 介绍
jitter buffer 抖动缓冲区
当网络不稳定时(发生抖动),增加buffer的长度,多缓存一些数据,以应对将来可能发生的抖动。
它对数据包丢失、乱序、延迟到达等情况进行处理,平滑的向解码模块输出数据包/帧,
抵抗各种弱网情况对播放/渲染造成的影响,降低卡顿,提高用户体验。
视频从采集到渲染的流程如下:
采集 -> 编码 -> 分包 -> 发送 ----------------> 网络
渲染 <- 解码 <- Jitter Buffer <- 组帧 <- 接收 <-|
********************************************************************************
*/
/*
********************************************************************************
二、jitter 估计
jitter 就是一种抖动。
RTP数据包从源地址发送到目的地址,会发生不一样的延迟,这样的延迟变动就是 jitter
jitter 会让音视频的播放不稳定,如音频的颤音、视频的忽快忽慢
解决 jitter 的方法是增加延时,这个延时称为抖动延迟(jitter delay)
抖动延迟由网络延迟、解码延迟、渲染延迟构成。解码、渲染延迟比较稳定,网络抖动延迟是动态变化的。
webrtc 认为网络抖动延迟由两部分构成:
1、网络噪声带来的抖动延迟(网络排队延迟)
2、传输大的视频帧(特别是关键帧)对网络造成冲击带来的抖动延迟
(计算信道速率,根据信道速率计算大的视频帧对网络冲击带来的延迟)
webrtc 使用卡尔曼滤波(kalman) 估算网络排队延迟和信道速率
modules\video_coding\jitter_estimator.cc
1、更新 jitter 估计
void VCMJitterEstimator::UpdateEstimate(
int64_t frameDelayMS, uint32_t frameSizeBytes, bool incompleteFrame = false);
其中 frameDelayMS 帧间延迟,指的是一帧数据因为分包和网络传输所造成的延时。
frameSizeBytes 指当前数据帧大小, incompleteFrame 指是否为完整的帧。
1.1、噪声阈值计算
VCMJitterEstimator::NoiseThreshold()
double noiseThreshold = _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;
1.2、计算 jitter 估计值
VCMJitterEstimator::CalculateEstimate()
double ret = _theta[0] * (_maxFrameSize - _avgFrameSize) + NoiseThreshold();
即
jitterDelay = _theta[0] * (_maxFrameSize - _avgFrameSize)
+ _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;
其中:
_theta[0] 为信道传输速率的倒数
_maxFrameSize 自会话开始以来所收到的最大帧大小
_avgFrameSize 平均帧大小
_noiseStdDevs 表示噪声系数,值为2.33
_varNoise 表示噪声方差,默认值为4.0 EstimateRandomJitter()中会不断更新该值
_noiseStdDevOffset 为噪声扣除常数,值为30.0
2、获取 jitter 估计
返回以毫秒为单位的当前抖动估计,并在重传情况下添加一个RTT相关项
int VCMJitterEstimator::GetJitterEstimate(
double rttMultiplier, absl::optional<double> rttMultAddCapMs)
其中: rttMultiplier 为RTT参数乘数
参考: http://www.ctiforum.com/news/guonei/512085.html
********************************************************************************
*/
/*
********************************************************************************
三、buffer 处理 rtp 包逻辑
modules\video_coding\jitter_buffer.h
buffer 接收 rtp 包的处理逻辑主要使用到以下三个队列
class VCMJitterBuffer {
UnorderedFrameList free_frames_ RTC_GUARDED_BY(crit_sect_);
FrameList decodable_frames_ RTC_GUARDED_BY(crit_sect_);
FrameList incomplete_frames_ RTC_GUARDED_BY(crit_sect_);
}
free_frames_ 队列用于管理空的frame,弹出空的frame来存放rtp包,解码完成后的frame重置后再次存入该队列。
incomplete_frames_ 队列用于存放尚未完整的frame,当frame完整时将其push到 decodable_frames_
decodable_frames_ 队列用于存放完整的可以解码的frame
1、第一次接收到一个rtp视频包,从 free_frames_ 队列中弹出一个空 frame 块,用来放置这个包。
之后每次接收一个rtp包,根据时间戳在 incomplete_frames_ 和 decodable_frames_
中寻找,看是否已经接收到过相同时间戳的包,如果找到则弹出该 frame 块。
否则,从 free_frames_ 中弹出一个空 frame
2、根据包的序列号,找到应该插入 frame 的位置将包插入,并更新 frame 的 state (frame中存放多个rtp包)
其中 state 的状态为
enum VCMFrameBufferStateEnum {
kStateEmpty, // frame popped by the RTP receiver
kStateIncomplete, // frame that have one or more packet(s) stored
kStateComplete, // frame that have all packets
};
3、根据不同的 buffer_state 将 frame 帧 push 回到队列中。
如果 buffer_state 为 kCompleteSession 并且 frame 已经在 decodable list (continuous 为 true)
将 frame push 到 decodable_frames_ 队列 decodable_frames_.InsertFrame(frame);
如果 buffer_state 为 kCompleteSession 或 kIncomplete
将 frame push 到 incomplete_frames_ 队列 incomplete_frames_.InsertFrame(frame);
如果 buffer_state 为 kNoError 或 kOutOfBoundsPacket 或 kDuplicatePacket
将 frame push 到 frame_list 队列 frame_list->InsertFrame(frame);
VCMJitterBuffer::InsertPacket -> VCMJitterBuffer::FindAndInsertContinuousFramesWithState()
将 incomplete_frames_ 队列中的 frame push 到 decodable_frames_ 队列
&nb

本文深入探讨WebRTC中的Jitter Buffer机制,包括其在不稳定网络条件下如何通过调整缓冲区大小来平滑音视频流,抵抗网络抖动,以及详细的内部实现流程。


被折叠的 条评论
为什么被折叠?



