一、背景介绍
虽然我们可通过时间戳的差值和采样率计算出发送端视频帧的发送节奏,但是由于网络延迟、抖动、丢包,仅知道视频发送端的发送节奏是明显不够的。我们还需要评估出视频接收端的视频帧的接收节奏,然后进行适当平滑,保证渲染的效果。
WebRTC引入了卡尔曼滤波,通过视频时间戳和到达时间进行调整,提高后续视频帧到达时间估算的准确性和稳定性。TimestampExtrapolator就是实现视频帧的到达时间的估算。选择卡尔曼滤波算法进行调整的原因:
**噪声抑制:**在实际的网络环境中,由于网络波动、设备性能差异等因素,接收到的视频帧时间戳往往包含噪声。卡尔曼滤波通过其内置的预测和更新机制,能够有效地抑制这些噪声,提高时间戳估算的精度。
**动态适应:**卡尔曼滤波能够根据历史数据和当前观测值动态调整其内部参数,以适应不断变化的网络环境。这种动态适应性能够更准确地预测未来帧的到达时间。
**平滑处理:**卡尔曼滤波在预测过程中会考虑历史数据的平滑性,避免因为个别异常值而导致预测结果的大幅波动。这种平滑处理有助于保持视频流的连续性和稳定性。
二、实现细节
1、时间戳记录
cpp
VideoStreamBufferController::InsertFrame
->VCMTiming::IncomingTimestamp
->TimestampExtrapolator::Update(Timestamp now, uint32_t ts90khz)
now:接收时间
ts90khz:该帧视频时间戳
每当接收到一个新的视频帧时,TimestampExtrapolator会记录该视频帧的RTP时间戳和本地接收时间。同时还会记录第一个视频帧的时间戳和本地接收时间,作为参考点。
2、时间差计算
卡尔曼滤波实时更新的观察值有两个:t_ms、residual
t_ms:计算视频帧本地接收时间之差:frame_recv_delta = frame_recv - first_frame_rcv。
residual:视频帧 发送端 两帧发送间隔 - 视频帧 接收端 两帧接收间隔
3、卡尔曼滤波
根据t_ms、residual建立线性关系,实时动态调整w_[0]、w_[1]。
w_[0] :预估的接收视频采样率
w_[1]:预估接收视频首帧时间(缓存成时间戳单位)
4、预估接收时间
根据当前的卡尔曼滤波器的状态估计,TimestampExtrapolator可以根据输入视频时间戳,计算出未来视频帧的预期接收时间。这个预期接收时间会被用于视频渲染流程中,以确保视频帧在正确的时间点被渲染出来。
5、更新渲染时间
1、RTP报文->组视频帧 函数调用关系
RtpDemuxer::OnRtpPacket
->RtpVideoStreamReceiver2::OnRtpPacket
->RtpVideoStreamReceiver2::ReceivePacket
->RtpVideoStreamReceiver2::OnReceivedPayloadData
->RtpVideoStreamReceiver2::OnInsertedPacket
->RtpVideoStreamReceiver2::OnAssembledFrame
->RtpVideoStreamReceiver2::OnCompleteFrames
->VideoReceiveStream2::OnCompleteFrame
->VideoStreamBufferController::InsertFrame
->VideoStreamBufferController::MaybeScheduleFrameForRelease
decode_timing_.OnFrameBufferUpdated
->VideoStreamBufferController::FrameReadyForDecode
->VideoStreamBufferController::OnFrameReady
->VCMTiming::RenderTime
->VCMTiming::RenderTimeInternal ---计算视频渲染时间核心函数
根据frame_timestamp计算预估的接收时间,更新视频帧渲染时间