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(¶ms_, 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