2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-04-05 08:30:10 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-29 14:27:38 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/tmmbr_help.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
#include <algorithm>
|
2015-12-10 05:05:27 -08:00
|
|
|
#include <limits>
|
|
|
|
|
|
2016-02-24 09:23:37 -08:00
|
|
|
#include "webrtc/base/checks.h"
|
2013-05-29 14:27:38 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
2016-08-05 03:37:38 -07:00
|
|
|
void TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize) {
|
2016-02-29 05:26:01 -08:00
|
|
|
clear();
|
|
|
|
|
reserve(minimumSize);
|
2012-05-03 14:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
void TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize) {
|
2016-02-29 05:26:01 -08:00
|
|
|
reserve(minimumSize);
|
2012-05-03 14:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TMMBRSet::SetEntry(unsigned int i,
|
2016-08-05 03:37:38 -07:00
|
|
|
uint32_t tmmbrSet,
|
|
|
|
|
uint32_t packetOHSet,
|
|
|
|
|
uint32_t ssrcSet) {
|
2016-02-29 05:26:01 -08:00
|
|
|
RTC_DCHECK_LT(i, capacity());
|
|
|
|
|
if (i >= size()) {
|
2016-08-05 03:37:38 -07:00
|
|
|
resize(i + 1);
|
2012-05-03 14:07:23 +00:00
|
|
|
}
|
2016-02-29 05:26:01 -08:00
|
|
|
(*this)[i].set_bitrate_bps(tmmbrSet * 1000);
|
|
|
|
|
(*this)[i].set_packet_overhead(packetOHSet);
|
|
|
|
|
(*this)[i].set_ssrc(ssrcSet);
|
2012-05-03 14:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
void TMMBRSet::AddEntry(uint32_t tmmbrSet,
|
|
|
|
|
uint32_t packetOHSet,
|
|
|
|
|
uint32_t ssrcSet) {
|
2016-02-29 05:26:01 -08:00
|
|
|
RTC_DCHECK_LT(size(), capacity());
|
|
|
|
|
SetEntry(size(), tmmbrSet, packetOHSet, ssrcSet);
|
2012-05-03 14:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
void TMMBRSet::RemoveEntry(uint32_t sourceIdx) {
|
2016-02-29 05:26:01 -08:00
|
|
|
RTC_DCHECK_LT(sourceIdx, size());
|
|
|
|
|
erase(begin() + sourceIdx);
|
2012-05-03 14:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
TMMBRSet* TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize) {
|
|
|
|
|
_candidateSet.VerifyAndAllocateSet(minimumSize);
|
|
|
|
|
return &_candidateSet;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
TMMBRSet* TMMBRHelp::CandidateSet() {
|
|
|
|
|
return &_candidateSet;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
int32_t TMMBRHelp::FindTMMBRBoundingSet(TMMBRSet*& boundingSet) {
|
|
|
|
|
// Work on local variable, will be modified
|
|
|
|
|
TMMBRSet candidateSet;
|
|
|
|
|
candidateSet.VerifyAndAllocateSet(_candidateSet.capacity());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
for (size_t i = 0; i < _candidateSet.size(); i++) {
|
|
|
|
|
if (_candidateSet.Tmmbr(i)) {
|
|
|
|
|
candidateSet.AddEntry(_candidateSet.Tmmbr(i), _candidateSet.PacketOH(i),
|
|
|
|
|
_candidateSet.Ssrc(i));
|
|
|
|
|
} else {
|
|
|
|
|
// make sure this is zero if tmmbr = 0
|
|
|
|
|
RTC_DCHECK_EQ(_candidateSet.PacketOH(i), 0u);
|
|
|
|
|
// Old code:
|
|
|
|
|
// _candidateSet.ptrPacketOHSet[i] = 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
// Number of set candidates
|
|
|
|
|
int32_t numSetCandidates = candidateSet.lengthOfSet();
|
|
|
|
|
// Find bounding set
|
|
|
|
|
uint32_t numBoundingSet = 0;
|
|
|
|
|
if (numSetCandidates > 0) {
|
|
|
|
|
FindBoundingSet(std::move(candidateSet), &_boundingSet);
|
|
|
|
|
numBoundingSet = _boundingSet.size();
|
|
|
|
|
if (numBoundingSet < 1 || (numBoundingSet > _candidateSet.size())) {
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
boundingSet = &_boundingSet;
|
|
|
|
|
}
|
|
|
|
|
return numBoundingSet;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
void TMMBRHelp::FindBoundingSet(std::vector<rtcp::TmmbItem> candidates,
|
|
|
|
|
std::vector<rtcp::TmmbItem>* bounding_set) {
|
|
|
|
|
RTC_DCHECK(bounding_set);
|
|
|
|
|
RTC_DCHECK(!candidates.empty());
|
|
|
|
|
size_t num_candidates = candidates.size();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
if (num_candidates == 1) {
|
|
|
|
|
RTC_DCHECK(candidates[0].bitrate_bps());
|
|
|
|
|
*bounding_set = std::move(candidates);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
// 1. Sort by increasing packet overhead.
|
|
|
|
|
std::sort(candidates.begin(), candidates.end(),
|
|
|
|
|
[](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
|
|
|
|
|
return lhs.packet_overhead() < rhs.packet_overhead();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 2. For tuples with same overhead, keep the one with the lowest bitrate.
|
|
|
|
|
for (auto it = candidates.begin(); it != candidates.end();) {
|
|
|
|
|
RTC_DCHECK(it->bitrate_bps());
|
|
|
|
|
auto current_min = it;
|
|
|
|
|
auto next_it = it + 1;
|
|
|
|
|
// Use fact candidates are sorted by overhead, so candidates with same
|
|
|
|
|
// overhead are adjusted.
|
|
|
|
|
while (next_it != candidates.end() &&
|
|
|
|
|
next_it->packet_overhead() == current_min->packet_overhead()) {
|
|
|
|
|
if (next_it->bitrate_bps() < current_min->bitrate_bps()) {
|
|
|
|
|
current_min->set_bitrate_bps(0);
|
|
|
|
|
current_min = next_it;
|
|
|
|
|
} else {
|
|
|
|
|
next_it->set_bitrate_bps(0);
|
|
|
|
|
}
|
|
|
|
|
++next_it;
|
|
|
|
|
--num_candidates;
|
2014-07-11 19:09:59 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
it = next_it;
|
|
|
|
|
}
|
2014-07-11 19:09:59 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
// 3. Select and remove tuple with lowest tmmbr.
|
|
|
|
|
// (If more than 1, choose the one with highest overhead).
|
|
|
|
|
auto min_bitrate_it = candidates.end();
|
|
|
|
|
for (auto it = candidates.begin(); it != candidates.end(); ++it) {
|
|
|
|
|
if (it->bitrate_bps()) {
|
|
|
|
|
min_bitrate_it = it;
|
|
|
|
|
break;
|
2014-07-11 19:09:59 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
for (auto it = min_bitrate_it; it != candidates.end(); ++it) {
|
|
|
|
|
if (it->bitrate_bps() &&
|
|
|
|
|
it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) {
|
|
|
|
|
// Get min bitrate.
|
|
|
|
|
min_bitrate_it = it;
|
2014-07-11 19:09:59 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
}
|
2014-07-11 19:09:59 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
bounding_set->clear();
|
|
|
|
|
bounding_set->reserve(num_candidates);
|
|
|
|
|
std::vector<float> intersection(num_candidates);
|
|
|
|
|
std::vector<float> max_packet_rate(num_candidates);
|
|
|
|
|
|
|
|
|
|
// First member of selected list.
|
|
|
|
|
bounding_set->push_back(*min_bitrate_it);
|
|
|
|
|
intersection[0] = 0;
|
|
|
|
|
// Calculate its maximum packet rate (where its line crosses x-axis).
|
|
|
|
|
uint16_t packet_overhead = bounding_set->back().packet_overhead();
|
|
|
|
|
if (packet_overhead == 0) {
|
|
|
|
|
// Avoid division by zero.
|
|
|
|
|
max_packet_rate[0] = std::numeric_limits<float>::max();
|
|
|
|
|
} else {
|
|
|
|
|
max_packet_rate[0] = bounding_set->back().bitrate_bps() /
|
|
|
|
|
static_cast<float>(packet_overhead);
|
|
|
|
|
}
|
|
|
|
|
// Remove from candidate list.
|
|
|
|
|
min_bitrate_it->set_bitrate_bps(0);
|
|
|
|
|
--num_candidates;
|
|
|
|
|
|
|
|
|
|
// 4. Discard from candidate list all tuple with lower overhead
|
|
|
|
|
// (next tuple must be steeper).
|
|
|
|
|
for (auto it = candidates.begin(); it != candidates.end(); ++it) {
|
|
|
|
|
if (it->bitrate_bps() &&
|
|
|
|
|
it->packet_overhead() < bounding_set->front().packet_overhead()) {
|
|
|
|
|
it->set_bitrate_bps(0);
|
|
|
|
|
--num_candidates;
|
2016-02-24 09:23:37 -08:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
}
|
2014-07-11 19:09:59 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
bool get_new_candidate = true;
|
|
|
|
|
rtcp::TmmbItem cur_candidate;
|
|
|
|
|
while (num_candidates > 0) {
|
|
|
|
|
if (get_new_candidate) {
|
|
|
|
|
// 5. Remove first remaining tuple from candidate list.
|
|
|
|
|
for (auto it = candidates.begin(); it != candidates.end(); ++it) {
|
|
|
|
|
if (it->bitrate_bps()) {
|
|
|
|
|
cur_candidate = *it;
|
|
|
|
|
it->set_bitrate_bps(0);
|
|
|
|
|
break;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
}
|
2014-07-11 19:09:59 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
// 6. Calculate packet rate and intersection of the current
|
|
|
|
|
// line with line of last tuple in selected list.
|
|
|
|
|
RTC_DCHECK_NE(cur_candidate.packet_overhead(),
|
|
|
|
|
bounding_set->back().packet_overhead());
|
|
|
|
|
float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
|
|
|
|
|
bounding_set->back().bitrate_bps()) /
|
|
|
|
|
(cur_candidate.packet_overhead() -
|
|
|
|
|
bounding_set->back().packet_overhead());
|
|
|
|
|
|
|
|
|
|
// 7. If the packet rate is equal or lower than intersection of
|
|
|
|
|
// last tuple in selected list,
|
|
|
|
|
// remove last tuple in selected list & go back to step 6.
|
|
|
|
|
if (packet_rate <= intersection[bounding_set->size() - 1]) {
|
|
|
|
|
// Remove last tuple and goto step 6.
|
|
|
|
|
bounding_set->pop_back();
|
|
|
|
|
get_new_candidate = false;
|
|
|
|
|
} else {
|
|
|
|
|
// 8. If packet rate is lower than maximum packet rate of
|
|
|
|
|
// last tuple in selected list, add current tuple to selected
|
|
|
|
|
// list.
|
|
|
|
|
if (packet_rate < max_packet_rate[bounding_set->size() - 1]) {
|
|
|
|
|
bounding_set->push_back(cur_candidate);
|
|
|
|
|
intersection[bounding_set->size() - 1] = packet_rate;
|
|
|
|
|
uint16_t packet_overhead = bounding_set->back().packet_overhead();
|
|
|
|
|
RTC_DCHECK_NE(packet_overhead, 0);
|
|
|
|
|
max_packet_rate[bounding_set->size() - 1] =
|
|
|
|
|
bounding_set->back().bitrate_bps() /
|
|
|
|
|
static_cast<float>(packet_overhead);
|
|
|
|
|
}
|
|
|
|
|
--num_candidates;
|
|
|
|
|
get_new_candidate = true;
|
2014-07-11 19:09:59 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
// 9. Go back to step 5 if any tuple remains in candidate list.
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
bool TMMBRHelp::IsOwner(const uint32_t ssrc, const uint32_t length) const {
|
2012-04-05 08:30:10 +00:00
|
|
|
if (length == 0) {
|
|
|
|
|
// Empty bounding set.
|
2012-03-30 16:54:13 +00:00
|
|
|
return false;
|
2012-04-05 08:30:10 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
for (size_t i = 0; (i < length) && (i < _boundingSet.size()); ++i) {
|
|
|
|
|
if (_boundingSet.Ssrc(i) == ssrc) {
|
2012-04-05 08:30:10 +00:00
|
|
|
return true;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-05 08:30:10 +00:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-03-30 16:54:13 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
bool TMMBRHelp::CalcMinBitRate(uint32_t* minBitrateKbit) const {
|
2016-02-29 05:26:01 -08:00
|
|
|
if (_candidateSet.size() == 0) {
|
2012-04-05 08:30:10 +00:00
|
|
|
// Empty bounding set.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*minBitrateKbit = std::numeric_limits<uint32_t>::max();
|
2012-03-30 16:54:13 +00:00
|
|
|
|
2016-08-05 03:37:38 -07:00
|
|
|
for (size_t i = 0; i < _candidateSet.lengthOfSet(); ++i) {
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i);
|
2012-04-05 08:30:10 +00:00
|
|
|
if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) {
|
|
|
|
|
curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE;
|
2012-03-30 16:54:13 +00:00
|
|
|
}
|
2016-08-05 03:37:38 -07:00
|
|
|
*minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ? curNetBitRateKbit
|
|
|
|
|
: *minBitrateKbit;
|
2012-04-05 08:30:10 +00:00
|
|
|
}
|
|
|
|
|
return true;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2013-07-03 15:12:26 +00:00
|
|
|
} // namespace webrtc
|