WebRTC研究:视频丢包判断

/*
sequence_number:当前收到的包序列号
*/
bool VCMJitterBuffer::UpdateNackList(uint16_t sequence_number) {
  if (nack_mode_ == kNoNack) {
    return true;
  }

  // Make sure we don't add packets which are already too old to be decoded.
  if (!last_decoded_state_.in_initial_state()) {

	  /* latest_received_sequence_number_:上一次收到的最新RTP包序列号 */
    latest_received_sequence_number_ = LatestSequenceNumber(
        latest_received_sequence_number_, last_decoded_state_.sequence_num());
  }

  /* 判断当前RTP包是否是新的数据包,而不是重传或者乱序包 */
  if (IsNewerSequenceNumber(sequence_number, latest_received_sequence_number_)) 
  {
	/* 
	从 latest_received_sequence_number_ + 1 开始判断是否满足 IsNewerSequenceNumber,
	即:判断当前包的序列号 sequence_number 是不是比排在 i 的后面,
	是的话,说明 [latest_received_sequence_number_ + 1, latest_received_sequence_number_] 区间的包丢了
	*/
    for (uint16_t i = latest_received_sequence_number_ + 1; IsNewerSequenceNumber(sequence_number, i); ++i) {

	  /* 将序列号 i 添加到 missing_sequence_numbers_(std::set类型),被认为包已经丢失 */
      missing_sequence_numbers_.insert(missing_sequence_numbers_.end(), i);
      TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "AddNack", "seqnum", i);
    }

	/*
	判断集合 missing_sequence_numbers_ 的容量是否超过最大限制
	是的话,通过调用 RecycleFramesUntilKeyFrame 不断丢包来减少集合中的序列号
	*/
    if (TooLargeNackList() && !HandleTooLargeNackList()) 
	{
      LOG(LS_WARNING) << "Requesting key frame due to too large NACK list.";
      return false;
    }

	/*
	判断集合 missing_sequence_numbers_ 里的包是否太旧了
	判断依据:当前包的序列号 sequence_number 与 集合 missing_sequence_numbers_ 中第一个包的序列号之间的差值是否超过限制
	是的话,通过调用 RecycleFramesUntilKeyFrame 不断丢包来减少集合中的序列号
	*/
    if (MissingTooOldPacket(sequence_number) && !HandleTooOldPackets(sequence_number)) {
      LOG(LS_WARNING) << "Requesting key frame due to missing too old packets";
      return false;
    }
  } 
  else 
  {
	/* 当前包是重传或者乱序包,直接从丢包集合中剔除 */
    missing_sequence_numbers_.erase(sequence_number);
    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RemoveNack",
                         "seqnum", sequence_number);
  }

  return true;
}

判断 missing_sequence_numbers_ 容量是否超过限制:

注意:
max_nack_list_size_ = 250

bool VCMJitterBuffer::TooLargeNackList() const 
{
  return missing_sequence_numbers_.size() > max_nack_list_size_;
}

判断 missing_sequence_numbers_ 里的包是否太旧了:

注意:
max_packet_age_to_nack_ = 450

bool VCMJitterBuffer::MissingTooOldPacket(uint16_t latest_sequence_number) const 
{
  if (missing_sequence_numbers_.empty()) 
  {
    return false;
  }
  const uint16_t age_of_oldest_missing_packet =
      latest_sequence_number - *missing_sequence_numbers_.begin();
  // Recycle frames if the NACK list contains too old sequence numbers as
  // the packets may have already been dropped by the sender.
  return age_of_oldest_missing_packet > max_packet_age_to_nack_;
}

当 missing_sequence_numbers_ 容量超过限制或 序列号太久时,会循环调用 RecycleFramesUntilKeyFrame:

bool VCMJitterBuffer::HandleTooLargeNackList() 
{
  /*
  回收 fames,直至 NACK list 足够的小
  请求一个 key frame 比重传这么多丢失的包代价要小得多
  */

  LOG_F(LS_WARNING) << "NACK list has grown too large: "
                    << missing_sequence_numbers_.size() << " > "
                    << max_nack_list_size_;
  
  bool key_frame_found = false;
  while (TooLargeNackList()) 
  {
    key_frame_found = RecycleFramesUntilKeyFrame();
  }
  
  return key_frame_found;
}
bool VCMJitterBuffer::HandleTooOldPackets(uint16_t latest_sequence_number) 
{
  bool key_frame_found = false;
  const uint16_t age_of_oldest_missing_packet =
      latest_sequence_number - *missing_sequence_numbers_.begin();
  
  LOG_F(LS_WARNING) << "NACK list contains too old sequence numbers: "
                    << age_of_oldest_missing_packet << " > "
                    << max_packet_age_to_nack_;
  
  while (MissingTooOldPacket(latest_sequence_number)) 
  {
    key_frame_found = RecycleFramesUntilKeyFrame();
  }
  return key_frame_found;
}
// Recycle oldest frames up to a key frame, used if jitter buffer is completely
// full.
bool VCMJitterBuffer::RecycleFramesUntilKeyFrame() 
{
  FrameList::iterator key_frame_it;
  bool key_frame_found = false;
  int dropped_frames = 0;

  /*
  释放不完整的 frames:
  释放 incomplete_frames_(std::map类型)头部所有节点,直至遇到 kVideoFrameKey 类型的 frame
  dropped_frames:释放的节点个数
  key_frame_it:指向 incomplete_frames_ 中 kVideoFrameKey 类型的 frame,若不存在这样的节点,则 == map.end()
  free_frames_:存储被释放的节点

  key_frame_it != incomplete_frames_.end(),表示 incomplete_frames_ 存在 kVideoFrameKey 类型的 frame
  key_frame_it == incomplete_frames_.end(),表示不存在这样的 frame,并且 incomplete_frames_ 中所有节点都被释放了
  */
  dropped_frames += incomplete_frames_.RecycleFramesUntilKeyFrame(&key_frame_it, &free_frames_);
  key_frame_found = key_frame_it != incomplete_frames_.end();

  /* 不存在不完整的 frames,则释放可解码的 frames */
  if (dropped_frames == 0) 
  {
    dropped_frames += decodable_frames_.RecycleFramesUntilKeyFrame(&key_frame_it, &free_frames_);
    key_frame_found = key_frame_it != decodable_frames_.end();
  }

  TRACE_EVENT_INSTANT0("webrtc", "JB::RecycleFramesUntilKeyFrame");

  /* incomplete_frames_ 或 decodable_frames_ 中存在 kVideoFrameKey 类型的 frame */
  if (key_frame_found) 
  {
    LOG(LS_INFO) << "Found key frame while dropping frames.";

	/*
	重置 最近的解码状态,以保证下一个被解码的是 key frame,并从这里
	*/
    // Reset last decoded state to make sure the next frame decoded is a key
    // frame, and start NACKing from here.
    last_decoded_state_.Reset();

	/*
	将 missing_sequence_numbers_ 开头到 EstimatedLowSequenceNumber 区间所有空间释放
	*/
    DropPacketsFromNackList(EstimatedLowSequenceNumber(*key_frame_it->second));
  } 
  else if (decodable_frames_.empty()) 
  {
	/*
	所有 frames 都释放了
	重置解码状态,并清空丢失的包序列号
	*/
    last_decoded_state_.Reset();
    missing_sequence_numbers_.clear();
  }

  return key_frame_found;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值