webrtc中的fec说明

 关于webrtcfec机制的理论分析,已经有大神分析的很好了[1]。我在这里举例说明,更加形象。
 假设现在媒体数据包个数为5,冗余包也为5。假设采用的掩码表为kPacketMaskBurstyTbl。
 那么函数ForwardErrorCorrection::GenerateFecPayloads中的packet_masks_=kPacketMaskBurstyTbl[4][4]=kMaskBursty5_5;

const uint8_t kMaskBursty5_5[10] = {
  0x80, 0x00,
  0xc0, 0x00,
  0x60, 0x00,
  0x30, 0x00,
  0x18, 0x00
};

 这个数组可以看成一个矩阵,(i,j)=c表示这个矩阵,它表示第i个fec包由组成c这个数字中1的位置指示的媒体数据包异或组成。
 第一个fec包由第1(0x80)媒体包异或组而成,第二个冗余包由第1,3,4(0xc0)媒体包异或而成,第三个冗余包由第2,3(0x60)媒体包异或而成……。假设第一个媒体包丢失了,拿第一个fec包顶上就是。
 这个异或的过程,就在函数GenerateFecPayloads完成。

void ForwardErrorCorrection::GenerateFecPayloads(
    const PacketList& media_packets,
    size_t num_fec_packets) {
  RTC_DCHECK(!media_packets.empty());
  for (size_t i = 0; i < num_fec_packets; ++i) {
    Packet* const fec_packet = &generated_fec_packets_[i];
    size_t pkt_mask_idx = i * packet_mask_size_;
    const size_t min_packet_mask_size = fec_header_writer_->MinPacketMaskSize(
        &packet_masks_[pkt_mask_idx], packet_mask_size_);
    const size_t fec_header_size =
        fec_header_writer_->FecHeaderSize(min_packet_mask_size);

    size_t media_pkt_idx = 0;
    auto media_packets_it = media_packets.cbegin();
    uint16_t prev_seq_num = ParseSequenceNumber((*media_packets_it)->data);
    while (media_packets_it != media_packets.end()) {
      Packet* const media_packet = media_packets_it->get();
      // Should |media_packet| be protected by |fec_packet|?
      if (packet_masks_[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) {
        size_t media_payload_length = media_packet->length - kRtpHeaderSize;

        bool first_protected_packet = (fec_packet->length == 0);
        size_t fec_packet_length = fec_header_size + media_payload_length;
        if (fec_packet_length > fec_packet->length) {
          // Recall that XORing with zero (which the FEC packets are prefilled
          // with) is the identity operator, thus all prior XORs are
          // still correct even though we expand the packet length here.
          fec_packet->length = fec_packet_length;
        }
        if (first_protected_packet) {
          // Write P, X, CC, M, and PT recovery fields.
          // Note that bits 0, 1, and 16 are overwritten in FinalizeFecHeaders.
          memcpy(&fec_packet->data[0], &media_packet->data[0], 2);
          // Write length recovery field. (This is a temporary location for
          // ULPFEC.)
          ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2],
                                               media_payload_length);
          // Write timestamp recovery field.
          memcpy(&fec_packet->data[4], &media_packet->data[4], 4);
          // Write payload.
          memcpy(&fec_packet->data[fec_header_size],
                 &media_packet->data[kRtpHeaderSize], media_payload_length);
        } else {
          XorHeaders(*media_packet, fec_packet);
          XorPayloads(*media_packet, media_payload_length, fec_header_size,
                      fec_packet);
        }
      }
      media_packets_it++;
      if (media_packets_it != media_packets.end()) {
        uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data);
        media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num);
        prev_seq_num = seq_num;
      }
      pkt_mask_idx += media_pkt_idx / 8;
      media_pkt_idx %= 8;
    }
    RTC_DCHECK_GT(fec_packet->length, 0)
        << "Packet mask is wrong or poorly designed.";
  }
}

[1]ULPFEC在WebRTC中的实现

猜你喜欢

转载自blog.csdn.net/u010643777/article/details/79512406
今日推荐