blob: b520278ac77689dbfa967dbcb8b9d181d4e6cf07 [file] [log] [blame]
/*
* 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"
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::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,
FilterPacketLossMode filter_mode,
WebRtc_UWord8 lossPr255) {
// Update the max window filter.
UpdateMaxLossHistory(lossPr255, nowMs);
// Update the recursive average filter.
_lossPr255.Apply(static_cast<float> (nowMs - _lastPrUpdateT),
static_cast<float> (lossPr255));
_lastPrUpdateT = nowMs;
// Filtered loss: default is received loss (no filtering).
WebRtc_UWord8 filtered_loss = lossPr255;
switch (filter_mode) {
case kNoFilter:
break;
case kAvgFilter:
filtered_loss = static_cast<WebRtc_UWord8> (_lossPr255.Value() + 0.5);
break;
case kMaxFilter:
filtered_loss = MaxFilteredLossPr(nowMs);
break;
}
return filtered_loss;
}
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;
}
}