2011-05-30 13:22:19 +02:00
|
|
|
/*
|
|
|
|
* 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 {
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
|
|
|
|
bool VCMProtectionMethod::BetterThan(VCMProtectionMethod *pm)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
if (pm == NULL) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return pm->_score > _score;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* /*parameters*/)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
// use FEC model with modification with RTT for now
|
2011-05-30 13:22:19 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* /*parameters*/)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
// use FEC model with modification with RTT for now
|
|
|
|
return true;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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 (and not in all cases, refer to JB logic)
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
const WebRtc_UWord8 plossMax = 129;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Compute the protection factor
|
|
|
|
fecMethod.ProtectionFactor(parameters);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Compute the effective packet loss
|
|
|
|
fecMethod.EffectivePacketLoss(parameters);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 protFactorK = fecMethod._protectionFactorK;
|
|
|
|
WebRtc_UWord8 protFactorD = fecMethod._protectionFactorD;
|
|
|
|
WebRtc_UWord8 effPacketLoss = fecMethod._effectivePacketLoss;
|
|
|
|
float resPacketLoss = fecMethod._residualPacketLoss;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Correct FEC rates based on the RTT ( NACK effectiveness)
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_Word16 rttIndex= (WebRtc_UWord16) parameters->rtt;
|
|
|
|
float softnessRtt = 1.0;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (parameters->rtt < kHighRttNackMs)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
// TODO(mikhal): update table
|
|
|
|
softnessRtt = (float)VCMNackFecTable[rttIndex] / (float)4096.0;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// soften ER with NACK on
|
|
|
|
// table depends on RTT relative to rttMax (NACK Threshold)
|
|
|
|
_effectivePacketLoss = (WebRtc_UWord8)(effPacketLoss * softnessRtt);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// soften FEC with NACK on
|
|
|
|
// table depends on RTT relative to rttMax (NACK Threshold)
|
2011-05-30 13:22:19 +02:00
|
|
|
_protectionFactorK = (WebRtc_UWord8) (protFactorK * softnessRtt);
|
|
|
|
_protectionFactorD = (WebRtc_UWord8) (protFactorD * softnessRtt);
|
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
// else - NACK is disabled, rely on FEC only
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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)));
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// check limit on amount of protection for I frame: 50% is max
|
|
|
|
if (_protectionFactorK >= plossMax)
|
|
|
|
_protectionFactorK = plossMax - 1;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Bit cost for NackFec
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// NACK cost: based on residual packet loss (since we should only NACK packets
|
|
|
|
// not recovered by FEC)
|
2011-05-30 13:22:19 +02:00
|
|
|
_efficiency = 0.0f;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (parameters->rtt < kHighRttNackMs)
|
|
|
|
{
|
2011-05-30 13:22:19 +02:00
|
|
|
_efficiency = parameters->bitRate * resPacketLoss / (1.0f + resPacketLoss);
|
2011-06-14 19:54:20 +02:00
|
|
|
} 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;
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
_score = _efficiency;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord8 codeRate = protFactorK;
|
|
|
|
_protectionFactorK = fecMethod.ConvertFECRate(codeRate);
|
|
|
|
codeRate = protFactorD;
|
|
|
|
_protectionFactorD = fecMethod.ConvertFECRate(codeRate);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMNackMethod::EffectivePacketLoss(WebRtc_UWord8 effPacketLoss, WebRtc_UWord16 rttTime)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
WebRtc_UWord16 rttMax = MaxRttNack();
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
_effectivePacketLoss = effPacketLoss;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
|
|
|
|
{
|
|
|
|
// Compute the effective packet loss for ER
|
|
|
|
WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord16 rttTime = (WebRtc_UWord16) parameters->rtt;
|
|
|
|
EffectivePacketLoss(effPacketLoss, rttTime);
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Compute the NACK bit cost
|
2011-05-30 13:22:19 +02:00
|
|
|
_efficiency = parameters->bitRate * parameters->lossPr / (1.0f + parameters->lossPr);
|
|
|
|
_score = _efficiency;
|
|
|
|
if (parameters->rtt > _NACK_MAX_RTT)
|
|
|
|
{
|
|
|
|
_score = 0.0f;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 VCMFecMethod::BoostCodeRateKey(WebRtc_UWord8 packetFrameDelta,
|
|
|
|
WebRtc_UWord8 packetFrameKey) const
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 boostRateKey = 2;
|
|
|
|
// default: ratio scales the FEC protection up for I frames
|
|
|
|
WebRtc_UWord8 ratio = 1;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
if (packetFrameDelta > 0)
|
|
|
|
ratio = (WebRtc_Word8) (packetFrameKey / packetFrameDelta);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
ratio = VCM_MAX(boostRateKey, ratio);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
return ratio;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 VCMFecMethod::ConvertFECRate(WebRtc_UWord8 codeRateRTP) const
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
return static_cast<WebRtc_UWord8> (VCM_MIN(255,(0.5 + 255.0*codeRateRTP/(float)(255 - codeRateRTP))));
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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));
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// parameters for tables
|
2011-05-30 13:22:19 +02:00
|
|
|
const WebRtc_UWord8 codeSize = 24;
|
|
|
|
const WebRtc_UWord8 plossMax = 129;
|
|
|
|
const WebRtc_UWord16 maxErTableSize = 38700;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Get index for table
|
|
|
|
const float protectionFactor = (float) _protectionFactorD / (float) 255;
|
|
|
|
WebRtc_UWord8 fecPacketsPerFrame = (WebRtc_UWord8) (0.5 + protectionFactor * avgTotPackets);
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord8 sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
if (fecPacketsPerFrame == 0) {
|
|
|
|
return 0.0; // no protection, so avg. recov from FEC == 0
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// table defined up to codeSizexcodeSize code
|
|
|
|
if (sourcePacketsPerFrame > codeSize) {
|
|
|
|
sourcePacketsPerFrame = codeSize;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// check: protection factor is maxed at 50%, so this should never happen
|
|
|
|
if (sourcePacketsPerFrame < 1) {
|
|
|
|
assert("average number of source packets below 1\n");
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// index for ER tables: up to codeSizexcodeSize mask
|
|
|
|
WebRtc_UWord16 codeIndexTable[codeSize * codeSize];
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord16 k = -1;
|
2011-06-14 19:54:20 +02:00
|
|
|
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;
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
const WebRtc_UWord8 lossRate = (WebRtc_UWord8) (255.0 * parameters->lossPr + 0.5f);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
const WebRtc_UWord16 codeIndex = (fecPacketsPerFrame - 1) * codeSize
|
|
|
|
+ (sourcePacketsPerFrame - 1);
|
2011-05-30 13:22:19 +02:00
|
|
|
const WebRtc_UWord16 indexTable = codeIndexTable[codeIndex] * plossMax + lossRate;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
const WebRtc_UWord16 codeIndex2 = (fecPacketsPerFrame) * codeSize + (sourcePacketsPerFrame);
|
|
|
|
WebRtc_UWord16 indexTable2 = codeIndexTable[codeIndex2] * plossMax + lossRate;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// checks on table index
|
|
|
|
if (indexTable >= maxErTableSize) {
|
|
|
|
assert("ER table index too large\n");
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
if (indexTable2 >= maxErTableSize) {
|
|
|
|
indexTable2 = indexTable;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
//
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Get the average effective packet loss recovery from FEC
|
|
|
|
// this is from tables, computed using random loss model
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord8 avgFecRecov1 = 0;
|
|
|
|
WebRtc_UWord8 avgFecRecov2 = 0;
|
|
|
|
float avgFecRecov = 0;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
if (fecPacketsPerFrame > 0) {
|
|
|
|
avgFecRecov1 = VCMAvgFECRecoveryXOR[indexTable];
|
|
|
|
avgFecRecov2 = VCMAvgFECRecoveryXOR[indexTable2];
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// 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;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
return avgFecRecov;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// FEC PROTECTION SETTINGS: varies with packet loss and bitrate
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
const float bitRate = parameters->bitRate;
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Size of tables
|
|
|
|
const WebRtc_UWord16 maxFecTableSize = 6450;
|
|
|
|
// Parameters for range of rate and packet loss for tables
|
2011-05-30 13:22:19 +02:00
|
|
|
const WebRtc_UWord8 ratePar1 = 5;
|
|
|
|
const WebRtc_UWord8 ratePar2 = 49;
|
|
|
|
const WebRtc_UWord8 plossMax = 129;
|
|
|
|
|
|
|
|
//
|
2011-06-14 19:54:20 +02:00
|
|
|
// Just for testing: for the case where we randomly lose slices instead of
|
|
|
|
// RTP packets and use SingleMode packetization in RTP module
|
|
|
|
// const WebRtc_UWord16 slice_size = 3000/6; //corresponds to rate=1000k with 4 cores
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
//float slice_mtu = (float)_maxPayloadSize/(float)slice_size;
|
|
|
|
const float slice_mtu = 1.0;
|
|
|
|
//
|
|
|
|
|
|
|
|
//Total (avg) bits available per frame: total rate over actual/sent frame rate
|
|
|
|
//units are kbits/frame
|
2011-06-14 19:54:20 +02:00
|
|
|
const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16> (slice_mtu * bitRate
|
|
|
|
/ (parameters->frameRate));
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
//Total (avg) number of packets per frame (source and fec):
|
2011-06-14 19:54:20 +02:00
|
|
|
const WebRtc_UWord8 avgTotPackets = 1 + (WebRtc_UWord8) ((float) bitRatePerFrame * 1000.0
|
|
|
|
/ (float) (8.0 * _maxPayloadSize) + 0.5);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// TODO(marpan): Tune model for FEC Protection.
|
|
|
|
// Better modulation of protection with available bits/frame
|
|
|
|
// (or avgTotpackets) using weight factors
|
|
|
|
// FEC Tables include this effect already, but need to tune model off-line
|
2011-05-30 13:22:19 +02:00
|
|
|
float weight1 = 0.5;
|
|
|
|
float weight2 = 0.5;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (avgTotPackets > 4) {
|
|
|
|
weight1 = 1.0;
|
|
|
|
weight2 = 0.;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
if (avgTotPackets > 6) {
|
|
|
|
weight1 = 1.5;
|
|
|
|
weight2 = 0.;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
//
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Fec rate parameters: for P and I frame
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord8 codeRateDelta = 0;
|
|
|
|
WebRtc_UWord8 codeRateKey = 0;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// Get index for new 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);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
// Restrict packet loss range to 50 for now%: current tables defined only up to 50%
|
2011-06-14 19:54:20 +02:00
|
|
|
if (packetLoss >= plossMax) {
|
|
|
|
packetLoss = plossMax - 1;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
WebRtc_UWord16 indexTable = rateIndexTable * plossMax + packetLoss;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// check on table index
|
|
|
|
if (indexTable >= maxFecTableSize) {
|
|
|
|
assert("FEC table index too large\n");
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
//
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
// For Key frame: effectively at a higher rate, so we scale/boost the rate
|
|
|
|
// index. 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.
|
|
|
|
// default is 2
|
|
|
|
const WebRtc_UWord8 packetFrameDelta = (WebRtc_UWord8) (0.5 + parameters->packetsPerFrame);
|
2011-05-30 13:22:19 +02:00
|
|
|
const WebRtc_UWord8 packetFrameKey = (WebRtc_UWord8) (0.5 + parameters->packetsPerFrameKey);
|
|
|
|
const WebRtc_UWord8 boostKey = BoostCodeRateKey(packetFrameDelta, packetFrameKey);
|
2011-06-14 19:54:20 +02:00
|
|
|
rateIndexTable
|
|
|
|
= (WebRtc_UWord8) VCM_MAX(VCM_MIN(1+(boostKey*bitRatePerFrame-ratePar1)/ratePar1,ratePar2),0);
|
2011-05-30 13:22:19 +02:00
|
|
|
WebRtc_UWord16 indexTableKey = rateIndexTable * plossMax + packetLoss;
|
|
|
|
|
|
|
|
indexTableKey = VCM_MIN(indexTableKey, maxFecTableSize);
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
codeRateDelta = VCMCodeRateXORTable[indexTable]; //protection factor for P frame
|
2011-05-30 13:22:19 +02:00
|
|
|
codeRateKey = VCMCodeRateXORTable[indexTableKey]; //protection factor for I frame
|
|
|
|
|
|
|
|
//average with minimum protection level given by (average) total number of packets
|
2011-06-14 19:54:20 +02:00
|
|
|
if (packetLoss > 0) {
|
|
|
|
codeRateDelta = static_cast<WebRtc_UWord8> ((weight1 * (float) codeRateDelta + weight2 * 255.0
|
|
|
|
/ (float) avgTotPackets));
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//check limit on amount of protection for P frame; 50% is max
|
2011-06-14 19:54:20 +02:00
|
|
|
if (codeRateDelta >= plossMax) {
|
|
|
|
codeRateDelta = plossMax - 1;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//make sure I frame protection is at least larger than P frame protection, and at least as high as received loss
|
2011-06-14 19:54:20 +02:00
|
|
|
codeRateKey
|
|
|
|
= static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,VCM_MAX(_scaleProtKey*codeRateDelta, codeRateKey)));
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
//check limit on amount of protection for I frame: 50% is max
|
2011-06-14 19:54:20 +02:00
|
|
|
if (codeRateKey >= plossMax) {
|
|
|
|
codeRateKey = plossMax - 1;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_protectionFactorK = codeRateKey;
|
|
|
|
_protectionFactorD = codeRateDelta;
|
|
|
|
|
|
|
|
// DONE WITH FEC PROTECTION SETTINGS
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
// 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 according to FilteredLoss
|
|
|
|
|
|
|
|
//The input packet loss:
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
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:
|
2011-06-14 19:54:20 +02:00
|
|
|
_residualPacketLoss = (float) (effPacketLoss - avgFecRecov) / (float) 255.0;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
|
|
|
//Effective Packet Loss for encoder:
|
|
|
|
_effectivePacketLoss = 0;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (effPacketLoss > 0) {
|
|
|
|
_effectivePacketLoss = VCM_MAX((effPacketLoss -
|
|
|
|
(WebRtc_UWord8)(scaleEr * avgFecRecov)),
|
|
|
|
static_cast<WebRtc_UWord8>(minErLevel * 255));
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// DONE WITH ER SETTING
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
return true;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
// Compute the protection factor
|
|
|
|
ProtectionFactor(parameters);
|
|
|
|
|
|
|
|
// Compute the effective packet loss
|
|
|
|
EffectivePacketLoss(parameters);
|
|
|
|
|
|
|
|
// Compute the bit cost
|
|
|
|
// Ignore key frames for now.
|
2011-06-14 19:54:20 +02:00
|
|
|
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;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
_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;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMIntraReqMethod::UpdateParameters(const VCMProtectionParameters* parameters)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
float packetRate = parameters->packetsPerFrame * parameters->frameRate;
|
|
|
|
// Assume that all lost packets cohere to different frames
|
|
|
|
float lossRate = parameters->lossPr * packetRate;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (parameters->keyFrameSize <= 1e-3) {
|
|
|
|
_score = FLT_MAX;
|
|
|
|
return false;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
_efficiency = lossRate * parameters->keyFrameSize;
|
|
|
|
_score = _efficiency;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (parameters->lossPr >= 1.0f / parameters->keyFrameSize || parameters->rtt > _IREQ_MAX_RTT) {
|
|
|
|
return false;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMPeriodicIntraMethod::UpdateParameters(const VCMProtectionParameters* /*parameters*/)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
// Periodic I-frames. The last thing we want to use.
|
|
|
|
_efficiency = 0.0f;
|
|
|
|
_score = FLT_MAX;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMMbIntraRefreshMethod::UpdateParameters(const VCMProtectionParameters* parameters)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
// Assume optimal for now.
|
|
|
|
_efficiency = parameters->bitRate * parameters->lossPr / (1.0f + parameters->lossPr);
|
|
|
|
_score = _efficiency;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (parameters->bitRate < _MBREF_MIN_BITRATE) {
|
|
|
|
return false;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord16 VCMNackMethod::MaxRttNack() const
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
return _NACK_MAX_RTT;
|
|
|
|
}
|
|
|
|
|
|
|
|
VCMLossProtectionLogic::~VCMLossProtectionLogic()
|
|
|
|
{
|
|
|
|
ClearLossProtections();
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::ClearLossProtections()
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
ListItem *item;
|
2011-06-14 19:54:20 +02:00
|
|
|
while ((item = _availableMethods.First()) != 0) {
|
|
|
|
VCMProtectionMethod *method = static_cast<VCMProtectionMethod*> (item->GetItem());
|
|
|
|
if (method != NULL) {
|
|
|
|
delete method;
|
|
|
|
}
|
|
|
|
_availableMethods.PopFront();
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
_selectedMethod = NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMLossProtectionLogic::AddMethod(VCMProtectionMethod *newMethod)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
VCMProtectionMethod *method;
|
|
|
|
ListItem *item;
|
2011-06-14 19:54:20 +02:00
|
|
|
if (newMethod == NULL) {
|
|
|
|
return false;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
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;
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
_availableMethods.PushBack(newMethod);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMLossProtectionLogic::RemoveMethod(VCMProtectionMethodEnum methodType)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
VCMProtectionMethod *method;
|
|
|
|
ListItem *item;
|
|
|
|
bool foundAndRemoved = false;
|
2011-06-14 19:54:20 +02:00
|
|
|
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;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
_availableMethods.Erase(item);
|
|
|
|
item = NULL;
|
|
|
|
delete method;
|
|
|
|
foundAndRemoved = true;
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return foundAndRemoved;
|
|
|
|
}
|
|
|
|
|
|
|
|
VCMProtectionMethod*
|
|
|
|
VCMLossProtectionLogic::FindMethod(VCMProtectionMethodEnum methodType) const
|
|
|
|
{
|
|
|
|
VCMProtectionMethod *method;
|
|
|
|
ListItem *item;
|
2011-06-14 19:54:20 +02:00
|
|
|
for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item)) {
|
|
|
|
method = static_cast<VCMProtectionMethod *> (item->GetItem());
|
|
|
|
if (method != NULL && method->Type() == methodType) {
|
|
|
|
return method;
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
float VCMLossProtectionLogic::HighestOverhead() const
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
VCMProtectionMethod *method;
|
|
|
|
ListItem *item;
|
|
|
|
float highestOverhead = 0.0f;
|
2011-06-14 19:54:20 +02:00
|
|
|
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();
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return highestOverhead;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateRtt(WebRtc_UWord32 rtt)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
_rtt = rtt;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss) {
|
2011-05-30 13:22:19 +02:00
|
|
|
_residualPacketLoss = residualPacketLoss;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateFecType(VCMFecTypes fecType)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
_fecType = fecType;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateLossPr(WebRtc_UWord8 lossPr255)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord32 now = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
|
2011-05-30 13:22:19 +02:00
|
|
|
UpdateMaxLossHistory(lossPr255, now);
|
2011-06-14 19:54:20 +02:00
|
|
|
_lossPr255.Apply(static_cast<float> (now - _lastPrUpdateT), static_cast<float> (lossPr255));
|
2011-05-30 13:22:19 +02:00
|
|
|
_lastPrUpdateT = now;
|
|
|
|
_lossPr = _lossPr255.Value() / 255.0f;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateMaxLossHistory(WebRtc_UWord8 lossPr255, WebRtc_Word64 now)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
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;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
_lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
|
|
|
|
_lossPrHistory[0].timeMs = now;
|
|
|
|
_shortMaxLossPr255 = 0;
|
2011-05-30 13:22:19 +02:00
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 VCMLossProtectionLogic::MaxFilteredLossPr(WebRtc_Word64 nowMs) const
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
WebRtc_UWord8 maxFound = _shortMaxLossPr255;
|
2011-06-14 19:54:20 +02:00
|
|
|
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;
|
|
|
|
}
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return maxFound;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord8 VCMLossProtectionLogic::FilteredLoss() const
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
//take the average received loss
|
|
|
|
//return static_cast<WebRtc_UWord8>(_lossPr255.Value() + 0.5f);
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
//TODO: Update for hybrid
|
2011-05-30 13:22:19 +02:00
|
|
|
//take the windowed max of the received loss
|
2011-06-14 19:54:20 +02:00
|
|
|
if (_selectedMethod != NULL && _selectedMethod->Type() == kFEC) {
|
|
|
|
return MaxFilteredLossPr(static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp()));
|
|
|
|
} else {
|
|
|
|
return static_cast<WebRtc_UWord8> (_lossPr255.Value() + 0.5);
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateFilteredLossPr(WebRtc_UWord8 packetLossEnc)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
_lossPr = (float) packetLossEnc / (float) 255.0;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateBitRate(float bitRate)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
_bitRate = bitRate;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord32 now = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
|
|
|
|
_packetsPerFrame.Apply(static_cast<float> (now - _lastPacketPerFrameUpdateT), nPackets);
|
2011-05-30 13:22:19 +02:00
|
|
|
_lastPacketPerFrameUpdateT = now;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
WebRtc_UWord32 now = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
|
|
|
|
_packetsPerFrameKey.Apply(static_cast<float> (now - _lastPacketPerFrameUpdateTKey), nPackets);
|
2011-05-30 13:22:19 +02:00
|
|
|
_lastPacketPerFrameUpdateTKey = now;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
|
|
|
_keyFrameSize = keyFrameSize;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
bool VCMLossProtectionLogic::UpdateMethod(VCMProtectionMethod *newMethod /*=NULL */)
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
_currentParameters.rtt = _rtt;
|
|
|
|
_currentParameters.lossPr = _lossPr;
|
2011-05-30 13:22:19 +02:00
|
|
|
_currentParameters.bitRate = _bitRate;
|
2011-06-14 19:54:20 +02:00
|
|
|
_currentParameters.frameRate = _frameRate; //should this be named actual frame rate?
|
2011-05-30 13:22:19 +02:00
|
|
|
_currentParameters.keyFrameSize = _keyFrameSize;
|
|
|
|
_currentParameters.fecRateDelta = _fecRateDelta;
|
2011-06-14 19:54:20 +02:00
|
|
|
_currentParameters.fecRateKey = _fecRateKey;
|
2011-05-30 13:22:19 +02:00
|
|
|
_currentParameters.packetsPerFrame = _packetsPerFrame.Value();
|
|
|
|
_currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value();
|
|
|
|
_currentParameters.residualPacketLoss = _residualPacketLoss;
|
|
|
|
_currentParameters.fecType = _fecType;
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
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) {
|
2011-05-30 13:22:19 +02:00
|
|
|
_selectedMethod = method;
|
2011-06-14 19:54:20 +02:00
|
|
|
}
|
|
|
|
method->UpdateParameters(&_currentParameters);
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
2011-06-14 19:54:20 +02:00
|
|
|
}
|
|
|
|
if (_selectedMethod != NULL && _selectedMethod->Type() != kFEC) {
|
|
|
|
_selectedMethod = method;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_selectedMethod = newMethod;
|
|
|
|
_selectedMethod->UpdateParameters(&_currentParameters);
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
VCMProtectionMethod*
|
|
|
|
VCMLossProtectionLogic::SelectedMethod() const
|
|
|
|
{
|
|
|
|
return _selectedMethod;
|
|
|
|
}
|
|
|
|
|
2011-06-14 19:54:20 +02:00
|
|
|
void VCMLossProtectionLogic::Reset()
|
2011-05-30 13:22:19 +02:00
|
|
|
{
|
2011-06-14 19:54:20 +02:00
|
|
|
_lastPrUpdateT = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
|
|
|
|
_lastPacketPerFrameUpdateT = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
|
2011-05-30 13:22:19 +02:00
|
|
|
_lossPr255.Reset(0.9999f);
|
|
|
|
_packetsPerFrame.Reset(0.9999f);
|
|
|
|
_fecRateDelta = _fecRateKey = 0;
|
2011-06-14 19:54:20 +02:00
|
|
|
for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++) {
|
|
|
|
_lossPrHistory[i].lossPr255 = 0;
|
|
|
|
_lossPrHistory[i].timeMs = -1;
|
2011-05-30 13:22:19 +02:00
|
|
|
}
|
|
|
|
_shortMaxLossPr255 = 0;
|
|
|
|
ClearLossProtections();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|