WebRTC QoS方法十三.2(Jitter延时的计算)
一、背景介绍
一些报文在网络传输中,会存在丢包重传和延时的情况。渲染时需要进行适当缓存,等待丢失被重传的报文或者正在路上传输的报文。
jitter延时计算是确认需要缓存的时间
另外,在检测到帧有重传情况时,也可适当在渲染时间内增加RTT延时时间,等待丢失重传的报文
二、jitter实现原理
JitterDelay由两部分延迟造成:传输大帧引起的延迟和网络噪声引起的延迟。计算公式如下:

其中:
estimate[0]:信道传输速率的倒数
MaxFrameSize:表示自会话开始以来所收到的最大帧size
AvgFrameSize:表示平均帧大小,排除keyframe等超大帧
kNoiseStdDevs: 表示噪声系数2.33
var_noise_ms2_: 表示噪声方差
kNoiseStdDevOffset: 表示噪声扣除常数30
实现函数:
JitterEstimator::CalculateEstimate

1、传输大帧引起的延迟
传输大帧引起的延迟
这个公式的原理是:[milliseconds] = [1 / bytes per millisecond] * [bytes]
实现函数:
double FrameDelayVariationKalmanFilter::GetFrameDelayVariationEstimateSizeBased(double frame_size_variation_bytes) const {// Unit: [1 / bytes per millisecond] * [bytes] = [milliseconds].return estimate_[0] * frame_size_variation_bytes;
}
filtered_max_frame_size_bytes
= std::max<double>(kPsi * max_frame_size_bytes_, frame_size.bytes());
constexpr double kPsi = 0.9999;
filtered_avg_frame_size_bytes
是每一帧的加权平均值,但是需要排除key frame这种超大帧

estimate_[0]参数计算:
使用一个简化卡尔曼滤波算法,在处理帧延迟变化(frame_delay_variation_ms)的估计,考虑了帧大小变化(frame_size_variation_bytes)和最大帧大小(max_frame_size_bytes)作为输入参数。
void FrameDelayVariationKalmanFilter::PredictAndUpdate(double frame_delay_variation_ms,double frame_size_variation_bytes,double max_frame_size_bytes,double var_noise) {// Sanity checks.if (max_frame_size_bytes < 1) {return;}if (var_noise <= 0.0) {return;}// This member function follows the data flow in// https://en.wikipedia.org/wiki/Kalman_filter#Details.// 1) Estimate prediction: `x = F*x`.// For this model, there is no need to explicitly predict the estimate, since// the state transition matrix is the identity.// 2) Estimate covariance prediction: `P = F*P*F' + Q`.// Again, since the state transition matrix is the identity, this update// is performed by simply adding the process noise covariance.estimate_cov_[0][0] += process_noise_cov_diag_[0];estimate_cov_[1][1] += process_noise_cov_diag_[1];// 3) Innovation: `y = z - H*x`.// This is the part of the measurement that cannot be explained by the current// estimate.double innovation =frame_delay_variation_ms -GetFrameDelayVariationEstimateTotal(frame_size_variation_bytes);// 4) Innovation variance: `s = H*P*H' + r`.double estim_cov_times_obs[2];estim_cov_times_obs[0] =estimate_cov_[0][0] * frame_size_variation_bytes + estimate_cov_[0][1];estim_cov_times_obs[1] =estimate_cov_[1][0] * frame_size_variation_bytes + estimate_cov_[1][1];double observation_noise_stddev =(300.0 * exp(-fabs(frame_size_variation_bytes) /(1e0 * max_frame_size_bytes)) +1) *sqrt(var_noise);if (observation_noise_stddev < 1.0) {observation_noise_stddev = 1.0;}// TODO(brandtr): Shouldn't we add observation_noise_stddev^2 here? Otherwise,// the dimensional analysis fails.double innovation_var = frame_size_variation_bytes * estim_cov_times_obs[0] +estim_cov_times_obs[1] + observation_noise_stddev;if ((innovation_var < 1e-9 && innovation_var >= 0) ||(innovation_var > -1e-9 && innovation_var <= 0)) {RTC_DCHECK_NOTREACHED();return;}// 5) Optimal Kalman gain: `K = P*H'/s`.// How much to trust the model vs. how much to trust the measurement.double kalman_gain[2];kalman_gain[0] = estim_cov_times_obs[0] / innovation_var;kalman_gain[1] = estim_cov_times_obs[1] / innovation_var;// 6) Estimate update: `x = x + K*y`.// Optimally weight the new information in the innovation and add it to the// old estimate.estimate_[0] += kalman_gain[0] * innovation;estimate_[1] += kalman_gain[1] * innovation;// (This clamping is not part of the linear Kalman filter.)if (estimate_[0] < kMaxBandwidth) {estimate_[0] = kMaxBandwidth;}// 7) Estimate covariance update: `P = (I - K*H)*P`double t00 = estimate_cov_[0][0];double t01 = estimate_cov_[0][1];estimate_cov_[0][0] =(1 - kalman_gain[0] * frame_size_variation_bytes) * t00 -kalman_gain[0] * estimate_cov_[1][0];estimate_cov_[0][1] =(1 - kalman_gain[0] * frame_size_variation_bytes) * t01 -kalman_gain[0] * estimate_cov_[1][1];estimate_cov_[1][0] = estimate_cov_[1][0] * (1 - kalman_gain[1]) -kalman_gain[1] * frame_size_variation_bytes * t00;estimate_cov_[1][1] = estimate_cov_[1][1] * (1 - kalman_gain[1]) -kalman_gain[1] * frame_size_variation_bytes * t01;// Covariance matrix, must be positive semi-definite.RTC_DCHECK(estimate_cov_[0][0] + estimate_cov_[1][1] >= 0 &&estimate_cov_[0][0] * estimate_cov_[1][1] -estimate_cov_[0][1] * estimate_cov_[1][0] >=0 &&estimate_cov_[0][0] >= 0);
}
2、网络噪声引起的延迟
网络噪声引起的延迟

constexpr double kNoiseStdDevs = 2.33; //噪声系数
constexpr double kNoiseStdDevOffset = 30.0;//噪声扣除常数
var_noise_ms2_ //噪声方差
实现函数:

噪声方差var_noise_ms2计算
var_noise_ms2 = alpha * var_noise_ms2_ +
(1 - alpha) *(d_dT - avg_noise_ms_) *(d_dT - avg_noise_ms_);
实现函数:JitterEstimator::EstimateRandomJitter

其中:
d_dT = 实际FrameDelay - 评估FrameDelay
在JitterEstimator::UpdateEstimate函数实现

实际FrameDelay = (两帧之间实际接收gap - 两帧之间实际发送gap)
在InterFrameDelayVariationCalculator::Calculate函数实现
absl::optional<TimeDelta> InterFrameDelayVariationCalculator::Calculate(uint32_t rtp_timestamp,Timestamp now) {int64_t rtp_timestamp_unwrapped = unwrapper_.Unwrap(rtp_timestamp);if (!prev_wall_clock_) {prev_wall_clock_ = now;prev_rtp_timestamp_unwrapped_ = rtp_timestamp_unwrapped;// Inter-frame delay variation is undefined for a single frame.// TODO(brandtr): Should this return absl::nullopt instead?return TimeDelta::Zero();}// Account for reordering in jitter variance estimate in the future?// Note that this also captures incomplete frames which are grabbed for// decoding after a later frame has been complete, i.e. real packet losses.uint32_t cropped_prev = static_cast<uint32_t>(prev_rtp_timestamp_unwrapped_);if (rtp_timestamp_unwrapped < prev_rtp_timestamp_unwrapped_ ||!IsNewerTimestamp(rtp_timestamp, cropped_prev)) {return absl::nullopt;}// Compute the compensated timestamp difference.TimeDelta delta_wall = now - *prev_wall_clock_;int64_t d_rtp_ticks = rtp_timestamp_unwrapped - prev_rtp_timestamp_unwrapped_;TimeDelta delta_rtp = d_rtp_ticks / k90kHz;// The inter-frame delay variation is the second order difference between the// RTP and wall clocks of the two frames, or in other words, the first order// difference between `delta_rtp` and `delta_wall`.TimeDelta inter_frame_delay_variation = delta_wall - delta_rtp;prev_wall_clock_ = now;prev_rtp_timestamp_unwrapped_ = rtp_timestamp_unwrapped;return inter_frame_delay_variation;
}
评估FrameDelay = estimate[0] * (FrameSize – PreFrameSize) + estimate[1]
评估FrameDelay实现函数:
double FrameDelayVariationKalmanFilter::GetFrameDelayVariationEstimateTotal(double frame_size_variation_bytes) const {double frame_transmission_delay_ms =GetFrameDelayVariationEstimateSizeBased(frame_size_variation_bytes);double link_queuing_delay_ms = estimate_[1];return frame_transmission_delay_ms + link_queuing_delay_ms;
}
3、jitter延时更新流程

三、RTT延时计算
VideoStreamBufferController::OnFrameReady函数,在判断帧有重传情况时,还会根据实际情况,在渲染帧时间里面增加RTT值。
![]()
JitterEstimator::GetJitterEstimate根据实际配置,可以在渲染时间中适当增加一定比例的RTT延时值。
四、参考
WebRTC视频接收缓冲区基于KalmanFilter的延迟模型 - 简书在WebRTC的视频处理流水线中,接收端缓冲区JitterBuffer是关键的组成部分:它负责RTP数据包乱序重排和组帧,RTP丢包重传,请求重传关键帧,估算缓冲区延迟等功能...
https://www.jianshu.com/p/bb34995c549a
相关文章:
WebRTC QoS方法十三.2(Jitter延时的计算)
一、背景介绍 一些报文在网络传输中,会存在丢包重传和延时的情况。渲染时需要进行适当缓存,等待丢失被重传的报文或者正在路上传输的报文。 jitter延时计算是确认需要缓存的时间 另外,在检测到帧有重传情况时,也可适当在渲染时…...
PHP进阶:前后端交互、cookie验证、sql与php
单词:construct 构造 destruct 摧毁 empty 空的 trim 修剪 strip 清除 slash 斜线 special 特殊 char 字符 query 询问 构造方法(魔术方法) 构造方法是一种特殊的函数࿰…...
优思学院|ANOVA方差分析是什么?如何用EXCEL进行计算?
在数据分析、六西格玛管理领域中,ANOVA(方差分析)是一种基本的统计工具,广泛用于确定三组或三组以上的独立群体之间的平均值是否存在统计学上的显着差异。ANOVA的主要目的在于评估一个或多个因素的影响,通过比较不同样…...
Mindspore框架循环神经网络RNN模型实现情感分类|(三)RNN模型构建
Mindspore框架循环神经网络RNN模型实现情感分类 Mindspore框架循环神经网络RNN模型实现情感分类|(一)IMDB影评数据集准备 Mindspore框架循环神经网络RNN模型实现情感分类|(二)预训练词向量 Mindspore框架循环神经网络RNN模型实现…...
深度解读大语言模型中的Transformer架构
一、Transformer的诞生背景 传统的循环神经网络(RNN)和长短期记忆网络(LSTM)在处理自然语言时存在诸多局限性。RNN 由于其递归的结构,在处理长序列时容易出现梯度消失和梯度爆炸的问题。这导致模型难以捕捉长距离的依…...
安装好anaconda,打开jupyter notebook,新建 报500错
解决办法: 打开anaconda prompt 输入 jupyter --version 重新进入jupyter notebook: 可以成功进入进行代码编辑...
C++20之设计模式:状态模式
状态模式 状态模式状态驱动的状态机手工状态机Boost.MSM 中的状态机总结 状态模式 我必须承认:我的行为是由我的状态支配的。如果我没有足够的睡眠,我会有点累。如果我喝了酒,我就不会开车了。所有这些都是状态(states),它们支配着我的行为:…...
数据库安全综合治理方案(可编辑54页PPT)
引言:数据库安全综合治理方案是一个系统性的工作,需要从多个方面入手,综合运用各种技术和管理手段,确保数据库系统的安全稳定运行。 方案介绍: 数据库安全综合治理方案是一个综合性的策略,旨在确保数据库系…...
人工智能:大语言模型提示注入攻击安全风险分析报告下载
大语言模型提示注入攻击安全风险分析报告下载 今天分享的是人工智能AI研究报告:《大语言模型提示注入攻击安全风险分析报告》。(报告出品方:大数据协同安全技术国家工程研究中心安全大脑国家新一代人工智能开放创新平台) 研究报告…...
【购买源码时有许多需要注意的坑】
购买源码时有许多需要注意的“坑”,这些坑可能会对项目的后续开发和使用造成严重影响。以下是一些需要特别注意的方面: 源码的完整性 编译测试:确保到手的源码能够从头至尾编译、打包、部署和功能测试无误。这一步非常关键,因为只…...
CAS的三大问题和解决方案
一、ABA问题的解决方案 变量第一次读取的值是1,后来其他线程改成了3,然后又被其他线程修改成了1,原来期望的值是第一个1才会设置新值,第二个1跟期望不符合,但是,可以设置新值。 解决方案: &a…...
EDA和统计分析有什么区别
EDA(Electronic Design Automation)和统计分析在多个方面存在显著的区别,这些区别主要体现在它们的应用领域、目的、方法以及所使用的工具上。 EDA(电子设计自动化) 定义与目的: EDA是电子设计自动化&…...
CentOS 7 修改DNS
1、nmcli connection show 命令找到设备名称 # nmcli connection show NAME UUID TYPE DEVICE enp4s0 99559edf-4e0a-4bae-a528-6d75065261e9 ethernet enp4s0 2、nmcli connection modify 命令修改dns nmcli connection modif…...
PHP基础语法-Part2
if-else语句、switch语句 与其他语言相同 循环结构 for循环while循环do-while循环foreach循环,搭配数组使用 foreach ($age as $avlue) //只输出值 {xxx; } foreach ($age as $key > $avlue) //键和值都输出 {xxx; }foreach ($age as $key >…...
数据结构门槛-顺序表
顺序表 1. 线性表2. 顺序表2.1 静态顺序表2.2 动态顺序表2.2.1 动态数据表初始化和销毁2.2.2 动态数据表的尾插尾删2.2.3 动态数据表的头插头删2.2.4 动态数据表的中间部分插入删除2.2.5 动态数据表的查询数据位置 3. 总结 1. 线性表 线性表(linear list࿰…...
软件测试面试准备工作
1、 什么是数据库? 答:数据库是按照某种数据模型组织起来的并存放二级存储器中的数据集合。 2、 什么是关系型数据库? 答:关系型数据库是建立在关系数据库模型基础上的数据库, 借助集合代数等概念和方法处理数据库中的数据。目前主流的关…...
Java面试八股之后Spring、spring mvc和spring boot的区别
Spring、spring mvc和spring boot的区别 Spring, Spring Boot和Spring MVC都是Spring框架家族的一部分,它们各自有其特定的用途和优势。下面是它们之间的主要区别: Spring: Spring 是一个开源的轻量级Java开发框架,最初由Rod Johnson创建&…...
linux对齐TOF和RGB摄像头画面
问题:TOF和RGB画面不对齐 linux同时接入TOF和RGB,两者出图时间是由驱动层控制(RGB硬件触发出图),应用层只负责读取数据。 现在两者画面不对齐,发现是开始的时候两者出图数量不一致导致的。底层解决不了&a…...
配置linux客户端免密登录服务端linux主机的root用户
1、客户端与服务端的ip 客户端IP地址服务端IP地址 2、定位客户端,由客户端制作公私钥对 [rootclient ~]# ssh-keygen -t rsa (RSA是非对称加密算法) # 一路回车 3、定位客户端,将公钥上传到服务器端root账户 [rootc…...
SpringMVC实现文件上传
导入文件上传相关依赖 <!--文件上传--> <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version> </dependency> <dependency><groupId>…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

