posts

vnn01

UlpFec_Generator_AddPacketAndGenerateFec

tags
ulpfec Ulpfec_gen webrtc

职责

  • 输入RtpPacketToSend的数据包,按ForwardErrorCorrection::Packet的格式缓存起来,在合适的时机生成FEC报文,并缓存起来。

概况序列图

  • 关键函数UlpfecGenerator::AddPacketAndGenerateFec
    • 输入RtpPacketToSend& packet
    • 检查并更新FEC参数
    • 将输入的packet包转化为ForwardErrorCorrection::Packet并缓存起来
    • 记录packet,使生成ULPFEC+RED包时可以复用它的RTP头信息
    • 当没有超过params_.max_fec_frames限制,且满足以下条件时,尽快生成fec
      • 收到至少min_num_media_packets_个媒体包
      • (actual overhead - requested/target overhead) 小于 `kMaxExcessOverhead`
      • 调用 ForwardErrorCorroction::EncodeFec 生成fec,并缓存到generated_fec_packets_

代码

void UlpfecGenerator::AddPacketAndGenerateFec(const RtpPacketToSend& packet) {
  RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
  RTC_DCHECK(generated_fec_packets_.empty());

  {
    MutexLock lock(&mutex_);
    if (pending_params_) {
      current_params_ = *pending_params_;
      pending_params_.reset();

      if (CurrentParams().fec_rate > kHighProtectionThreshold) {
        min_num_media_packets_ = kMinMediaPackets;
      } else {
        min_num_media_packets_ = 1;
      }
    }
  }

  if (packet.is_key_frame()) {
    media_contains_keyframe_ = true;
  }
  const bool complete_frame = packet.Marker();
  if (media_packets_.size() < kUlpfecMaxMediaPackets) {
    // Our packet masks can only protect up to `kUlpfecMaxMediaPackets` packets.
    auto fec_packet = std::make_unique<ForwardErrorCorrection::Packet>();
    fec_packet->data = packet.Buffer();
    media_packets_.push_back(std::move(fec_packet));

    // Keep a copy of the last RTP packet, so we can copy the RTP header
    // from it when creating newly generated ULPFEC+RED packets.
    RTC_DCHECK_GE(packet.headers_size(), kRtpHeaderSize);
    last_media_packet_ = packet;
  }

  if (complete_frame) {
    ++num_protected_frames_;
  }

  auto params = CurrentParams();

  // Produce FEC over at most `params_.max_fec_frames` frames, or as soon as:
  // (1) the excess overhead (actual overhead - requested/target overhead) is
  // less than `kMaxExcessOverhead`, and
  // (2) at least `min_num_media_packets_` media packets is reached.
  if (complete_frame &&
      (num_protected_frames_ >= params.max_fec_frames ||
       (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
    // We are not using Unequal Protection feature of the parity erasure code.
    constexpr int kNumImportantPackets = 0;
    constexpr bool kUseUnequalProtection = false;
    fec_->EncodeFec(media_packets_, params.fec_rate, kNumImportantPackets,
                    kUseUnequalProtection, params.fec_mask_type,
                    &generated_fec_packets_);
    if (generated_fec_packets_.empty()) {
      ResetState();
    }
  }
}

Links to this note