webrtc/modules/video_coding/main/source/media_opt_util.cc

932 lines
28 KiB
C++
Raw Normal View History

/*
* 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 "video_coding_defines.h"
#include "fec_tables_xor.h"
#include "er_tables_xor.h"
#include "nack_fec_tables.h"
#include "qm_select_data.h"
#include "media_opt_util.h"
#include <math.h>
#include <float.h>
#include <limits.h>
namespace webrtc {
bool
VCMProtectionMethod::BetterThan(VCMProtectionMethod *pm)
{
if (pm == NULL)
{
return true;
}
return pm->_score > _score;
}
bool
VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* /*parameters*/)
{
// use FEC model with modification with RTT for now
return true;
}
bool
VCMNackFecMethod::EffectivePacketLoss(const
VCMProtectionParameters* /*parameters*/)
{
// use FEC model with modification with RTT for now
return true;
}
bool
VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
{
// Hybrid Nack FEC has three operational modes:
// 1. Low RTT - Nack only (Set FEC rates to zero)
// 2. High RTT - FEC Only
// 3. Medium RTT values - Hybrid ; in hybrid mode, we will only nack the
// residual following the decoding of the FEC (refer to JB logic)
// Low RTT - NACK only mode
if (parameters->rtt < kLowRttNackMs)
{
// Set the FEC parameters to 0
_protectionFactorK = 0;
_protectionFactorD = 0;
// assume packets will be restored via NACK
// TODO: relax this assumption?
_effectivePacketLoss = 0;
_score = _efficiency;
return true;
}
// otherwise: we count on FEC; if the RTT is below a threshold, then we can
// nack the residual, based on a decision made in the JB.
// TODO(mikhal): adapt the FEC rate based on the RTT, i.e. the the level on
// which we will rely on NACK, e.g. less as we approach upper threshold.
VCMFecMethod fecMethod;
const WebRtc_UWord8 plossMax = 129;
// Compute the protection factor
fecMethod.ProtectionFactor(parameters);
// Compute the effective packet loss
fecMethod.EffectivePacketLoss(parameters);
WebRtc_UWord8 protFactorK = fecMethod._protectionFactorK;
WebRtc_UWord8 protFactorD = fecMethod._protectionFactorD;
WebRtc_UWord8 effPacketLoss = fecMethod._effectivePacketLoss;
float resPacketLoss = fecMethod._residualPacketLoss;
// Correct FEC rates based on the RTT ( NACK effectiveness)
WebRtc_Word16 rttIndex= (WebRtc_UWord16) parameters->rtt;
float softnessRtt = 1.0;
if (parameters->rtt < kHighRttNackMs)
{
// TODO(mikhal): update table
softnessRtt = (float)VCMNackFecTable[rttIndex] / (float)4096.0;
// soften ER with NACK on
// table depends on RTT relative to rttMax (NACK Threshold)
_effectivePacketLoss = (WebRtc_UWord8)(effPacketLoss * softnessRtt);
// soften FEC with NACK on
// table depends on RTT relative to rttMax (NACK Threshold)
_protectionFactorK = (WebRtc_UWord8) (protFactorK * softnessRtt);
_protectionFactorD = (WebRtc_UWord8) (protFactorD * softnessRtt);
}
// else - NACK is disabled, rely on FEC only
// make sure I frame protection is at least larger than P frame protection,
// and at least as high as received loss
WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
_protectionFactorK = static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,
VCM_MAX(_scaleProtKey * protFactorD, protFactorK)));
// check limit on amount of protection for I frame: 50% is max
if (_protectionFactorK >= plossMax)
_protectionFactorK = plossMax - 1;
// Bit cost for NackFec
// NACK cost: based on residual packet loss (since we should only NACK
// packets not recovered by FEC)
_efficiency = 0.0f;
if (parameters->rtt < kHighRttNackMs)
{
_efficiency = parameters->bitRate * resPacketLoss /
(1.0f + resPacketLoss);
}
else
{
// efficiency based on FEC only
// add FEC cost: ignore I frames for now
float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
if (fecRate >= 0.0f)
_efficiency += parameters->bitRate * fecRate;
}
_score = _efficiency;
// 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
WebRtc_UWord8 codeRate = protFactorK;
_protectionFactorK = fecMethod.ConvertFECRate(codeRate);
codeRate = protFactorD;
_protectionFactorD = fecMethod.ConvertFECRate(codeRate);
return true;
}
bool
VCMNackMethod::EffectivePacketLoss(WebRtc_UWord8 effPacketLoss,
WebRtc_UWord16 rttTime)
{
WebRtc_UWord16 rttMax = MaxRttNack();
// For large RTT, we should rely on some Error Resilience, so we set
// packetLossEnc = 0 for RTT less than the NACK threshold
if (rttTime < rttMax)
{
effPacketLoss = 0; //may want a softer transition here
}
_effectivePacketLoss = effPacketLoss;
return true;
}
bool
VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
{
// Compute the effective packet loss for ER
WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
WebRtc_UWord16 rttTime = (WebRtc_UWord16) parameters->rtt;
EffectivePacketLoss(effPacketLoss, rttTime);
// Compute the NACK bit cost
_efficiency = parameters->bitRate * parameters->lossPr /
(1.0f + parameters->lossPr);
_score = _efficiency;
if (parameters->rtt > _NACK_MAX_RTT)
{
_score = 0.0f;
return false;
}
return true;
}
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))));
}
// AvgRecoveryFEC: average recovery from FEC, assuming random packet loss model
// Computed offline 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 (avg) 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);
// parameters for tables
const WebRtc_UWord8 codeSize = 24;
const WebRtc_UWord8 plossMax = 129;
const WebRtc_UWord16 maxErTableSize = 38700;
// Get index for table
const float protectionFactor = (float) _protectionFactorD / (float) 255;
WebRtc_UWord8 fecPacketsPerFrame = (WebRtc_UWord8) (0.5 + protectionFactor
* avgTotPackets);
WebRtc_UWord8 sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
if (fecPacketsPerFrame == 0)
{
return 0.0; // no protection, so avg. recov from FEC == 0
}
// table defined up to codeSizexcodeSize code
if (sourcePacketsPerFrame > codeSize)
{
sourcePacketsPerFrame = codeSize;
}
// check: protection factor is maxed at 50%, so this should never happen
if (sourcePacketsPerFrame < 1)
{
assert("average number of source packets below 1\n");
}
// index for ER tables: up to codeSizexcodeSize mask
WebRtc_UWord16 codeIndexTable[codeSize * codeSize];
WebRtc_UWord16 k = -1;
for (WebRtc_UWord8 i = 1; i <= codeSize; i++)
{
for (WebRtc_UWord8 j = 1; j <= i; j++)
{
k += 1;
codeIndexTable[(j - 1) * codeSize + i - 1] = k;
}
}
const WebRtc_UWord8 lossRate = (WebRtc_UWord8) (255.0 *
parameters->lossPr + 0.5f);
const WebRtc_UWord16 codeIndex = (fecPacketsPerFrame - 1) * codeSize
+ (sourcePacketsPerFrame - 1);
const WebRtc_UWord16 indexTable = codeIndexTable[codeIndex] * plossMax
+ lossRate;
const WebRtc_UWord16 codeIndex2 = (fecPacketsPerFrame) * codeSize
+ (sourcePacketsPerFrame);
WebRtc_UWord16 indexTable2 = codeIndexTable[codeIndex2] * plossMax
+ lossRate;
// checks on table index
if (indexTable >= maxErTableSize)
{
assert("ER table index too large\n");
}
if (indexTable2 >= maxErTableSize)
{
indexTable2 = indexTable;
}
// Get the average effective packet loss recovery from FEC
// this is from tables, computed using random loss model
WebRtc_UWord8 avgFecRecov1 = 0;
WebRtc_UWord8 avgFecRecov2 = 0;
float avgFecRecov = 0;
if (fecPacketsPerFrame > 0)
{
avgFecRecov1 = VCMAvgFECRecoveryXOR[indexTable];
avgFecRecov2 = VCMAvgFECRecoveryXOR[indexTable2];
}
// interpolate over two FEC codes
const float weightRpl = (float) (0.5 + protectionFactor * avgTotPackets)
- (float) fecPacketsPerFrame;
avgFecRecov = (float) weightRpl * (float) avgFecRecov2 + (float)
(1.0 - weightRpl) * (float) avgFecRecov1;
return avgFecRecov;
}
bool
VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
{
// FEC PROTECTION SETTINGS: varies with packet loss and bitrate
WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
// No protection if (filtered) packetLoss is 0
if (packetLoss == 0)
{
_protectionFactorK = 0;
_protectionFactorD = 0;
return true;
}
// Size of tables
const WebRtc_UWord16 maxFecTableSize = 6450;
// Parameters for range of rate and packet loss for tables
const WebRtc_UWord8 ratePar1 = 5;
const WebRtc_UWord8 ratePar2 = 49;
const WebRtc_UWord8 plossMax = 129;
const float bitRate = parameters->bitRate;
// Total (avg) bits available per frame: total rate over actual/frame_rate.
// Units are kbits/frame
const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16>
(bitRate /
(parameters->frameRate));
// Total (avg) 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);
// First partition protection: ~ 20%
WebRtc_UWord8 firstPartitionProt = (WebRtc_UWord8) (255 * 0.20);
// Threshold on packetLoss and bitRrate/frameRate (=average #packets),
// above which we allocate protection to cover at least roughly
// first partition size.
WebRtc_UWord8 lossThr = 0;
WebRtc_UWord8 packetNumThr = 1;
// Modulation of protection with available bits/frame (or avgTotpackets)
float weight1 = 0.5;
float weight2 = 0.5;
if (avgTotPackets > 4)
{
weight1 = 0.75;
weight2 = 0.25;
}
if (avgTotPackets > 6)
{
weight1 = 1.5;
weight2 = 0.;
}
// 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 the (average)
// available bits/frame. The range on the rate index corresponds to rates
// (bps) from 200k to 8000k, for 30fps
WebRtc_UWord8 rateIndexTable =
(WebRtc_UWord8) VCM_MAX(VCM_MIN((bitRatePerFrame - ratePar1) /
ratePar1, ratePar2), 0);
// Restrict packet loss range to 50:
// current tables defined only up to 50%
if (packetLoss >= plossMax)
{
packetLoss = plossMax - 1;
}
WebRtc_UWord16 indexTable = rateIndexTable * plossMax + packetLoss;
// Check on table index
assert(indexTable < maxFecTableSize);
// Protection factor for P frame
codeRateDelta = VCMCodeRateXORTable[indexTable];
if (packetLoss > lossThr && avgTotPackets > packetNumThr)
{
// Average with minimum protection level given by (average) total
// number of packets
codeRateDelta = static_cast<WebRtc_UWord8>((weight1 *
(float) codeRateDelta + weight2 * 255.0 / (float) avgTotPackets));
// 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 >= plossMax)
{
codeRateDelta = plossMax - 1;
}
// 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 * bitRatePerFrame - ratePar1) /
ratePar1,ratePar2),0);
WebRtc_UWord16 indexTableKey = rateIndexTable * plossMax + packetLoss;
indexTableKey = VCM_MIN(indexTableKey, maxFecTableSize);
// Check on table index
assert(indexTableKey < maxFecTableSize);
// Protection factor for I frame
codeRateKey = VCMCodeRateXORTable[indexTableKey];
// Boosting for Key frame.
WebRtc_UWord32 boostKeyProt = _scaleProtKey * codeRateDelta;
if ( boostKeyProt >= plossMax)
{
boostKeyProt = plossMax - 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 >= plossMax)
{
codeRateKey = plossMax - 1;
}
_protectionFactorK = codeRateKey;
_protectionFactorD = codeRateDelta;
// DONE WITH FEC PROTECTION SETTINGS
return true;
}
bool
VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
{
// ER SETTINGS:
// 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 input packet loss:
WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
float scaleErRS = 0.5;
float scaleErXOR = 0.5;
float minErLevel = (float) 0.025;
// float scaleErRS = 1.0;
// float scaleErXOR = 1.0;
// float minErLevel = (float) 0.0;
float avgFecRecov = 0.;
// Effective packet loss for ER:
float scaleEr = scaleErXOR;
avgFecRecov = AvgRecoveryFEC(parameters);
// Residual Packet Loss:
_residualPacketLoss = (float) (effPacketLoss - avgFecRecov) / (float) 255.0;
//Effective Packet Loss for encoder:
_effectivePacketLoss = 0;
if (effPacketLoss > 0) {
_effectivePacketLoss = VCM_MAX((effPacketLoss -
(WebRtc_UWord8)(scaleEr * avgFecRecov)),
static_cast<WebRtc_UWord8>(minErLevel * 255));
}
// DONE WITH ER SETTING
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;
}
else
{
_efficiency = 0.0f;
}
_score = _efficiency;
// 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;
}
bool
VCMIntraReqMethod::UpdateParameters(const VCMProtectionParameters* parameters)
{
float packetRate = parameters->packetsPerFrame * parameters->frameRate;
// Assume that all lost packets cohere to different frames
float lossRate = parameters->lossPr * packetRate;
if (parameters->keyFrameSize <= 1e-3)
{
_score = FLT_MAX;
return false;
}
_efficiency = lossRate * parameters->keyFrameSize;
_score = _efficiency;
if (parameters->lossPr >= 1.0f / parameters->keyFrameSize ||
parameters->rtt > _IREQ_MAX_RTT)
{
return false;
}
return true;
}
bool
VCMPeriodicIntraMethod::UpdateParameters(const
VCMProtectionParameters* /*parameters*/)
{
// Periodic I-frames. The last thing we want to use.
_efficiency = 0.0f;
_score = FLT_MAX;
return true;
}
bool
VCMMbIntraRefreshMethod::UpdateParameters(const
VCMProtectionParameters* parameters)
{
// Assume optimal for now.
_efficiency = parameters->bitRate * parameters->lossPr /
(1.0f + parameters->lossPr);
_score = _efficiency;
if (parameters->bitRate < _MBREF_MIN_BITRATE)
{
return false;
}
return true;
}
WebRtc_UWord16
VCMNackMethod::MaxRttNack() const
{
return _NACK_MAX_RTT;
}
VCMLossProtectionLogic::~VCMLossProtectionLogic()
{
ClearLossProtections();
}
void
VCMLossProtectionLogic::ClearLossProtections()
{
ListItem *item;
while ((item = _availableMethods.First()) != 0) {
VCMProtectionMethod *method = static_cast<VCMProtectionMethod*>
(item->GetItem());
if (method != NULL)
{
delete method;
}
_availableMethods.PopFront();
}
_selectedMethod = NULL;
}
bool
VCMLossProtectionLogic::AddMethod(VCMProtectionMethod *newMethod)
{
VCMProtectionMethod *method;
ListItem *item;
if (newMethod == NULL)
{
return false;
}
for (item = _availableMethods.First(); item != NULL;
item = _availableMethods.Next(item))
{
method = static_cast<VCMProtectionMethod *> (item->GetItem());
if (method != NULL && method->Type() == newMethod->Type())
{
return false;
}
}
_availableMethods.PushBack(newMethod);
return true;
}
bool
VCMLossProtectionLogic::RemoveMethod(VCMProtectionMethodEnum methodType)
{
VCMProtectionMethod *method;
ListItem *item;
bool foundAndRemoved = false;
for (item = _availableMethods.First(); item != NULL;
item = _availableMethods.Next(item))
{
method = static_cast<VCMProtectionMethod *> (item->GetItem());
if (method != NULL && method->Type() == methodType)
{
if (_selectedMethod != NULL &&
_selectedMethod->Type() == method->Type())
{
_selectedMethod = NULL;
}
_availableMethods.Erase(item);
item = NULL;
delete method;
foundAndRemoved = true;
}
}
return foundAndRemoved;
}
VCMProtectionMethod*
VCMLossProtectionLogic::FindMethod(VCMProtectionMethodEnum methodType) const
{
VCMProtectionMethod *method;
ListItem *item;
for (item = _availableMethods.First(); item != NULL;
item = _availableMethods.Next(item))
{
method = static_cast<VCMProtectionMethod *> (item->GetItem());
if (method != NULL && method->Type() == methodType)
{
return method;
}
}
return NULL;
}
float
VCMLossProtectionLogic::HighestOverhead() const
{
VCMProtectionMethod *method;
ListItem *item;
float highestOverhead = 0.0f;
for (item = _availableMethods.First(); item != NULL;
item = _availableMethods.Next(item))
{
method = static_cast<VCMProtectionMethod *> (item->GetItem());
if (method != NULL && method->RequiredBitRate() > highestOverhead)
{
highestOverhead = method->RequiredBitRate();
}
}
return highestOverhead;
}
void
VCMLossProtectionLogic::UpdateRtt(WebRtc_UWord32 rtt)
{
_rtt = rtt;
}
void
VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss)
{
_residualPacketLoss = residualPacketLoss;
}
void
VCMLossProtectionLogic::UpdateFecType(VCMFecTypes fecType)
{
_fecType = fecType;
}
void
VCMLossProtectionLogic::UpdateLossPr(WebRtc_UWord8 lossPr255)
{
const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
UpdateMaxLossHistory(lossPr255, now);
_lossPr255.Apply(static_cast<float> (now - _lastPrUpdateT),
static_cast<float> (lossPr255));
_lastPrUpdateT = now;
_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() const
{
//take the average received loss
//return static_cast<WebRtc_UWord8>(_lossPr255.Value() + 0.5f);
//TODO: Update for hybrid
//take the windowed max of the received loss
if (_selectedMethod != NULL && _selectedMethod->Type() == kFEC)
{
return MaxFilteredLossPr(VCMTickTime::MillisecondTimestamp());
}
else
{
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)
{
const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
_packetsPerFrame.Apply(static_cast<float>(now - _lastPacketPerFrameUpdateT),
nPackets);
_lastPacketPerFrameUpdateT = now;
}
void
VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets)
{
const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
_packetsPerFrameKey.Apply(static_cast<float>(now -
_lastPacketPerFrameUpdateTKey), nPackets);
_lastPacketPerFrameUpdateTKey = now;
}
void
VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
{
_keyFrameSize = keyFrameSize;
}
bool
VCMLossProtectionLogic::UpdateMethod(VCMProtectionMethod *newMethod /*=NULL */)
{
_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.residualPacketLoss = _residualPacketLoss;
_currentParameters.fecType = _fecType;
if (newMethod == NULL)
{
//_selectedMethod = _bestNotOkMethod = NULL;
VCMProtectionMethod *method;
ListItem *item;
for (item = _availableMethods.First(); item != NULL;
item = _availableMethods.Next(item))
{
method = static_cast<VCMProtectionMethod *> (item->GetItem());
if (method != NULL)
{
if (method->Type() == kFEC)
{
_selectedMethod = method;
}
if (method->Type() == kNACK)
{
_selectedMethod = method;
}
if (method->Type() == kNackFec)
{
_selectedMethod = method;
}
method->UpdateParameters(&_currentParameters);
}
}
if (_selectedMethod != NULL && _selectedMethod->Type() != kFEC)
{
_selectedMethod = method;
}
}
else
{
_selectedMethod = newMethod;
_selectedMethod->UpdateParameters(&_currentParameters);
}
return true;
}
VCMProtectionMethod*
VCMLossProtectionLogic::SelectedMethod() const
{
return _selectedMethod;
}
void VCMLossProtectionLogic::Reset()
{
const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
_lastPrUpdateT = now;
_lastPacketPerFrameUpdateT = now;
_lastPacketPerFrameUpdateTKey = now;
_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;
ClearLossProtections();
}
}