blob: 5aa8f945aaf4853756dde63194c7682044793b12 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000011#include "webrtc/modules/rtp_rtcp/source/tmmbr_help.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
danilchap262e4862016-08-05 03:37:38 -070013#include <algorithm>
danilchapb8b6fbb2015-12-10 05:05:27 -080014#include <limits>
Danil Chapovalovdaa90a72016-08-10 11:29:50 +020015#include <utility>
danilchapb8b6fbb2015-12-10 05:05:27 -080016
danilchapf6ff9712016-02-24 09:23:37 -080017#include "webrtc/base/checks.h"
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000018#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
20namespace webrtc {
danilchap262e4862016-08-05 03:37:38 -070021void TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize) {
danilchapa4f31bd2016-02-29 05:26:01 -080022 clear();
23 reserve(minimumSize);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000024}
25
danilchap262e4862016-08-05 03:37:38 -070026void TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize) {
danilchapa4f31bd2016-02-29 05:26:01 -080027 reserve(minimumSize);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000028}
29
30void TMMBRSet::SetEntry(unsigned int i,
danilchap262e4862016-08-05 03:37:38 -070031 uint32_t tmmbrSet,
32 uint32_t packetOHSet,
33 uint32_t ssrcSet) {
danilchapa4f31bd2016-02-29 05:26:01 -080034 RTC_DCHECK_LT(i, capacity());
35 if (i >= size()) {
danilchap262e4862016-08-05 03:37:38 -070036 resize(i + 1);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000037 }
danilchapa4f31bd2016-02-29 05:26:01 -080038 (*this)[i].set_bitrate_bps(tmmbrSet * 1000);
39 (*this)[i].set_packet_overhead(packetOHSet);
40 (*this)[i].set_ssrc(ssrcSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000041}
42
pbos@webrtc.org2f446732013-04-08 11:08:41 +000043void TMMBRSet::AddEntry(uint32_t tmmbrSet,
44 uint32_t packetOHSet,
45 uint32_t ssrcSet) {
danilchapa4f31bd2016-02-29 05:26:01 -080046 RTC_DCHECK_LT(size(), capacity());
47 SetEntry(size(), tmmbrSet, packetOHSet, ssrcSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000048}
49
pbos@webrtc.org2f446732013-04-08 11:08:41 +000050void TMMBRSet::RemoveEntry(uint32_t sourceIdx) {
danilchapa4f31bd2016-02-29 05:26:01 -080051 RTC_DCHECK_LT(sourceIdx, size());
52 erase(begin() + sourceIdx);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000053}
54
danilchap262e4862016-08-05 03:37:38 -070055TMMBRSet* TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize) {
56 _candidateSet.VerifyAndAllocateSet(minimumSize);
57 return &_candidateSet;
hta@webrtc.org54536bb2012-05-03 14:07:23 +000058}
59
danilchap262e4862016-08-05 03:37:38 -070060TMMBRSet* TMMBRHelp::CandidateSet() {
61 return &_candidateSet;
niklase@google.com470e71d2011-07-07 08:21:25 +000062}
63
Danil Chapovalovdaa90a72016-08-10 11:29:50 +020064std::vector<rtcp::TmmbItem> TMMBRHelp::FindTMMBRBoundingSet() {
danilchap262e4862016-08-05 03:37:38 -070065 // Work on local variable, will be modified
66 TMMBRSet candidateSet;
67 candidateSet.VerifyAndAllocateSet(_candidateSet.capacity());
niklase@google.com470e71d2011-07-07 08:21:25 +000068
danilchap262e4862016-08-05 03:37:38 -070069 for (size_t i = 0; i < _candidateSet.size(); i++) {
70 if (_candidateSet.Tmmbr(i)) {
71 candidateSet.AddEntry(_candidateSet.Tmmbr(i), _candidateSet.PacketOH(i),
72 _candidateSet.Ssrc(i));
danilchapf6ff9712016-02-24 09:23:37 -080073 } else {
danilchap262e4862016-08-05 03:37:38 -070074 // make sure this is zero if tmmbr = 0
75 RTC_DCHECK_EQ(_candidateSet.PacketOH(i), 0u);
76 // Old code:
77 // _candidateSet.ptrPacketOHSet[i] = 0;
danilchapf6ff9712016-02-24 09:23:37 -080078 }
danilchap262e4862016-08-05 03:37:38 -070079 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +000080
danilchap262e4862016-08-05 03:37:38 -070081 // Number of set candidates
82 int32_t numSetCandidates = candidateSet.lengthOfSet();
83 // Find bounding set
Danil Chapovalovdaa90a72016-08-10 11:29:50 +020084 std::vector<rtcp::TmmbItem> bounding;
danilchap262e4862016-08-05 03:37:38 -070085 if (numSetCandidates > 0) {
Danil Chapovalovdaa90a72016-08-10 11:29:50 +020086 FindBoundingSet(std::move(candidateSet), &bounding);
87 size_t numBoundingSet = bounding.size();
88 RTC_DCHECK_GE(numBoundingSet, 1u);
89 RTC_DCHECK_LE(numBoundingSet, _candidateSet.size());
danilchap262e4862016-08-05 03:37:38 -070090 }
Danil Chapovalovdaa90a72016-08-10 11:29:50 +020091 return bounding;
niklase@google.com470e71d2011-07-07 08:21:25 +000092}
93
danilchap262e4862016-08-05 03:37:38 -070094void TMMBRHelp::FindBoundingSet(std::vector<rtcp::TmmbItem> candidates,
95 std::vector<rtcp::TmmbItem>* bounding_set) {
96 RTC_DCHECK(bounding_set);
97 RTC_DCHECK(!candidates.empty());
98 size_t num_candidates = candidates.size();
99
100 if (num_candidates == 1) {
101 RTC_DCHECK(candidates[0].bitrate_bps());
102 *bounding_set = std::move(candidates);
103 return;
104 }
105
106 // 1. Sort by increasing packet overhead.
107 std::sort(candidates.begin(), candidates.end(),
108 [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
109 return lhs.packet_overhead() < rhs.packet_overhead();
110 });
111
112 // 2. For tuples with same overhead, keep the one with the lowest bitrate.
113 for (auto it = candidates.begin(); it != candidates.end();) {
114 RTC_DCHECK(it->bitrate_bps());
115 auto current_min = it;
116 auto next_it = it + 1;
117 // Use fact candidates are sorted by overhead, so candidates with same
118 // overhead are adjusted.
119 while (next_it != candidates.end() &&
120 next_it->packet_overhead() == current_min->packet_overhead()) {
121 if (next_it->bitrate_bps() < current_min->bitrate_bps()) {
122 current_min->set_bitrate_bps(0);
123 current_min = next_it;
124 } else {
125 next_it->set_bitrate_bps(0);
126 }
127 ++next_it;
128 --num_candidates;
129 }
130 it = next_it;
131 }
132
133 // 3. Select and remove tuple with lowest tmmbr.
134 // (If more than 1, choose the one with highest overhead).
135 auto min_bitrate_it = candidates.end();
136 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
137 if (it->bitrate_bps()) {
138 min_bitrate_it = it;
139 break;
140 }
141 }
142
143 for (auto it = min_bitrate_it; it != candidates.end(); ++it) {
144 if (it->bitrate_bps() &&
145 it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) {
146 // Get min bitrate.
147 min_bitrate_it = it;
148 }
149 }
150
151 bounding_set->clear();
152 bounding_set->reserve(num_candidates);
153 std::vector<float> intersection(num_candidates);
154 std::vector<float> max_packet_rate(num_candidates);
155
156 // First member of selected list.
157 bounding_set->push_back(*min_bitrate_it);
158 intersection[0] = 0;
159 // Calculate its maximum packet rate (where its line crosses x-axis).
160 uint16_t packet_overhead = bounding_set->back().packet_overhead();
161 if (packet_overhead == 0) {
162 // Avoid division by zero.
163 max_packet_rate[0] = std::numeric_limits<float>::max();
164 } else {
165 max_packet_rate[0] = bounding_set->back().bitrate_bps() /
166 static_cast<float>(packet_overhead);
167 }
168 // Remove from candidate list.
169 min_bitrate_it->set_bitrate_bps(0);
170 --num_candidates;
171
172 // 4. Discard from candidate list all tuple with lower overhead
173 // (next tuple must be steeper).
174 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
175 if (it->bitrate_bps() &&
176 it->packet_overhead() < bounding_set->front().packet_overhead()) {
177 it->set_bitrate_bps(0);
178 --num_candidates;
179 }
180 }
181
182 bool get_new_candidate = true;
183 rtcp::TmmbItem cur_candidate;
184 while (num_candidates > 0) {
185 if (get_new_candidate) {
186 // 5. Remove first remaining tuple from candidate list.
187 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
188 if (it->bitrate_bps()) {
189 cur_candidate = *it;
190 it->set_bitrate_bps(0);
191 break;
192 }
193 }
194 }
195
196 // 6. Calculate packet rate and intersection of the current
197 // line with line of last tuple in selected list.
198 RTC_DCHECK_NE(cur_candidate.packet_overhead(),
199 bounding_set->back().packet_overhead());
200 float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
201 bounding_set->back().bitrate_bps()) /
202 (cur_candidate.packet_overhead() -
203 bounding_set->back().packet_overhead());
204
205 // 7. If the packet rate is equal or lower than intersection of
206 // last tuple in selected list,
207 // remove last tuple in selected list & go back to step 6.
208 if (packet_rate <= intersection[bounding_set->size() - 1]) {
209 // Remove last tuple and goto step 6.
210 bounding_set->pop_back();
211 get_new_candidate = false;
212 } else {
213 // 8. If packet rate is lower than maximum packet rate of
214 // last tuple in selected list, add current tuple to selected
215 // list.
216 if (packet_rate < max_packet_rate[bounding_set->size() - 1]) {
217 bounding_set->push_back(cur_candidate);
218 intersection[bounding_set->size() - 1] = packet_rate;
219 uint16_t packet_overhead = bounding_set->back().packet_overhead();
220 RTC_DCHECK_NE(packet_overhead, 0);
221 max_packet_rate[bounding_set->size() - 1] =
222 bounding_set->back().bitrate_bps() /
223 static_cast<float>(packet_overhead);
224 }
225 --num_candidates;
226 get_new_candidate = true;
227 }
228
229 // 9. Go back to step 5 if any tuple remains in candidate list.
230 }
231}
232
Danil Chapovalovdaa90a72016-08-10 11:29:50 +0200233bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
234 uint32_t ssrc) {
235 for (const rtcp::TmmbItem& item : bounding) {
236 if (item.ssrc() == ssrc) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000237 return true;
238 }
239 }
240 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241}
242
danilchap262e4862016-08-05 03:37:38 -0700243bool TMMBRHelp::CalcMinBitRate(uint32_t* minBitrateKbit) const {
danilchapa4f31bd2016-02-29 05:26:01 -0800244 if (_candidateSet.size() == 0) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000245 // Empty bounding set.
246 return false;
247 }
248 *minBitrateKbit = std::numeric_limits<uint32_t>::max();
249
danilchap262e4862016-08-05 03:37:38 -0700250 for (size_t i = 0; i < _candidateSet.lengthOfSet(); ++i) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000251 uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i);
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000252 if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) {
253 curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 }
danilchap262e4862016-08-05 03:37:38 -0700255 *minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ? curNetBitRateKbit
256 : *minBitrateKbit;
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000257 }
258 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000260} // namespace webrtc