VLC网速估计算法
ExoPlayer是根据以往的下载速度来估计当前的网速
现介绍一下几个符号:
采样数组定义如下:
private final ArrayList<Sample> samples;
上述采样数组用于存储历史采样点。
采样点定义如下:
private static class Sample {
public int index;
public int weight;
public float value;
}
index存储的是当前采样点在采样数组的索引,它是用来还原采样数组顺序用的,可以忽略
weight存储的是每次下载数据大小的平方根,下载数据的单位是byte
value存储的是每次下载的速度,单位是bit/s(bps)
网速估计的过程
1.采样点的添加方法
- 每下载一次数据,生成一个Sample,权重weight为每次下载到的数据的Bytes数的平方根;value为每次下载数据的bps
- 将Sample按照时间顺序加入采样数组samples里
- 采样数组samples的大小定义为totalWeight,totalWeight是所有采样点Sample中weight的和(注意这里采样数组大小的定义,不是以往的按照采样点来定义的),这个大小有个上限定义为maxWeight=2000
- 当加入当前采样点后,如果totalWeight>maxWeight,把最先加入采样数组的sample移除,直到totalWeight<=maxWeight
2.网速估计方法:
- 将采样数组按照采样点中的value值从小到大排序
- 定义一个desiredWeight,desiredWeight=totalWeight/2
- 从头遍历排序完的采样数组(从小value开始),依次累加各个样本的weight值,当累加值大于等于desiredWeight时,此时对应的value值为估计的网速。如果此时累加所有的采样点的值仍小于desiredWeight时,返回最近采样点的value值。
原理文档
其网速估计类名为SlidingPercetile.java,官网给出了该算法的原理链接,Wiki: Moving average, Wiki: Selection algorithm
个人理解
其实ExoPlayer的网速估计算法类似于移动平均,但是又不完全相同,没找到具体的讲ExoPlayer网速估计的算法文章了。个人理解,是这样的,假设每次下载的片段大小时一样的,那么这时候取的网速其实是所有网速的一个中位数,这样就去除了大值和小值的影响,这样预测出来的网速准确性未知,毕竟没找到相应的文章写这个算法的网速预测结果。
网速估计获取
上述Sample中的weight和value在ExoPlayer中按照如下方法计算所得:
- DefaultBandwidthMeter::onTransferStart()用于记录下载起始时间sampleStartTimeMs。在DefaultHttpDataSource::open()调用(每次下载数据起始)
- DefaultBandwidthMeter::onBytesTransferred()用于记录下载的总字节数sampleBytesTransferred。在DefaultHttpDataSource::read()中调用。
- DefaultBandwidthMeter::onTransferEnd(),记录下载结束时间,同时生成本次下载过程的Sample(权重和bps),加入采样数组中,并调用上面的算法计算出当前的bitrateEstimate;最后清零sampleBytesTransferred,准备计算下个Sample。在DefaultHttpDataSource::close() 中调用。
注意:播放列表和音视频数据下载的Sample都会统计到计算中。
这一步完成之后,会得到当前的估计网速,bitrateEstimate。