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