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 | |
pbos@webrtc.org | a048d7c | 2013-05-29 14:27:38 +0000 | [diff] [blame] | 11 | #include "webrtc/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 | |
danilchap | f6ff971 | 2016-02-24 09:23:37 -0800 | [diff] [blame] | 16 | #include "webrtc/base/checks.h" |
pbos@webrtc.org | a048d7c | 2013-05-29 14:27:38 +0000 | [diff] [blame] | 17 | #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 18 | |
| 19 | namespace webrtc { |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 20 | void TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize) { |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 21 | clear(); |
| 22 | reserve(minimumSize); |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 23 | } |
| 24 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 25 | void TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize) { |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 26 | reserve(minimumSize); |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 27 | } |
| 28 | |
| 29 | void TMMBRSet::SetEntry(unsigned int i, |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 30 | uint32_t tmmbrSet, |
| 31 | uint32_t packetOHSet, |
| 32 | uint32_t ssrcSet) { |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 33 | RTC_DCHECK_LT(i, capacity()); |
| 34 | if (i >= size()) { |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 35 | resize(i + 1); |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 36 | } |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 37 | (*this)[i].set_bitrate_bps(tmmbrSet * 1000); |
| 38 | (*this)[i].set_packet_overhead(packetOHSet); |
| 39 | (*this)[i].set_ssrc(ssrcSet); |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 40 | } |
| 41 | |
pbos@webrtc.org | 2f44673 | 2013-04-08 11:08:41 +0000 | [diff] [blame] | 42 | void TMMBRSet::AddEntry(uint32_t tmmbrSet, |
| 43 | uint32_t packetOHSet, |
| 44 | uint32_t ssrcSet) { |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 45 | RTC_DCHECK_LT(size(), capacity()); |
| 46 | SetEntry(size(), tmmbrSet, packetOHSet, ssrcSet); |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 47 | } |
| 48 | |
pbos@webrtc.org | 2f44673 | 2013-04-08 11:08:41 +0000 | [diff] [blame] | 49 | void TMMBRSet::RemoveEntry(uint32_t sourceIdx) { |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 50 | RTC_DCHECK_LT(sourceIdx, size()); |
| 51 | erase(begin() + sourceIdx); |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 52 | } |
| 53 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 54 | TMMBRSet* TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize) { |
| 55 | _candidateSet.VerifyAndAllocateSet(minimumSize); |
| 56 | return &_candidateSet; |
hta@webrtc.org | 54536bb | 2012-05-03 14:07:23 +0000 | [diff] [blame] | 57 | } |
| 58 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 59 | TMMBRSet* TMMBRHelp::CandidateSet() { |
| 60 | return &_candidateSet; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 61 | } |
| 62 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 63 | int32_t TMMBRHelp::FindTMMBRBoundingSet(TMMBRSet*& boundingSet) { |
| 64 | // Work on local variable, will be modified |
| 65 | TMMBRSet candidateSet; |
| 66 | candidateSet.VerifyAndAllocateSet(_candidateSet.capacity()); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 67 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 68 | for (size_t i = 0; i < _candidateSet.size(); i++) { |
| 69 | if (_candidateSet.Tmmbr(i)) { |
| 70 | candidateSet.AddEntry(_candidateSet.Tmmbr(i), _candidateSet.PacketOH(i), |
| 71 | _candidateSet.Ssrc(i)); |
danilchap | f6ff971 | 2016-02-24 09:23:37 -0800 | [diff] [blame] | 72 | } else { |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 73 | // make sure this is zero if tmmbr = 0 |
| 74 | RTC_DCHECK_EQ(_candidateSet.PacketOH(i), 0u); |
| 75 | // Old code: |
| 76 | // _candidateSet.ptrPacketOHSet[i] = 0; |
danilchap | f6ff971 | 2016-02-24 09:23:37 -0800 | [diff] [blame] | 77 | } |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 78 | } |
tommi@webrtc.org | eec6ecd | 2014-07-11 19:09:59 +0000 | [diff] [blame] | 79 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 80 | // Number of set candidates |
| 81 | int32_t numSetCandidates = candidateSet.lengthOfSet(); |
| 82 | // Find bounding set |
| 83 | uint32_t numBoundingSet = 0; |
| 84 | if (numSetCandidates > 0) { |
| 85 | FindBoundingSet(std::move(candidateSet), &_boundingSet); |
| 86 | numBoundingSet = _boundingSet.size(); |
| 87 | if (numBoundingSet < 1 || (numBoundingSet > _candidateSet.size())) { |
| 88 | return -1; |
tommi@webrtc.org | eec6ecd | 2014-07-11 19:09:59 +0000 | [diff] [blame] | 89 | } |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 90 | boundingSet = &_boundingSet; |
| 91 | } |
| 92 | return numBoundingSet; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 93 | } |
| 94 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 95 | void TMMBRHelp::FindBoundingSet(std::vector<rtcp::TmmbItem> candidates, |
| 96 | std::vector<rtcp::TmmbItem>* bounding_set) { |
| 97 | RTC_DCHECK(bounding_set); |
| 98 | RTC_DCHECK(!candidates.empty()); |
| 99 | size_t num_candidates = candidates.size(); |
| 100 | |
| 101 | if (num_candidates == 1) { |
| 102 | RTC_DCHECK(candidates[0].bitrate_bps()); |
| 103 | *bounding_set = std::move(candidates); |
| 104 | return; |
| 105 | } |
| 106 | |
| 107 | // 1. Sort by increasing packet overhead. |
| 108 | std::sort(candidates.begin(), candidates.end(), |
| 109 | [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) { |
| 110 | return lhs.packet_overhead() < rhs.packet_overhead(); |
| 111 | }); |
| 112 | |
| 113 | // 2. For tuples with same overhead, keep the one with the lowest bitrate. |
| 114 | for (auto it = candidates.begin(); it != candidates.end();) { |
| 115 | RTC_DCHECK(it->bitrate_bps()); |
| 116 | auto current_min = it; |
| 117 | auto next_it = it + 1; |
| 118 | // Use fact candidates are sorted by overhead, so candidates with same |
| 119 | // overhead are adjusted. |
| 120 | while (next_it != candidates.end() && |
| 121 | next_it->packet_overhead() == current_min->packet_overhead()) { |
| 122 | if (next_it->bitrate_bps() < current_min->bitrate_bps()) { |
| 123 | current_min->set_bitrate_bps(0); |
| 124 | current_min = next_it; |
| 125 | } else { |
| 126 | next_it->set_bitrate_bps(0); |
| 127 | } |
| 128 | ++next_it; |
| 129 | --num_candidates; |
| 130 | } |
| 131 | it = next_it; |
| 132 | } |
| 133 | |
| 134 | // 3. Select and remove tuple with lowest tmmbr. |
| 135 | // (If more than 1, choose the one with highest overhead). |
| 136 | auto min_bitrate_it = candidates.end(); |
| 137 | for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 138 | if (it->bitrate_bps()) { |
| 139 | min_bitrate_it = it; |
| 140 | break; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | for (auto it = min_bitrate_it; it != candidates.end(); ++it) { |
| 145 | if (it->bitrate_bps() && |
| 146 | it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) { |
| 147 | // Get min bitrate. |
| 148 | min_bitrate_it = it; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | bounding_set->clear(); |
| 153 | bounding_set->reserve(num_candidates); |
| 154 | std::vector<float> intersection(num_candidates); |
| 155 | std::vector<float> max_packet_rate(num_candidates); |
| 156 | |
| 157 | // First member of selected list. |
| 158 | bounding_set->push_back(*min_bitrate_it); |
| 159 | intersection[0] = 0; |
| 160 | // Calculate its maximum packet rate (where its line crosses x-axis). |
| 161 | uint16_t packet_overhead = bounding_set->back().packet_overhead(); |
| 162 | if (packet_overhead == 0) { |
| 163 | // Avoid division by zero. |
| 164 | max_packet_rate[0] = std::numeric_limits<float>::max(); |
| 165 | } else { |
| 166 | max_packet_rate[0] = bounding_set->back().bitrate_bps() / |
| 167 | static_cast<float>(packet_overhead); |
| 168 | } |
| 169 | // Remove from candidate list. |
| 170 | min_bitrate_it->set_bitrate_bps(0); |
| 171 | --num_candidates; |
| 172 | |
| 173 | // 4. Discard from candidate list all tuple with lower overhead |
| 174 | // (next tuple must be steeper). |
| 175 | for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 176 | if (it->bitrate_bps() && |
| 177 | it->packet_overhead() < bounding_set->front().packet_overhead()) { |
| 178 | it->set_bitrate_bps(0); |
| 179 | --num_candidates; |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | bool get_new_candidate = true; |
| 184 | rtcp::TmmbItem cur_candidate; |
| 185 | while (num_candidates > 0) { |
| 186 | if (get_new_candidate) { |
| 187 | // 5. Remove first remaining tuple from candidate list. |
| 188 | for (auto it = candidates.begin(); it != candidates.end(); ++it) { |
| 189 | if (it->bitrate_bps()) { |
| 190 | cur_candidate = *it; |
| 191 | it->set_bitrate_bps(0); |
| 192 | break; |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | // 6. Calculate packet rate and intersection of the current |
| 198 | // line with line of last tuple in selected list. |
| 199 | RTC_DCHECK_NE(cur_candidate.packet_overhead(), |
| 200 | bounding_set->back().packet_overhead()); |
| 201 | float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() - |
| 202 | bounding_set->back().bitrate_bps()) / |
| 203 | (cur_candidate.packet_overhead() - |
| 204 | bounding_set->back().packet_overhead()); |
| 205 | |
| 206 | // 7. If the packet rate is equal or lower than intersection of |
| 207 | // last tuple in selected list, |
| 208 | // remove last tuple in selected list & go back to step 6. |
| 209 | if (packet_rate <= intersection[bounding_set->size() - 1]) { |
| 210 | // Remove last tuple and goto step 6. |
| 211 | bounding_set->pop_back(); |
| 212 | get_new_candidate = false; |
| 213 | } else { |
| 214 | // 8. If packet rate is lower than maximum packet rate of |
| 215 | // last tuple in selected list, add current tuple to selected |
| 216 | // list. |
| 217 | if (packet_rate < max_packet_rate[bounding_set->size() - 1]) { |
| 218 | bounding_set->push_back(cur_candidate); |
| 219 | intersection[bounding_set->size() - 1] = packet_rate; |
| 220 | uint16_t packet_overhead = bounding_set->back().packet_overhead(); |
| 221 | RTC_DCHECK_NE(packet_overhead, 0); |
| 222 | max_packet_rate[bounding_set->size() - 1] = |
| 223 | bounding_set->back().bitrate_bps() / |
| 224 | static_cast<float>(packet_overhead); |
| 225 | } |
| 226 | --num_candidates; |
| 227 | get_new_candidate = true; |
| 228 | } |
| 229 | |
| 230 | // 9. Go back to step 5 if any tuple remains in candidate list. |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | bool TMMBRHelp::IsOwner(const uint32_t ssrc, const uint32_t length) const { |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 235 | if (length == 0) { |
| 236 | // Empty bounding set. |
henrike@webrtc.org | 0ad5186 | 2012-03-30 16:54:13 +0000 | [diff] [blame] | 237 | return false; |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 238 | } |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 239 | for (size_t i = 0; (i < length) && (i < _boundingSet.size()); ++i) { |
| 240 | if (_boundingSet.Ssrc(i) == ssrc) { |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 241 | return true; |
| 242 | } |
| 243 | } |
| 244 | return false; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 245 | } |
| 246 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 247 | bool TMMBRHelp::CalcMinBitRate(uint32_t* minBitrateKbit) const { |
danilchap | a4f31bd | 2016-02-29 05:26:01 -0800 | [diff] [blame] | 248 | if (_candidateSet.size() == 0) { |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 249 | // Empty bounding set. |
| 250 | return false; |
| 251 | } |
| 252 | *minBitrateKbit = std::numeric_limits<uint32_t>::max(); |
| 253 | |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 254 | for (size_t i = 0; i < _candidateSet.lengthOfSet(); ++i) { |
pbos@webrtc.org | 2f44673 | 2013-04-08 11:08:41 +0000 | [diff] [blame] | 255 | uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i); |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 256 | if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) { |
| 257 | curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 258 | } |
danilchap | 262e486 | 2016-08-05 03:37:38 -0700 | [diff] [blame^] | 259 | *minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ? curNetBitRateKbit |
| 260 | : *minBitrateKbit; |
pwestin@webrtc.org | cac7878 | 2012-04-05 08:30:10 +0000 | [diff] [blame] | 261 | } |
| 262 | return true; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 263 | } |
pbos@webrtc.org | d900e8b | 2013-07-03 15:12:26 +0000 | [diff] [blame] | 264 | } // namespace webrtc |