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
RedPacket(size_t length)40 RedPacket::RedPacket(size_t length)
41 : data_(new uint8_t[length]),
42 length_(length),
43 header_length_(0) {
44 }
45
~RedPacket()46 RedPacket::~RedPacket() {
47 delete [] data_;
48 }
49
CreateHeader(const uint8_t * rtp_header,size_t header_length,int red_pl_type,int pl_type)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
SetSeqNum(int seq_num)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
AssignPayload(const uint8_t * payload,size_t length)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
ClearMarkerBit()74 void RedPacket::ClearMarkerBit() {
75 data_[1] &= 0x7F;
76 }
77
data() const78 uint8_t* RedPacket::data() const {
79 return data_;
80 }
81
length() const82 size_t RedPacket::length() const {
83 return length_;
84 }
85
ProducerFec(ForwardErrorCorrection * fec)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
~ProducerFec()99 ProducerFec::~ProducerFec() {
100 DeletePackets();
101 }
102
SetFecParameters(const FecProtectionParams * params,int num_first_partition)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
BuildRedPacket(const uint8_t * data_buffer,size_t payload_length,size_t rtp_header_length,int red_pl_type)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
AddRtpPacketAndGenerateFec(const uint8_t * data_buffer,size_t payload_length,size_t rtp_header_length)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.
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_.empty();
208 }
209
NumAvailableFecPackets() const210 size_t ProducerFec::NumAvailableFecPackets() const {
211 return fec_packets_.size();
212 }
213
GetFecPackets(int red_pl_type,int fec_pl_type,uint16_t first_seq_num,size_t rtp_header_length)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
Overhead() const246 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
DeletePackets()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