
--- Fixes for re-enabling more MSVC level 4 warnings: webrtc/ edition This contains fixes for the following sorts of issues: * Possibly-uninitialized local variable * Signedness mismatch * Assignment inside conditional This also contains a small number of other cleanups to nearby code. In particular several warning-disables for MSVC are removed because they don't seem to be necessary (either that warning is not enabled or the code does not trigger it). BUG=crbug.com/81439 TEST=none R=henrika@webrtc.org, pkasting@chromium.org Review URL: https://webrtc-codereview.appspot.com/18769004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6667 4adac7df-926f-26a2-2b94-8c16560cd09d
480 lines
14 KiB
C++
480 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "webrtc/modules/rtp_rtcp/source/tmmbr_help.h"
|
|
|
|
#include <assert.h>
|
|
#include <limits>
|
|
#include <string.h>
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
|
|
|
namespace webrtc {
|
|
TMMBRSet::TMMBRSet() :
|
|
_sizeOfSet(0),
|
|
_lengthOfSet(0)
|
|
{
|
|
}
|
|
|
|
TMMBRSet::~TMMBRSet()
|
|
{
|
|
_sizeOfSet = 0;
|
|
_lengthOfSet = 0;
|
|
}
|
|
|
|
void
|
|
TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize)
|
|
{
|
|
if(minimumSize > _sizeOfSet)
|
|
{
|
|
// make sure that our buffers are big enough
|
|
_data.resize(minimumSize);
|
|
_sizeOfSet = minimumSize;
|
|
}
|
|
// reset memory
|
|
for(uint32_t i = 0; i < _sizeOfSet; i++)
|
|
{
|
|
_data.at(i).tmmbr = 0;
|
|
_data.at(i).packet_oh = 0;
|
|
_data.at(i).ssrc = 0;
|
|
}
|
|
_lengthOfSet = 0;
|
|
}
|
|
|
|
void
|
|
TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize)
|
|
{
|
|
if(minimumSize > _sizeOfSet)
|
|
{
|
|
{
|
|
_data.resize(minimumSize);
|
|
}
|
|
_sizeOfSet = minimumSize;
|
|
}
|
|
}
|
|
|
|
void TMMBRSet::SetEntry(unsigned int i,
|
|
uint32_t tmmbrSet,
|
|
uint32_t packetOHSet,
|
|
uint32_t ssrcSet) {
|
|
assert(i < _sizeOfSet);
|
|
_data.at(i).tmmbr = tmmbrSet;
|
|
_data.at(i).packet_oh = packetOHSet;
|
|
_data.at(i).ssrc = ssrcSet;
|
|
if (i >= _lengthOfSet) {
|
|
_lengthOfSet = i + 1;
|
|
}
|
|
}
|
|
|
|
void TMMBRSet::AddEntry(uint32_t tmmbrSet,
|
|
uint32_t packetOHSet,
|
|
uint32_t ssrcSet) {
|
|
assert(_lengthOfSet < _sizeOfSet);
|
|
SetEntry(_lengthOfSet, tmmbrSet, packetOHSet, ssrcSet);
|
|
}
|
|
|
|
void TMMBRSet::RemoveEntry(uint32_t sourceIdx) {
|
|
assert(sourceIdx < _lengthOfSet);
|
|
_data.erase(_data.begin() + sourceIdx);
|
|
_lengthOfSet--;
|
|
_data.resize(_sizeOfSet); // Ensure that size remains the same.
|
|
}
|
|
|
|
void TMMBRSet::SwapEntries(uint32_t i, uint32_t j) {
|
|
SetElement temp;
|
|
temp = _data[i];
|
|
_data[i] = _data[j];
|
|
_data[j] = temp;
|
|
}
|
|
|
|
void TMMBRSet::ClearEntry(uint32_t idx) {
|
|
SetEntry(idx, 0, 0, 0);
|
|
}
|
|
|
|
TMMBRHelp::TMMBRHelp()
|
|
: _criticalSection(CriticalSectionWrapper::CreateCriticalSection()),
|
|
_candidateSet(),
|
|
_boundingSet(),
|
|
_boundingSetToSend(),
|
|
_ptrIntersectionBoundingSet(NULL),
|
|
_ptrMaxPRBoundingSet(NULL) {
|
|
}
|
|
|
|
TMMBRHelp::~TMMBRHelp() {
|
|
delete [] _ptrIntersectionBoundingSet;
|
|
delete [] _ptrMaxPRBoundingSet;
|
|
_ptrIntersectionBoundingSet = 0;
|
|
_ptrMaxPRBoundingSet = 0;
|
|
delete _criticalSection;
|
|
}
|
|
|
|
TMMBRSet*
|
|
TMMBRHelp::VerifyAndAllocateBoundingSet(uint32_t minimumSize)
|
|
{
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
if(minimumSize > _boundingSet.sizeOfSet())
|
|
{
|
|
// make sure that our buffers are big enough
|
|
if(_ptrIntersectionBoundingSet)
|
|
{
|
|
delete [] _ptrIntersectionBoundingSet;
|
|
delete [] _ptrMaxPRBoundingSet;
|
|
}
|
|
_ptrIntersectionBoundingSet = new float[minimumSize];
|
|
_ptrMaxPRBoundingSet = new float[minimumSize];
|
|
}
|
|
_boundingSet.VerifyAndAllocateSet(minimumSize);
|
|
return &_boundingSet;
|
|
}
|
|
|
|
TMMBRSet* TMMBRHelp::BoundingSet() {
|
|
return &_boundingSet;
|
|
}
|
|
|
|
int32_t
|
|
TMMBRHelp::SetTMMBRBoundingSetToSend(const TMMBRSet* boundingSetToSend,
|
|
const uint32_t maxBitrateKbit)
|
|
{
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
if (boundingSetToSend == NULL)
|
|
{
|
|
_boundingSetToSend.clearSet();
|
|
return 0;
|
|
}
|
|
|
|
VerifyAndAllocateBoundingSetToSend(boundingSetToSend->lengthOfSet());
|
|
_boundingSetToSend.clearSet();
|
|
for (uint32_t i = 0; i < boundingSetToSend->lengthOfSet(); i++)
|
|
{
|
|
// cap at our configured max bitrate
|
|
uint32_t bitrate = boundingSetToSend->Tmmbr(i);
|
|
if(maxBitrateKbit)
|
|
{
|
|
// do we have a configured max bitrate?
|
|
if(bitrate > maxBitrateKbit)
|
|
{
|
|
bitrate = maxBitrateKbit;
|
|
}
|
|
}
|
|
_boundingSetToSend.SetEntry(i, bitrate,
|
|
boundingSetToSend->PacketOH(i),
|
|
boundingSetToSend->Ssrc(i));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t
|
|
TMMBRHelp::VerifyAndAllocateBoundingSetToSend(uint32_t minimumSize)
|
|
{
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
_boundingSetToSend.VerifyAndAllocateSet(minimumSize);
|
|
return 0;
|
|
}
|
|
|
|
TMMBRSet*
|
|
TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize)
|
|
{
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
_candidateSet.VerifyAndAllocateSet(minimumSize);
|
|
return &_candidateSet;
|
|
}
|
|
|
|
TMMBRSet*
|
|
TMMBRHelp::CandidateSet()
|
|
{
|
|
return &_candidateSet;
|
|
}
|
|
|
|
TMMBRSet*
|
|
TMMBRHelp::BoundingSetToSend()
|
|
{
|
|
return &_boundingSetToSend;
|
|
}
|
|
|
|
int32_t
|
|
TMMBRHelp::FindTMMBRBoundingSet(TMMBRSet*& boundingSet)
|
|
{
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
// Work on local variable, will be modified
|
|
TMMBRSet candidateSet;
|
|
candidateSet.VerifyAndAllocateSet(_candidateSet.sizeOfSet());
|
|
|
|
// TODO(hta) Figure out if this should be lengthOfSet instead.
|
|
for (uint32_t i = 0; i < _candidateSet.sizeOfSet(); 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
|
|
assert(_candidateSet.PacketOH(i) == 0);
|
|
// Old code:
|
|
// _candidateSet.ptrPacketOHSet[i] = 0;
|
|
}
|
|
}
|
|
|
|
// Number of set candidates
|
|
int32_t numSetCandidates = candidateSet.lengthOfSet();
|
|
// Find bounding set
|
|
uint32_t numBoundingSet = 0;
|
|
if (numSetCandidates > 0)
|
|
{
|
|
numBoundingSet = FindTMMBRBoundingSet(numSetCandidates, candidateSet);
|
|
if(numBoundingSet < 1 || (numBoundingSet > _candidateSet.sizeOfSet()))
|
|
{
|
|
return -1;
|
|
}
|
|
boundingSet = &_boundingSet;
|
|
}
|
|
return numBoundingSet;
|
|
}
|
|
|
|
|
|
int32_t
|
|
TMMBRHelp::FindTMMBRBoundingSet(int32_t numCandidates, TMMBRSet& candidateSet)
|
|
{
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
uint32_t numBoundingSet = 0;
|
|
VerifyAndAllocateBoundingSet(candidateSet.sizeOfSet());
|
|
|
|
if (numCandidates == 1)
|
|
{
|
|
// TODO(hta): lengthOfSet instead of sizeOfSet?
|
|
for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
|
|
{
|
|
if (candidateSet.Tmmbr(i) > 0)
|
|
{
|
|
_boundingSet.AddEntry(candidateSet.Tmmbr(i),
|
|
candidateSet.PacketOH(i),
|
|
candidateSet.Ssrc(i));
|
|
numBoundingSet++;
|
|
}
|
|
}
|
|
return (numBoundingSet == 1) ? 1 : -1;
|
|
}
|
|
|
|
// 1. Sort by increasing packetOH
|
|
for (int i = candidateSet.sizeOfSet() - 1; i >= 0; i--)
|
|
{
|
|
for (int j = 1; j <= i; j++)
|
|
{
|
|
if (candidateSet.PacketOH(j-1) > candidateSet.PacketOH(j))
|
|
{
|
|
candidateSet.SwapEntries(j-1, j);
|
|
}
|
|
}
|
|
}
|
|
// 2. For tuples with same OH, keep the one w/ the lowest bitrate
|
|
for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
|
|
{
|
|
if (candidateSet.Tmmbr(i) > 0)
|
|
{
|
|
// get min bitrate for packets w/ same OH
|
|
uint32_t currentPacketOH = candidateSet.PacketOH(i);
|
|
uint32_t currentMinTMMBR = candidateSet.Tmmbr(i);
|
|
uint32_t currentMinIndexTMMBR = i;
|
|
for (uint32_t j = i+1; j < candidateSet.sizeOfSet(); j++)
|
|
{
|
|
if(candidateSet.PacketOH(j) == currentPacketOH)
|
|
{
|
|
if(candidateSet.Tmmbr(j) < currentMinTMMBR)
|
|
{
|
|
currentMinTMMBR = candidateSet.Tmmbr(j);
|
|
currentMinIndexTMMBR = j;
|
|
}
|
|
}
|
|
}
|
|
// keep lowest bitrate
|
|
for (uint32_t j = 0; j < candidateSet.sizeOfSet(); j++)
|
|
{
|
|
if(candidateSet.PacketOH(j) == currentPacketOH
|
|
&& j != currentMinIndexTMMBR)
|
|
{
|
|
candidateSet.ClearEntry(j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 3. Select and remove tuple w/ lowest tmmbr.
|
|
// (If more than 1, choose the one w/ highest OH).
|
|
uint32_t minTMMBR = 0;
|
|
uint32_t minIndexTMMBR = 0;
|
|
for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
|
|
{
|
|
if (candidateSet.Tmmbr(i) > 0)
|
|
{
|
|
minTMMBR = candidateSet.Tmmbr(i);
|
|
minIndexTMMBR = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
|
|
{
|
|
if (candidateSet.Tmmbr(i) > 0 && candidateSet.Tmmbr(i) <= minTMMBR)
|
|
{
|
|
// get min bitrate
|
|
minTMMBR = candidateSet.Tmmbr(i);
|
|
minIndexTMMBR = i;
|
|
}
|
|
}
|
|
// first member of selected list
|
|
_boundingSet.SetEntry(numBoundingSet,
|
|
candidateSet.Tmmbr(minIndexTMMBR),
|
|
candidateSet.PacketOH(minIndexTMMBR),
|
|
candidateSet.Ssrc(minIndexTMMBR));
|
|
|
|
// set intersection value
|
|
_ptrIntersectionBoundingSet[numBoundingSet] = 0;
|
|
// calculate its maximum packet rate (where its line crosses x-axis)
|
|
_ptrMaxPRBoundingSet[numBoundingSet]
|
|
= _boundingSet.Tmmbr(numBoundingSet) * 1000
|
|
/ float(8 * _boundingSet.PacketOH(numBoundingSet));
|
|
numBoundingSet++;
|
|
// remove from candidate list
|
|
candidateSet.ClearEntry(minIndexTMMBR);
|
|
numCandidates--;
|
|
|
|
// 4. Discard from candidate list all tuple w/ lower OH
|
|
// (next tuple must be steeper)
|
|
for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
|
|
{
|
|
if(candidateSet.Tmmbr(i) > 0
|
|
&& candidateSet.PacketOH(i) < _boundingSet.PacketOH(0))
|
|
{
|
|
candidateSet.ClearEntry(i);
|
|
numCandidates--;
|
|
}
|
|
}
|
|
|
|
if (numCandidates == 0)
|
|
{
|
|
// Should be true already:_boundingSet.lengthOfSet = numBoundingSet;
|
|
assert(_boundingSet.lengthOfSet() == numBoundingSet);
|
|
return numBoundingSet;
|
|
}
|
|
|
|
bool getNewCandidate = true;
|
|
int curCandidateTMMBR = 0;
|
|
int curCandidateIndex = 0;
|
|
int curCandidatePacketOH = 0;
|
|
int curCandidateSSRC = 0;
|
|
do
|
|
{
|
|
if (getNewCandidate)
|
|
{
|
|
// 5. Remove first remaining tuple from candidate list
|
|
for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
|
|
{
|
|
if (candidateSet.Tmmbr(i) > 0)
|
|
{
|
|
curCandidateTMMBR = candidateSet.Tmmbr(i);
|
|
curCandidatePacketOH = candidateSet.PacketOH(i);
|
|
curCandidateSSRC = candidateSet.Ssrc(i);
|
|
curCandidateIndex = i;
|
|
candidateSet.ClearEntry(curCandidateIndex);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 6. Calculate packet rate and intersection of the current
|
|
// line with line of last tuple in selected list
|
|
float packetRate
|
|
= float(curCandidateTMMBR
|
|
- _boundingSet.Tmmbr(numBoundingSet-1))*1000
|
|
/ (8*(curCandidatePacketOH
|
|
- _boundingSet.PacketOH(numBoundingSet-1)));
|
|
|
|
// 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(packetRate <= _ptrIntersectionBoundingSet[numBoundingSet-1])
|
|
{
|
|
// remove last tuple and goto step 6
|
|
numBoundingSet--;
|
|
_boundingSet.ClearEntry(numBoundingSet);
|
|
_ptrIntersectionBoundingSet[numBoundingSet] = 0;
|
|
_ptrMaxPRBoundingSet[numBoundingSet] = 0;
|
|
getNewCandidate = 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 (packetRate < _ptrMaxPRBoundingSet[numBoundingSet-1])
|
|
{
|
|
_boundingSet.SetEntry(numBoundingSet,
|
|
curCandidateTMMBR,
|
|
curCandidatePacketOH,
|
|
curCandidateSSRC);
|
|
_ptrIntersectionBoundingSet[numBoundingSet] = packetRate;
|
|
_ptrMaxPRBoundingSet[numBoundingSet]
|
|
= _boundingSet.Tmmbr(numBoundingSet)*1000
|
|
/ float(8*_boundingSet.PacketOH(numBoundingSet));
|
|
numBoundingSet++;
|
|
}
|
|
numCandidates--;
|
|
getNewCandidate = true;
|
|
}
|
|
|
|
// 9. Go back to step 5 if any tuple remains in candidate list
|
|
} while (numCandidates > 0);
|
|
|
|
return numBoundingSet;
|
|
}
|
|
|
|
bool TMMBRHelp::IsOwner(const uint32_t ssrc,
|
|
const uint32_t length) const {
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
if (length == 0) {
|
|
// Empty bounding set.
|
|
return false;
|
|
}
|
|
for(uint32_t i = 0;
|
|
(i < length) && (i < _boundingSet.sizeOfSet()); ++i) {
|
|
if(_boundingSet.Ssrc(i) == ssrc) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool TMMBRHelp::CalcMinBitRate( uint32_t* minBitrateKbit) const {
|
|
CriticalSectionScoped lock(_criticalSection);
|
|
|
|
if (_candidateSet.sizeOfSet() == 0) {
|
|
// Empty bounding set.
|
|
return false;
|
|
}
|
|
*minBitrateKbit = std::numeric_limits<uint32_t>::max();
|
|
|
|
for (uint32_t i = 0; i < _candidateSet.lengthOfSet(); ++i) {
|
|
uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i);
|
|
if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) {
|
|
curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE;
|
|
}
|
|
*minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ?
|
|
curNetBitRateKbit : *minBitrateKbit;
|
|
}
|
|
return true;
|
|
}
|
|
} // namespace webrtc
|