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 "modules/rtp_rtcp/source/tmmbr_help.h"
12
13 #include <stddef.h>
14
15 #include <limits>
16
17 #include "absl/algorithm/container.h"
18 #include "rtc_base/checks.h"
19
20 namespace webrtc {
FindBoundingSet(std::vector<rtcp::TmmbItem> candidates)21 std::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;
29 }
30
31 if (candidates.size() <= 1)
32 return candidates;
33
34 size_t num_candidates = candidates.size();
35
36 // 1. Sort by increasing packet overhead.
37 absl::c_sort(candidates,
38 [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
39 return lhs.packet_overhead() < rhs.packet_overhead();
40 });
41
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
63 // 3. Select and remove tuple with lowest bitrate.
64 // (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
81 std::vector<rtcp::TmmbItem> bounding_set;
82 bounding_set.reserve(num_candidates);
83 std::vector<float> intersection(num_candidates);
84 std::vector<float> max_packet_rate(num_candidates);
85
86 // First member of selected list.
87 bounding_set.push_back(*min_bitrate_it);
88 intersection[0] = 0;
89 // Calculate its maximum packet rate (where its line crosses x-axis).
90 uint16_t packet_overhead = bounding_set.back().packet_overhead();
91 if (packet_overhead == 0) {
92 // Avoid division by zero.
93 max_packet_rate[0] = std::numeric_limits<float>::max();
94 } else {
95 max_packet_rate[0] =
96 bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead);
97 }
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() &&
106 it->packet_overhead() < bounding_set.front().packet_overhead()) {
107 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(),
129 bounding_set.back().packet_overhead());
130 float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
131 bounding_set.back().bitrate_bps()) /
132 (cur_candidate.packet_overhead() -
133 bounding_set.back().packet_overhead());
134
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.
138 if (packet_rate <= intersection[bounding_set.size() - 1]) {
139 // Remove last tuple and goto step 6.
140 bounding_set.pop_back();
141 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.
146 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();
150 RTC_DCHECK_NE(packet_overhead, 0);
151 max_packet_rate[bounding_set.size() - 1] =
152 bounding_set.back().bitrate_bps() /
153 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 }
161 RTC_DCHECK(!bounding_set.empty());
162 return bounding_set;
163 }
164
IsOwner(const std::vector<rtcp::TmmbItem> & bounding,uint32_t ssrc)165 bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
166 uint32_t ssrc) {
167 for (const rtcp::TmmbItem& item : bounding) {
168 if (item.ssrc() == ssrc) {
169 return true;
170 }
171 }
172 return false;
173 }
174
CalcMinBitrateBps(const std::vector<rtcp::TmmbItem> & candidates)175 uint64_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;
183 }
184 } // namespace webrtc
185