• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RedPacket(int length)39 RedPacket::RedPacket(int length)
40     : data_(new uint8_t[length]),
41       length_(length),
42       header_length_(0) {
43 }
44 
~RedPacket()45 RedPacket::~RedPacket() {
46   delete [] data_;
47 }
48 
CreateHeader(const uint8_t * rtp_header,int header_length,int red_pl_type,int pl_type)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 
SetSeqNum(int seq_num)62 void RedPacket::SetSeqNum(int seq_num) {
63   assert(seq_num >= 0 && seq_num < (1<<16));
64   RtpUtility::AssignUWord16ToBuffer(&data_[2], seq_num);
65 }
66 
AssignPayload(const uint8_t * payload,int length)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 
ClearMarkerBit()72 void RedPacket::ClearMarkerBit() {
73   data_[1] &= 0x7F;
74 }
75 
data() const76 uint8_t* RedPacket::data() const {
77   return data_;
78 }
79 
length() const80 int RedPacket::length() const {
81   return length_;
82 }
83 
ProducerFec(ForwardErrorCorrection * fec)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(&params_, 0, sizeof(params_));
95   memset(&new_params_, 0, sizeof(new_params_));
96 }
97 
~ProducerFec()98 ProducerFec::~ProducerFec() {
99   DeletePackets();
100 }
101 
SetFecParameters(const FecProtectionParams * params,int num_first_partition)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 
BuildRedPacket(const uint8_t * data_buffer,int payload_length,int rtp_header_length,int red_pl_type)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 
AddRtpPacketAndGenerateFec(const uint8_t * data_buffer,int payload_length,int rtp_header_length)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.
ExcessOverheadBelowMax()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.
MinimumMediaPacketsReached()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 
FecAvailable() const206 bool ProducerFec::FecAvailable() const {
207   return (fec_packets_.size() > 0);
208 }
209 
GetFecPacket(int red_pl_type,int fec_pl_type,uint16_t seq_num,int rtp_header_length)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 
Overhead() const240 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 
DeletePackets()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