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/forward_error_correction.h" 14 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" 15 16 namespace webrtc { 17 18 enum { kREDForFECHeaderLength = 1 }; 19 // This controls the maximum amount of excess overhead (actual - target) 20 // allowed in order to trigger GenerateFEC(), before |params_.max_fec_frames| 21 // is reached. Overhead here is defined as relative to number of media packets. 22 enum { kMaxExcessOverhead = 50 }; // Q8. 23 // This is the minimum number of media packets required (above some protection 24 // level) in order to trigger GenerateFEC(), before |params_.max_fec_frames| is 25 // reached. 26 enum { kMinimumMediaPackets = 4 }; 27 // Threshold on the received FEC protection level, above which we enforce at 28 // least |kMinimumMediaPackets| packets for the FEC code. Below this 29 // threshold |kMinimumMediaPackets| is set to default value of 1. 30 enum { kHighProtectionThreshold = 80 }; // Corresponds to ~30 overhead, range 31 // is 0 to 255, where 255 corresponds to 100% overhead (relative to number of 32 // media packets). 33 34 struct RtpPacket { 35 uint16_t rtpHeaderLength; 36 ForwardErrorCorrection::Packet* pkt; 37 }; 38 39 RedPacket::RedPacket(int length) 40 : data_(new uint8_t[length]), 41 length_(length), 42 header_length_(0) { 43 } 44 45 RedPacket::~RedPacket() { 46 delete [] data_; 47 } 48 49 void RedPacket::CreateHeader(const uint8_t* rtp_header, int header_length, 50 int red_pl_type, int pl_type) { 51 assert(header_length + kREDForFECHeaderLength <= length_); 52 memcpy(data_, rtp_header, header_length); 53 // Replace payload type. 54 data_[1] &= 0x80; 55 data_[1] += red_pl_type; 56 // Add RED header 57 // f-bit always 0 58 data_[header_length] = pl_type; 59 header_length_ = header_length + kREDForFECHeaderLength; 60 } 61 62 void RedPacket::SetSeqNum(int seq_num) { 63 assert(seq_num >= 0 && seq_num < (1<<16)); 64 ModuleRTPUtility::AssignUWord16ToBuffer(&data_[2], seq_num); 65 } 66 67 void RedPacket::AssignPayload(const uint8_t* payload, int length) { 68 assert(header_length_ + length <= length_); 69 memcpy(data_ + header_length_, payload, length); 70 } 71 72 void RedPacket::ClearMarkerBit() { 73 data_[1] &= 0x7F; 74 } 75 76 uint8_t* RedPacket::data() const { 77 return data_; 78 } 79 80 int RedPacket::length() const { 81 return length_; 82 } 83 84 ProducerFec::ProducerFec(ForwardErrorCorrection* fec) 85 : fec_(fec), 86 media_packets_fec_(), 87 fec_packets_(), 88 num_frames_(0), 89 incomplete_frame_(false), 90 num_first_partition_(0), 91 minimum_media_packets_fec_(1), 92 params_(), 93 new_params_() { 94 memset(¶ms_, 0, sizeof(params_)); 95 memset(&new_params_, 0, sizeof(new_params_)); 96 } 97 98 ProducerFec::~ProducerFec() { 99 DeletePackets(); 100 } 101 102 void ProducerFec::SetFecParameters(const FecProtectionParams* params, 103 int num_first_partition) { 104 // Number of first partition packets cannot exceed kMaxMediaPackets 105 assert(params->fec_rate >= 0 && params->fec_rate < 256); 106 if (num_first_partition > 107 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) { 108 num_first_partition = 109 ForwardErrorCorrection::kMaxMediaPackets; 110 } 111 // Store the new params and apply them for the next set of FEC packets being 112 // produced. 113 new_params_ = *params; 114 num_first_partition_ = num_first_partition; 115 if (params->fec_rate > kHighProtectionThreshold) { 116 minimum_media_packets_fec_ = kMinimumMediaPackets; 117 } else { 118 minimum_media_packets_fec_ = 1; 119 } 120 } 121 122 RedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer, 123 int payload_length, 124 int rtp_header_length, 125 int red_pl_type) { 126 RedPacket* red_packet = new RedPacket(payload_length + 127 kREDForFECHeaderLength + 128 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 int payload_length, 138 int rtp_header_length) { 139 assert(fec_packets_.empty()); 140 if (media_packets_fec_.empty()) { 141 params_ = new_params_; 142 } 143 incomplete_frame_ = true; 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 incomplete_frame_ = false; 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 (!incomplete_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_.size() > 0); 208 } 209 210 RedPacket* ProducerFec::GetFecPacket(int red_pl_type, 211 int fec_pl_type, 212 uint16_t seq_num, 213 int rtp_header_length) { 214 if (fec_packets_.empty()) 215 return NULL; 216 // Build FEC packet. The FEC packets in |fec_packets_| doesn't 217 // have RTP headers, so we're reusing the header from the last 218 // media packet. 219 ForwardErrorCorrection::Packet* packet_to_send = fec_packets_.front(); 220 ForwardErrorCorrection::Packet* last_media_packet = media_packets_fec_.back(); 221 RedPacket* return_packet = new RedPacket(packet_to_send->length + 222 kREDForFECHeaderLength + 223 rtp_header_length); 224 return_packet->CreateHeader(last_media_packet->data, 225 rtp_header_length, 226 red_pl_type, 227 fec_pl_type); 228 return_packet->SetSeqNum(seq_num); 229 return_packet->ClearMarkerBit(); 230 return_packet->AssignPayload(packet_to_send->data, packet_to_send->length); 231 fec_packets_.pop_front(); 232 if (fec_packets_.empty()) { 233 // Done with all the FEC packets. Reset for next run. 234 DeletePackets(); 235 num_frames_ = 0; 236 } 237 return return_packet; 238 } 239 240 int ProducerFec::Overhead() const { 241 // Overhead is defined as relative to the number of media packets, and not 242 // relative to total number of packets. This definition is inhereted from the 243 // protection factor produced by video_coding module and how the FEC 244 // generation is implemented. 245 assert(!media_packets_fec_.empty()); 246 int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_fec_.size(), 247 params_.fec_rate); 248 // Return the overhead in Q8. 249 return (num_fec_packets << 8) / media_packets_fec_.size(); 250 } 251 252 void ProducerFec::DeletePackets() { 253 while (!media_packets_fec_.empty()) { 254 delete media_packets_fec_.front(); 255 media_packets_fec_.pop_front(); 256 } 257 assert(media_packets_fec_.empty()); 258 } 259 260 } // namespace webrtc 261