自适应编码实现

来源:互联网 发布:淘宝条形码怎么填 编辑:程序博客网 时间:2024/06/11 04:24

经过一段时间实验,关于自适应编码得到些成果,但还有很多问题,现把我的做法贴出来,欢迎高手指教!

原理: 
网络传输的反馈信息是通过RTCP包中的RR(接受者报告)包得到。通过RR包中的累积丢包数等反馈信息可以计算出当前的传输丢包率。当丢包率低于预先设定的最小值时,增加编码输出速率。当丢包率大于设定的最大值时,降低编码输出速率。当网络拥塞时,发送速率乘性减小,降低对所需带宽的要求。同时设置最小发送码率,保证发送端所需的最小带宽。当网络空闲时,线性增加发送码率。同时设置最大发送码率,保证发送端不会过度占用资源。当网络负载正常时不作任何调整。
丢包率计算:
(1) 计算该发送时隙丢失的数据包数L(n):前端一个发送时隙前后接收的两个RR包中包丢失的累计数之差就是该发送时隙丢失的数据包数,即
L(n)=C(n) - C(n-I)
其中C(n)是第n个发送时隙后共丢失的数据包数。
(2) 计算该时隙中应收到的数据包的数R(n):两个接收数据包中的最高序列号扩展的差就是接收者在该时隙中应收到的数据包数,即
R(n)=H(n) - H(n-1),
其中H(n)是第n个发送时隙后收到的数据包的最高序列号。
(3) 计算该时隙中数据包丢失比例F(n):L(n)与R(n)之比即在该时隙中数据包丢失比例,即
F(n)=L(n)/R(n);
(4) 计算该时隙中数据包的丢失比率,就是每秒钟的丢包数f(n):数据包的丢失比率等于丢失比例除以两个RR中NTP时间戳的差,即
f(n) = F(n) / ( NTP(n) - NTP(n-1) )

关于时间戳如何取得:
在SR包中包含NTP时间戳,而RR包的LSR 就是最近的SR中的64位NTP时间标识的中间32位,故我取 LSR的差值表示NTP的差值。
码率调整: 
输出速率的调整根据AIMD(加性递增乘性递减)的策略。
ratio 码率
β 递减参数 取0.8 从其他论文中得到
α 递增参数 取5kbps 可根据网络情况定义
PthMax 最大丢包率 取0.5% 自己试验得到 
PthMin 最小丢包率 取0.1% 自己试验得到
ratio < PthMax . R= max(β* R , MinRate) 
ratio> PthMin, R=min( R+α, MaxRate )

AIMD策略: 
采用加性递增,即根据网络带宽保守增加比特率,避免引起较大波动。采用乘性递减的方法,可使发送端迅速减小比特率以缩短拥塞周期和丢包率。
代码:
1. 以下是码率计算的函数
unsigned int RtpSender::RevRTCP_RR()
{
RTPTime *RRTime;

// 计算丢包率
int LostNum;
unsigned int RevNum;
float ratio;

unsigned int DiffNtp;
unsigned int LastSec=0;

sess.BeginDataAccess();
if (sess.GotoFirstSource() ) 


do

RTPPacket* packet;
RTPSourceData *srcdat;
if( (srcdat = sess.GetCurrentSourceInfo()) != 0)
{
if(srcdat->RR_HasInfo()) //如果有收到rr包

*RRTime= srcdat->RR_GetReceiveTime(); 
if( srcdat->RR_GetLastSRTimestamp() != LastRR.LSRTimestamp )//收到的RR包不一样时计算每秒丢包率
{
LostNum= srcdat->RR_GetPacketsLost()-LastRR.PacketsLost;
RevNum= srcdat->RR_GetExtendedHighestSequenceNumber()- LastRR.ExHSeqNum;

ratio= LostNum *65536.0 /RevNum/DiffNtp;// 每秒的丢包率
//计算输出码率
if(ratio > PthMax)
{
if( BitRate * 0.8 > BitMin) 
BitRate = BitRate * 0.8;
else
BitRate = BitMin;

if(ratio < PthMin )

BitRate = (BitRate + 5000) < BitMax ? (BitRate + 5000) : BitMax; 
}
}
//赋值,以便下次计算
LastRR.FractionLost= srcdat->RR_GetFractionLost();
LastRR.PacketsLost= srcdat->RR_GetPacketsLost();
LastRR.ExHSeqNum = srcdat->RR_GetExtendedHighestSequenceNumber();
LastRR.Jitter= srcdat->RR_GetJitter();
LastRR.LSRTimestamp = srcdat->RR_GetLastSRTimestamp();
LastRR.DLSR = srcdat->RR_GetDelaySinceLastSR();

}// RR_HasInfo 
srcdat-> FlushPackets();
}
} while (sess.GotoNextSource()); //接收另一个packet
}//end if
sess.EndDataAccess();
return BitRate;
}

2.通过重新初始化编码器,设置编码输出速率
在编码器初始化函数中添加如下代码:
/* init plugins */
xvid_plugin_single_t single;// for bitrate (wethty) 
xvid_enc_plugin_t plugins[1];// for single plugin (wethty)
memset(&single, 0, sizeof(xvid_plugin_single_t));
single.version = XVID_VERSION;
//single.bitrate = ARG_BITRATE;
single.bitrate = bitrate; //经过计算的编码速率
single.reaction_delay_factor = ARG_REACTION;
single.averaging_period = ARG_AVERAGING;
single.buffer = ARG_SMOOTHER;
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single;
plugins[xvid_enc_create.num_plugins].param = &single;
xvid_enc_create.num_plugins++;

测试: 

1. 两台虚拟机连接,一个负责发送视频,一个负责接收。
2. 两个虚拟机分别运行运行测试工具iperf,一个以sever方式运行,一个以client方式运行。
3. Server: iperf -s
      Client: iperf -c 192.168.1.128 -i 1 -P 50 -t 100
Iperf 的client端会根据命令向server端发送 TCP数据包。
运行iperf 目的是人为造成阻塞,试验自适应编码的效果。

存在问题: 
1. Iperf无法以固定速率发送TCP包,有时200Mbit/s ,有时600Mbit/s。
2. 设置编码输出速率后,在接受端用 wireshark ,vlc 测试发现速率只有设置的一半,这是什么原因?
3. 采用重新初始化xvid编码器的方法设置输出速率,每次编码输出速率改变,都会重新初始化。这就带来一个问题:每次初始化时,视频画面都有停顿,当有运动物体时尤为明显,不知这个问题如何解决。

原创粉丝点击