Ortp源码简介

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangdapao12138/article/details/82535113

1ORTP库概览

(1)库本身没有main,提供一堆功能函数,都在src目录下

(2)库的使用给了案例,有main,在src/tests目录下

(3)相关数据结构和头文件在include/ortp目录下

(4)ortp实现了rtp和rtcp协议,前者负责传输,后者负责控制和同步协调

2ORTP库的使用案例

(1)src/tests/rtpsend.c

(2)ortp_init及av_profile_init

(3)ortp_scheduler_init和ORTP调度器:一个任务中完成多个会话的发送和接收,类似于select

(4)rtp_session_new和rtp的会话管理

3rtpsession

(1)rtp通过会话来管理数据发送和接收,会话的本质是一个结构体,管理很多信息

(2)创建会话用rtp_session_new

(3)rtp发送用rtp_session_send_with_ts

(4)底层真正干活的还是socket接口那一套,参考rtpsession_inet.c

4ORTP的一些小细节

(1)port.c中对OS的常用机制(任务创建和销毁、进程管理和信号量等)进行了封装,便于将ortp移植到不同平台中

(2)utils.c中实现了一个双向链表

(3)str_util.c中实现了一个队列管理

(4)rtpparse.c和rtcpparse.c文件实现了解析收到的rtp数据包的部分

(5)jitterctl.c中实现了jitter buffer来防抖。jitter buffer技术是ip 音视频通信里相对比较高级的主题,jitter buffer模块好坏通常是衡量一个voip客户端/服务器好坏的技术点之一,尤其是在网络抖动比较严重,如3g, wifi环境,数据包的rtt值不均衡往往会导致语音卡顿,丢字等现象,jitter buffer 模块通过缓存一段数据包,把数据包重排,并均匀的送给播放端,一个好的jitter buffer实现通长是动态调整缓存大小的,在网络延迟大,抖动严重时会动态增加缓存大小,在网络恢复时动态减小缓存大小以减少端到端的播放延迟。

5.Jitter buffer

如果网络是理想的,即无丢包、无抖动、低延时,那么接收到一帧完整数据就直接播放,效果一定会非常好。但是实际的网络往往很复杂,尤其是无线网络。如果还是这样直接播放,网络稍微变差,视频就会卡顿,出现马赛克等异常情况。所以,在接收端对接收的数据做一个缓冲是很有必要的。

缓冲一定是以延时作为代价的,延时越大,对抖动的过滤效果越好。一个优秀的视频jitterbuffer,不仅要能够对丢包、乱序、延时到达等异常情况进行处理,而且还要能够让视频平稳的播放,尽可能的避免出现明显的加速播放和缓慢播放。

主流的实时音视频框架基本都会实现jitterbuffer功能,诸如WebRTCdoubango等。WebRTCjitterbuffer相当优秀,按照功能分类的话,可以分为jitterbufferbuffer主要对丢包、乱序、延时到达等异常情况进行处理,还会和NACKFECFIRQOS相互配合。jitter主要根据当前帧的大小和延时评估出jitter delay,再结合decode delayrender delay以及音视频同步延时,得到render time,来控制平稳的渲染视频帧。

下面将分别对jitterbuffer做介绍。

Buffer

http://www.ucpaas.com/u/allimg/1706/8-1F602094T0135.jpg

buffer运行机制图

buffer对接收到的rtp包的主要处理操作如下:

  • 第一次接收到一个视频包,从freeframes队列中弹出一个空frame块,用来放置这个包。
  • 之后每次接收到一个RTP包,根据时间戳在incompleteframesdecodableframes中寻找,看是否已经接收到过相同时间戳的包,如果找到,则弹出该frame块,否则,从freeframes弹出一个空frame
  • 根据包的序列号,找到应该插入frame的位置,并更新state。其中stateemptyincompletedecodablecompleteempty为没有数据的状态,incomplete为至少有一个包的状态,decodable为可解码状态,complete为这一帧所有数据都已经到齐。decodable会根据decode_error_mode 有不同的规则,QOS的不同策略会设置不同的decode_error_mode ,包含kNoErrorskSelectiveErrors以及kWithErrorsdecode_error_mode 就决定了解码线程从buffer中取出来的帧是否包含错误,即当前帧是否有丢包。
  • 根据不同的stateframepush回到队列中去。其中stateincomplete时,pushincompleteframes队列,decodablecomplete状态的framepush回到decodableframes队列中。
  • freeframes队列有初始sizefreeframes队列为空时,会增加队列size,但有最大值。也会定期从incompleteframesdecodable队列中清除一些过时的framepushfreeframes队列。
  • 解码线程取出frame,解码完成之后,pushfreeframes队列。

jitterbufferQOS策略联系紧密,比如,incompleteframesdecodable队列清除一些frame之后,需要FIR(关键帧请求),根据包序号检测到丢包之后要NACK(丢包重传)等。

Jitter

所谓jitter就是一种抖动。具体如何解释呢?从源地址发送到目标地址,会发生不一样的延迟,这样的延迟变动就是jitter

jitter会带来什么影响?jitter会让音视频的播放不平稳,如音频的颤音,视频的忽快忽慢。那么如何对抗jitter呢?增加延时。需要增加一个因为jitter而存在的delay,即jitterdelay

http://www.ucpaas.com/u/allimg/1706/8-1F602094Z4a1.jpg

更新jitterdelay

其中,frameDelayMS指的是一帧数据因为分包和网络传输所造成的延时总和、帧间延迟。具体如下图,即RTP1RTP2到达Receiver的时间差。

http://www.ucpaas.com/u/allimg/1706/8-1F602095000292.jpg

帧间延迟图

framesizeBytes指当前帧数据大小,incompleteFrame指是否为完整的帧,UpdateEstimate为根据这三个参数来更新jitterdelay的模块,这个模块为核心模块,其中会用到卡尔曼滤波对帧间延迟进行滤波。

JitterDelay =theta[0] * (MaxFS – AvgFS) + [noiseStdDevs * sqrt(varNoise) –noiseStdDevOffset]

其中theta[0]是信道传输速率的倒数,MaxFS是自会话开始以来所收到的最大帧大小,AvgFS表示平均帧大小。noiseStdDevs表示噪声系数2.33varNoise表示噪声方差,noiseStdDevOffset是噪声扣除常数30UpdateEstimate会不断地对varNoise等进行更新。

在得到jitterdelay之后,通过jitterdelay+ decodedelay +renderdelay,再确保大于音视频同步的延时,加上当前系统时间得到rendertime,这样就可以控制播放时间。控制播放,也就间接控制了buffer的大小。

取帧,解码播放

http://www.ucpaas.com/u/allimg/1706/8-1F602094922253.jpg

取帧解码播放图

本文只介绍jitterbuffer相关内容,所以这里只详细介绍取帧这一步。

解码线程会一直从buffer中寻找期望的数据,这里说的期望的数据分为必须完整的和可以不完整的。如果期望的数据是完整的,那就要从decodableframes队列取出状态为completeframe,如果期望的数据可以是不完整的,就要从decodableframesincompleteframes队列取出数据。取数据之前,总是先去找到数据的时间戳,然后计算完jitterdelay和渲染时间,再经过一段时间的延时(这个延时为渲染时间减去当前时间、decodedelayrender delay)之后再去取得数据,传递到解码,渲染。

取完整的帧时,有一个最大等待时间,即当前buffer中没有完整的帧,那么可以等待一段时间,以期望在这段时间里,可以出现完整的帧。

后记

从上述原理可以看出,WebRTC中的接收buffer并非是固定的,而是根据网络波动等因素随时变化的。jitter则是为了对抗网络波动造成的抖动,使得视频能够平稳播放。

那么,jitterbuffer是否存在可以优化的空间呢?jitterbuffer已经较为优秀,但我们可以通过调整里面的一些策略,来使视频质量更好。比如,增大缓冲区,因为jitterbuffer是动态的,直接增大freeframessize是无效的,只能通过调整延时,来增大缓冲区。再比如,调整等待时间,以期望获得更多完整的帧。再如,配合NACKFIRFECQOS策略,来对抗丢包。

当然,这都是以牺牲延时为代价的。总之,要在延时和丢包、抖动之间做出平衡。

6.SDP文件格式

m=video 8080 RTP/AVP 96

a=rtpmap:96 H264

a=framerate:25

c=IN IP4 192.168.1.20

http://hi.csdn.net/attachment/201010/31/0_12885381881DLg.gif

2 SDP各个参数简单介绍

下面示例摘自3264协议[1]

v=0                                                                              

o=carol 28908764872 28908764872 IN IP4 100.3.6.6        //会话ID号和版本

s=-                                     //用于传递会话主题

t=0 0                                   //会话时间,一般由其它信令消息控制,因此填0

c=IN IP4 192.0.2.4              //描述本端将用于传输媒体流的IP

m=audio 0 RTP/AVP 0 1 3     //媒体类型 端口号 本端媒体使用的编码标识(Payload)集

a=rtpmap:0 PCMU/8000 //rtpmap映射表,各种编码详细描述参数,包括使用带宽(bandwidth

a=rtpmap:1 1016/8000

a=rtpmap:3 GSM/8000

a=sendonly     //说明本端媒体流的方向,取值包括sendonly/recvonly/sendrecv/inactive

a=ptime:20                           //说明媒体流打包时长

m=video 0 RTP/AVP 31 34

a=rtpmap:31 H261/90000

a=rtpmap:34 H263/90000

猜你喜欢

转载自blog.csdn.net/wangdapao12138/article/details/82535113