将 当前收包序列号:sequence_number 从丢包集合 nack_list_ 中剔除;
将 sequence_number 与 最近收到的新包:sequence_num_last_received_rtp_ 对比,判断当前包是否为重传或乱序包。如若是的话,直接终止判断,否则继续;
对比 当前包 与 最新收到的包 的序列号与时间戳,更新每个包的样本数:samples_per_packet_;
更新 nack_list_ 中部分包的丢包状态:is_missing = true,这些包我们之前认为后续再考虑,现在需要把它们当做丢包。这些包满足:序列号 在 sequence_number - nack_threshold_packets_ 之前(nack_threshold_packets_ = 2);
如果 最新收到的包 与 当前包 不连续,则区间内的包都要被放到 nack_list_,其中那些太旧的包(判断标准同上一步)会被直接认为丢包,剩下的包当后续包达到时,会在上一步中再明确是否为丢包;
将 最近收到的新包 的序列号: sequence_num_last_received_rtp_ 与时间戳更新为 当前包 的序列号与时间戳;
丢弃掉集合 nack_list_ 中不能重传的包信息,同时保证集合容量不超过限制(最大容量 max_nack_list_size_ = 500,即对于单位长度为 20ms 的帧,保留 10s 长度)。不能重传的包满足序列号在 最新收到的包序列号 - static_cast
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
/*
sequence_number:当前收到的包的序列号
timestamp:当前收到的包的时间戳
*/
void NackTracker::UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp)
{
/*
如果这是第一个包
any_rtp_received_ = true,表示收到了任意包
*/
if (!any_rtp_received_)
{
/* 第一个包仅仅记录序列号与时间戳 */
sequence_num_last_received_rtp_ = sequence_number;
timestamp_last_received_rtp_ = timestamp;
any_rtp_received_ = true;
// If no packet is decoded, to have a reasonable estimate of time-to-play
// use the given values.
if (!any_rtp_decoded_)
{
sequence_num_last_decoded_rtp_ = sequence_number;
timestamp_last_decoded_rtp_ = timestamp;
}
return;
}
/* 如果是上一个包, */
if (sequence_number == sequence_num_last_received_rtp_)
return;
/* nack_list_:丢包集合 */
nack_list_.erase(sequence_number);
/*
将当前包 与 最近收到的新包 对比,判断当前包是否为重传或乱序包
是的话,直接返回
*/
if (IsNewerSequenceNumber(sequence_num_last_received_rtp_, sequence_number))
return;
/* 对比 当前包 与 最新收到的包 的序列号与时间戳,更新每个包的样本数:samples_per_packet_ */
UpdateSamplesPerPacket(sequence_number, timestamp);
/* 更新丢包集合:nack_list_ */
UpdateList(sequence_number);
/* 更新最新收包的序列号与时间戳 */
sequence_num_last_received_rtp_ = sequence_number;
timestamp_last_received_rtp_ = timestamp;
/* 丢弃掉集合 nack_list_ 中不能重传的包信息,同时保证集合容量不超过限制 */
LimitNackListSize();
}
void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp)
{
/*
更新 nack_list_ 中部分包的丢包状态:is_missing = true,
这些包我们之前认为后续再考虑,现在需要把它们当做丢包
*/
ChangeFromLateToMissing(sequence_number_current_received_rtp);
/*
如果当前收到的包 比 sequence_num_last_received_rtp_ + 1 新,
即:最近收到的新包 与 当前收到的包 不连续
*/
if (IsNewerSequenceNumber(sequence_number_current_received_rtp,
sequence_num_last_received_rtp_ + 1))
AddToList(sequence_number_current_received_rtp);
}
void NackTracker::ChangeFromLateToMissing(uint16_t sequence_number_current_received_rtp)
{
/*
nack_threshold_packets_ = 2,表示:
当序列号为 N 的包到达时,序列号在 ( , N - |nack_threshold_packets_| ) 区间、所有未到达的包,都会被认为丢失
而对于序列号在 [ N - |nack_threshold_packets_| , N-1 ] 区间、所有未达到的包,后面再考虑
*/
/* 查找 大于等于 N - |nack_threshold_packets_| 的第一个元素 */
NackList::const_iterator lower_bound =
nack_list_.lower_bound(static_cast(
sequence_number_current_received_rtp - nack_threshold_packets_));
for (NackList::iterator it = nack_list_.begin(); it != lower_bound; ++it)
it->second.is_missing = true;
}
void NackTracker::AddToList(uint16_t sequence_number_current_received_rtp)
{
assert(!any_rtp_decoded_ ||
IsNewerSequenceNumber(sequence_number_current_received_rtp,
sequence_num_last_decoded_rtp_));
/*
序列号在 upper_bound_missing 之前的包(不包括 upper_bound_missing),都认为是丢包,添加到 nack_list_
upper_bound_missing 以及之后的包,一并添加到 nack_list_,但后面再考虑
*/
uint16_t upper_bound_missing =
sequence_number_current_received_rtp - nack_threshold_packets_;
/*
最近收到的新包 到 当前收到的包 区间内的包,都可能是丢包,都会被添加到 nack_list_
但只有在 upper_bound_missing 之前的包,才直接认为丢包
*/
for (uint16_t n = sequence_num_last_received_rtp_ + 1;
IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n)
{
bool is_missing = IsNewerSequenceNumber(upper_bound_missing, n);
uint32_t timestamp = EstimateTimestamp(n);
NackElement nack_element(TimeToPlay(timestamp), timestamp, is_missing);
nack_list_.insert(nack_list_.end(), std::make_pair(n, nack_element));
}
}
void NackTracker::LimitNackListSize()
{
/* max_nack_list_size_ = 500 */
uint16_t limit = sequence_num_last_received_rtp_ - static_cast(max_nack_list_size_) - 1;
/* 删除 [ start, end ) 区间内的节点 */
nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(limit));
}
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓