niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 1 | /* |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame^] | 11 | #include "modules/rtp_rtcp/source/tmmbr_help.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 12 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 13 | #include <algorithm> |
danilchap | b8b6fbb | 2015-12-10 05:05:27 -0800 | [diff] [blame] | 14 | #include <limits> |
| 15 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame^] | 16 | #include "rtc_base/checks.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 17 | |
| 18 | namespace webrtc { |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 19 | std::vector<rtcp::TmmbItem> TMMBRHelp::FindBoundingSet( |
| 20 | std::vector<rtcp::TmmbItem> candidates) { |
| 21 | // Filter out candidates with 0 bitrate. |
| 22 | for (auto it = candidates.begin(); it != candidates.end();) { |
| 23 | if (!it->bitrate_bps()) |
| 24 | it = candidates.erase(it); |
| 25 | else |
| 26 | ++it; |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 27 | } |
tommi@webrtc.org | eec6ecd | 2014-07-11 19:09:59 +0000 | [diff] [blame] | 28 | |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 29 | if (candidates.size() <= 1) |
| 30 | return candidates; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 31 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 32 | size_t num_candidates = candidates.size(); |
| 33 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 34 | // 1. Sort by increasing packet overhead. |
| 35 | std::sort(candidates.begin(), candidates.end(), |
| 36 | [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) { |
| 37 | return lhs.packet_overhead() < rhs.packet_overhead(); |
| 38 | }); |
| 39 | |
| 40 | // 2. For tuples with same overhead, keep the one with the lowest bitrate. |
| 41 | for (auto it = candidates.begin(); it != candidates.end();) { |
| 42 | RTC_DCHECK(it->bitrate_bps()); |
| 43 | auto current_min = it; |
| 44 | auto next_it = it + 1; |
| 45 | // Use fact candidates are sorted by overhead, so candidates with same |
| 46 | // overhead are adjusted. |
| 47 | while (next_it != candidates.end() && |
| 48 | next_it->packet_overhead() == current_min->packet_overhead()) { |
| 49 | if (next_it->bitrate_bps() < current_min->bitrate_bps()) { |
| 50 | current_min->set_bitrate_bps(0); |
| 51 | current_min = next_it; |
| 52 | } else { |
| 53 | next_it->set_bitrate_bps(0); |
| 54 | } |
| 55 | ++next_it; |
| 56 | --num_candidates; |
| 57 | } |
| 58 | it = next_it; |
| 59 | } |
| 60 | |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 61 | // 3. Select and remove tuple with lowest bitrate. |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 62 | // (If more than 1, choose the one with highest overhead). |
| 63 | auto min_bitrate_it = candidates.end(); |
| 64 | for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 65 | if (it->bitrate_bps()) { |
| 66 | min_bitrate_it = it; |
| 67 | break; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | for (auto it = min_bitrate_it; it != candidates.end(); ++it) { |
| 72 | if (it->bitrate_bps() && |
| 73 | it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) { |
| 74 | // Get min bitrate. |
| 75 | min_bitrate_it = it; |
| 76 | } |
| 77 | } |
| 78 | |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 79 | std::vector<rtcp::TmmbItem> bounding_set; |
| 80 | bounding_set.reserve(num_candidates); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 81 | std::vector<float> intersection(num_candidates); |
| 82 | std::vector<float> max_packet_rate(num_candidates); |
| 83 | |
| 84 | // First member of selected list. |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 85 | bounding_set.push_back(*min_bitrate_it); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 86 | intersection[0] = 0; |
| 87 | // Calculate its maximum packet rate (where its line crosses x-axis). |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 88 | uint16_t packet_overhead = bounding_set.back().packet_overhead(); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 89 | if (packet_overhead == 0) { |
| 90 | // Avoid division by zero. |
| 91 | max_packet_rate[0] = std::numeric_limits<float>::max(); |
| 92 | } else { |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 93 | max_packet_rate[0] = |
| 94 | bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 95 | } |
| 96 | // Remove from candidate list. |
| 97 | min_bitrate_it->set_bitrate_bps(0); |
| 98 | --num_candidates; |
| 99 | |
| 100 | // 4. Discard from candidate list all tuple with lower overhead |
| 101 | // (next tuple must be steeper). |
| 102 | for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 103 | if (it->bitrate_bps() && |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 104 | it->packet_overhead() < bounding_set.front().packet_overhead()) { |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 105 | it->set_bitrate_bps(0); |
| 106 | --num_candidates; |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | bool get_new_candidate = true; |
| 111 | rtcp::TmmbItem cur_candidate; |
| 112 | while (num_candidates > 0) { |
| 113 | if (get_new_candidate) { |
| 114 | // 5. Remove first remaining tuple from candidate list. |
| 115 | for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 116 | if (it->bitrate_bps()) { |
| 117 | cur_candidate = *it; |
| 118 | it->set_bitrate_bps(0); |
| 119 | break; |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | // 6. Calculate packet rate and intersection of the current |
| 125 | // line with line of last tuple in selected list. |
| 126 | RTC_DCHECK_NE(cur_candidate.packet_overhead(), |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 127 | bounding_set.back().packet_overhead()); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 128 | float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() - |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 129 | bounding_set.back().bitrate_bps()) / |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 130 | (cur_candidate.packet_overhead() - |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 131 | bounding_set.back().packet_overhead()); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 132 | |
| 133 | // 7. If the packet rate is equal or lower than intersection of |
| 134 | // last tuple in selected list, |
| 135 | // remove last tuple in selected list & go back to step 6. |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 136 | if (packet_rate <= intersection[bounding_set.size() - 1]) { |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 137 | // Remove last tuple and goto step 6. |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 138 | bounding_set.pop_back(); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 139 | get_new_candidate = false; |
| 140 | } else { |
| 141 | // 8. If packet rate is lower than maximum packet rate of |
| 142 | // last tuple in selected list, add current tuple to selected |
| 143 | // list. |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 144 | if (packet_rate < max_packet_rate[bounding_set.size() - 1]) { |
| 145 | bounding_set.push_back(cur_candidate); |
| 146 | intersection[bounding_set.size() - 1] = packet_rate; |
| 147 | uint16_t packet_overhead = bounding_set.back().packet_overhead(); |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 148 | RTC_DCHECK_NE(packet_overhead, 0); |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 149 | max_packet_rate[bounding_set.size() - 1] = |
| 150 | bounding_set.back().bitrate_bps() / |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 151 | static_cast<float>(packet_overhead); |
| 152 | } |
| 153 | --num_candidates; |
| 154 | get_new_candidate = true; |
| 155 | } |
| 156 | |
| 157 | // 9. Go back to step 5 if any tuple remains in candidate list. |
| 158 | } |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 159 | RTC_DCHECK(!bounding_set.empty()); |
| 160 | return bounding_set; |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame] | 161 | } |
| 162 | |
Danil Chapovalov | daa90a7 | 2016-08-10 11:29:50 +0200 | [diff] [blame] | 163 | bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding, |
| 164 | uint32_t ssrc) { |
| 165 | for (const rtcp::TmmbItem& item : bounding) { |
| 166 | if (item.ssrc() == ssrc) { |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 167 | return true; |
| 168 | } |
| 169 | } |
| 170 | return false; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 171 | } |
| 172 | |
danilchap | 2f69ce9 | 2016-08-16 03:21:38 -0700 | [diff] [blame] | 173 | uint64_t TMMBRHelp::CalcMinBitrateBps( |
| 174 | const std::vector<rtcp::TmmbItem>& candidates) { |
| 175 | RTC_DCHECK(!candidates.empty()); |
| 176 | uint64_t min_bitrate_bps = std::numeric_limits<uint64_t>::max(); |
| 177 | for (const rtcp::TmmbItem& item : candidates) |
| 178 | if (item.bitrate_bps() < min_bitrate_bps) |
| 179 | min_bitrate_bps = item.bitrate_bps(); |
| 180 | return min_bitrate_bps; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 181 | } |
pbos@webrtc.org | d900e8b | 2013-07-03 15:12:26 +0000 | [diff] [blame] | 182 | } // namespace webrtc |