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

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

Powered by Google App Engine
This is Rietveld 408576698