Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(383)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/producer_fec.cc

Issue 2110763002: Style updates to ProducerFec/FecReceiver. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rename kNumPacketsPerFrameThresholdForMinNumMediaPacketsAdditiveAdaptation Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/modules/rtp_rtcp/source/producer_fec.h" 11 #include "webrtc/modules/rtp_rtcp/source/producer_fec.h"
12 12
13 #include "webrtc/base/basictypes.h"
14 #include "webrtc/base/checks.h"
13 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" 15 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
14 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" 16 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
15 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" 17 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
16 18
17 namespace webrtc { 19 namespace webrtc {
18 20
19 enum { kREDForFECHeaderLength = 1 }; 21 constexpr size_t kRedForFecHeaderLength = 1;
22
20 // This controls the maximum amount of excess overhead (actual - target) 23 // This controls the maximum amount of excess overhead (actual - target)
21 // allowed in order to trigger GenerateFec(), before |params_.max_fec_frames| 24 // 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. 25 // is reached. Overhead here is defined as relative to number of media packets.
23 enum { kMaxExcessOverhead = 50 }; // Q8. 26 constexpr int kMaxExcessOverhead = 50; // Q8.
27
24 // This is the minimum number of media packets required (above some protection 28 // 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 29 // level) in order to trigger GenerateFec(), before |params_.max_fec_frames| is
26 // reached. 30 // reached.
27 enum { kMinimumMediaPackets = 4 }; 31 constexpr size_t kMinMediaPackets = 4;
32
28 // Threshold on the received FEC protection level, above which we enforce at 33 // Threshold on the received FEC protection level, above which we enforce at
29 // least |kMinimumMediaPackets| packets for the FEC code. Below this 34 // least |kMinMediaPackets| packets for the FEC code. Below this
30 // threshold |kMinimumMediaPackets| is set to default value of 1. 35 // threshold |kMinMediaPackets| is set to default value of 1.
31 enum { kHighProtectionThreshold = 80 }; // Corresponds to ~30 overhead, range 36 //
32 // is 0 to 255, where 255 corresponds to 100% overhead (relative to number of 37 // The range is between 0 and 255, where 255 corresponds to 100% overhead
33 // media packets). 38 // (relative to the number of protected media packets).
39 constexpr uint8_t kHighProtectionThreshold = 80;
40
41 // This threshold is used to adapt the |kMinMediaPackets| threshold, based
42 // on the average number of packets per frame seen so far. When there are few
43 // packets per frame (as given by this threshold), at least
44 // |kMinMediaPackets| + 1 packets are sent to the FEC code.
45 constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f;
34 46
35 RedPacket::RedPacket(size_t length) 47 RedPacket::RedPacket(size_t length)
36 : data_(new uint8_t[length]), 48 : data_(new uint8_t[length]),
37 length_(length), 49 length_(length),
38 header_length_(0) { 50 header_length_(0) {
39 } 51 }
40 52
41 RedPacket::~RedPacket() {
42 delete [] data_;
43 }
44
45 void RedPacket::CreateHeader(const uint8_t* rtp_header, size_t header_length, 53 void RedPacket::CreateHeader(const uint8_t* rtp_header, size_t header_length,
46 int red_pl_type, int pl_type) { 54 int red_payload_type, int payload_type) {
47 assert(header_length + kREDForFECHeaderLength <= length_); 55 RTC_DCHECK_LT(header_length + kRedForFecHeaderLength, length_);
48 memcpy(data_, rtp_header, header_length); 56 memcpy(data_.get(), rtp_header, header_length);
49 // Replace payload type. 57 // Replace payload type.
50 data_[1] &= 0x80; 58 data_[1] &= 0x80;
51 data_[1] += red_pl_type; 59 data_[1] += red_payload_type;
52 // Add RED header 60 // Add RED header
53 // f-bit always 0 61 // f-bit always 0
54 data_[header_length] = static_cast<uint8_t>(pl_type); 62 data_[header_length] = static_cast<uint8_t>(payload_type);
55 header_length_ = header_length + kREDForFECHeaderLength; 63 header_length_ = header_length + kRedForFecHeaderLength;
56 } 64 }
57 65
58 void RedPacket::SetSeqNum(int seq_num) { 66 void RedPacket::SetSeqNum(int seq_num) {
59 assert(seq_num >= 0 && seq_num < (1<<16)); 67 RTC_DCHECK_GE(seq_num, 0);
68 RTC_DCHECK_LT(seq_num, 1<<16);
60 69
61 ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num); 70 ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num);
62 } 71 }
63 72
64 void RedPacket::AssignPayload(const uint8_t* payload, size_t length) { 73 void RedPacket::AssignPayload(const uint8_t* payload, size_t length) {
65 assert(header_length_ + length <= length_); 74 RTC_DCHECK_LE(header_length_ + length, length_);
66 memcpy(data_ + header_length_, payload, length); 75 memcpy(data_.get() + header_length_, payload, length);
67 } 76 }
68 77
69 void RedPacket::ClearMarkerBit() { 78 void RedPacket::ClearMarkerBit() {
70 data_[1] &= 0x7F; 79 data_[1] &= 0x7F;
71 } 80 }
72 81
73 uint8_t* RedPacket::data() const { 82 uint8_t* RedPacket::data() const {
74 return data_; 83 return data_.get();
75 } 84 }
76 85
77 size_t RedPacket::length() const { 86 size_t RedPacket::length() const {
78 return length_; 87 return length_;
79 } 88 }
80 89
81 ProducerFec::ProducerFec(ForwardErrorCorrection* fec) 90 ProducerFec::ProducerFec(ForwardErrorCorrection* fec)
82 : fec_(fec), 91 : fec_(fec),
83 media_packets_fec_(), 92 media_packets_(),
84 fec_packets_(), 93 generated_fec_packets_(),
85 num_frames_(0), 94 num_protected_frames_(0),
86 num_first_partition_(0), 95 num_important_packets_(0),
87 minimum_media_packets_fec_(1), 96 min_num_media_packets_(1),
88 params_(), 97 params_(),
89 new_params_() { 98 new_params_() {
90 memset(&params_, 0, sizeof(params_)); 99 memset(&params_, 0, sizeof(params_));
91 memset(&new_params_, 0, sizeof(new_params_)); 100 memset(&new_params_, 0, sizeof(new_params_));
92 } 101 }
93 102
94 ProducerFec::~ProducerFec() { 103 ProducerFec::~ProducerFec() {
95 DeletePackets(); 104 DeleteMediaPackets();
105 }
106
107 std::unique_ptr<RedPacket> ProducerFec::BuildRedPacket(
108 const uint8_t* data_buffer,
109 size_t payload_length,
110 size_t rtp_header_length,
111 int red_payload_type) {
112 std::unique_ptr<RedPacket> red_packet(
113 new RedPacket(payload_length + kRedForFecHeaderLength +
114 rtp_header_length));
115 int payload_type = data_buffer[1] & 0x7f;
116 red_packet->CreateHeader(data_buffer, rtp_header_length,
117 red_payload_type, payload_type);
118 red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
119 return red_packet;
96 } 120 }
97 121
98 void ProducerFec::SetFecParameters(const FecProtectionParams* params, 122 void ProducerFec::SetFecParameters(const FecProtectionParams* params,
99 int num_first_partition) { 123 int num_important_packets) {
100 // Number of first partition packets cannot exceed kMaxMediaPackets 124 // Number of important packets (i.e. number of packets receiving additional
101 assert(params->fec_rate >= 0 && params->fec_rate < 256); 125 // protection in 'unequal protection mode') cannot exceed kMaxMediaPackets.
102 if (num_first_partition > 126 RTC_DCHECK_GE(params->fec_rate, 0);
127 RTC_DCHECK_LE(params->fec_rate, 255);
128 if (num_important_packets >
103 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) { 129 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)) {
104 num_first_partition = 130 num_important_packets =
105 ForwardErrorCorrection::kMaxMediaPackets; 131 ForwardErrorCorrection::kMaxMediaPackets;
106 } 132 }
107 // Store the new params and apply them for the next set of FEC packets being 133 // Store the new params and apply them for the next set of FEC packets being
108 // produced. 134 // produced.
109 new_params_ = *params; 135 new_params_ = *params;
110 num_first_partition_ = num_first_partition; 136 num_important_packets_ = num_important_packets;
111 if (params->fec_rate > kHighProtectionThreshold) { 137 if (params->fec_rate > kHighProtectionThreshold) {
112 minimum_media_packets_fec_ = kMinimumMediaPackets; 138 min_num_media_packets_ = kMinMediaPackets;
113 } else { 139 } else {
114 minimum_media_packets_fec_ = 1; 140 min_num_media_packets_ = 1;
115 } 141 }
116 } 142 }
117 143
118 RedPacket* ProducerFec::BuildRedPacket(const uint8_t* data_buffer,
119 size_t payload_length,
120 size_t rtp_header_length,
121 int red_pl_type) {
122 RedPacket* red_packet = new RedPacket(
123 payload_length + kREDForFECHeaderLength + rtp_header_length);
124 int pl_type = data_buffer[1] & 0x7f;
125 red_packet->CreateHeader(data_buffer, rtp_header_length,
126 red_pl_type, pl_type);
127 red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
128 return red_packet;
129 }
130
131 int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer, 144 int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
132 size_t payload_length, 145 size_t payload_length,
133 size_t rtp_header_length) { 146 size_t rtp_header_length) {
134 assert(fec_packets_.empty()); 147 RTC_DCHECK(generated_fec_packets_.empty());
135 if (media_packets_fec_.empty()) { 148 if (media_packets_.empty()) {
136 params_ = new_params_; 149 params_ = new_params_;
137 } 150 }
138 bool complete_frame = false; 151 bool complete_frame = false;
139 const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false; 152 const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
140 if (media_packets_fec_.size() < ForwardErrorCorrection::kMaxMediaPackets) { 153 if (media_packets_.size() < ForwardErrorCorrection::kMaxMediaPackets) {
141 // Generic FEC can only protect up to kMaxMediaPackets packets. 154 // Generic FEC can only protect up to |kMaxMediaPackets| packets.
142 ForwardErrorCorrection::Packet* packet = 155 ForwardErrorCorrection::Packet* packet =
143 new ForwardErrorCorrection::Packet(); 156 new ForwardErrorCorrection::Packet();
144 packet->length = payload_length + rtp_header_length; 157 packet->length = payload_length + rtp_header_length;
145 memcpy(packet->data, data_buffer, packet->length); 158 memcpy(packet->data, data_buffer, packet->length);
146 media_packets_fec_.push_back(packet); 159 media_packets_.push_back(packet);
147 } 160 }
148 if (marker_bit) { 161 if (marker_bit) {
149 ++num_frames_; 162 ++num_protected_frames_;
150 complete_frame = true; 163 complete_frame = true;
151 } 164 }
152 // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as: 165 // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
153 // (1) the excess overhead (actual overhead - requested/target overhead) is 166 // (1) the excess overhead (actual overhead - requested/target overhead) is
154 // less than |kMaxExcessOverhead|, and 167 // less than |kMaxExcessOverhead|, and
155 // (2) at least |minimum_media_packets_fec_| media packets is reached. 168 // (2) at least |min_num_media_packets_| media packets is reached.
156 if (complete_frame && 169 if (complete_frame &&
157 (num_frames_ == params_.max_fec_frames || 170 (num_protected_frames_ == params_.max_fec_frames ||
158 (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) { 171 (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
159 assert(num_first_partition_ <= 172 RTC_DCHECK_LE(num_important_packets_,
160 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets)); 173 static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
161 // TODO(pbos): Consider whether unequal protection should be enabled or not, 174 // TODO(pbos): Consider whether unequal protection should be enabled or not,
162 // it is currently always disabled. 175 // it is currently always disabled.
163 int ret = fec_->GenerateFec(media_packets_fec_, params_.fec_rate, 176 constexpr bool kUseUnequalProtection = false;
164 num_first_partition_, false, 177 // TODO(brandtr): The fact above means that the value of
danilchap 2016/07/19 14:55:32 set a goal or remove TODO() prefix in the comment.
brandtr 2016/07/21 09:03:58 Done.
165 params_.fec_mask_type, &fec_packets_); 178 // |num_important_packets_| has no importance when calling GenerateFec().
166 if (fec_packets_.empty()) { 179 int ret = fec_->GenerateFec(media_packets_, params_.fec_rate,
167 num_frames_ = 0; 180 num_important_packets_, kUseUnequalProtection,
168 DeletePackets(); 181 params_.fec_mask_type, &generated_fec_packets_);
182 if (generated_fec_packets_.empty()) {
183 num_protected_frames_ = 0;
184 DeleteMediaPackets();
169 } 185 }
170 return ret; 186 return ret;
171 } 187 }
172 return 0; 188 return 0;
173 } 189 }
174 190
175 // Returns true if the excess overhead (actual - target) for the FEC is below 191 bool ProducerFec::ExcessOverheadBelowMax() const {
176 // the amount |kMaxExcessOverhead|. This effects the lower protection level
177 // cases and low number of media packets/frame. The target overhead is given by
178 // |params_.fec_rate|, and is only achievable in the limit of large number of
179 // media packets.
180 bool ProducerFec::ExcessOverheadBelowMax() {
181 return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead); 192 return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
182 } 193 }
183 194
184 // Returns true if the media packet list for the FEC is at least 195 bool ProducerFec::MinimumMediaPacketsReached() const {
185 // |minimum_media_packets_fec_|. This condition tries to capture the effect 196 float num_media_packets = static_cast<float>(media_packets_.size());
186 // that, for the same amount of protection/overhead, longer codes 197 float average_num_packets_per_frame = num_media_packets/num_protected_frames_;
danilchap 2016/07/19 14:55:32 add spaces around operator / (e.g. by running git
brandtr 2016/07/21 09:03:58 Done.
187 // (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses. 198 if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) {
188 bool ProducerFec::MinimumMediaPacketsReached() { 199 return (num_media_packets >= min_num_media_packets_);
danilchap 2016/07/19 14:55:32 instead of return (something); write return someth
brandtr 2016/07/21 09:03:58 Fixed!
189 float avg_num_packets_frame = static_cast<float>(media_packets_fec_.size()) /
190 num_frames_;
191 if (avg_num_packets_frame < 2.0f) {
192 return (static_cast<int>(media_packets_fec_.size()) >=
193 minimum_media_packets_fec_);
194 } else { 200 } else {
195 // For larger rates (more packets/frame), increase the threshold. 201 // For larger rates (more packets/frame), increase the threshold.
196 return (static_cast<int>(media_packets_fec_.size()) >= 202 // TODO(brandtr): Investigate what impact this adaptation has.
197 minimum_media_packets_fec_ + 1); 203 return (num_media_packets >= min_num_media_packets_ + 1);
danilchap 2016/07/19 14:55:32 same here. (both about () and float vs int)
brandtr 2016/07/21 09:03:58 Done.
198 } 204 }
199 } 205 }
200 206
201 bool ProducerFec::FecAvailable() const { 207 bool ProducerFec::FecAvailable() const {
202 return !fec_packets_.empty(); 208 return !generated_fec_packets_.empty();
203 } 209 }
204 210
205 size_t ProducerFec::NumAvailableFecPackets() const { 211 size_t ProducerFec::NumAvailableFecPackets() const {
206 return fec_packets_.size(); 212 return generated_fec_packets_.size();
207 } 213 }
208 214
209 std::vector<RedPacket*> ProducerFec::GetFecPackets(int red_pl_type, 215 std::vector<std::unique_ptr<RedPacket>> ProducerFec::GetFecPacketsAsRed(
210 int fec_pl_type, 216 int red_payload_type,
211 uint16_t first_seq_num, 217 int ulpfec_payload_type,
212 size_t rtp_header_length) { 218 uint16_t first_seq_num,
213 std::vector<RedPacket*> fec_packets; 219 size_t rtp_header_length) {
214 fec_packets.reserve(fec_packets_.size()); 220 std::vector<std::unique_ptr<RedPacket>> red_packets;
215 uint16_t sequence_number = first_seq_num; 221 red_packets.reserve(generated_fec_packets_.size());
216 while (!fec_packets_.empty()) { 222 RTC_DCHECK(!media_packets_.empty());
217 // Build FEC packet. The FEC packets in |fec_packets_| doesn't 223 ForwardErrorCorrection::Packet* last_media_packet = media_packets_.back();
218 // have RTP headers, so we're reusing the header from the last 224 uint16_t seq_num = first_seq_num;
219 // media packet. 225 for (const auto& fec_packet : generated_fec_packets_) {
220 ForwardErrorCorrection::Packet* packet_to_send = fec_packets_.front(); 226 // Wrap FEC packet (including FEC headers) in a RED packet. Since the
221 ForwardErrorCorrection::Packet* last_media_packet = 227 // FEC packets in |generated_fec_packets_| don't have RTP headers, we
222 media_packets_fec_.back(); 228 // reuse the header from the last media packet.
229 std::unique_ptr<RedPacket> red_packet(new RedPacket(
230 fec_packet->length + kRedForFecHeaderLength + rtp_header_length));
231 red_packet->CreateHeader(last_media_packet->data, rtp_header_length,
232 red_payload_type, ulpfec_payload_type);
233 red_packet->SetSeqNum(seq_num++);
234 red_packet->ClearMarkerBit();
235 red_packet->AssignPayload(fec_packet->data, fec_packet->length);
223 236
224 RedPacket* red_packet = new RedPacket( 237 red_packets.push_back(std::move(red_packet));
225 packet_to_send->length + kREDForFECHeaderLength + rtp_header_length); 238 }
226 red_packet->CreateHeader(last_media_packet->data, rtp_header_length,
227 red_pl_type, fec_pl_type);
228 red_packet->SetSeqNum(sequence_number++);
229 red_packet->ClearMarkerBit();
230 red_packet->AssignPayload(packet_to_send->data, packet_to_send->length);
231 239
232 fec_packets.push_back(red_packet); 240 // Reset state.
241 DeleteMediaPackets();
242 generated_fec_packets_.clear();
243 num_protected_frames_ = 0;
233 244
234 fec_packets_.pop_front(); 245 return red_packets;
235 }
236 DeletePackets();
237 num_frames_ = 0;
238 return fec_packets;
239 } 246 }
240 247
241 int ProducerFec::Overhead() const { 248 int ProducerFec::Overhead() const {
242 // Overhead is defined as relative to the number of media packets, and not 249 // Overhead is defined as relative to the number of media packets, and not
243 // relative to total number of packets. This definition is inhereted from the 250 // relative to total number of packets. This definition is inherited from the
244 // protection factor produced by video_coding module and how the FEC 251 // protection factor produced by video_coding module and how the FEC
245 // generation is implemented. 252 // generation is implemented.
246 assert(!media_packets_fec_.empty()); 253 RTC_DCHECK(!media_packets_.empty());
247 int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_fec_.size(), 254 int num_fec_packets = fec_->GetNumberOfFecPackets(media_packets_.size(),
248 params_.fec_rate); 255 params_.fec_rate);
249 // Return the overhead in Q8. 256 // Return the overhead in Q8.
250 return (num_fec_packets << 8) / media_packets_fec_.size(); 257 return (num_fec_packets << 8) / media_packets_.size();
251 } 258 }
252 259
253 void ProducerFec::DeletePackets() { 260 void ProducerFec::DeleteMediaPackets() {
254 while (!media_packets_fec_.empty()) { 261 while (!media_packets_.empty()) {
255 delete media_packets_fec_.front(); 262 delete media_packets_.front();
256 media_packets_fec_.pop_front(); 263 media_packets_.pop_front();
257 } 264 }
258 assert(media_packets_fec_.empty()); 265 RTC_DCHECK(media_packets_.empty());
259 } 266 }
260 267
261 } // namespace webrtc 268 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698