blob: 315a4c21209eadbe2baf82363d38f49a14318ea8 [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>
danilchap262e4862016-08-05 03:37:38 -070014#include <algorithm>
danilchapb8b6fbb2015-12-10 05:05:27 -080015#include <limits>
16
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/checks.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
19namespace webrtc {
danilchap2f69ce92016-08-16 03:21:38 -070020std::vector<rtcp::TmmbItem> TMMBRHelp::FindBoundingSet(
21 std::vector<rtcp::TmmbItem> candidates) {
22 // Filter out candidates with 0 bitrate.
23 for (auto it = candidates.begin(); it != candidates.end();) {
24 if (!it->bitrate_bps())
25 it = candidates.erase(it);
26 else
27 ++it;
danilchap262e4862016-08-05 03:37:38 -070028 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +000029
danilchap2f69ce92016-08-16 03:21:38 -070030 if (candidates.size() <= 1)
31 return candidates;
niklase@google.com470e71d2011-07-07 08:21:25 +000032
danilchap262e4862016-08-05 03:37:38 -070033 size_t num_candidates = candidates.size();
34
danilchap262e4862016-08-05 03:37:38 -070035 // 1. Sort by increasing packet overhead.
36 std::sort(candidates.begin(), candidates.end(),
37 [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
38 return lhs.packet_overhead() < rhs.packet_overhead();
39 });
40
41 // 2. For tuples with same overhead, keep the one with the lowest bitrate.
42 for (auto it = candidates.begin(); it != candidates.end();) {
43 RTC_DCHECK(it->bitrate_bps());
44 auto current_min = it;
45 auto next_it = it + 1;
46 // Use fact candidates are sorted by overhead, so candidates with same
47 // overhead are adjusted.
48 while (next_it != candidates.end() &&
49 next_it->packet_overhead() == current_min->packet_overhead()) {
50 if (next_it->bitrate_bps() < current_min->bitrate_bps()) {
51 current_min->set_bitrate_bps(0);
52 current_min = next_it;
53 } else {
54 next_it->set_bitrate_bps(0);
55 }
56 ++next_it;
57 --num_candidates;
58 }
59 it = next_it;
60 }
61
danilchap2f69ce92016-08-16 03:21:38 -070062 // 3. Select and remove tuple with lowest bitrate.
danilchap262e4862016-08-05 03:37:38 -070063 // (If more than 1, choose the one with highest overhead).
64 auto min_bitrate_it = candidates.end();
65 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
66 if (it->bitrate_bps()) {
67 min_bitrate_it = it;
68 break;
69 }
70 }
71
72 for (auto it = min_bitrate_it; it != candidates.end(); ++it) {
73 if (it->bitrate_bps() &&
74 it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) {
75 // Get min bitrate.
76 min_bitrate_it = it;
77 }
78 }
79
danilchap2f69ce92016-08-16 03:21:38 -070080 std::vector<rtcp::TmmbItem> bounding_set;
81 bounding_set.reserve(num_candidates);
danilchap262e4862016-08-05 03:37:38 -070082 std::vector<float> intersection(num_candidates);
83 std::vector<float> max_packet_rate(num_candidates);
84
85 // First member of selected list.
danilchap2f69ce92016-08-16 03:21:38 -070086 bounding_set.push_back(*min_bitrate_it);
danilchap262e4862016-08-05 03:37:38 -070087 intersection[0] = 0;
88 // Calculate its maximum packet rate (where its line crosses x-axis).
danilchap2f69ce92016-08-16 03:21:38 -070089 uint16_t packet_overhead = bounding_set.back().packet_overhead();
danilchap262e4862016-08-05 03:37:38 -070090 if (packet_overhead == 0) {
91 // Avoid division by zero.
92 max_packet_rate[0] = std::numeric_limits<float>::max();
93 } else {
danilchap2f69ce92016-08-16 03:21:38 -070094 max_packet_rate[0] =
95 bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead);
danilchap262e4862016-08-05 03:37:38 -070096 }
97 // Remove from candidate list.
98 min_bitrate_it->set_bitrate_bps(0);
99 --num_candidates;
100
101 // 4. Discard from candidate list all tuple with lower overhead
102 // (next tuple must be steeper).
103 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
104 if (it->bitrate_bps() &&
danilchap2f69ce92016-08-16 03:21:38 -0700105 it->packet_overhead() < bounding_set.front().packet_overhead()) {
danilchap262e4862016-08-05 03:37:38 -0700106 it->set_bitrate_bps(0);
107 --num_candidates;
108 }
109 }
110
111 bool get_new_candidate = true;
112 rtcp::TmmbItem cur_candidate;
113 while (num_candidates > 0) {
114 if (get_new_candidate) {
115 // 5. Remove first remaining tuple from candidate list.
116 for (auto it = candidates.begin(); it != candidates.end(); ++it) {
117 if (it->bitrate_bps()) {
118 cur_candidate = *it;
119 it->set_bitrate_bps(0);
120 break;
121 }
122 }
123 }
124
125 // 6. Calculate packet rate and intersection of the current
126 // line with line of last tuple in selected list.
127 RTC_DCHECK_NE(cur_candidate.packet_overhead(),
danilchap2f69ce92016-08-16 03:21:38 -0700128 bounding_set.back().packet_overhead());
danilchap262e4862016-08-05 03:37:38 -0700129 float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
danilchap2f69ce92016-08-16 03:21:38 -0700130 bounding_set.back().bitrate_bps()) /
danilchap262e4862016-08-05 03:37:38 -0700131 (cur_candidate.packet_overhead() -
danilchap2f69ce92016-08-16 03:21:38 -0700132 bounding_set.back().packet_overhead());
danilchap262e4862016-08-05 03:37:38 -0700133
134 // 7. If the packet rate is equal or lower than intersection of
135 // last tuple in selected list,
136 // remove last tuple in selected list & go back to step 6.
danilchap2f69ce92016-08-16 03:21:38 -0700137 if (packet_rate <= intersection[bounding_set.size() - 1]) {
danilchap262e4862016-08-05 03:37:38 -0700138 // Remove last tuple and goto step 6.
danilchap2f69ce92016-08-16 03:21:38 -0700139 bounding_set.pop_back();
danilchap262e4862016-08-05 03:37:38 -0700140 get_new_candidate = false;
141 } else {
142 // 8. If packet rate is lower than maximum packet rate of
143 // last tuple in selected list, add current tuple to selected
144 // list.
danilchap2f69ce92016-08-16 03:21:38 -0700145 if (packet_rate < max_packet_rate[bounding_set.size() - 1]) {
146 bounding_set.push_back(cur_candidate);
147 intersection[bounding_set.size() - 1] = packet_rate;
148 uint16_t packet_overhead = bounding_set.back().packet_overhead();
danilchap262e4862016-08-05 03:37:38 -0700149 RTC_DCHECK_NE(packet_overhead, 0);
danilchap2f69ce92016-08-16 03:21:38 -0700150 max_packet_rate[bounding_set.size() - 1] =
151 bounding_set.back().bitrate_bps() /
danilchap262e4862016-08-05 03:37:38 -0700152 static_cast<float>(packet_overhead);
153 }
154 --num_candidates;
155 get_new_candidate = true;
156 }
157
158 // 9. Go back to step 5 if any tuple remains in candidate list.
159 }
danilchap2f69ce92016-08-16 03:21:38 -0700160 RTC_DCHECK(!bounding_set.empty());
161 return bounding_set;
danilchap262e4862016-08-05 03:37:38 -0700162}
163
Danil Chapovalovdaa90a72016-08-10 11:29:50 +0200164bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
165 uint32_t ssrc) {
166 for (const rtcp::TmmbItem& item : bounding) {
167 if (item.ssrc() == ssrc) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000168 return true;
169 }
170 }
171 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000172}
173
danilchap2f69ce92016-08-16 03:21:38 -0700174uint64_t TMMBRHelp::CalcMinBitrateBps(
175 const std::vector<rtcp::TmmbItem>& candidates) {
176 RTC_DCHECK(!candidates.empty());
177 uint64_t min_bitrate_bps = std::numeric_limits<uint64_t>::max();
178 for (const rtcp::TmmbItem& item : candidates)
179 if (item.bitrate_bps() < min_bitrate_bps)
180 min_bitrate_bps = item.bitrate_bps();
181 return min_bitrate_bps;
niklase@google.com470e71d2011-07-07 08:21:25 +0000182}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000183} // namespace webrtc