Home | History | Annotate | Download | only in source
      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/producer_fec.h"
     12 
     13 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
     14 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
     15 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
     16 
     17 namespace webrtc {
     18 
     19 enum { kREDForFECHeaderLength = 1 };
     20 // This controls the maximum amount of excess overhead (actual - target)
     21 // allowed in order to trigger GenerateFEC(), before |params_.max_fec_frames|
     22 // is reached. Overhead here is defined as relative to number of media packets.
     23 enum { kMaxExcessOverhead = 50 };  // Q8.
     24 // This is the minimum number of media packets required (above some protection
     25 // level) in order to trigger GenerateFEC(), before |params_.max_fec_frames| is
     26 // reached.
     27 enum { kMinimumMediaPackets = 4 };
     28 // Threshold on the received FEC protection level, above which we enforce at
     29 // least |kMinimumMediaPackets| packets for the FEC code. Below this
     30 // threshold |kMinimumMediaPackets| is set to default value of 1.
     31 enum { kHighProtectionThreshold = 80 };  // Corresponds to ~30 overhead, range
     32 // is 0 to 255, where 255 corresponds to 100% overhead (relative to number of
     33 // media packets).
     34 
     35 struct RtpPacket {
     36   uint16_t rtpHeaderLength;
     37   ForwardErrorCorrection::Packet* pkt;
     38 };
     39 
     40 RedPacket::RedPacket(size_t length)
     41     : data_(new uint8_t[length]),
     42       length_(length),
     43       header_length_(0) {
     44 }
     45 
     46 RedPacket::~RedPacket() {
     47   delete [] data_;
     48 }
     49 
     50 void RedPacket::CreateHeader(const uint8_t* rtp_header, size_t header_length,
     51                              int red_pl_type, int pl_type) {
     52   assert(header_length + kREDForFECHeaderLength <= length_);
     53   memcpy(data_, rtp_header, header_length);
     54   // Replace payload type.
     55   data_[1] &= 0x80;
     56   data_[1] += red_pl_type;
     57   // Add RED header
     58   // f-bit always 0
     59   data_[header_length] = static_cast<uint8_t>(pl_type);
     60   header_length_ = header_length + kREDForFECHeaderLength;
     61 }
     62 
     63 void RedPacket::SetSeqNum(int seq_num) {
     64   assert(seq_num >= 0 && seq_num < (1<<16));
     65 
     66   ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num);
     67 }
     68 
     69 void RedPacket::AssignPayload(const uint8_t* payload, size_t length) {
     70   assert(header_length_ + length <= length_);
     71   memcpy(data_ + header_length_, payload, length);
     72 }
     73 
     74 void RedPacket::ClearMarkerBit() {
     75   data_[1] &= 0x7F;
     76 }
     77 
     78 uint8_t* RedPacket::data() const {
     79   return data_;
     80 }
     81 
     82 size_t RedPacket::length() const {
     83   return length_;
     84 }
     85 
     86 ProducerFec::ProducerFec(ForwardErrorCorrection* fec)
     87     : fec_(fec),
     88       media_packets_fec_(),
     89       fec_packets_(),
     90       num_frames_(0),
     91       num_first_partition_(0),
     92       minimum_media_packets_fec_(1),
     93       params_(),
     94       new_params_() {
     95   memset(&params_, 0, sizeof(params_));
     96   memset(&new_params_, 0, sizeof(new_params_));
     97 }
     98 
     99 ProducerFec::~ProducerFec() {
    100   DeletePackets();
    101 }
    102 
    103 void ProducerFec::SetFecParameters(const FecProtectionParams* params,
    104                                    int num_first_partition) {
    105   // Number of first partition packets cannot exceed kMaxMediaPackets
    106   assert(params->fec_rate >= 0 && params->fec_rate < 256);
    107   if (num_first_partition >
    108       static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) {
    109       num_first_partition =
    110           ForwardErrorCorrection::kMaxMediaPackets;
    111   }
    112   // Store the new params and apply them for the next set of FEC packets being
    113   // produced.
    114   new_params_ = *params;
    115   num_first_partition_ = num_first_partition;
    116   if (params->fec_rate > kHighProtectionThreshold) {
    117     minimum_media_packets_fec_ = kMinimumMediaPackets;
    118   } else {
    119     minimum_media_packets_fec_ = 1;
    120   }
    121 }
    122 
    123 RedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer,
    124                                        size_t payload_length,
    125                                        size_t rtp_header_length,
    126                                        int red_pl_type) {
    127   RedPacket* red_packet = new RedPacket(
    128       payload_length + kREDForFECHeaderLength + rtp_header_length);
    129   int pl_type = data_buffer[1] & 0x7f;
    130   red_packet->CreateHeader(data_buffer, rtp_header_length,
    131                            red_pl_type, pl_type);
    132   red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
    133   return red_packet;
    134 }
    135 
    136 int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
    137                                             size_t payload_length,
    138                                             size_t rtp_header_length) {
    139   assert(fec_packets_.empty());
    140   if (media_packets_fec_.empty()) {
    141     params_ = new_params_;
    142   }
    143   bool complete_frame = false;
    144   const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
    145   if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
    146     // Generic FEC can only protect up to kMaxMediaPackets packets.
    147     ForwardErrorCorrection::Packet* packet = new ForwardErrorCorrection::Packet;
    148     packet->length = payload_length + rtp_header_length;
    149     memcpy(packet->data, data_buffer, packet->length);
    150     media_packets_fec_.push_back(packet);
    151   }
    152   if (marker_bit) {
    153     ++num_frames_;
    154     complete_frame = true;
    155   }
    156   // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
    157   // (1) the excess overhead (actual overhead - requested/target overhead) is
    158   // less than |kMaxExcessOverhead|, and
    159   // (2) at least |minimum_media_packets_fec_| media packets is reached.
    160   if (complete_frame &&
    161       (num_frames_ == params_.max_fec_frames ||
    162           (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
    163     assert(num_first_partition_ <=
    164            static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
    165     int ret = fec_->GenerateFEC(media_packets_fec_,
    166                                 params_.fec_rate,
    167                                 num_first_partition_,
    168                                 params_.use_uep_protection,
    169                                 params_.fec_mask_type,
    170                                 &fec_packets_);
    171     if (fec_packets_.empty()) {
    172       num_frames_ = 0;
    173       DeletePackets();
    174     }
    175     return ret;
    176   }
    177   return 0;
    178 }
    179 
    180 // Returns true if the excess overhead (actual - target) for the FEC is below
    181 // the amount |kMaxExcessOverhead|. This effects the lower protection level
    182 // cases and low number of media packets/frame. The target overhead is given by
    183 // |params_.fec_rate|, and is only achievable in the limit of large number of
    184 // media packets.
    185 bool ProducerFec::ExcessOverheadBelowMax() {
    186   return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
    187 }
    188 
    189 // Returns true if the media packet list for the FEC is at least
    190 // |minimum_media_packets_fec_|. This condition tries to capture the effect
    191 // that, for the same amount of protection/overhead, longer codes
    192 // (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses.
    193 bool ProducerFec::MinimumMediaPacketsReached() {
    194   float avg_num_packets_frame = static_cast<float>(media_packets_fec_.size()) /
    195                                 num_frames_;
    196   if (avg_num_packets_frame < 2.0f) {
    197   return (static_cast<int>(media_packets_fec_.size()) >=
    198       minimum_media_packets_fec_);
    199   } else {
    200     // For larger rates (more packets/frame), increase the threshold.
    201     return (static_cast<int>(media_packets_fec_.size()) >=
    202         minimum_media_packets_fec_ + 1);
    203   }
    204 }
    205 
    206 bool ProducerFec::FecAvailable() const {
    207   return !fec_packets_.empty();
    208 }
    209 
    210 size_t ProducerFec::NumAvailableFecPackets() const {
    211   return fec_packets_.size();
    212 }
    213 
    214 std::vector<RedPacket*> ProducerFec::GetFecPackets(int red_pl_type,
    215                                                    int fec_pl_type,
    216                                                    uint16_t first_seq_num,
    217                                                    size_t rtp_header_length) {
    218   std::vector<RedPacket*> fec_packets;
    219   fec_packets.reserve(fec_packets_.size());
    220   uint16_t sequence_number = first_seq_num;
    221   while (!fec_packets_.empty()) {
    222     // Build FEC packet. The FEC packets in |fec_packets_| doesn't
    223     // have RTP headers, so we're reusing the header from the last
    224     // media packet.
    225     ForwardErrorCorrection::Packet* packet_to_send = fec_packets_.front();
    226     ForwardErrorCorrection::Packet* last_media_packet =
    227         media_packets_fec_.back();
    228 
    229     RedPacket* red_packet = new RedPacket(
    230         packet_to_send->length + kREDForFECHeaderLength + rtp_header_length);
    231     red_packet->CreateHeader(last_media_packet->data, rtp_header_length,
    232                              red_pl_type, fec_pl_type);
    233     red_packet->SetSeqNum(sequence_number++);
    234     red_packet->ClearMarkerBit();
    235     red_packet->AssignPayload(packet_to_send->data, packet_to_send->length);
    236 
    237     fec_packets.push_back(red_packet);
    238 
    239     fec_packets_.pop_front();
    240   }
    241   DeletePackets();
    242   num_frames_ = 0;
    243   return fec_packets;
    244 }
    245 
    246 int ProducerFec::Overhead() const {
    247   // Overhead is defined as relative to the number of media packets, and not
    248   // relative to total number of packets. This definition is inhereted from the
    249   // protection factor produced by video_coding module and how the FEC
    250   // generation is implemented.
    251   assert(!media_packets_fec_.empty());
    252   int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_fec_.size(),
    253                                                     params_.fec_rate);
    254   // Return the overhead in Q8.
    255   return (num_fec_packets << 8) / media_packets_fec_.size();
    256 }
    257 
    258 void ProducerFec::DeletePackets() {
    259   while (!media_packets_fec_.empty()) {
    260     delete media_packets_fec_.front();
    261     media_packets_fec_.pop_front();
    262   }
    263   assert(media_packets_fec_.empty());
    264 }
    265 
    266 }  // namespace webrtc
    267