blob: 569ed4d8e00fe117fdd6b364d1c2b7c757fe2c7b [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/tmmbr_help.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <stddef.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
danilchapb8b6fbb2015-12-10 05:05:27 -080015#include <limits>
16
Steve Anton91c26062019-03-28 10:56:11 -070017#include "absl/algorithm/container.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
20namespace webrtc {
danilchap2f69ce92016-08-16 03:21:38 -070021std::vector<rtcp::TmmbItem> TMMBRHelp::FindBoundingSet(
22 std::vector<rtcp::TmmbItem> candidates) {
23 // Filter out candidates with 0 bitrate.
24 for (auto it = candidates.begin(); it != candidates.end();) {
25 if (!it->bitrate_bps())
26 it = candidates.erase(it);
27 else
28 ++it;
danilchap262e4862016-08-05 03:37:38 -070029 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +000030
danilchap2f69ce92016-08-16 03:21:38 -070031 if (candidates.size() <= 1)
32 return candidates;
niklase@google.com470e71d2011-07-07 08:21:25 +000033
danilchap262e4862016-08-05 03:37:38 -070034 size_t num_candidates = candidates.size();
35
danilchap262e4862016-08-05 03:37:38 -070036 // 1. Sort by increasing packet overhead.
Steve Anton91c26062019-03-28 10:56:11 -070037 absl::c_sort(candidates,
38 [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
39 return lhs.packet_overhead() < rhs.packet_overhead();
40 });
danilchap262e4862016-08-05 03:37:38 -070041
42 // 2. For tuples with same overhead, keep the one with the lowest bitrate.
43 for (auto it = candidates.begin(); it != candidates.end();) {
44 RTC_DCHECK(it->bitrate_bps());
45 auto current_min = it;
46 auto next_it = it + 1;
47 // Use fact candidates are sorted by overhead, so candidates with same
48 // overhead are adjusted.
49 while (next_it != candidates.end() &&
50 next_it->packet_overhead() == current_min->packet_overhead()) {
51 if (next_it->bitrate_bps() < current_min->bitrate_bps()) {
52 current_min->set_bitrate_bps(0);
53 current_min = next_it;
54 } else {
55 next_it->set_bitrate_bps(0);
56 }
57 ++next_it;
58 --num_candidates;
59 }
60 it = next_it;
61 }
62
danilchap2f69ce92016-08-16 03:21:38 -070063 // 3. Select and remove tuple with lowest bitrate.
danilchap262e4862016-08-05 03:37:38 -070064 // (If more than 1, choose the one with highest overhead).
65 auto min_bitrate_it = candidates.end();
66 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
67 if (it->bitrate_bps()) {
68 min_bitrate_it = it;
69 break;
70 }
71 }
72
73 for (auto it = min_bitrate_it; it != candidates.end(); ++it) {
74 if (it->bitrate_bps() &&
75 it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) {
76 // Get min bitrate.
77 min_bitrate_it = it;
78 }
79 }
80
danilchap2f69ce92016-08-16 03:21:38 -070081 std::vector<rtcp::TmmbItem> bounding_set;
82 bounding_set.reserve(num_candidates);
danilchap262e4862016-08-05 03:37:38 -070083 std::vector<float> intersection(num_candidates);
84 std::vector<float> max_packet_rate(num_candidates);
85
86 // First member of selected list.
danilchap2f69ce92016-08-16 03:21:38 -070087 bounding_set.push_back(*min_bitrate_it);
danilchap262e4862016-08-05 03:37:38 -070088 intersection[0] = 0;
89 // Calculate its maximum packet rate (where its line crosses x-axis).
danilchap2f69ce92016-08-16 03:21:38 -070090 uint16_t packet_overhead = bounding_set.back().packet_overhead();
danilchap262e4862016-08-05 03:37:38 -070091 if (packet_overhead == 0) {
92 // Avoid division by zero.
93 max_packet_rate[0] = std::numeric_limits<float>::max();
94 } else {
danilchap2f69ce92016-08-16 03:21:38 -070095 max_packet_rate[0] =
96 bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead);
danilchap262e4862016-08-05 03:37:38 -070097 }
98 // Remove from candidate list.
99 min_bitrate_it->set_bitrate_bps(0);
100 --num_candidates;
101
102 // 4. Discard from candidate list all tuple with lower overhead
103 // (next tuple must be steeper).
104 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
105 if (it->bitrate_bps() &&
danilchap2f69ce92016-08-16 03:21:38 -0700106 it->packet_overhead() < bounding_set.front().packet_overhead()) {
danilchap262e4862016-08-05 03:37:38 -0700107 it->set_bitrate_bps(0);
108 --num_candidates;
109 }
110 }
111
112 bool get_new_candidate = true;
113 rtcp::TmmbItem cur_candidate;
114 while (num_candidates > 0) {
115 if (get_new_candidate) {
116 // 5. Remove first remaining tuple from candidate list.
117 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
118 if (it->bitrate_bps()) {
119 cur_candidate = *it;
120 it->set_bitrate_bps(0);
121 break;
122 }
123 }
124 }
125
126 // 6. Calculate packet rate and intersection of the current
127 // line with line of last tuple in selected list.
128 RTC_DCHECK_NE(cur_candidate.packet_overhead(),
danilchap2f69ce92016-08-16 03:21:38 -0700129 bounding_set.back().packet_overhead());
danilchap262e4862016-08-05 03:37:38 -0700130 float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
danilchap2f69ce92016-08-16 03:21:38 -0700131 bounding_set.back().bitrate_bps()) /
danilchap262e4862016-08-05 03:37:38 -0700132 (cur_candidate.packet_overhead() -
danilchap2f69ce92016-08-16 03:21:38 -0700133 bounding_set.back().packet_overhead());
danilchap262e4862016-08-05 03:37:38 -0700134
135 // 7. If the packet rate is equal or lower than intersection of
136 // last tuple in selected list,
137 // remove last tuple in selected list & go back to step 6.
danilchap2f69ce92016-08-16 03:21:38 -0700138 if (packet_rate <= intersection[bounding_set.size() - 1]) {
danilchap262e4862016-08-05 03:37:38 -0700139 // Remove last tuple and goto step 6.
danilchap2f69ce92016-08-16 03:21:38 -0700140 bounding_set.pop_back();
danilchap262e4862016-08-05 03:37:38 -0700141 get_new_candidate = false;
142 } else {
143 // 8. If packet rate is lower than maximum packet rate of
144 // last tuple in selected list, add current tuple to selected
145 // list.
danilchap2f69ce92016-08-16 03:21:38 -0700146 if (packet_rate < max_packet_rate[bounding_set.size() - 1]) {
147 bounding_set.push_back(cur_candidate);
148 intersection[bounding_set.size() - 1] = packet_rate;
149 uint16_t packet_overhead = bounding_set.back().packet_overhead();
danilchap262e4862016-08-05 03:37:38 -0700150 RTC_DCHECK_NE(packet_overhead, 0);
danilchap2f69ce92016-08-16 03:21:38 -0700151 max_packet_rate[bounding_set.size() - 1] =
152 bounding_set.back().bitrate_bps() /
danilchap262e4862016-08-05 03:37:38 -0700153 static_cast<float>(packet_overhead);
154 }
155 --num_candidates;
156 get_new_candidate = true;
157 }
158
159 // 9. Go back to step 5 if any tuple remains in candidate list.
160 }
danilchap2f69ce92016-08-16 03:21:38 -0700161 RTC_DCHECK(!bounding_set.empty());
162 return bounding_set;
danilchap262e4862016-08-05 03:37:38 -0700163}
164
Danil Chapovalovdaa90a72016-08-10 11:29:50 +0200165bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
166 uint32_t ssrc) {
167 for (const rtcp::TmmbItem& item : bounding) {
168 if (item.ssrc() == ssrc) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000169 return true;
170 }
171 }
172 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000173}
174
danilchap2f69ce92016-08-16 03:21:38 -0700175uint64_t TMMBRHelp::CalcMinBitrateBps(
176 const std::vector<rtcp::TmmbItem>& candidates) {
177 RTC_DCHECK(!candidates.empty());
178 uint64_t min_bitrate_bps = std::numeric_limits<uint64_t>::max();
179 for (const rtcp::TmmbItem& item : candidates)
180 if (item.bitrate_bps() < min_bitrate_bps)
181 min_bitrate_bps = item.bitrate_bps();
182 return min_bitrate_bps;
niklase@google.com470e71d2011-07-07 08:21:25 +0000183}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000184} // namespace webrtc