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 "webrtc/modules/rtp_rtcp/source/tmmbr_help.h" 12 13 #include <assert.h> 14 #include <string.h> 15 16 #include <limits> 17 18 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h" 19 20 namespace webrtc { 21 TMMBRSet::TMMBRSet() : 22 _sizeOfSet(0), 23 _lengthOfSet(0) 24 { 25 } 26 27 TMMBRSet::~TMMBRSet() 28 { 29 _sizeOfSet = 0; 30 _lengthOfSet = 0; 31 } 32 33 void 34 TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize) 35 { 36 if(minimumSize > _sizeOfSet) 37 { 38 // make sure that our buffers are big enough 39 _data.resize(minimumSize); 40 _sizeOfSet = minimumSize; 41 } 42 // reset memory 43 for(uint32_t i = 0; i < _sizeOfSet; i++) 44 { 45 _data.at(i).tmmbr = 0; 46 _data.at(i).packet_oh = 0; 47 _data.at(i).ssrc = 0; 48 } 49 _lengthOfSet = 0; 50 } 51 52 void 53 TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize) 54 { 55 if(minimumSize > _sizeOfSet) 56 { 57 { 58 _data.resize(minimumSize); 59 } 60 _sizeOfSet = minimumSize; 61 } 62 } 63 64 void TMMBRSet::SetEntry(unsigned int i, 65 uint32_t tmmbrSet, 66 uint32_t packetOHSet, 67 uint32_t ssrcSet) { 68 assert(i < _sizeOfSet); 69 _data.at(i).tmmbr = tmmbrSet; 70 _data.at(i).packet_oh = packetOHSet; 71 _data.at(i).ssrc = ssrcSet; 72 if (i >= _lengthOfSet) { 73 _lengthOfSet = i + 1; 74 } 75 } 76 77 void TMMBRSet::AddEntry(uint32_t tmmbrSet, 78 uint32_t packetOHSet, 79 uint32_t ssrcSet) { 80 assert(_lengthOfSet < _sizeOfSet); 81 SetEntry(_lengthOfSet, tmmbrSet, packetOHSet, ssrcSet); 82 } 83 84 void TMMBRSet::RemoveEntry(uint32_t sourceIdx) { 85 assert(sourceIdx < _lengthOfSet); 86 _data.erase(_data.begin() + sourceIdx); 87 _lengthOfSet--; 88 _data.resize(_sizeOfSet); // Ensure that size remains the same. 89 } 90 91 void TMMBRSet::SwapEntries(uint32_t i, uint32_t j) { 92 SetElement temp; 93 temp = _data[i]; 94 _data[i] = _data[j]; 95 _data[j] = temp; 96 } 97 98 void TMMBRSet::ClearEntry(uint32_t idx) { 99 SetEntry(idx, 0, 0, 0); 100 } 101 102 TMMBRHelp::TMMBRHelp() 103 : _criticalSection(CriticalSectionWrapper::CreateCriticalSection()), 104 _candidateSet(), 105 _boundingSet(), 106 _boundingSetToSend(), 107 _ptrIntersectionBoundingSet(NULL), 108 _ptrMaxPRBoundingSet(NULL) { 109 } 110 111 TMMBRHelp::~TMMBRHelp() { 112 delete [] _ptrIntersectionBoundingSet; 113 delete [] _ptrMaxPRBoundingSet; 114 _ptrIntersectionBoundingSet = 0; 115 _ptrMaxPRBoundingSet = 0; 116 delete _criticalSection; 117 } 118 119 TMMBRSet* 120 TMMBRHelp::VerifyAndAllocateBoundingSet(uint32_t minimumSize) 121 { 122 CriticalSectionScoped lock(_criticalSection); 123 124 if(minimumSize > _boundingSet.sizeOfSet()) 125 { 126 // make sure that our buffers are big enough 127 if(_ptrIntersectionBoundingSet) 128 { 129 delete [] _ptrIntersectionBoundingSet; 130 delete [] _ptrMaxPRBoundingSet; 131 } 132 _ptrIntersectionBoundingSet = new float[minimumSize]; 133 _ptrMaxPRBoundingSet = new float[minimumSize]; 134 } 135 _boundingSet.VerifyAndAllocateSet(minimumSize); 136 return &_boundingSet; 137 } 138 139 TMMBRSet* TMMBRHelp::BoundingSet() { 140 return &_boundingSet; 141 } 142 143 int32_t 144 TMMBRHelp::SetTMMBRBoundingSetToSend(const TMMBRSet* boundingSetToSend, 145 const uint32_t maxBitrateKbit) 146 { 147 CriticalSectionScoped lock(_criticalSection); 148 149 if (boundingSetToSend == NULL) 150 { 151 _boundingSetToSend.clearSet(); 152 return 0; 153 } 154 155 VerifyAndAllocateBoundingSetToSend(boundingSetToSend->lengthOfSet()); 156 _boundingSetToSend.clearSet(); 157 for (uint32_t i = 0; i < boundingSetToSend->lengthOfSet(); i++) 158 { 159 // cap at our configured max bitrate 160 uint32_t bitrate = boundingSetToSend->Tmmbr(i); 161 if(maxBitrateKbit) 162 { 163 // do we have a configured max bitrate? 164 if(bitrate > maxBitrateKbit) 165 { 166 bitrate = maxBitrateKbit; 167 } 168 } 169 _boundingSetToSend.SetEntry(i, bitrate, 170 boundingSetToSend->PacketOH(i), 171 boundingSetToSend->Ssrc(i)); 172 } 173 return 0; 174 } 175 176 int32_t 177 TMMBRHelp::VerifyAndAllocateBoundingSetToSend(uint32_t minimumSize) 178 { 179 CriticalSectionScoped lock(_criticalSection); 180 181 _boundingSetToSend.VerifyAndAllocateSet(minimumSize); 182 return 0; 183 } 184 185 TMMBRSet* 186 TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize) 187 { 188 CriticalSectionScoped lock(_criticalSection); 189 190 _candidateSet.VerifyAndAllocateSet(minimumSize); 191 return &_candidateSet; 192 } 193 194 TMMBRSet* 195 TMMBRHelp::CandidateSet() 196 { 197 return &_candidateSet; 198 } 199 200 TMMBRSet* 201 TMMBRHelp::BoundingSetToSend() 202 { 203 return &_boundingSetToSend; 204 } 205 206 int32_t 207 TMMBRHelp::FindTMMBRBoundingSet(TMMBRSet*& boundingSet) 208 { 209 CriticalSectionScoped lock(_criticalSection); 210 211 // Work on local variable, will be modified 212 TMMBRSet candidateSet; 213 candidateSet.VerifyAndAllocateSet(_candidateSet.sizeOfSet()); 214 215 // TODO(hta) Figure out if this should be lengthOfSet instead. 216 for (uint32_t i = 0; i < _candidateSet.sizeOfSet(); i++) 217 { 218 if(_candidateSet.Tmmbr(i)) 219 { 220 candidateSet.AddEntry(_candidateSet.Tmmbr(i), 221 _candidateSet.PacketOH(i), 222 _candidateSet.Ssrc(i)); 223 } 224 else 225 { 226 // make sure this is zero if tmmbr = 0 227 assert(_candidateSet.PacketOH(i) == 0); 228 // Old code: 229 // _candidateSet.ptrPacketOHSet[i] = 0; 230 } 231 } 232 233 // Number of set candidates 234 int32_t numSetCandidates = candidateSet.lengthOfSet(); 235 // Find bounding set 236 uint32_t numBoundingSet = 0; 237 if (numSetCandidates > 0) 238 { 239 numBoundingSet = FindTMMBRBoundingSet(numSetCandidates, candidateSet); 240 if(numBoundingSet < 1 || (numBoundingSet > _candidateSet.sizeOfSet())) 241 { 242 return -1; 243 } 244 boundingSet = &_boundingSet; 245 } 246 return numBoundingSet; 247 } 248 249 250 int32_t 251 TMMBRHelp::FindTMMBRBoundingSet(int32_t numCandidates, TMMBRSet& candidateSet) 252 { 253 CriticalSectionScoped lock(_criticalSection); 254 255 uint32_t numBoundingSet = 0; 256 VerifyAndAllocateBoundingSet(candidateSet.sizeOfSet()); 257 258 if (numCandidates == 1) 259 { 260 // TODO(hta): lengthOfSet instead of sizeOfSet? 261 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++) 262 { 263 if (candidateSet.Tmmbr(i) > 0) 264 { 265 _boundingSet.AddEntry(candidateSet.Tmmbr(i), 266 candidateSet.PacketOH(i), 267 candidateSet.Ssrc(i)); 268 numBoundingSet++; 269 } 270 } 271 return (numBoundingSet == 1) ? 1 : -1; 272 } 273 274 // 1. Sort by increasing packetOH 275 for (int i = candidateSet.sizeOfSet() - 1; i >= 0; i--) 276 { 277 for (int j = 1; j <= i; j++) 278 { 279 if (candidateSet.PacketOH(j-1) > candidateSet.PacketOH(j)) 280 { 281 candidateSet.SwapEntries(j-1, j); 282 } 283 } 284 } 285 // 2. For tuples with same OH, keep the one w/ the lowest bitrate 286 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++) 287 { 288 if (candidateSet.Tmmbr(i) > 0) 289 { 290 // get min bitrate for packets w/ same OH 291 uint32_t currentPacketOH = candidateSet.PacketOH(i); 292 uint32_t currentMinTMMBR = candidateSet.Tmmbr(i); 293 uint32_t currentMinIndexTMMBR = i; 294 for (uint32_t j = i+1; j < candidateSet.sizeOfSet(); j++) 295 { 296 if(candidateSet.PacketOH(j) == currentPacketOH) 297 { 298 if(candidateSet.Tmmbr(j) < currentMinTMMBR) 299 { 300 currentMinTMMBR = candidateSet.Tmmbr(j); 301 currentMinIndexTMMBR = j; 302 } 303 } 304 } 305 // keep lowest bitrate 306 for (uint32_t j = 0; j < candidateSet.sizeOfSet(); j++) 307 { 308 if(candidateSet.PacketOH(j) == currentPacketOH 309 && j != currentMinIndexTMMBR) 310 { 311 candidateSet.ClearEntry(j); 312 } 313 } 314 } 315 } 316 // 3. Select and remove tuple w/ lowest tmmbr. 317 // (If more than 1, choose the one w/ highest OH). 318 uint32_t minTMMBR = 0; 319 uint32_t minIndexTMMBR = 0; 320 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++) 321 { 322 if (candidateSet.Tmmbr(i) > 0) 323 { 324 minTMMBR = candidateSet.Tmmbr(i); 325 minIndexTMMBR = i; 326 break; 327 } 328 } 329 330 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++) 331 { 332 if (candidateSet.Tmmbr(i) > 0 && candidateSet.Tmmbr(i) <= minTMMBR) 333 { 334 // get min bitrate 335 minTMMBR = candidateSet.Tmmbr(i); 336 minIndexTMMBR = i; 337 } 338 } 339 // first member of selected list 340 _boundingSet.SetEntry(numBoundingSet, 341 candidateSet.Tmmbr(minIndexTMMBR), 342 candidateSet.PacketOH(minIndexTMMBR), 343 candidateSet.Ssrc(minIndexTMMBR)); 344 345 // set intersection value 346 _ptrIntersectionBoundingSet[numBoundingSet] = 0; 347 // calculate its maximum packet rate (where its line crosses x-axis) 348 _ptrMaxPRBoundingSet[numBoundingSet] 349 = _boundingSet.Tmmbr(numBoundingSet) * 1000 350 / float(8 * _boundingSet.PacketOH(numBoundingSet)); 351 numBoundingSet++; 352 // remove from candidate list 353 candidateSet.ClearEntry(minIndexTMMBR); 354 numCandidates--; 355 356 // 4. Discard from candidate list all tuple w/ lower OH 357 // (next tuple must be steeper) 358 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++) 359 { 360 if(candidateSet.Tmmbr(i) > 0 361 && candidateSet.PacketOH(i) < _boundingSet.PacketOH(0)) 362 { 363 candidateSet.ClearEntry(i); 364 numCandidates--; 365 } 366 } 367 368 if (numCandidates == 0) 369 { 370 // Should be true already:_boundingSet.lengthOfSet = numBoundingSet; 371 assert(_boundingSet.lengthOfSet() == numBoundingSet); 372 return numBoundingSet; 373 } 374 375 bool getNewCandidate = true; 376 int curCandidateTMMBR = 0; 377 int curCandidateIndex = 0; 378 int curCandidatePacketOH = 0; 379 int curCandidateSSRC = 0; 380 do 381 { 382 if (getNewCandidate) 383 { 384 // 5. Remove first remaining tuple from candidate list 385 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++) 386 { 387 if (candidateSet.Tmmbr(i) > 0) 388 { 389 curCandidateTMMBR = candidateSet.Tmmbr(i); 390 curCandidatePacketOH = candidateSet.PacketOH(i); 391 curCandidateSSRC = candidateSet.Ssrc(i); 392 curCandidateIndex = i; 393 candidateSet.ClearEntry(curCandidateIndex); 394 break; 395 } 396 } 397 } 398 399 // 6. Calculate packet rate and intersection of the current 400 // line with line of last tuple in selected list 401 float packetRate 402 = float(curCandidateTMMBR 403 - _boundingSet.Tmmbr(numBoundingSet-1))*1000 404 / (8*(curCandidatePacketOH 405 - _boundingSet.PacketOH(numBoundingSet-1))); 406 407 // 7. If the packet rate is equal or lower than intersection of 408 // last tuple in selected list, 409 // remove last tuple in selected list & go back to step 6 410 if(packetRate <= _ptrIntersectionBoundingSet[numBoundingSet-1]) 411 { 412 // remove last tuple and goto step 6 413 numBoundingSet--; 414 _boundingSet.ClearEntry(numBoundingSet); 415 _ptrIntersectionBoundingSet[numBoundingSet] = 0; 416 _ptrMaxPRBoundingSet[numBoundingSet] = 0; 417 getNewCandidate = false; 418 } else 419 { 420 // 8. If packet rate is lower than maximum packet rate of 421 // last tuple in selected list, add current tuple to selected 422 // list 423 if (packetRate < _ptrMaxPRBoundingSet[numBoundingSet-1]) 424 { 425 _boundingSet.SetEntry(numBoundingSet, 426 curCandidateTMMBR, 427 curCandidatePacketOH, 428 curCandidateSSRC); 429 _ptrIntersectionBoundingSet[numBoundingSet] = packetRate; 430 _ptrMaxPRBoundingSet[numBoundingSet] 431 = _boundingSet.Tmmbr(numBoundingSet)*1000 432 / float(8*_boundingSet.PacketOH(numBoundingSet)); 433 numBoundingSet++; 434 } 435 numCandidates--; 436 getNewCandidate = true; 437 } 438 439 // 9. Go back to step 5 if any tuple remains in candidate list 440 } while (numCandidates > 0); 441 442 return numBoundingSet; 443 } 444 445 bool TMMBRHelp::IsOwner(const uint32_t ssrc, 446 const uint32_t length) const { 447 CriticalSectionScoped lock(_criticalSection); 448 449 if (length == 0) { 450 // Empty bounding set. 451 return false; 452 } 453 for(uint32_t i = 0; 454 (i < length) && (i < _boundingSet.sizeOfSet()); ++i) { 455 if(_boundingSet.Ssrc(i) == ssrc) { 456 return true; 457 } 458 } 459 return false; 460 } 461 462 bool TMMBRHelp::CalcMinBitRate( uint32_t* minBitrateKbit) const { 463 CriticalSectionScoped lock(_criticalSection); 464 465 if (_candidateSet.sizeOfSet() == 0) { 466 // Empty bounding set. 467 return false; 468 } 469 *minBitrateKbit = std::numeric_limits<uint32_t>::max(); 470 471 for (uint32_t i = 0; i < _candidateSet.lengthOfSet(); ++i) { 472 uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i); 473 if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) { 474 curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE; 475 } 476 *minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ? 477 curNetBitRateKbit : *minBitrateKbit; 478 } 479 return true; 480 } 481 } // namespace webrtc 482