Line data Source code
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/ulpfec_generator.h"
12 :
13 : #include <memory>
14 : #include <utility>
15 :
16 : #include "webrtc/base/basictypes.h"
17 : #include "webrtc/base/checks.h"
18 : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
19 : #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
20 : #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
21 :
22 : namespace webrtc {
23 :
24 : namespace {
25 :
26 : constexpr size_t kRedForFecHeaderLength = 1;
27 :
28 : // This controls the maximum amount of excess overhead (actual - target)
29 : // allowed in order to trigger EncodeFec(), before |params_.max_fec_frames|
30 : // is reached. Overhead here is defined as relative to number of media packets.
31 : constexpr int kMaxExcessOverhead = 50; // Q8.
32 :
33 : // This is the minimum number of media packets required (above some protection
34 : // level) in order to trigger EncodeFec(), before |params_.max_fec_frames| is
35 : // reached.
36 : constexpr size_t kMinMediaPackets = 4;
37 :
38 : // Threshold on the received FEC protection level, above which we enforce at
39 : // least |kMinMediaPackets| packets for the FEC code. Below this
40 : // threshold |kMinMediaPackets| is set to default value of 1.
41 : //
42 : // The range is between 0 and 255, where 255 corresponds to 100% overhead
43 : // (relative to the number of protected media packets).
44 : constexpr uint8_t kHighProtectionThreshold = 80;
45 :
46 : // This threshold is used to adapt the |kMinMediaPackets| threshold, based
47 : // on the average number of packets per frame seen so far. When there are few
48 : // packets per frame (as given by this threshold), at least
49 : // |kMinMediaPackets| + 1 packets are sent to the FEC code.
50 : constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f;
51 :
52 : } // namespace
53 :
54 0 : RedPacket::RedPacket(size_t length)
55 0 : : data_(new uint8_t[length]), length_(length), header_length_(0) {}
56 :
57 0 : void RedPacket::CreateHeader(const uint8_t* rtp_header,
58 : size_t header_length,
59 : int red_payload_type,
60 : int payload_type) {
61 0 : RTC_DCHECK_LE(header_length + kRedForFecHeaderLength, length_);
62 0 : memcpy(data_.get(), rtp_header, header_length);
63 : // Replace payload type.
64 0 : data_[1] &= 0x80;
65 0 : data_[1] += red_payload_type;
66 : // Add RED header
67 : // f-bit always 0
68 0 : data_[header_length] = static_cast<uint8_t>(payload_type);
69 0 : header_length_ = header_length + kRedForFecHeaderLength;
70 0 : }
71 :
72 0 : void RedPacket::SetSeqNum(int seq_num) {
73 0 : RTC_DCHECK_GE(seq_num, 0);
74 0 : RTC_DCHECK_LT(seq_num, 1 << 16);
75 :
76 0 : ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num);
77 0 : }
78 :
79 0 : void RedPacket::AssignPayload(const uint8_t* payload, size_t length) {
80 0 : RTC_DCHECK_LE(header_length_ + length, length_);
81 0 : memcpy(data_.get() + header_length_, payload, length);
82 0 : }
83 :
84 0 : void RedPacket::ClearMarkerBit() {
85 0 : data_[1] &= 0x7F;
86 0 : }
87 :
88 0 : uint8_t* RedPacket::data() const {
89 0 : return data_.get();
90 : }
91 :
92 0 : size_t RedPacket::length() const {
93 0 : return length_;
94 : }
95 :
96 0 : UlpfecGenerator::UlpfecGenerator()
97 0 : : UlpfecGenerator(ForwardErrorCorrection::CreateUlpfec()) {}
98 :
99 0 : UlpfecGenerator::UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec)
100 0 : : fec_(std::move(fec)),
101 : num_protected_frames_(0),
102 0 : min_num_media_packets_(1) {
103 0 : memset(¶ms_, 0, sizeof(params_));
104 0 : memset(&new_params_, 0, sizeof(new_params_));
105 0 : }
106 :
107 : UlpfecGenerator::~UlpfecGenerator() = default;
108 :
109 0 : std::unique_ptr<RedPacket> UlpfecGenerator::BuildRedPacket(
110 : const uint8_t* data_buffer,
111 : size_t payload_length,
112 : size_t rtp_header_length,
113 : int red_payload_type) {
114 : std::unique_ptr<RedPacket> red_packet(new RedPacket(
115 0 : payload_length + kRedForFecHeaderLength + rtp_header_length));
116 0 : int payload_type = data_buffer[1] & 0x7f;
117 0 : red_packet->CreateHeader(data_buffer, rtp_header_length, red_payload_type,
118 0 : payload_type);
119 0 : red_packet->AssignPayload(data_buffer + rtp_header_length, payload_length);
120 0 : return red_packet;
121 : }
122 :
123 0 : void UlpfecGenerator::SetFecParameters(const FecProtectionParams& params) {
124 0 : RTC_DCHECK_GE(params.fec_rate, 0);
125 0 : RTC_DCHECK_LE(params.fec_rate, 255);
126 : // Store the new params and apply them for the next set of FEC packets being
127 : // produced.
128 0 : new_params_ = params;
129 0 : if (params.fec_rate > kHighProtectionThreshold) {
130 0 : min_num_media_packets_ = kMinMediaPackets;
131 : } else {
132 0 : min_num_media_packets_ = 1;
133 : }
134 0 : }
135 :
136 0 : int UlpfecGenerator::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
137 : size_t payload_length,
138 : size_t rtp_header_length) {
139 0 : RTC_DCHECK(generated_fec_packets_.empty());
140 0 : if (media_packets_.empty()) {
141 0 : params_ = new_params_;
142 : }
143 0 : bool complete_frame = false;
144 0 : const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
145 0 : if (media_packets_.size() < kUlpfecMaxMediaPackets) {
146 : // Our packet masks can only protect up to |kUlpfecMaxMediaPackets| packets.
147 : std::unique_ptr<ForwardErrorCorrection::Packet> packet(
148 0 : new ForwardErrorCorrection::Packet());
149 0 : packet->length = payload_length + rtp_header_length;
150 0 : memcpy(packet->data, data_buffer, packet->length);
151 0 : media_packets_.push_back(std::move(packet));
152 : }
153 0 : if (marker_bit) {
154 0 : ++num_protected_frames_;
155 0 : complete_frame = true;
156 : }
157 : // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
158 : // (1) the excess overhead (actual overhead - requested/target overhead) is
159 : // less than |kMaxExcessOverhead|, and
160 : // (2) at least |min_num_media_packets_| media packets is reached.
161 0 : if (complete_frame &&
162 0 : (num_protected_frames_ == params_.max_fec_frames ||
163 0 : (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
164 : // We are not using Unequal Protection feature of the parity erasure code.
165 0 : constexpr int kNumImportantPackets = 0;
166 0 : constexpr bool kUseUnequalProtection = false;
167 0 : int ret = fec_->EncodeFec(media_packets_, params_.fec_rate,
168 : kNumImportantPackets, kUseUnequalProtection,
169 0 : params_.fec_mask_type, &generated_fec_packets_);
170 0 : if (generated_fec_packets_.empty()) {
171 0 : ResetState();
172 : }
173 0 : return ret;
174 : }
175 0 : return 0;
176 : }
177 :
178 0 : bool UlpfecGenerator::ExcessOverheadBelowMax() const {
179 0 : return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
180 : }
181 :
182 0 : bool UlpfecGenerator::MinimumMediaPacketsReached() const {
183 : float average_num_packets_per_frame =
184 0 : static_cast<float>(media_packets_.size()) / num_protected_frames_;
185 0 : int num_media_packets = static_cast<int>(media_packets_.size());
186 0 : if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) {
187 0 : return num_media_packets >= min_num_media_packets_;
188 : } else {
189 : // For larger rates (more packets/frame), increase the threshold.
190 : // TODO(brandtr): Investigate what impact this adaptation has.
191 0 : return num_media_packets >= min_num_media_packets_ + 1;
192 : }
193 : }
194 :
195 0 : bool UlpfecGenerator::FecAvailable() const {
196 0 : return !generated_fec_packets_.empty();
197 : }
198 :
199 0 : size_t UlpfecGenerator::NumAvailableFecPackets() const {
200 0 : return generated_fec_packets_.size();
201 : }
202 :
203 0 : size_t UlpfecGenerator::MaxPacketOverhead() const {
204 0 : return fec_->MaxPacketOverhead();
205 : }
206 :
207 0 : std::vector<std::unique_ptr<RedPacket>> UlpfecGenerator::GetUlpfecPacketsAsRed(
208 : int red_payload_type,
209 : int ulpfec_payload_type,
210 : uint16_t first_seq_num,
211 : size_t rtp_header_length) {
212 0 : std::vector<std::unique_ptr<RedPacket>> red_packets;
213 0 : red_packets.reserve(generated_fec_packets_.size());
214 0 : RTC_DCHECK(!media_packets_.empty());
215 : ForwardErrorCorrection::Packet* last_media_packet =
216 0 : media_packets_.back().get();
217 0 : uint16_t seq_num = first_seq_num;
218 0 : for (const auto& fec_packet : generated_fec_packets_) {
219 : // Wrap FEC packet (including FEC headers) in a RED packet. Since the
220 : // FEC packets in |generated_fec_packets_| don't have RTP headers, we
221 : // reuse the header from the last media packet.
222 : std::unique_ptr<RedPacket> red_packet(new RedPacket(
223 0 : fec_packet->length + kRedForFecHeaderLength + rtp_header_length));
224 0 : red_packet->CreateHeader(last_media_packet->data, rtp_header_length,
225 0 : red_payload_type, ulpfec_payload_type);
226 0 : red_packet->SetSeqNum(seq_num++);
227 0 : red_packet->ClearMarkerBit();
228 0 : red_packet->AssignPayload(fec_packet->data, fec_packet->length);
229 0 : red_packets.push_back(std::move(red_packet));
230 : }
231 :
232 0 : ResetState();
233 :
234 0 : return red_packets;
235 : }
236 :
237 0 : int UlpfecGenerator::Overhead() const {
238 0 : RTC_DCHECK(!media_packets_.empty());
239 : int num_fec_packets =
240 0 : fec_->NumFecPackets(media_packets_.size(), params_.fec_rate);
241 : // Return the overhead in Q8.
242 0 : return (num_fec_packets << 8) / media_packets_.size();
243 : }
244 :
245 0 : void UlpfecGenerator::ResetState() {
246 0 : media_packets_.clear();
247 0 : generated_fec_packets_.clear();
248 0 : num_protected_frames_ = 0;
249 0 : }
250 :
251 : } // namespace webrtc
|