LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/rtp_rtcp/source - ulpfec_generator.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 113 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/modules/rtp_rtcp/source/ulpfec_generator.h"
      12             : 
      13             : #include <memory>
      14             : #include <utility>
      15             : 
      16             : #include "webrtc/base/basictypes.h"
      17             : #include "webrtc/base/checks.h"
      18             : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
      19             : #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
      20             : #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
      21             : 
      22             : namespace webrtc {
      23             : 
      24             : namespace {
      25             : 
      26             : constexpr size_t kRedForFecHeaderLength = 1;
      27             : 
      28             : // This controls the maximum amount of excess overhead (actual - target)
      29             : // allowed in order to trigger EncodeFec(), before |params_.max_fec_frames|
      30             : // is reached. Overhead here is defined as relative to number of media packets.
      31             : constexpr int kMaxExcessOverhead = 50;  // Q8.
      32             : 
      33             : // This is the minimum number of media packets required (above some protection
      34             : // level) in order to trigger EncodeFec(), before |params_.max_fec_frames| is
      35             : // reached.
      36             : constexpr size_t kMinMediaPackets = 4;
      37             : 
      38             : // Threshold on the received FEC protection level, above which we enforce at
      39             : // least |kMinMediaPackets| packets for the FEC code. Below this
      40             : // threshold |kMinMediaPackets| is set to default value of 1.
      41             : //
      42             : // The range is between 0 and 255, where 255 corresponds to 100% overhead
      43             : // (relative to the number of protected media packets).
      44             : constexpr uint8_t kHighProtectionThreshold = 80;
      45             : 
      46             : // This threshold is used to adapt the |kMinMediaPackets| threshold, based
      47             : // on the average number of packets per frame seen so far. When there are few
      48             : // packets per frame (as given by this threshold), at least
      49             : // |kMinMediaPackets| + 1 packets are sent to the FEC code.
      50             : constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f;
      51             : 
      52             : }  // namespace
      53             : 
      54           0 : RedPacket::RedPacket(size_t length)
      55           0 :     : data_(new uint8_t[length]), length_(length), header_length_(0) {}
      56             : 
      57           0 : void RedPacket::CreateHeader(const uint8_t* rtp_header,
      58             :                              size_t header_length,
      59             :                              int red_payload_type,
      60             :                              int payload_type) {
      61           0 :   RTC_DCHECK_LE(header_length + kRedForFecHeaderLength, length_);
      62           0 :   memcpy(data_.get(), rtp_header, header_length);
      63             :   // Replace payload type.
      64           0 :   data_[1] &= 0x80;
      65           0 :   data_[1] += red_payload_type;
      66             :   // Add RED header
      67             :   // f-bit always 0
      68           0 :   data_[header_length] = static_cast<uint8_t>(payload_type);
      69           0 :   header_length_ = header_length + kRedForFecHeaderLength;
      70           0 : }
      71             : 
      72           0 : void RedPacket::SetSeqNum(int seq_num) {
      73           0 :   RTC_DCHECK_GE(seq_num, 0);
      74           0 :   RTC_DCHECK_LT(seq_num, 1 << 16);
      75             : 
      76           0 :   ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num);
      77           0 : }
      78             : 
      79           0 : void RedPacket::AssignPayload(const uint8_t* payload, size_t length) {
      80           0 :   RTC_DCHECK_LE(header_length_ + length, length_);
      81           0 :   memcpy(data_.get() + header_length_, payload, length);
      82           0 : }
      83             : 
      84           0 : void RedPacket::ClearMarkerBit() {
      85           0 :   data_[1] &= 0x7F;
      86           0 : }
      87             : 
      88           0 : uint8_t* RedPacket::data() const {
      89           0 :   return data_.get();
      90             : }
      91             : 
      92           0 : size_t RedPacket::length() const {
      93           0 :   return length_;
      94             : }
      95             : 
      96           0 : UlpfecGenerator::UlpfecGenerator()
      97           0 :     : UlpfecGenerator(ForwardErrorCorrection::CreateUlpfec()) {}
      98             : 
      99           0 : UlpfecGenerator::UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec)
     100           0 :     : fec_(std::move(fec)),
     101             :       num_protected_frames_(0),
     102           0 :       min_num_media_packets_(1) {
     103           0 :   memset(&params_, 0, sizeof(params_));
     104           0 :   memset(&new_params_, 0, sizeof(new_params_));
     105           0 : }
     106             : 
     107             : UlpfecGenerator::~UlpfecGenerator() = default;
     108             : 
     109           0 : std::unique_ptr<RedPacket> UlpfecGenerator::BuildRedPacket(
     110             :     const uint8_t* data_buffer,
     111             :     size_t payload_length,
     112             :     size_t rtp_header_length,
     113             :     int red_payload_type) {
     114             :   std::unique_ptr<RedPacket> red_packet(new RedPacket(
     115           0 :       payload_length + kRedForFecHeaderLength + rtp_header_length));
     116           0 :   int payload_type = data_buffer[1] & 0x7f;
     117           0 :   red_packet->CreateHeader(data_buffer, rtp_header_length, red_payload_type,
     118           0 :                            payload_type);
     119           0 :   red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
     120           0 :   return red_packet;
     121             : }
     122             : 
     123           0 : void UlpfecGenerator::SetFecParameters(const FecProtectionParams& params) {
     124           0 :   RTC_DCHECK_GE(params.fec_rate, 0);
     125           0 :   RTC_DCHECK_LE(params.fec_rate, 255);
     126             :   // Store the new params and apply them for the next set of FEC packets being
     127             :   // produced.
     128           0 :   new_params_ = params;
     129           0 :   if (params.fec_rate > kHighProtectionThreshold) {
     130           0 :     min_num_media_packets_ = kMinMediaPackets;
     131             :   } else {
     132           0 :     min_num_media_packets_ = 1;
     133             :   }
     134           0 : }
     135             : 
     136           0 : int UlpfecGenerator::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
     137             :                                                 size_t payload_length,
     138             :                                                 size_t rtp_header_length) {
     139           0 :   RTC_DCHECK(generated_fec_packets_.empty());
     140           0 :   if (media_packets_.empty()) {
     141           0 :     params_ = new_params_;
     142             :   }
     143           0 :   bool complete_frame = false;
     144           0 :   const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
     145           0 :   if (media_packets_.size() < kUlpfecMaxMediaPackets) {
     146             :     // Our packet masks can only protect up to |kUlpfecMaxMediaPackets| packets.
     147             :     std::unique_ptr<ForwardErrorCorrection::Packet> packet(
     148           0 :         new ForwardErrorCorrection::Packet());
     149           0 :     packet->length = payload_length + rtp_header_length;
     150           0 :     memcpy(packet->data, data_buffer, packet->length);
     151           0 :     media_packets_.push_back(std::move(packet));
     152             :   }
     153           0 :   if (marker_bit) {
     154           0 :     ++num_protected_frames_;
     155           0 :     complete_frame = true;
     156             :   }
     157             :   // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
     158             :   // (1) the excess overhead (actual overhead - requested/target overhead) is
     159             :   // less than |kMaxExcessOverhead|, and
     160             :   // (2) at least |min_num_media_packets_| media packets is reached.
     161           0 :   if (complete_frame &&
     162           0 :       (num_protected_frames_ == params_.max_fec_frames ||
     163           0 :        (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
     164             :     // We are not using Unequal Protection feature of the parity erasure code.
     165           0 :     constexpr int kNumImportantPackets = 0;
     166           0 :     constexpr bool kUseUnequalProtection = false;
     167           0 :     int ret = fec_->EncodeFec(media_packets_, params_.fec_rate,
     168             :                               kNumImportantPackets, kUseUnequalProtection,
     169           0 :                               params_.fec_mask_type, &generated_fec_packets_);
     170           0 :     if (generated_fec_packets_.empty()) {
     171           0 :       ResetState();
     172             :     }
     173           0 :     return ret;
     174             :   }
     175           0 :   return 0;
     176             : }
     177             : 
     178           0 : bool UlpfecGenerator::ExcessOverheadBelowMax() const {
     179           0 :   return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
     180             : }
     181             : 
     182           0 : bool UlpfecGenerator::MinimumMediaPacketsReached() const {
     183             :   float average_num_packets_per_frame =
     184           0 :       static_cast<float>(media_packets_.size()) / num_protected_frames_;
     185           0 :   int num_media_packets = static_cast<int>(media_packets_.size());
     186           0 :   if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) {
     187           0 :     return num_media_packets >= min_num_media_packets_;
     188             :   } else {
     189             :     // For larger rates (more packets/frame), increase the threshold.
     190             :     // TODO(brandtr): Investigate what impact this adaptation has.
     191           0 :     return num_media_packets >= min_num_media_packets_ + 1;
     192             :   }
     193             : }
     194             : 
     195           0 : bool UlpfecGenerator::FecAvailable() const {
     196           0 :   return !generated_fec_packets_.empty();
     197             : }
     198             : 
     199           0 : size_t UlpfecGenerator::NumAvailableFecPackets() const {
     200           0 :   return generated_fec_packets_.size();
     201             : }
     202             : 
     203           0 : size_t UlpfecGenerator::MaxPacketOverhead() const {
     204           0 :   return fec_->MaxPacketOverhead();
     205             : }
     206             : 
     207           0 : std::vector<std::unique_ptr<RedPacket>> UlpfecGenerator::GetUlpfecPacketsAsRed(
     208             :     int red_payload_type,
     209             :     int ulpfec_payload_type,
     210             :     uint16_t first_seq_num,
     211             :     size_t rtp_header_length) {
     212           0 :   std::vector<std::unique_ptr<RedPacket>> red_packets;
     213           0 :   red_packets.reserve(generated_fec_packets_.size());
     214           0 :   RTC_DCHECK(!media_packets_.empty());
     215             :   ForwardErrorCorrection::Packet* last_media_packet =
     216           0 :       media_packets_.back().get();
     217           0 :   uint16_t seq_num = first_seq_num;
     218           0 :   for (const auto& fec_packet : generated_fec_packets_) {
     219             :     // Wrap FEC packet (including FEC headers) in a RED packet. Since the
     220             :     // FEC packets in |generated_fec_packets_| don't have RTP headers, we
     221             :     // reuse the header from the last media packet.
     222             :     std::unique_ptr<RedPacket> red_packet(new RedPacket(
     223           0 :         fec_packet->length + kRedForFecHeaderLength + rtp_header_length));
     224           0 :     red_packet->CreateHeader(last_media_packet->data, rtp_header_length,
     225           0 :                              red_payload_type, ulpfec_payload_type);
     226           0 :     red_packet->SetSeqNum(seq_num++);
     227           0 :     red_packet->ClearMarkerBit();
     228           0 :     red_packet->AssignPayload(fec_packet->data, fec_packet->length);
     229           0 :     red_packets.push_back(std::move(red_packet));
     230             :   }
     231             : 
     232           0 :   ResetState();
     233             : 
     234           0 :   return red_packets;
     235             : }
     236             : 
     237           0 : int UlpfecGenerator::Overhead() const {
     238           0 :   RTC_DCHECK(!media_packets_.empty());
     239             :   int num_fec_packets =
     240           0 :       fec_->NumFecPackets(media_packets_.size(), params_.fec_rate);
     241             :   // Return the overhead in Q8.
     242           0 :   return (num_fec_packets << 8) / media_packets_.size();
     243             : }
     244             : 
     245           0 : void UlpfecGenerator::ResetState() {
     246           0 :   media_packets_.clear();
     247           0 :   generated_fec_packets_.clear();
     248           0 :   num_protected_frames_ = 0;
     249           0 : }
     250             : 
     251             : }  // namespace webrtc

Generated by: LCOV version 1.13