Files
webrtc/src/modules/video_coding/main/source/media_opt_util.cc
henrik.lundin@webrtc.org 7d8c72e2db Re-implement dependency injection of TickTime into VCM and tests
This change basicly re-enables the change of r1220, which was
reverted in r1235 due to Clang issues.

The difference from r1220 is that the TickTimeInterface was
renamed to TickTimeClass, and no longer inherits from TickTime.

Review URL: http://webrtc-codereview.appspot.com/335006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1267 4adac7df-926f-26a2-2b94-8c16560cd09d
2011-12-21 15:24:01 +00:00

894 lines
28 KiB
C++

/*
* Copyright (c) 2011 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 "modules/video_coding/main/source/media_opt_util.h"
#include <math.h>
#include <float.h>
#include <limits.h>
#include "modules/interface/module_common_types.h"
#include "modules/video_coding/codecs/vp8/main/interface/vp8_common_types.h"
#include "modules/video_coding/main/interface/video_coding_defines.h"
#include "modules/video_coding/main/source/er_tables_xor.h"
#include "modules/video_coding/main/source/fec_tables_xor.h"
#include "modules/video_coding/main/source/nack_fec_tables.h"
#include "modules/video_coding/main/source/qm_select_data.h"
namespace webrtc {
VCMProtectionMethod::VCMProtectionMethod():
_effectivePacketLoss(0),
_protectionFactorK(0),
_protectionFactorD(0),
_residualPacketLossFec(0.0f),
_scaleProtKey(2.0f),
_maxPayloadSize(1460),
_qmRobustness(new VCMQmRobustness()),
_useUepProtectionK(false),
_useUepProtectionD(true),
_corrFecCost(1.0),
_type(kNone),
_efficiency(0)
{
//
}
VCMProtectionMethod::~VCMProtectionMethod()
{
delete _qmRobustness;
}
void
VCMProtectionMethod::UpdateContentMetrics(const
VideoContentMetrics* contentMetrics)
{
_qmRobustness->UpdateContent(contentMetrics);
}
VCMNackFecMethod::VCMNackFecMethod(int lowRttNackThresholdMs,
int highRttNackThresholdMs)
: VCMFecMethod(),
_lowRttNackMs(lowRttNackThresholdMs),
_highRttNackMs(highRttNackThresholdMs) {
assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
assert(highRttNackThresholdMs == -1 ||
lowRttNackThresholdMs <= highRttNackThresholdMs);
assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
_type = kNackFec;
}
VCMNackFecMethod::~VCMNackFecMethod()
{
//
}
bool
VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
{
// Hybrid Nack FEC has three operational modes:
// 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate
// (_protectionFactorD) to zero. -1 means no FEC.
// 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors.
// -1 means always allow NACK.
// 3. Medium RTT values - Hybrid mode: We will only nack the
// residual following the decoding of the FEC (refer to JB logic). FEC
// delta protection factor will be adjusted based on the RTT.
// Otherwise: we count on FEC; if the RTT is below a threshold, then we
// nack the residual, based on a decision made in the JB.
// Compute the protection factors
VCMFecMethod::ProtectionFactor(parameters);
if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs)
{
_protectionFactorD = 0;
VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
}
// When in Hybrid mode (RTT range), adjust FEC rates based on the
// RTT (NACK effectiveness) - adjustment factor is in the range [0,1].
else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
{
// TODO(mikhal): Disabling adjustment temporarily.
// WebRtc_UWord16 rttIndex = (WebRtc_UWord16) parameters->rtt;
float adjustRtt = 1.0f;// (float)VCMNackFecTable[rttIndex] / 100.0f;
// Adjust FEC with NACK on (for delta frame only)
// table depends on RTT relative to rttMax (NACK Threshold)
_protectionFactorD = static_cast<WebRtc_UWord8>
(adjustRtt *
static_cast<float>(_protectionFactorD));
// update FEC rates after applying adjustment
VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
}
return true;
}
bool
VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
{
// Set the effective packet loss for encoder (based on FEC code).
// Compute the effective packet loss and residual packet loss due to FEC.
VCMFecMethod::EffectivePacketLoss(parameters);
return true;
}
bool
VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
{
ProtectionFactor(parameters);
EffectivePacketLoss(parameters);
// Efficiency computation is based on FEC and NACK
// Add FEC cost: ignore I frames for now
float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
_efficiency = parameters->bitRate * fecRate * _corrFecCost;
// Add NACK cost, when applicable
if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
{
// nackCost = (bitRate - nackCost) * (lossPr)
_efficiency += parameters->bitRate * _residualPacketLossFec /
(1.0f + _residualPacketLossFec);
}
// Protection/fec rates obtained above are defined relative to total number
// of packets (total rate: source + fec) FEC in RTP module assumes
// protection factor is defined relative to source number of packets so we
// should convert the factor to reduce mismatch between mediaOpt's rate and
// the actual one
_protectionFactorK = VCMFecMethod::ConvertFECRate(_protectionFactorK);
_protectionFactorD = VCMFecMethod::ConvertFECRate(_protectionFactorD);
return true;
}
VCMNackMethod::VCMNackMethod():
VCMProtectionMethod()
{
_type = kNack;
}
VCMNackMethod::~VCMNackMethod()
{
//
}
bool
VCMNackMethod::EffectivePacketLoss(const VCMProtectionParameters* parameter)
{
// Effective Packet Loss, NA in current version.
_effectivePacketLoss = 0;
return true;
}
bool
VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
{
// Compute the effective packet loss
EffectivePacketLoss(parameters);
// nackCost = (bitRate - nackCost) * (lossPr)
_efficiency = parameters->bitRate * parameters->lossPr /
(1.0f + parameters->lossPr);
return true;
}
VCMFecMethod::VCMFecMethod():
VCMProtectionMethod()
{
_type = kFec;
}
VCMFecMethod::~VCMFecMethod()
{
//
}
WebRtc_UWord8
VCMFecMethod::BoostCodeRateKey(WebRtc_UWord8 packetFrameDelta,
WebRtc_UWord8 packetFrameKey) const
{
WebRtc_UWord8 boostRateKey = 2;
// Default: ratio scales the FEC protection up for I frames
WebRtc_UWord8 ratio = 1;
if (packetFrameDelta > 0)
{
ratio = (WebRtc_Word8) (packetFrameKey / packetFrameDelta);
}
ratio = VCM_MAX(boostRateKey, ratio);
return ratio;
}
WebRtc_UWord8
VCMFecMethod::ConvertFECRate(WebRtc_UWord8 codeRateRTP) const
{
return static_cast<WebRtc_UWord8> (VCM_MIN(255,(0.5 + 255.0 * codeRateRTP /
(float)(255 - codeRateRTP))));
}
// Update FEC with protectionFactorD
void
VCMFecMethod::UpdateProtectionFactorD(WebRtc_UWord8 protectionFactorD)
{
_protectionFactorD = protectionFactorD;
}
// Update FEC with protectionFactorK
void
VCMFecMethod::UpdateProtectionFactorK(WebRtc_UWord8 protectionFactorK)
{
_protectionFactorK = protectionFactorK;
}
// AvgRecoveryFEC: computes the residual packet loss (RPL) function.
// This is the average recovery from the FEC, assuming random packet loss model.
// Computed off-line for a range of FEC code parameters and loss rates.
float
VCMFecMethod::AvgRecoveryFEC(const VCMProtectionParameters* parameters) const
{
// Total (avg) bits available per frame: total rate over actual/sent frame
// rate units are kbits/frame
const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16>
(parameters->bitRate / (parameters->frameRate));
// Total (average) number of packets per frame (source and fec):
const WebRtc_UWord8 avgTotPackets = 1 + static_cast<WebRtc_UWord8>
(static_cast<float> (bitRatePerFrame * 1000.0) /
static_cast<float> (8.0 * _maxPayloadSize) + 0.5);
const float protectionFactor = static_cast<float>(_protectionFactorD) /
255.0;
WebRtc_UWord8 fecPacketsPerFrame = static_cast<WebRtc_UWord8>
(0.5 + protectionFactor * avgTotPackets);
WebRtc_UWord8 sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
if ( (fecPacketsPerFrame == 0) || (sourcePacketsPerFrame == 0) )
{
// No protection, or rate too low: so average recovery from FEC == 0.
return 0.0;
}
// Table defined up to kMaxNumPackets
if (sourcePacketsPerFrame > kMaxNumPackets)
{
sourcePacketsPerFrame = kMaxNumPackets;
}
// Table defined up to kMaxNumPackets
if (fecPacketsPerFrame > kMaxNumPackets)
{
fecPacketsPerFrame = kMaxNumPackets;
}
// Code index for tables: up to (kMaxNumPackets * kMaxNumPackets)
WebRtc_UWord16 codeIndexTable[kMaxNumPackets * kMaxNumPackets];
WebRtc_UWord16 k = 0;
for (WebRtc_UWord8 i = 1; i <= kMaxNumPackets; i++)
{
for (WebRtc_UWord8 j = 1; j <= i; j++)
{
codeIndexTable[(j - 1) * kMaxNumPackets + i - 1] = k;
k += 1;
}
}
WebRtc_UWord8 lossRate = static_cast<WebRtc_UWord8> (255.0 *
parameters->lossPr + 0.5f);
// Constrain lossRate to 50%: tables defined up to 50%
if (lossRate >= kPacketLossMax)
{
lossRate = kPacketLossMax - 1;
}
const WebRtc_UWord16 codeIndex = (fecPacketsPerFrame - 1) * kMaxNumPackets +
(sourcePacketsPerFrame - 1);
const WebRtc_UWord16 indexTable = codeIndexTable[codeIndex] * kPacketLossMax +
lossRate;
// Check on table index
assert(indexTable < kSizeAvgFECRecoveryXOR);
float avgFecRecov = static_cast<float>(kAvgFECRecoveryXOR[indexTable]);
return avgFecRecov;
}
bool
VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
{
// FEC PROTECTION SETTINGS: varies with packet loss and bitrate
// No protection if (filtered) packetLoss is 0
WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
if (packetLoss == 0)
{
_protectionFactorK = 0;
_protectionFactorD = 0;
return true;
}
// Parameters for FEC setting:
// first partition size, thresholds, table pars, spatial resoln fac.
// First partition protection: ~ 20%
WebRtc_UWord8 firstPartitionProt = (WebRtc_UWord8) (255 * 0.20);
// Minimum protection level needed to generate one FEC packet for one
// source packet/frame (in RTP sender)
WebRtc_UWord8 minProtLevelFec = 85;
// Threshold on packetLoss and bitRrate/frameRate (=average #packets),
// above which we allocate protection to cover at least first partition.
WebRtc_UWord8 lossThr = 0;
WebRtc_UWord8 packetNumThr = 1;
// Parameters for range of rate index of table.
const WebRtc_UWord8 ratePar1 = 5;
const WebRtc_UWord8 ratePar2 = 49;
// Spatial resolution size, relative to a reference size.
float spatialSizeToRef = static_cast<float>
(parameters->codecWidth * parameters->codecHeight) /
(static_cast<float>(704 * 576));
// resolnFac: This parameter will generally increase/decrease the FEC rate
// (for fixed bitRate and packetLoss) based on system size.
// Use a smaller exponent (< 1) to control/soften system size effect.
const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f);
const int bitRatePerFrame = BitsPerFrame(parameters);
// Average number of packets per frame (source and fec):
const WebRtc_UWord8 avgTotPackets = 1 + (WebRtc_UWord8)
((float) bitRatePerFrame * 1000.0
/ (float) (8.0 * _maxPayloadSize) + 0.5);
// FEC rate parameters: for P and I frame
WebRtc_UWord8 codeRateDelta = 0;
WebRtc_UWord8 codeRateKey = 0;
// Get index for table: the FEC protection depends on an effective rate.
// The range on the rate index corresponds to rates (bps)
// from ~200k to ~8000k, for 30fps
const WebRtc_UWord16 effRateFecTable = static_cast<WebRtc_UWord16>
(resolnFac * bitRatePerFrame);
WebRtc_UWord8 rateIndexTable =
(WebRtc_UWord8) VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) /
ratePar1, ratePar2), 0);
// Restrict packet loss range to 50:
// current tables defined only up to 50%
if (packetLoss >= kPacketLossMax)
{
packetLoss = kPacketLossMax - 1;
}
WebRtc_UWord16 indexTable = rateIndexTable * kPacketLossMax + packetLoss;
// Check on table index
assert(indexTable < kSizeCodeRateXORTable);
// Protection factor for P frame
codeRateDelta = kCodeRateXORTable[indexTable];
if (packetLoss > lossThr && avgTotPackets > packetNumThr)
{
// Set a minimum based on first partition size.
if (codeRateDelta < firstPartitionProt)
{
codeRateDelta = firstPartitionProt;
}
}
// Check limit on amount of protection for P frame; 50% is max.
if (codeRateDelta >= kPacketLossMax)
{
codeRateDelta = kPacketLossMax - 1;
}
float adjustFec = 1.0f;
// Avoid additional adjustments when layers are active.
// TODO(mikhal/marco): Update adjusmtent based on layer info.
if (parameters->numLayers == 1)
{
adjustFec = _qmRobustness->AdjustFecFactor(codeRateDelta,
parameters->bitRate,
parameters->frameRate,
parameters->rtt,
packetLoss);
}
codeRateDelta = static_cast<WebRtc_UWord8>(codeRateDelta * adjustFec);
// For Key frame:
// Effectively at a higher rate, so we scale/boost the rate
// The boost factor may depend on several factors: ratio of packet
// number of I to P frames, how much protection placed on P frames, etc.
const WebRtc_UWord8 packetFrameDelta = (WebRtc_UWord8)
(0.5 + parameters->packetsPerFrame);
const WebRtc_UWord8 packetFrameKey = (WebRtc_UWord8)
(0.5 + parameters->packetsPerFrameKey);
const WebRtc_UWord8 boostKey = BoostCodeRateKey(packetFrameDelta,
packetFrameKey);
rateIndexTable = (WebRtc_UWord8) VCM_MAX(VCM_MIN(
1 + (boostKey * effRateFecTable - ratePar1) /
ratePar1,ratePar2),0);
WebRtc_UWord16 indexTableKey = rateIndexTable * kPacketLossMax + packetLoss;
indexTableKey = VCM_MIN(indexTableKey, kSizeCodeRateXORTable);
// Check on table index
assert(indexTableKey < kSizeCodeRateXORTable);
// Protection factor for I frame
codeRateKey = kCodeRateXORTable[indexTableKey];
// Boosting for Key frame.
int boostKeyProt = _scaleProtKey * codeRateDelta;
if (boostKeyProt >= kPacketLossMax)
{
boostKeyProt = kPacketLossMax - 1;
}
// Make sure I frame protection is at least larger than P frame protection,
// and at least as high as filtered packet loss.
codeRateKey = static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,
VCM_MAX(boostKeyProt, codeRateKey)));
// Check limit on amount of protection for I frame: 50% is max.
if (codeRateKey >= kPacketLossMax)
{
codeRateKey = kPacketLossMax - 1;
}
_protectionFactorK = codeRateKey;
_protectionFactorD = codeRateDelta;
// Generally there is a rate mis-match between the FEC cost estimated
// in mediaOpt and the actual FEC cost sent out in RTP module.
// This is more significant at low rates (small # of source packets), where
// the granularity of the FEC decreases. In this case, non-zero protection
// in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC
// is based on rounding off protectionFactor on actual source packet number).
// The correction factor (_corrFecCost) attempts to corrects this, at least
// for cases of low rates (small #packets) and low protection levels.
float numPacketsFl = 1.0f + ((float) bitRatePerFrame * 1000.0
/ (float) (8.0 * _maxPayloadSize) + 0.5);
const float estNumFecGen = 0.5f + static_cast<float> (_protectionFactorD *
numPacketsFl / 255.0f);
// We reduce cost factor (which will reduce overhead for FEC and
// hybrid method) and not the protectionFactor.
_corrFecCost = 1.0f;
if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec)
{
_corrFecCost = 0.5f;
}
if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec)
{
_corrFecCost = 0.0f;
}
// TODO (marpan): Set the UEP protection on/off for Key and Delta frames
_useUepProtectionK = _qmRobustness->SetUepProtection(codeRateKey,
parameters->bitRate,
packetLoss,
0);
_useUepProtectionD = _qmRobustness->SetUepProtection(codeRateDelta,
parameters->bitRate,
packetLoss,
1);
// DONE WITH FEC PROTECTION SETTINGS
return true;
}
int VCMFecMethod::BitsPerFrame(const VCMProtectionParameters* parameters) {
// When temporal layers are available FEC will only be applied on the base
// layer.
const float bitRateRatio =
kVp8LayerRateAlloction[parameters->numLayers - 1][0];
float frameRateRatio = powf(1 / 2, parameters->numLayers - 1);
float bitRate = parameters->bitRate * bitRateRatio;
float frameRate = parameters->frameRate * frameRateRatio;
// TODO(mikhal): Update factor following testing.
float adjustmentFactor = 1;
// Average bits per frame (units of kbits)
return static_cast<int>(adjustmentFactor * bitRate / frameRate);
}
bool
VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
{
// Effective packet loss to encoder is based on RPL (residual packet loss)
// this is a soft setting based on degree of FEC protection
// RPL = received/input packet loss - average_FEC_recovery
// note: received/input packet loss may be filtered based on FilteredLoss
// The packet loss:
WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
float avgFecRecov = AvgRecoveryFEC(parameters);
// Residual Packet Loss:
_residualPacketLossFec = (float) (packetLoss - avgFecRecov) / 255.0f;
// Effective Packet Loss, NA in current version.
_effectivePacketLoss = 0;
return true;
}
bool
VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
{
// Compute the protection factor
ProtectionFactor(parameters);
// Compute the effective packet loss
EffectivePacketLoss(parameters);
// Compute the bit cost
// Ignore key frames for now.
float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
if (fecRate >= 0.0f)
{
// use this formula if the fecRate (protection factor) is defined
// relative to number of source packets
// this is the case for the previous tables:
// _efficiency = parameters->bitRate * ( 1.0 - 1.0 / (1.0 + fecRate));
// in the new tables, the fecRate is defined relative to total number of
// packets (total rate), so overhead cost is:
_efficiency = parameters->bitRate * fecRate * _corrFecCost;
}
else
{
_efficiency = 0.0f;
}
// Protection/fec rates obtained above is defined relative to total number
// of packets (total rate: source+fec) FEC in RTP module assumes protection
// factor is defined relative to source number of packets so we should
// convert the factor to reduce mismatch between mediaOpt suggested rate and
// the actual rate
_protectionFactorK = ConvertFECRate(_protectionFactorK);
_protectionFactorD = ConvertFECRate(_protectionFactorD);
return true;
}
VCMLossProtectionLogic::VCMLossProtectionLogic(int64_t nowMs):
_selectedMethod(NULL),
_currentParameters(),
_rtt(0),
_lossPr(0.0f),
_bitRate(0.0f),
_frameRate(0.0f),
_keyFrameSize(0.0f),
_fecRateKey(0),
_fecRateDelta(0),
_lastPrUpdateT(0),
_lossPr255(0.9999f),
_lossPrHistory(),
_shortMaxLossPr255(0),
_packetsPerFrame(0.9999f),
_packetsPerFrameKey(0.9999f),
_residualPacketLossFec(0),
_boostRateKey(2),
_codecWidth(0),
_codecHeight(0),
_numLayers(1)
{
Reset(nowMs);
}
VCMLossProtectionLogic::~VCMLossProtectionLogic()
{
Release();
}
bool
VCMLossProtectionLogic::SetMethod(enum VCMProtectionMethodEnum newMethodType)
{
if (_selectedMethod != NULL)
{
if (_selectedMethod->Type() == newMethodType)
{
// Nothing to update
return false;
}
// New method - delete existing one
delete _selectedMethod;
}
VCMProtectionMethod *newMethod = NULL;
switch (newMethodType)
{
case kNack:
{
newMethod = new VCMNackMethod();
break;
}
case kFec:
{
newMethod = new VCMFecMethod();
break;
}
case kNackFec:
{
// Default to always having NACK enabled for the hybrid mode.
newMethod = new VCMNackFecMethod(kLowRttNackMs, -1);
break;
}
default:
{
return false;
break;
}
}
_selectedMethod = newMethod;
return true;
}
bool
VCMLossProtectionLogic::RemoveMethod(enum VCMProtectionMethodEnum method)
{
if (_selectedMethod == NULL)
{
return false;
}
else if (_selectedMethod->Type() == method)
{
delete _selectedMethod;
_selectedMethod = NULL;
}
return true;
}
float
VCMLossProtectionLogic::RequiredBitRate() const
{
float RequiredBitRate = 0.0f;
if (_selectedMethod != NULL)
{
RequiredBitRate = _selectedMethod->RequiredBitRate();
}
return RequiredBitRate;
}
void
VCMLossProtectionLogic::UpdateRtt(WebRtc_UWord32 rtt)
{
_rtt = rtt;
}
void
VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss)
{
_residualPacketLossFec = residualPacketLoss;
}
void
VCMLossProtectionLogic::UpdateLossPr(WebRtc_UWord8 lossPr255,
int64_t nowMs)
{
UpdateMaxLossHistory(lossPr255, nowMs);
_lossPr255.Apply(static_cast<float> (nowMs - _lastPrUpdateT),
static_cast<float> (lossPr255));
_lastPrUpdateT = nowMs;
_lossPr = _lossPr255.Value() / 255.0f;
}
void
VCMLossProtectionLogic::UpdateMaxLossHistory(WebRtc_UWord8 lossPr255,
WebRtc_Word64 now)
{
if (_lossPrHistory[0].timeMs >= 0 &&
now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs)
{
if (lossPr255 > _shortMaxLossPr255)
{
_shortMaxLossPr255 = lossPr255;
}
}
else
{
// Only add a new value to the history once a second
if (_lossPrHistory[0].timeMs == -1)
{
// First, no shift
_shortMaxLossPr255 = lossPr255;
}
else
{
// Shift
for (WebRtc_Word32 i = (kLossPrHistorySize - 2); i >= 0; i--)
{
_lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
_lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
}
}
if (_shortMaxLossPr255 == 0)
{
_shortMaxLossPr255 = lossPr255;
}
_lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
_lossPrHistory[0].timeMs = now;
_shortMaxLossPr255 = 0;
}
}
WebRtc_UWord8
VCMLossProtectionLogic::MaxFilteredLossPr(WebRtc_Word64 nowMs) const
{
WebRtc_UWord8 maxFound = _shortMaxLossPr255;
if (_lossPrHistory[0].timeMs == -1)
{
return maxFound;
}
for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++)
{
if (_lossPrHistory[i].timeMs == -1)
{
break;
}
if (nowMs - _lossPrHistory[i].timeMs >
kLossPrHistorySize * kLossPrShortFilterWinMs)
{
// This sample (and all samples after this) is too old
break;
}
if (_lossPrHistory[i].lossPr255 > maxFound)
{
// This sample is the largest one this far into the history
maxFound = _lossPrHistory[i].lossPr255;
}
}
return maxFound;
}
WebRtc_UWord8
VCMLossProtectionLogic::FilteredLoss(int64_t nowMs) const
{
if (_selectedMethod != NULL &&
(_selectedMethod->Type() == kFec ||
_selectedMethod->Type() == kNackFec))
{
// Take the windowed max of the received loss.
return MaxFilteredLossPr(nowMs);
}
else
{
// Take the average received loss.
return static_cast<WebRtc_UWord8> (_lossPr255.Value() + 0.5);
}
}
void
VCMLossProtectionLogic::UpdateFilteredLossPr(WebRtc_UWord8 packetLossEnc)
{
_lossPr = (float) packetLossEnc / (float) 255.0;
}
void
VCMLossProtectionLogic::UpdateBitRate(float bitRate)
{
_bitRate = bitRate;
}
void
VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets, int64_t nowMs)
{
_packetsPerFrame.Apply(static_cast<float>(nowMs - _lastPacketPerFrameUpdateT),
nPackets);
_lastPacketPerFrameUpdateT = nowMs;
}
void
VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets, int64_t nowMs)
{
_packetsPerFrameKey.Apply(static_cast<float>(nowMs -
_lastPacketPerFrameUpdateTKey), nPackets);
_lastPacketPerFrameUpdateTKey = nowMs;
}
void
VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
{
_keyFrameSize = keyFrameSize;
}
void
VCMLossProtectionLogic::UpdateFrameSize(WebRtc_UWord16 width,
WebRtc_UWord16 height)
{
_codecWidth = width;
_codecHeight = height;
}
void VCMLossProtectionLogic::UpdateNumLayers(int numLayers) {
_numLayers = (numLayers == 0) ? 1 : numLayers;
}
bool
VCMLossProtectionLogic::UpdateMethod()
{
if (_selectedMethod == NULL)
{
return false;
}
_currentParameters.rtt = _rtt;
_currentParameters.lossPr = _lossPr;
_currentParameters.bitRate = _bitRate;
_currentParameters.frameRate = _frameRate; // rename actual frame rate?
_currentParameters.keyFrameSize = _keyFrameSize;
_currentParameters.fecRateDelta = _fecRateDelta;
_currentParameters.fecRateKey = _fecRateKey;
_currentParameters.packetsPerFrame = _packetsPerFrame.Value();
_currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value();
_currentParameters.residualPacketLossFec = _residualPacketLossFec;
_currentParameters.codecWidth = _codecWidth;
_currentParameters.codecHeight = _codecHeight;
_currentParameters.numLayers = _numLayers;
return _selectedMethod->UpdateParameters(&_currentParameters);
}
VCMProtectionMethod*
VCMLossProtectionLogic::SelectedMethod() const
{
return _selectedMethod;
}
VCMProtectionMethodEnum
VCMLossProtectionLogic::SelectedType() const
{
return _selectedMethod->Type();
}
void
VCMLossProtectionLogic::Reset(int64_t nowMs)
{
_lastPrUpdateT = nowMs;
_lastPacketPerFrameUpdateT = nowMs;
_lastPacketPerFrameUpdateTKey = nowMs;
_lossPr255.Reset(0.9999f);
_packetsPerFrame.Reset(0.9999f);
_fecRateDelta = _fecRateKey = 0;
for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++)
{
_lossPrHistory[i].lossPr255 = 0;
_lossPrHistory[i].timeMs = -1;
}
_shortMaxLossPr255 = 0;
Release();
}
void
VCMLossProtectionLogic::Release()
{
delete _selectedMethod;
_selectedMethod = NULL;
}
}