JCHub

  • Home
  • Category
    • A/V
    • WebRTC
    • Beauty of Programming
    • Linux
    • Windows
    • Moments of Life
    • Campus Life
  • Reference
    • API Reference
    • Utilities
    • AV Test
    • Doc
  • Message Board
  • About
WebRTC
WebRTC

WebRTC研究:Trendline滤波器-TrendlineEstimator

前面文章WebRTC研究:包组时间差计算-InterArrival讲到了相关包组时间差计算,输出包组发送时间差,到达时间差等参数。本篇文章主要介绍下这些参数在判断网络拥塞情况方面的应用。 到达时间模型 在WebRTC研究:包组时间差计算-InterArrival说到了到达时间模型,主要包含几个包组时间差计算的概念: 到达时间差:\(t_{i} - t_{i-1}\) 发送时间差:\(T_{i} - T_{i-1}\) 时延变化:\(d_{i} = t_{i} - t_{i-1} - (T_{i} - T_{i-1})\) 这个时延变化用于评估时延增长趋势,判断网络拥塞状况。在[1]中,这个时延变化叫做单向时延梯度(one way delay gradient)。那这个时延梯度为什么可以判断网络拥塞情况呢? 时延梯度计算 首先我们通过一张图看下时延梯度的计算: 对于两个包组:\(i\)以及\(i-1\),它们的时延梯度: 判断依据 网络无拥塞的正常情况下: 网络拥塞情况下: 第一张图是没有任何拥塞下的网络传输,时延梯度 第二张图是存在拥塞时的网络传输,包在\(t_{1}\)时刻到达,因为网络发生拥塞,导致到达时间比原本要晚,原本应在虚线箭头处时刻到达,时延梯度 由上可知,正常无拥塞情况下,包组间时延梯度等于0,拥塞时大于0,我们可以通过数学方法估计这个时延梯度的变化情况评估当前网络的拥塞情况,这个就是WebRTC基于时延的带宽估计的理论基础。 线性回归 WebRTC用到了线性回归这个数学方法进行时延梯度趋势预测。通过最小二乘法求得拟合直线斜率,根据斜率判断增长趋势。 对于一堆样本点\((x,y)\),拟合直线方程\(y=bx+a\)的斜率\(b\)按如下公式计算: 网络状态 在WebRTC中,定义了三种网络状态:normal,overuse,underuse,用于表示当前带宽的使用情况,具体含义跟单词本身含义一样。 例如如果是overuse状态,表示带宽使用过载了,从而判断网络发生拥塞,如果是underuse状态,表示当前带宽未充分利用。后面会介绍如何根据时延梯度增长趋势得到当前的网络状态。 代码导读 由TrendlineEstimator类实现。主要接口就一个:UpdateTrendline。传入包组时间差,时间,包大小等参数,判断当前网络状态。 [crayon-69bce4def0456604201117/] 说下输入的各个参数的含义: recv_delta_ms:包组接收时间差 send_delta_ms:包组发送时间差 send_time_ms:当前处理的RTP的包发送时间 arrival_time_ms:当前处理的RTP的包到达时间 packet_size:当前处理的RTP包的大小 内部相关函数调用如下: [crayon-69bce4def045c678132564/] 下面结合代码说下UpdateTrendline函数内部计算过程。 1)计算时延变化累积值: [crayon-69bce4def045d667284166/] 2)根据1)中的时延累积值计算得到平滑后的时延: [crayon-69bce4def045e867473225/] 3)将从第一个包到达至当前RTP包到达的经历时间,平滑时延值存到双端队列delay_hist_中: [crayon-69bce4def045f715633250/] 4)当队列delay_hist_大小等于设定的窗口大小时,开始进行时延变化趋势计算,得到直线斜率,直线横坐标为经历时间,纵坐标为平滑时延值: [crayon-69bce4def0460034115486/] 5)通过计算得到的时延变化趋势拟合直线斜率,发送时间差,到达时间判断网络状态: [crayon-69bce4def0461719712204/] LinearFitSlope函数 使用最小二乘法求解线性回归,得到时延变化增长趋势的拟合直线斜率。 看下内部代码实现: [crayon-69bce4def0462834689834/] Detect函数 该函数主要根据时延变化增长趋势计算当前网络状态,在WebRTC旧版GCC算法,接收端基于时延的带宽预测代码中,这部分属于过载检测器的内容,跟在卡尔曼滤波后面,我们不做讨论,我们讨论的全部是最新代码,全部在发送端进行带宽预测。 在Detect函数内部,会根据前面计算得到的斜率得到一个调整后的斜率值:modified_trend: [crayon-69bce4def0463258261890/] 然后与一个动态阈值threshold_做对比,从而得到网络状态 modified_trend > threshold_,且持续一段时间,同时这段时间内,modified_trend没有变小趋势,认为处于overuse状态 modified_trend < -threshold_,认为处于underuse状态 -threshold_ <= modified_trend <= threshold_,认为处于normal状态 如下图所示,上下两条红色曲线表示动态阈值,蓝色曲线表示调整后的斜率值,阈值随时间动态变化,调整后的斜率值也动态变化,这样网络状态也动态变化。 本图截取自文末参考[1],倒数第三个状态应为normal,不是overuse 相关实现代码如下: [crayon-69bce4def0465906954798/] 这个阈值threshold_是动态调整的,代码实现在UpdateThreshold函数中。 UpdateThreshold函数 阈值threshold_动态调整为了改变算法对时延梯度的敏感度。根据[1]主要有以下两方面原因: 1)时延梯度是变化的,有时很大,有时很小,如果阈值是固定的,对于时延梯度来说可能太大或者太小,这样就会出现检测不够敏感,无法检测到网络拥塞,或者过于敏感,导致一直检测为网络拥塞; 2)固定的阈值会导致与TCP(采用基于丢包的拥塞控制)的竞争中被饿死。 这个阈值根据如下公式计算: 每处理一个新包组信息,就会更新一次阈值,其中\(\Delta T\)表示距离上次阈值更新经历的时间,\(m(t_{i})\)是前面说到的调整后的斜率值modified_trend。 \(k_{\gamma }(t_{i})\)按如下定义: \(k_{d}\)与\(k_{u}\)分别决定阈值增加以及减小的速度。 具体实现代码如下: [crayon-69bce4def0466963815509/] 总结 本文主要介绍了如何根据时延梯度得到网络状态,判断网络拥塞状况,并结合WebRTC相关源码进行分析。当我们得到当前网络拥塞状况后,就要对发送码率进行调节,以适应当前网络。后续文章我们将研究如何根据网络状态进行相应码率调整。 参考 [1] Analysis and Design of the Google Congestion Control for Web Real-time Communication (WebRTC).http://dl.acm.org/ft_gateway.cfm?id=2910605&ftid=1722453&dwn=1&CFID=649873557&CFTOKEN=47458294. [2] A Google Congestion Control Algorithm for Real-Time Communication draft-ietf-rmcat-gcc-02.https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02.

2019年11月29日 22comments 10997hotness 11likes Jeff Read all
WebRTC

WebRTC研究:包组时间差计算-InterArrival

在新版GCC(Google Congestion Control)也就是Sendside BWE中,包含两种拥塞控制模型。一种是基于丢包的,一种是基于时延的,全部在发送端计算。Sendside BWE最后综合这两种估计值取小的那个作为目标码率。 基于时延的拥塞控制算法主要由四部分组成:预处理(pre-filtering), 到达时间滤波器(arrival-time filter), 过载检测器(over-use detector),码率控制器(and a rate controller)。本文主要介绍其中的到达时间滤波器。 到达时间模型 在参考[1]中定义了一种到达时间模型(Arrival-time model),在这里我们先介绍几个概念。 两个包组(包组概念下一小节介绍,包组属于预处理部分的内容)的到达时间差:inter-arrival时间: [crayon-69bce4def2d29481219377/] 两个包组离开(发送)时间差:inter-departure时间: [crayon-69bce4def2d2e394495720/] 包组i与包组i-1的时延变化: [crayon-69bce4def2d30455689513/] 这个时延变化将在后续评估网络时延增长趋势的滤波器中用到,用于判断网络拥塞状况,这里就先不展开讨论,本文主要介绍这些时间差如何计算。 包组 在WebRTC中计算时延不是一个个包计算的,而是通过将包分组,然后计算这些包组间的时延,这样做目的主要是为了提高带宽估计准确性,避免无线网络环境下突发数据的影响,具体影响后面写篇专门文章分析。WebRTC中这些包组称作TimestampGroup。这里我们看下WebRTC中TimestampGroup的结构: [crayon-69bce4def2d31375700986/] 那么如何对包进行分组呢? WebRTC是通过计算发送时间差值来分组。在包组中,除了第一个包外,后面的包距离包组第一个包的发送时间差小于5ms。假设每个包都有一个发送时间t,第一个包的发送时间为t0,如果后续的包发送时间与t0时间差△t = t - to <= 5ms,那么这些包都可以与t0发送时间的包归为一组,如果某个包得到的△t > 5ms,那么该包就作为下一个包组的第一个包,接着后面的包就跟该包继续比较时间差,判断能否归为一组。下面我们举个例子说明下。 上图中有两个包组TG1和TG2,其中序列号为1的包与4的时间差小于5毫秒,那么序列号1~4的包被划到一个包组TG1。序列号为5的包与1之间的时间间隔超过5毫秒,那么5就是TG2的第一个包,它与序列号6、7、8划到一个包组TG2。 在后续评估时延增长趋势的滤波器需要三个主要参数:发送时刻差值(timestamp_delta)、到达时刻差值(arrival_time_delta)和包组数据大小差值(packet_size_delta)。由上图可知: [crayon-69bce4def2d32635939265/] 代码导读 ComputeDeltas函数 前面说到的时间差值计算以及包组判断代码主要由InterArrival类实现。InterArrival类主要就一个接口:ComputeDeltas。传入每个RTP包时间、大小等参数,计算包组时间间隔,包组大小差值,得到新的包组相关差值后返回true。 [crayon-69bce4def2d33024011953/] 下面解释下各个参数: timestamp:RTP包发送时间 arrival_time_ms:RTP包到达时间 system_time_ms:当前时间 timestamp_delta(output):包组发送时间差 arrival_time_delta_ms(output): 包组到达时间差 packet_size_delta(output) :包组大小差值 接下来看下相关代码流程,看timestamp_delta、arrival_time_delta_ms如何计算: [crayon-69bce4def2d35054101098/] packet_size_delta计算如下: [crayon-69bce4def2d36353604517/] NewTimestampGroup函数 WebRTC新包组判断代码: [crayon-69bce4def2d38105153109/] 若是第一个包,得作为后续包对比基准,不认为是新包组 若是突发数据(burst),不认为是新包组 与第一个包发送时间间隔大于kMaxBurstDurationMs(值为5),认为该包属于新包组 BelongsToBurst函数 这里我们也介绍下上一小节说到的突发数据。有些客户端发送数据时,没用使用pacing平滑发送模块,没有控制发送速率,这样容易导致突发流量,尤其是发送关键帧数据时,或者在无线网络环境下,也容易出现突发流量。我们看下WebRTC中如何判断突发数据的。 [crayon-69bce4def2d39536307586/] 总结 本篇文章主要讲了到达时间模型以及在WebRTC中的源码实现:InterArrival。后面文章我们将研究下trendline滤波器。前面计算得到的相关差值我们将传递给trendline滤波器,进行网络拥塞情况判断。 WebRTC研究:Trendline滤波器-TrendlineEstimator 参考 [1] A Google Congestion Control Algorithm for Real-Time Communication.https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02.

2019年11月12日 21comments 11675hotness 6likes Jeff Read all
WebRTC

WebRTC研究:应用受限区域探测器-AlrDetector

在WebRTC GCC(Google Congestion Control)中,有一个叫做AlrDetector(应用受限区域探测器,Application limited region detector)的模块。该模块利用某段时间值,以及这段时间发送的字节数判断当前输出网络流量是否受限。这些限制主要跟应用程序本身输出网络流量的能力有关,例如编码器性能,不能编码出设置的目标码率。下面举个简单例子说明下。 假设我们经过带宽预测后,获取到一个目标码流target_bitrate_bps,此时我们程序需要按照该码率大小进行数据发送,但是一切都不是那么完美,例如编码器。编码器由于各种问题,编码出的数据码率低于target_bitrate_bps,使得数据发送码率低于要求,带宽利用率不足,发送码率占最大预算码率值比例低于某个值的话Alr(Application limited region)就会被触发了,恢复到某个值以上,Alr会停止。 下面说下AlrDetector的工作流程。 1)首先是在构造函数初始化相关参数配置,相关参数如下: [crayon-69bce4df003e4054519450/] IntervalBudget::can_build_up_underuse_初始化为true。IntervalBudget根据输入的评估码率,计算当前还能发送多少数据。 2)设置带宽预测得到的码率: [crayon-69bce4df003e9337984675/] 3)发送数据时调用: [crayon-69bce4df003eb415885869/] 通过IntervalBudget::budget_ratio与start_budget_level_ratio以及stop_budget_level_ratio对比,设置AlrDetector的状态。 [crayon-69bce4df003ec679663734/] IntervalBudget::budget_ratio表示剩余要发送的数据占最大预算发送数据max_bytes_in_budget_的比例,定义如下: [crayon-69bce4df003ed173809025/] max_bytes_in_budget_按500ms时间窗口计算得到: [crayon-69bce4df003ee036053010/] 可知如果IntervalBudget::budget_ratio大于start_budget_level_ratio,即剩余数据还有很多,发送码率低了,带宽没充分利用,Alr触发了,小于stop_budget_level_ratio时,alr_started_time_ms_重置,Alr停止。 4)通过获取AlrDetector::alr_started_time_ms_判断当前Alr是否触发,调用函数如下: [crayon-69bce4df003ef199022088/]

2019年11月4日 8comments 5503hotness 4likes Jeff Read all
WebRTC

WebRTC研究:MediaStream概念以及定义

根据W3C的WebRTC 1.0: Real-time Communication Between Browsers规范,WebRTC的源码中定义了两套主要的C++接口,分别是MediaStream与PeerConnection相关的API。本篇文章主要介绍下MediaStream API中一些概念,方便理解内部代码如何处理。 MediaStream 相关API定义在源码api\media_stream_interface.h中。里面主要涉及这4个概念:source,sink,mediatrack,mediastream。 source与sink 在浏览器中,存在source到sink的媒体管道,source是生产媒体资源的,sink负责消费。传统的source一般是些静态资源,例如文件,以及web资源,不随时间改变。对于我们的WebRTC来说,source是动态资源,例如麦克风采集的音频,相机采集的视频,随时间而改变。sink的工作就是将这些source呈现给用户。sink可以是<img>,<video>,<audio>这些标签,用于本地渲染,也可以是RTCPeerConnection,将source通过网络传递到远端。在网络流传输中,RTCPeerConnection可同时扮演source与sink的角色,作为sink,可以将获取的source降低码率,缩放,调整帧率等,然后传递到远端,作为source,将获取的远端码流传递到本地渲染。 下面我们以video source举例,说下WebRTC源码中,source与sink定义。 在api\video\video_source_interface.h中,video source定义如下: [crayon-69bce4df01988348169039/] source可以添加、移除、更新sink,从而将VideoFrame送给对应的sink处理,一个source可对应多个sink。 在video\video_sink_interface.h中,video sink定义如下: [crayon-69bce4df0198e245037468/] sink通过OnFrame获取source传递的VideoFrame。 MediaStreamTrack与MediaStream MediaStream API中有两个重要组成:MediaStreamTrack以及MediaStream。MediaStreamTrack对象代表单一类型的媒体流,产生自客户端的media source,可以是音频或者视频,但只能是其中一种,是音频称作audio track,视频的话称作video track,这其实就是我们平时所说的音轨与视频轨。 一个track由source与sink组成。source给track提供数据。 Medi aStream用于将多个MediaStreamTrack对象打包到一起。一个MediaStream可包含audio track 与video track。类似我们平时的多媒体文件,可包含音频与视频。 一个MediaStream对象包含0或多个MediaStreamTrack对象。MediaStream中的所有MediaStreamTrack对象在渲染时必须同步。就像我们平时播放媒体文件时,音视频的同步。 简单点说,source 与sink构成一个track,多个track构成MediaStram。 在api\media_stream_interface.h中,MediaStream定义如下: [crayon-69bce4df0198f770804479/] MediaStream可以添加移除audio track以及video track。 下面说下MediaTrack的定义,这里我们举例VideoTrack,代码同样位于api\media_stream_interface.h中。 [crayon-69bce4df01991670481147/] 可以看到VideoTrack由video source与video sink组成。 pc\video_track.cc中,我们看下MediaTrack接口的一些具体实现: [crayon-69bce4df01992832668340/] 由于VideoTrack由video source与video sink组成,所以对VideoTrack进行AddOrUpdateSink操作时,其实就是让VideoTrack的source进行AddOrUpdateSink。 示例 为了更好地理解上述概念,我们举个例子说明。下图home client中,摄像机产生视频video source。source的宽高设置分别是800以及600像素。home client 中三个MediaStream包含的track使用该摄像机视频作为source,此时就有三个video track了。三个video track分别连接三个不同的sink:<video>标签A,<video>标签B以及一个peer connection C。<video>A与<video>B分别对source的视频进行缩放处理后渲染到本地浏览器界面中。peer connection C作为sink把该video source 推流到remote client。在remote client,两个media stream使用peer connection作为source,连接到两个<video>sink(Y与Z),进行本地渲染。 参考 [1] Media Capture and Streams.https://www.w3.org/TR/mediacapture-streams/. [2] WebRTC 1.0: Real-time Communication Between Browsers.http://w3c.github.io/webrtc-pc/.

2019年10月22日 1comments 3143hotness 13likes Jeff Read all
WebRTC

WebRTC研究:丢包判断

使用RTP协议封装数据时,我们可以通过RTP报头的序列号连续性判断是否丢包。但由于RTP报头序列号只有两字节表示,值范围[0,65535],存在回绕问题(参考之前文章:WebRTC研究:RTP中的序列号以及时间戳比较,建议先阅读一遍此文章)。所以判断序列号连续性时得考虑回绕问题。下面我们就结合WebRTC这相关源码,讲下如何有效地根据序列号进行丢包判断。 首先看下这块代码,代码位于jitter_buffer.cc中: [crayon-69bce4df02ddc175160707/] IsNewerSequenceNumber函数以及latest_received_sequence_number_介绍在之前文章说过,读者可参考前面给的文字链接。上述代码丢包判断用到的相关定义如下: IsNewerSequenceNumber:判断是否是最新的序列号 sequence_number:当前收到的包序列号 latest_received_sequence_number_:上一次收到的最新RTP包序列号 missing_sequence_numbers_:存储丢包序列号 丢包判断流程如下: 首先IsNewerSequenceNumber传入当前收到的包序列号sequence_number以及之前收到的最新RTP包序列号latest_received_sequence_number_,判断当前RTP包是否是新的数据包,而不是重传包或者乱序包 在for循环中,从latest_received_sequence_number_ + 1开始判断(因为如果丢包了,两个包序列号间隔大于1),满足IsNewerSequenceNumber(sequence_number, i)则说明i为丢失的RTP包序列号,插入missing_sequence_numbers_中,接着++i继续判断,否则退出 通过如上方法,我们就可以获取那些丢失的包序列号,是不是很简单。

2019年9月2日 3comments 3122hotness 11likes Jeff Read all
WebRTC

WebRTC研究:RTP中的序列号以及时间戳比较

在使用RTP协议时,如果需要网络对抗,保障QoS(Quality of Service,服务质量),我们需要通过序列号以及时间戳的比较,进行丢包判断。但是有个问题,比如一个RTP包,序列号为number1:5000,另一个RTP包序列号为number2:60000,可以说60000一定比5000大,是个更新的RTP包吗? 当然不是了,首先我们先重温下RTP数据包的结构。 在RFC3550中RTP固定报头结构按如下定义: [crayon-69bce4df0426c145913511/] 可以看到,RTP序列号sequence number用两字节表示,时间戳timestamp用四字节表示。所以序列号以及时间戳就存在一个取值范围。由于是无符号数,所以序列号范围为:[0,2^16-1],时间戳范围为:[0,2^32-1]。当达到最大值时,将发生所谓的回绕。例如,序列号到了2^16-1,下个包序列号就将是0。所以我们不能直接根据数学意义上的大小进行序列号以及时间戳的比较。 在WebRTC中定义了一个大小比较算法,包含数字回绕处理,判断是否是更新的数字。下面说下算法原理: 1)假设有两个U类型的无符号整数:value, prev_value; 2)定义一个常量kBreakpoint,为U类型取值范围的一半; 3)value > prev_value,满足value - prev_value = kBreakpoint时,value大于prev_value; 4)value与prev_value不相等,满足(U)(valude - prev_value) < kBreakpoint时,value大于prev_value。 总结起来就是value与prev_value距离小于取值范围的一半且不相等或者value与prev_value距离等于取值范围的一半,value大于prev_value,就可以说明value大于prev_value。 在modules\include\module_common_types_public.h,相应代码如下: [crayon-69bce4df04271807001025/] 顺便也说下如上函数的一个应用。在WebRTC丢包重传判断中(jitter_buffer模块),需要保存上一次收到的最新RTP序列号latest_received_sequence_number_,以便用于丢包判断(请参考:WebRTC研究:丢包判断),这个RTP包必须是新的数据,不能是重传的旧数据。所以每来一个RTP包时,可以将该RTP包序列号传入如上函数,与之前收到的最新RTP序列号进行对比,从而判断当前RTP包是不是最新的。相应代码如下: [crayon-69bce4df04274724982419/] 参考 [1].rfc1982.https://tools.ietf.org/html/rfc1982

2019年7月6日 5comments 4587hotness 12likes Jeff Read all
WebRTC

WebRTC研究:关键帧请求

WebRTC采用UDP传输流媒体数据,不可避免存在丢包情况。WebRTC主要采用FEC(Forward Error Correction,前向纠错)以及NACK(negative-acknowledge character,否定应答)对抗网络丢包。对于NACK,遇到丢包了才通知发送端重传对应数据包,但不是所有情况下某个包丢了就一定重传该包,有些场景下,重传该包会带来其它问题,例如增大延时,缓存过大,同时也可能发送端没有该数据包缓存,导致无法重传,此时会放弃重传该包。由于关键帧可以单独解码出图像,不参考前后视频帧,所以会采取请求关键帧这种更便捷的方式替代重传该数据包,使解码端能立刻刷新出新图像,避免丢包过多,长时间等待重传数据包导致的画面停顿问题,以及获取不到重传包导致后续数据解码花屏问题。除了丢包,在WebRTC还存在其他请求关键帧的场景。 关键帧请求场景 下面结合代码列举几种常见场景。 H264解码无sps,pps信息 解码H264时无法获取sps,pps,导致无法解码,此时就需要请求获取关键帧,在H264SpsPpsTracker中,相关处理代码如下: [crayon-69bce4df05769556526608/] 丢失包过多 在非常高的丢包率情况下,丢失的包太多,若都一一重传,将造成延时增大(等帧数据完整了才会去解码渲染),此时新来的数据也只能一直缓存,所以jitterbuffer大小也会不断增大,此时不如直接请求发送一个关键帧来得实际,以前丢的那些包都不管了,由于关键帧可以单独解码,所以不会造成解码端花屏马赛克现象。但是由于前面那些视频帧都丢弃了,此时生成的关键帧会与之前播放的视频存在不连贯性,所以画面变化大时会有轻微卡顿现象,相当于跳帧了。NackModule中相关处理代码如下: [crayon-69bce4df0576e385210892/] 上面代码中,要重传的包数量nack_list_.size()在进行RemovePacketsUntilKeyFrame()操作后若还超过规定大小,就开始清空要重传的数据包列表:nack_list_.clear(),然后请求关键帧。 丢失包过旧 发送端默认缓存600个RTP包,如果丢失的包太旧,超出缓存范围,此时发送端就没有该数据包的缓存,就无法重传该包。在VCMJitterBuffer中,相关处理代码如下: [crayon-69bce4df0576f249680367/] 获取帧数据超时 要解码的帧数据存放在FrameBuffer中,解码器解码时如果超过规定时间一直无法从FrameBuffer中获取解码数据,此时就会请求关键帧。相关处理代码如下: [crayon-69bce4df05771226320679/] 解码出错 当解码器返回解码失败,或者解码器返回请求关键帧结果时,需要请求关键帧。相关处理代码如下: [crayon-69bce4df05772987543683/] 在上面我们列举了几种需要关键帧请求的情况,我们只需要规定好RTCP报文格式,就能通知编码发送端发送关键帧。关键帧请求RTCP报文格式比较简单,在RFC4585(RTP/AVPF)以及RFC5104(AVPF)规定了两种不同的关键帧请求报文格式:Picture Loss Indication (PLI)、Full Intra Request (FIR)。WebRTC中关键帧请求也只用到了这两种消息,相关代码如下: [crayon-69bce4df05773040127737/] Picture Loss Indication (PLI) 在RFC4585中定义,属于RTCP反馈消息中的一种。RTCP反馈消息数据包格式按如下规定: [crayon-69bce4df05774576923032/] 其中PT字段按如下规定: [crayon-69bce4df05777214278688/] 对于PLI,由于只需要通知发送关键帧,无需携带其他消息,所以FCI部分为空。对于FMT规定为1,PT规定为PSFB。 在WebRTC源码中,PLI相关解析封装代码位于webrtc::Pli中。相关代码如下: [crayon-69bce4df05778204659611/] PLI消息用于解码端通知编码端我要解码的图像的编码数据丢失了。对于基于帧间预测的视频编码类型,编码端收到PLI消息就要知道视频数据丢失了,由于帧间预测需要基于前后完整的视频帧才能解码(例如H264中,存在B帧,需要参考前后帧才能解码),前面的数据丢失了,后面的视频帧不能正常解码出图像,此时编码端可以直接生成一个关键帧,然后发送给解码端。 Full Intra Request (FIR) 在RFC5104中定义。参照上一小节RTCP反馈消息数据包格式,对于FMT规定为4,PT规定为PSFB。由于FIR可用于通知多个编码发送端(例如多点视频会议情况),所以用到了FCI部分,填充多个发送端的ssrc信息。具体包格式如下: [crayon-69bce4df05779486565555/] 在WebRTC源码中,FIR相关解析封装代码位于webrtc::Fir中。相关处理代码就不贴出来了,类似PLI处理,除了FCI部分要填充一些信息。 当解码端需要刷新时,可以发送FIR消息给编码端,编码端此时发送关键帧,刷新解码端。这有点类似PLI消息,但是PLI消息是用于丢包情况下的通知,而FIR却不是,在有些非丢包情况下,FIR就要用到。举两个例子: 1)解码端需要切换到另一路不同视频时,由于需要新的解码参数,所以可通过发送FIR消息,通知编码端生成关键帧,获取新的解码参数,刷新视频解码器; 2)在视频会议中,新用户随机时刻加入,各个编码端发送的视频不一定都是关键帧,所以新用户不一定能正常解码。此时该新加入用户发送FIR消息,通知各个编码端给它发关键帧,获取关键帧后即可正常解码。 总结 本文主要介绍了几种关键帧请求场景,讲了AVPF中定义的两种关键帧请求消息,虽然这两种消息获取的结果一样,但是表达的意义却不一样,用于不同场景,使用时需要区分下。

2019年5月28日 8comments 6178hotness 15likes Jeff Read all
WebRTC

Windows平台WebRTC编译-VS2017

在音视频领域,想深入研究的话,必定会接触WebRTC。WebRTC是一个庞大的工程,就像是音视频领域的百科全书,音视频采集,编解码,传输,渲染等一条龙在WebRTC里都有,而且WebRTC还有很多先进的音视频处理算法。由于WebRTC代码过于庞大,所以最好单步调试跟踪代码运行,这样才可以更好地学习WebRTC,否则很难有头绪。工欲善其事必先利其器,作为调试神器,宇宙第一IDE Visual Studio必不可少。所以本篇文章主要讲下如何在Windows上编译WebRTC,同时得到VS工程,然后调试。 本文内容截止2020.04.01,最新代码测试编译通过。最新VS2017以上版本编译见文末。 系统要求 Win7及以上64位系统。 内存至少8G,当然越大越好。 至少50G磁盘空间(NTFS格式),不能是FAT32,因为会生成大于4G的文件。 Visual Studio安装 WebRTC用到了很多C++最新特性,所以编译最新WebRTC代码VS要求为2017(>=15.7.2) 版本。我用的是VS2017社区版(VS新老版本下载)。VS最好安装在C盘,按默认路径安装,否则可能遇到问题(见问题0x02)。安装VS2017时选择自定义安装,必须勾选如下几项: Desktop development with C++组件中10.0.18362或以上的Win10 SDK,后面还要安装调试工具 Desktop development with C++组件中MFC以及ATL这两项 2020.04.01更新:由于最新WebRTC源码要求10.0.18362及以上Win10 SDK。所以请下载10.0.18362 或以上的Win10 SDK。本文写于2019年,那时VS2019还没发布。由于10.0.18362 Win10 SDK存在于VS2019安装选项中,VS2017安装选项不带有该SDK,所以使用VS2017得从Win10 SDK下载另外下载最新Win10 SDK,或者再装个VS2019选择安装该SDK 安装完VS2017后,必须安装SDK调试工具。打开控制面板->程序与功能,找到刚才安装的最新Windows Software Development Kit,鼠标右键->change。 勾选Debugging Tools For Windows,然后点击change。 depot_tools安装 下载depot_tools然后解压到某个目录,比我的解压到E盘根目录。接着将该depot_tools目录的路径加到系统环境变量Path里,然后把该路径移到最前面(避免已安装的python与git造成影响)。 获取WebRTC源码 由于WebRTC的源码地址被墙了,所以需要通过代理或者vpn才能得到源码。后面都是命令行操作,打开cmd窗口,由于我用的是ss代理,在cmd窗口我按如下设置: [crayon-69bce4df06e92230585815/] 设置当前cmd窗口代理上网,如果cmd窗口关闭了重开得重新设置。当然了,也可以设置系统全局代理上网。其他代理方法也类似。如果是VPN之类非代理,就不用这样设置了。 接着执行gclient命令,安装编译需要用到的一些工具,比如git以及python。 [crayon-69bce4df06e98304932250/] 再接着设置一些环境变量,设置下我们的VS安装路径。 [crayon-69bce4df06e99987720612/] 然后cd到要放源码的地方(要遵守前面说的磁盘要求),执行: [crayon-69bce4df06e9a447200835/] 这一过程是个漫长的等待,要下的东西将近10G,包括源码以及一些测试的音视频文件资源等,如果因为网络等原因中断了,就再执行gclient sync。如果这一步一直卡着不动,可以执行ctrl+c,然后执行gclient sync。 使用gclient sync可能遇到的问题 问题0x01 [crayon-69bce4df06e9b663274024/] Unicode字符编码问题,python的一个bug,因为很多人系统语言都是中文的,所以得按如下设置,把系统区域改为英文,然后重启即可。 问题0x02 2019.04.01更新。去年的版本我编译时没报这个问题,我看到评论里有人提出来了,我下了今天的最新代码,编译时也碰到了,看了下是最新WebRTC windows相关脚本变化导致 报Exception: No supported Visual Studio can be found. Supported versions are: 16.0 (2019), 15.0 (2017)错误: [crayon-69bce4df06e9c202131161/] 解决方法为修改src\build目录下的vs_toolchain.py脚本,加了一行,直接写死我们的VS路径代码: [crayon-69bce4df06e9d364420561/] 脚本中的代码默认以C盘处理的,如果我们的VS安装在C盘默认目录就不会报这个错,但我想很多人VS不会装在C盘。 执行:python src/build/vs_toolchain.py get_toolchain_dir验证修改,控制台打印如下: [crayon-69bce4df06ea0993101165/] 说明修改成功。接着我们使用gclient sync会报如下问题: [crayon-69bce4df06ea1764155273/] 因为我们修改了脚本,所以执行gclient sync --force即可。 gclient sync --force成功结束后,vs_toolchain.py文件会被还原,所以得按前面重新修改vs_toolchain.py。vs_toolchain.py中会优先选择高版本VS编译,由于本文使用VS2017编译,假如我们电脑安装有VS2019,需要按如下修改,把VS2017放前面,避免造成影响。 [crayon-69bce4df06ea2805607793/] 编译 生成VS2017工程文件: [crayon-69bce4df06ea3722238072/] 可以在src\out\Default\ 下得到 all.sln解决方案文件。 如果不想使用默认编译参数,可以使用gn args out/Default --list查看当前编译参数,通过类似如下方式设置: [crayon-69bce4df06ea4979072427/] 接着执行编译命令: [crayon-69bce4df06ea5653691514/] 用VS2017打开: 可以看到众多工程,到此算是完成了。找到我们感兴趣的,就可以用VS单步调试,跟踪代码运行了。这么多宝贝够研究很久了。 代码更新 [crayon-69bce4df06ea6696214589/] 引用WebRTC库 WebRTC编译后会在src\out\Default\obj目录下生成整个WebRTC工程的静态库:webrtc.lib,链接下这个就可以了。 总结 总之WebRTC在Windows上的编译很考验耐心,也很苛刻,需要有个好的访问被墙地址工具。最新VS2019编译可以参考我的这篇文章: Windows平台WebRTC编译(持续更新),本文也不再更新。 参考 1. WebRTC Native code Development 2. Chromium’s build instructions for Windows

2019年3月14日 91comments 40454hotness 30likes Jeff Read all
12345
Copyright Statement

Unauthorized reproduction or plagiarism in any form is strictly prohibited. For reprint requests, please contact via email.

Recent Comments
Mirzoemele Published at 2 months ago(01 01202613104 06 06pm26) Double blind randomised controlled trial of two to...
PedarPhago Published at 7 months ago(08 08202583109 12 12pm25) Association between selective serotonin reuptake i...
EsielTooft Published at 8 months ago(07 07202573112 29 29am25) International scientific apply guidelines for the ...
dongxuh Published at 8 months ago(07 07202573103 27 27pm25) 真心不错的博客,有机会能一起分享
南南 Published at 8 months ago(07 07202573103 15 15pm25) 写的超棒!

COPYRIGHT © 2026 jianchihu.net. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang