blob: 7c29ed8776a786751f7aeca6daa40f5687f122c3 [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>
15
danilchapf6ff9712016-02-24 09:23:37 -080016#include "webrtc/base/checks.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000017
18namespace webrtc {
danilchap262e4862016-08-05 03:37:38 -070019void TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize) {
danilchapa4f31bd2016-02-29 05:26:01 -080020 clear();
21 reserve(minimumSize);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000022}
23
danilchap262e4862016-08-05 03:37:38 -070024void TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize) {
danilchapa4f31bd2016-02-29 05:26:01 -080025 reserve(minimumSize);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000026}
27
28void TMMBRSet::SetEntry(unsigned int i,
danilchap262e4862016-08-05 03:37:38 -070029 uint32_t tmmbrSet,
30 uint32_t packetOHSet,
31 uint32_t ssrcSet) {
danilchapa4f31bd2016-02-29 05:26:01 -080032 RTC_DCHECK_LT(i, capacity());
33 if (i >= size()) {
danilchap262e4862016-08-05 03:37:38 -070034 resize(i + 1);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000035 }
danilchapa4f31bd2016-02-29 05:26:01 -080036 (*this)[i].set_bitrate_bps(tmmbrSet * 1000);
37 (*this)[i].set_packet_overhead(packetOHSet);
38 (*this)[i].set_ssrc(ssrcSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000039}
40
pbos@webrtc.org2f446732013-04-08 11:08:41 +000041void TMMBRSet::AddEntry(uint32_t tmmbrSet,
42 uint32_t packetOHSet,
43 uint32_t ssrcSet) {
danilchapa4f31bd2016-02-29 05:26:01 -080044 RTC_DCHECK_LT(size(), capacity());
45 SetEntry(size(), tmmbrSet, packetOHSet, ssrcSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000046}
47
pbos@webrtc.org2f446732013-04-08 11:08:41 +000048void TMMBRSet::RemoveEntry(uint32_t sourceIdx) {
danilchapa4f31bd2016-02-29 05:26:01 -080049 RTC_DCHECK_LT(sourceIdx, size());
50 erase(begin() + sourceIdx);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000051}
52
danilchap2f69ce92016-08-16 03:21:38 -070053std::vector<rtcp::TmmbItem> TMMBRHelp::FindBoundingSet(
54 std::vector<rtcp::TmmbItem> candidates) {
55 // Filter out candidates with 0 bitrate.
56 for (auto it = candidates.begin(); it != candidates.end();) {
57 if (!it->bitrate_bps())
58 it = candidates.erase(it);
59 else
60 ++it;
danilchap262e4862016-08-05 03:37:38 -070061 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +000062
danilchap2f69ce92016-08-16 03:21:38 -070063 if (candidates.size() <= 1)
64 return candidates;
niklase@google.com470e71d2011-07-07 08:21:25 +000065
danilchap262e4862016-08-05 03:37:38 -070066 size_t num_candidates = candidates.size();
67
danilchap262e4862016-08-05 03:37:38 -070068 // 1. Sort by increasing packet overhead.
69 std::sort(candidates.begin(), candidates.end(),
70 [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
71 return lhs.packet_overhead() < rhs.packet_overhead();
72 });
73
74 // 2. For tuples with same overhead, keep the one with the lowest bitrate.
75 for (auto it = candidates.begin(); it != candidates.end();) {
76 RTC_DCHECK(it->bitrate_bps());
77 auto current_min = it;
78 auto next_it = it + 1;
79 // Use fact candidates are sorted by overhead, so candidates with same
80 // overhead are adjusted.
81 while (next_it != candidates.end() &&
82 next_it->packet_overhead() == current_min->packet_overhead()) {
83 if (next_it->bitrate_bps() < current_min->bitrate_bps()) {
84 current_min->set_bitrate_bps(0);
85 current_min = next_it;
86 } else {
87 next_it->set_bitrate_bps(0);
88 }
89 ++next_it;
90 --num_candidates;
91 }
92 it = next_it;
93 }
94
danilchap2f69ce92016-08-16 03:21:38 -070095 // 3. Select and remove tuple with lowest bitrate.
danilchap262e4862016-08-05 03:37:38 -070096 // (If more than 1, choose the one with highest overhead).
97 auto min_bitrate_it = candidates.end();
98 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
99 if (it->bitrate_bps()) {
100 min_bitrate_it = it;
101 break;
102 }
103 }
104
105 for (auto it = min_bitrate_it; it != candidates.end(); ++it) {
106 if (it->bitrate_bps() &&
107 it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) {
108 // Get min bitrate.
109 min_bitrate_it = it;
110 }
111 }
112
danilchap2f69ce92016-08-16 03:21:38 -0700113 std::vector<rtcp::TmmbItem> bounding_set;
114 bounding_set.reserve(num_candidates);
danilchap262e4862016-08-05 03:37:38 -0700115 std::vector<float> intersection(num_candidates);
116 std::vector<float> max_packet_rate(num_candidates);
117
118 // First member of selected list.
danilchap2f69ce92016-08-16 03:21:38 -0700119 bounding_set.push_back(*min_bitrate_it);
danilchap262e4862016-08-05 03:37:38 -0700120 intersection[0] = 0;
121 // Calculate its maximum packet rate (where its line crosses x-axis).
danilchap2f69ce92016-08-16 03:21:38 -0700122 uint16_t packet_overhead = bounding_set.back().packet_overhead();
danilchap262e4862016-08-05 03:37:38 -0700123 if (packet_overhead == 0) {
124 // Avoid division by zero.
125 max_packet_rate[0] = std::numeric_limits<float>::max();
126 } else {
danilchap2f69ce92016-08-16 03:21:38 -0700127 max_packet_rate[0] =
128 bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead);
danilchap262e4862016-08-05 03:37:38 -0700129 }
130 // Remove from candidate list.
131 min_bitrate_it->set_bitrate_bps(0);
132 --num_candidates;
133
134 // 4. Discard from candidate list all tuple with lower overhead
135 // (next tuple must be steeper).
136 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
137 if (it->bitrate_bps() &&
danilchap2f69ce92016-08-16 03:21:38 -0700138 it->packet_overhead() < bounding_set.front().packet_overhead()) {
danilchap262e4862016-08-05 03:37:38 -0700139 it->set_bitrate_bps(0);
140 --num_candidates;
141 }
142 }
143
144 bool get_new_candidate = true;
145 rtcp::TmmbItem cur_candidate;
146 while (num_candidates > 0) {
147 if (get_new_candidate) {
148 // 5. Remove first remaining tuple from candidate list.
149 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
150 if (it->bitrate_bps()) {
151 cur_candidate = *it;
152 it->set_bitrate_bps(0);
153 break;
154 }
155 }
156 }
157
158 // 6. Calculate packet rate and intersection of the current
159 // line with line of last tuple in selected list.
160 RTC_DCHECK_NE(cur_candidate.packet_overhead(),
danilchap2f69ce92016-08-16 03:21:38 -0700161 bounding_set.back().packet_overhead());
danilchap262e4862016-08-05 03:37:38 -0700162 float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
danilchap2f69ce92016-08-16 03:21:38 -0700163 bounding_set.back().bitrate_bps()) /
danilchap262e4862016-08-05 03:37:38 -0700164 (cur_candidate.packet_overhead() -
danilchap2f69ce92016-08-16 03:21:38 -0700165 bounding_set.back().packet_overhead());
danilchap262e4862016-08-05 03:37:38 -0700166
167 // 7. If the packet rate is equal or lower than intersection of
168 // last tuple in selected list,
169 // remove last tuple in selected list & go back to step 6.
danilchap2f69ce92016-08-16 03:21:38 -0700170 if (packet_rate <= intersection[bounding_set.size() - 1]) {
danilchap262e4862016-08-05 03:37:38 -0700171 // Remove last tuple and goto step 6.
danilchap2f69ce92016-08-16 03:21:38 -0700172 bounding_set.pop_back();
danilchap262e4862016-08-05 03:37:38 -0700173 get_new_candidate = false;
174 } else {
175 // 8. If packet rate is lower than maximum packet rate of
176 // last tuple in selected list, add current tuple to selected
177 // list.
danilchap2f69ce92016-08-16 03:21:38 -0700178 if (packet_rate < max_packet_rate[bounding_set.size() - 1]) {
179 bounding_set.push_back(cur_candidate);
180 intersection[bounding_set.size() - 1] = packet_rate;
181 uint16_t packet_overhead = bounding_set.back().packet_overhead();
danilchap262e4862016-08-05 03:37:38 -0700182 RTC_DCHECK_NE(packet_overhead, 0);
danilchap2f69ce92016-08-16 03:21:38 -0700183 max_packet_rate[bounding_set.size() - 1] =
184 bounding_set.back().bitrate_bps() /
danilchap262e4862016-08-05 03:37:38 -0700185 static_cast<float>(packet_overhead);
186 }
187 --num_candidates;
188 get_new_candidate = true;
189 }
190
191 // 9. Go back to step 5 if any tuple remains in candidate list.
192 }
danilchap2f69ce92016-08-16 03:21:38 -0700193 RTC_DCHECK(!bounding_set.empty());
194 return bounding_set;
danilchap262e4862016-08-05 03:37:38 -0700195}
196
Danil Chapovalovdaa90a72016-08-10 11:29:50 +0200197bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
198 uint32_t ssrc) {
199 for (const rtcp::TmmbItem& item : bounding) {
200 if (item.ssrc() == ssrc) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000201 return true;
202 }
203 }
204 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
206
danilchap2f69ce92016-08-16 03:21:38 -0700207uint64_t TMMBRHelp::CalcMinBitrateBps(
208 const std::vector<rtcp::TmmbItem>& candidates) {
209 RTC_DCHECK(!candidates.empty());
210 uint64_t min_bitrate_bps = std::numeric_limits<uint64_t>::max();
211 for (const rtcp::TmmbItem& item : candidates)
212 if (item.bitrate_bps() < min_bitrate_bps)
213 min_bitrate_bps = item.bitrate_bps();
214 return min_bitrate_bps;
niklase@google.com470e71d2011-07-07 08:21:25 +0000215}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000216} // namespace webrtc