| /* |
| * 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 "qm_select.h" |
| #include "internal_defines.h" |
| #include "qm_select_data.h" |
| |
| #include "module_common_types.h" |
| #include "video_coding_defines.h" |
| #include "trace.h" |
| |
| #include <math.h> |
| |
| namespace webrtc { |
| |
| // QM-METHOD class |
| |
| VCMQmMethod::VCMQmMethod() |
| { |
| _contentMetrics = new VideoContentMetrics(); |
| ResetQM(); |
| } |
| |
| VCMQmMethod::~VCMQmMethod() |
| { |
| delete _contentMetrics; |
| } |
| |
| void |
| VCMQmMethod::ResetQM() |
| { |
| _motion.Reset(); |
| _spatial.Reset(); |
| _coherence.Reset(); |
| _stationaryMotion = 0; |
| _aspectRatio = 1; |
| _imageType = 2; |
| return; |
| } |
| |
| void |
| VCMQmMethod::UpdateContent(const VideoContentMetrics* contentMetrics) |
| { |
| _contentMetrics = contentMetrics; |
| } |
| |
| void |
| VCMQmMethod::MotionNFD() |
| { |
| _motion.value = _contentMetrics->motionMagnitudeNZ; |
| |
| // Determine motion level |
| if (_motion.value < LOW_MOTION_NFD) |
| { |
| _motion.level = kLow; |
| } |
| else if (_motion.value > HIGH_MOTION_NFD) |
| { |
| _motion.level = kHigh; |
| } |
| else |
| { |
| _motion.level = kDefault; |
| } |
| |
| } |
| |
| void |
| VCMQmMethod::Motion() |
| { |
| |
| float sizeZeroMotion = _contentMetrics->sizeZeroMotion; |
| float motionMagNZ = _contentMetrics->motionMagnitudeNZ; |
| |
| // Take product of size and magnitude with equal weight |
| _motion.value = (1.0f - sizeZeroMotion) * motionMagNZ; |
| |
| // Stabilize: motionMagNZ could be large when only a |
| // few motion blocks are non-zero |
| _stationaryMotion = false; |
| if (sizeZeroMotion > HIGH_ZERO_MOTION_SIZE) |
| { |
| _motion.value = 0.0f; |
| _stationaryMotion = true; |
| } |
| // Determine motion level |
| if (_motion.value < LOW_MOTION) |
| { |
| _motion.level = kLow; |
| } |
| else if (_motion.value > HIGH_MOTION) |
| { |
| _motion.level = kHigh; |
| } |
| else |
| { |
| _motion.level = kDefault; |
| } |
| } |
| |
| |
| void |
| VCMQmMethod::Spatial() |
| { |
| float spatialErr = _contentMetrics->spatialPredErr; |
| float spatialErrH = _contentMetrics->spatialPredErrH; |
| float spatialErrV = _contentMetrics->spatialPredErrV; |
| // Spatial measure: take average of 3 prediction errors |
| _spatial.value = (spatialErr + spatialErrH + spatialErrV) / 3.0f; |
| |
| float scale = 1.0f; |
| // Reduce thresholds for HD scenes |
| if (_imageType > 3) |
| { |
| scale = (float)SCALE_TEXTURE_HD; |
| } |
| |
| if (_spatial.value > scale * HIGH_TEXTURE) |
| { |
| _spatial.level = kHigh; |
| } |
| else if (_spatial.value < scale * LOW_TEXTURE) |
| { |
| _spatial.level = kLow; |
| } |
| else |
| { |
| _spatial.level = kDefault; |
| } |
| } |
| |
| void |
| VCMQmMethod::Coherence() |
| { |
| float horizNZ = _contentMetrics->motionHorizontalness; |
| float distortionNZ = _contentMetrics->motionClusterDistortion; |
| |
| // Coherence measure: combine horizontalness with cluster distortion |
| _coherence.value = COH_MAX; |
| if (distortionNZ > 0.) |
| { |
| _coherence.value = horizNZ / distortionNZ; |
| } |
| _coherence.value = VCM_MIN(COH_MAX, _coherence.value); |
| |
| if (_coherence.value < COHERENCE_THR) |
| { |
| _coherence.level = kLow; |
| } |
| else |
| { |
| _coherence.level = kHigh; |
| } |
| |
| } |
| |
| WebRtc_Word8 |
| VCMQmMethod::GetImageType(WebRtc_UWord32 width, WebRtc_UWord32 height) |
| { |
| // Match image type |
| WebRtc_UWord32 imageSize = width * height; |
| WebRtc_Word8 imageType; |
| |
| if (imageSize < kFrameSizeTh[0]) |
| { |
| imageType = 0; |
| } |
| else if (imageSize < kFrameSizeTh[1]) |
| { |
| imageType = 1; |
| } |
| else if (imageSize < kFrameSizeTh[2]) |
| { |
| imageType = 2; |
| } |
| else if (imageSize < kFrameSizeTh[3]) |
| { |
| imageType = 3; |
| } |
| else if (imageSize < kFrameSizeTh[4]) |
| { |
| imageType = 4; |
| } |
| else if (imageSize < kFrameSizeTh[5]) |
| { |
| imageType = 5; |
| } |
| else |
| { |
| imageType = 6; |
| } |
| |
| return imageType; |
| } |
| |
| // DONE WITH QM CLASS |
| |
| |
| //RESOLUTION CLASS |
| |
| VCMQmResolution::VCMQmResolution() |
| { |
| _qm = new VCMResolutionScale(); |
| Reset(); |
| } |
| |
| VCMQmResolution::~VCMQmResolution() |
| { |
| delete _qm; |
| } |
| |
| void |
| VCMQmResolution::ResetRates() |
| { |
| _sumEncodedBytes = 0; |
| _sumTargetRate = 0.0f; |
| _sumIncomingFrameRate = 0.0f; |
| _sumFrameRateMM = 0.0f; |
| _sumSeqRateMM = 0.0f; |
| _sumPacketLoss = 0.0f; |
| _frameCnt = 0; |
| _frameCntDelta = 0; |
| _lowBufferCnt = 0; |
| _updateRateCnt = 0; |
| return; |
| } |
| |
| void |
| VCMQmResolution::Reset() |
| { |
| _stateDecFactorSpatial = 1; |
| _stateDecFactorTemp = 1; |
| _bufferLevel = 0.0f; |
| _targetBitRate = 0.0f; |
| _incomingFrameRate = 0.0f; |
| _userFrameRate = 0.0f; |
| _perFrameBandwidth =0.0f; |
| ResetRates(); |
| ResetQM(); |
| return; |
| } |
| |
| // Initialize rate control quantities after reset of encoder |
| WebRtc_Word32 |
| VCMQmResolution::Initialize(float bitRate, float userFrameRate, |
| WebRtc_UWord32 width, WebRtc_UWord32 height) |
| { |
| if (userFrameRate == 0.0f || width == 0 || height == 0) |
| { |
| return VCM_PARAMETER_ERROR; |
| } |
| _targetBitRate = bitRate; |
| _userFrameRate = userFrameRate; |
| |
| // Encoder width and height |
| _width = width; |
| _height = height; |
| |
| // Aspect ratio: used for selection of 1x2,2x1,2x2 |
| _aspectRatio = static_cast<float>(_width) / static_cast<float>(_height); |
| |
| // Set the imageType for the encoder width/height. |
| _imageType = GetImageType(_width, _height); |
| |
| // Initial buffer level |
| _bufferLevel = INIT_BUFFER_LEVEL * _targetBitRate; |
| |
| // Per-frame bandwidth |
| if ( _incomingFrameRate == 0 ) |
| { |
| _perFrameBandwidth = _targetBitRate / _userFrameRate; |
| _incomingFrameRate = _userFrameRate; |
| } |
| else |
| { |
| // Take average: this is due to delay in update of new encoder frame rate: |
| // userFrameRate is the new one, |
| // incomingFrameRate is the old one (based on previous ~ 1sec/RTCP report) |
| _perFrameBandwidth = 0.5 *( _targetBitRate / _userFrameRate + |
| _targetBitRate / _incomingFrameRate ); |
| } |
| _init = true; |
| |
| |
| return VCM_OK; |
| } |
| |
| // Update after every encoded frame |
| void |
| VCMQmResolution::UpdateEncodedSize(WebRtc_Word64 encodedSize, |
| FrameType encodedFrameType) |
| { |
| // Update encoded size; |
| _sumEncodedBytes += encodedSize; |
| _frameCnt++; |
| |
| // Convert to Kbps |
| float encodedSizeKbits = (float)((encodedSize * 8.0) / 1000.0); |
| |
| // Update the buffer level: |
| // per_frame_BW is updated when encoder is updated, every RTCP reports |
| _bufferLevel += _perFrameBandwidth - encodedSizeKbits; |
| |
| // Mismatch here is based on difference of actual encoded frame size and |
| // per-frame bandwidth, for delta frames |
| // This is a much stronger condition on rate mismatch than sumSeqRateMM |
| // Note: not used in this version |
| /* |
| const bool deltaFrame = (encodedFrameType != kVideoFrameKey && |
| encodedFrameType != kVideoFrameGolden); |
| |
| // Sum the frame mismatch: |
| if (deltaFrame) |
| { |
| _frameCntDelta++; |
| if (encodedSizeKbits > 0) |
| _sumFrameRateMM += |
| (float) (fabs(encodedSizeKbits - _perFrameBandwidth) / |
| encodedSizeKbits); |
| } |
| */ |
| |
| // Counter for occurrences of low buffer level |
| if (_bufferLevel <= PERC_BUFFER_THR * OPT_BUFFER_LEVEL * _targetBitRate) |
| { |
| _lowBufferCnt++; |
| } |
| |
| } |
| |
| // Update various quantities after SetTargetRates in MediaOpt |
| void |
| VCMQmResolution::UpdateRates(float targetBitRate, float avgSentBitRate, |
| float incomingFrameRate, WebRtc_UWord8 packetLoss) |
| { |
| |
| // Sum the target bitrate and incoming frame rate: |
| // these values are the encoder rates (from previous update ~1sec), |
| // i.e, before the update for next ~1sec |
| _sumTargetRate += _targetBitRate; |
| _sumIncomingFrameRate += _incomingFrameRate; |
| _updateRateCnt++; |
| |
| // Sum the received (from RTCP reports) packet loss rates |
| _sumPacketLoss += (float) packetLoss / 255.0f; |
| |
| // Convert average sent bitrate to kbps |
| float avgSentBitRatekbps = avgSentBitRate / 1000.0f; |
| |
| // Sum the sequence rate mismatch: |
| // Mismatch here is based on difference between target rate the encoder |
| // used (in previous ~1sec) and the average actual |
| // encoding rate measured at current time |
| if (fabs(_targetBitRate - avgSentBitRatekbps) < THRESH_SUM_MM && |
| _targetBitRate > 0.0 ) |
| { |
| _sumSeqRateMM += (float) |
| (fabs(_targetBitRate - avgSentBitRatekbps) / _targetBitRate ); |
| } |
| |
| // Update QM with the current new target and frame rate: |
| // these values are ones the encoder will use for the current/next ~1sec |
| _targetBitRate = targetBitRate; |
| _incomingFrameRate = incomingFrameRate; |
| |
| // Update QM with an (average) encoder per_frame_bandwidth: |
| // this is the per_frame_bw for the current/next ~1sec |
| _perFrameBandwidth = 0.0f; |
| if (_incomingFrameRate > 0.0f) |
| { |
| _perFrameBandwidth = _targetBitRate / _incomingFrameRate; |
| } |
| |
| } |
| |
| // Select the resolution factors: frame size and frame rate change: (QM modes) |
| // Selection is for going back up in resolution, or going down in. |
| WebRtc_Word32 |
| VCMQmResolution::SelectResolution(VCMResolutionScale** qm) |
| { |
| if (!_init) |
| { |
| return VCM_UNINITIALIZED; |
| } |
| if (_contentMetrics == NULL) |
| { |
| Reset(); //default values |
| *qm = _qm; |
| return VCM_OK; |
| } |
| |
| // Default settings |
| _qm->spatialWidthFact = 1; |
| _qm->spatialHeightFact = 1; |
| _qm->temporalFact = 1; |
| |
| // Update native values |
| _nativeWidth = _contentMetrics->nativeWidth; |
| _nativeHeight = _contentMetrics->nativeHeight; |
| _nativeFrameRate = _contentMetrics->nativeFrameRate; |
| |
| float avgTargetRate = 0.0f; |
| float avgIncomingFrameRate = 0.0f; |
| float ratioBufferLow = 0.0f; |
| float rateMisMatch = 0.0f; |
| float avgPacketLoss = 0.0f; |
| if (_frameCnt > 0) |
| { |
| ratioBufferLow = (float)_lowBufferCnt / (float)_frameCnt; |
| } |
| if (_updateRateCnt > 0) |
| { |
| // Use seq-rate mismatch for now |
| rateMisMatch = (float)_sumSeqRateMM / (float)_updateRateCnt; |
| //rateMisMatch = (float)_sumFrameRateMM / (float)_frameCntDelta; |
| |
| // Average target and incoming frame rates |
| avgTargetRate = (float)_sumTargetRate / (float)_updateRateCnt; |
| avgIncomingFrameRate = (float)_sumIncomingFrameRate / |
| (float)_updateRateCnt; |
| |
| // Average received packet loss rate |
| avgPacketLoss = (float)_sumPacketLoss / (float)_updateRateCnt; |
| } |
| |
| // For QM selection below, may want to weight the average encoder rates |
| // with the current (for next ~1sec) rate values. |
| // Uniform average for now: |
| float w1 = 0.5f; |
| float w2 = 0.5f; |
| avgTargetRate = w1 * avgTargetRate + w2 * _targetBitRate; |
| avgIncomingFrameRate = w1 * avgIncomingFrameRate + w2 * _incomingFrameRate; |
| |
| // Set the maximum transitional rate and image type: |
| // for up-sampled spatial dimensions. |
| // This is needed to get the transRate for going back up in |
| // spatial resolution (only 2x2 allowed in this version). |
| WebRtc_UWord8 imageType2 = GetImageType(2 * _width, 2 * _height); |
| WebRtc_UWord32 maxRateQM2 = kMaxRateQm[imageType2]; |
| |
| // Set the maximum transitional rate and image type: |
| // for the encoder spatial dimensions. |
| WebRtc_UWord32 maxRateQM = kMaxRateQm[_imageType]; |
| |
| // Compute class state of the content. |
| MotionNFD(); |
| Spatial(); |
| |
| // |
| // Get transitional rate from table, based on image type and content class. |
| // |
| |
| // Get image class and content class: for going down spatially |
| WebRtc_UWord8 imageClass = 1; |
| if (_imageType <= 3) imageClass = 0; |
| WebRtc_UWord8 contentClass = 3 * _motion.level + _spatial.level; |
| WebRtc_UWord8 tableIndex = imageClass * 9 + contentClass; |
| float scaleTransRate = kScaleTransRateQm[tableIndex]; |
| |
| // Get image class and content class: for going up spatially |
| WebRtc_UWord8 imageClass2 = 1; |
| if (imageType2 <= 3) |
| { |
| imageClass2 = 0; |
| } |
| WebRtc_UWord8 tableIndex2 = imageClass2 * 9 + contentClass; |
| float scaleTransRate2 = kScaleTransRateQm[tableIndex2]; |
| |
| // Transitonal rate for going down |
| WebRtc_UWord32 estimatedTransRateDown = static_cast<WebRtc_UWord32> |
| (_incomingFrameRate * scaleTransRate * maxRateQM / 30); |
| |
| // Transitional rate for going up temporally |
| WebRtc_UWord32 estimatedTransRateUpT = static_cast<WebRtc_UWord32> |
| (TRANS_RATE_SCALE_UP_TEMP * 2 * _incomingFrameRate * |
| scaleTransRate * maxRateQM / 30); |
| |
| // Transitional rate for going up spatially |
| WebRtc_UWord32 estimatedTransRateUpS = static_cast<WebRtc_UWord32> |
| (TRANS_RATE_SCALE_UP_SPATIAL * _incomingFrameRate * |
| scaleTransRate2 * maxRateQM2 / 30); |
| |
| // |
| // Done with transitional rates |
| // |
| |
| // |
| //CHECK FOR GOING BACK UP IN RESOLUTION |
| // |
| bool selectedUp = false; |
| // Check if native has been spatially down-sampled |
| if (_stateDecFactorSpatial > 1) |
| { |
| // Check conditions on buffer level and rate_mismatch |
| if ( (avgTargetRate > estimatedTransRateUpS) && |
| (ratioBufferLow < MAX_BUFFER_LOW) && (rateMisMatch < MAX_RATE_MM)) |
| { |
| // width/height scaled back up: |
| // setting 0 indicates scaling back to native |
| _qm->spatialHeightFact = 0; |
| _qm->spatialWidthFact = 0; |
| selectedUp = true; |
| } |
| } |
| //Check if native has been temporally down-sampled |
| if (_stateDecFactorTemp > 1) |
| { |
| if ( (avgTargetRate > estimatedTransRateUpT) && |
| (ratioBufferLow < MAX_BUFFER_LOW) && (rateMisMatch < MAX_RATE_MM)) |
| { |
| // temporal scale back up: |
| // setting 0 indicates scaling back to native |
| _qm->temporalFact = 0; |
| selectedUp = true; |
| } |
| } |
| |
| // Leave QM if we selected to go back up in either spatial or temporal |
| if (selectedUp == true) |
| { |
| // Update down-sampling state |
| // Note: only temp reduction by 2 is allowed |
| if (_qm->temporalFact == 0) |
| { |
| _stateDecFactorTemp = _stateDecFactorTemp / 2; |
| } |
| // Update down-sampling state |
| // Note: only spatial reduction by 2x2 is allowed |
| if (_qm->spatialHeightFact == 0 && _qm->spatialWidthFact == 0 ) |
| { |
| _stateDecFactorSpatial = _stateDecFactorSpatial / 4; |
| } |
| *qm = _qm; |
| return VCM_OK; |
| } |
| |
| // |
| // Done with checking for going back up in resolution |
| // |
| |
| // |
| //CHECK FOR RESOLUTION REDUCTION |
| // |
| |
| // Resolution reduction if: |
| // (1) target rate is lower than transitional rate, or |
| // (2) buffer level is not stable, or |
| // (3) rate mismatch is larger than threshold |
| |
| // Bias down-sampling based on packet loss conditions |
| if (avgPacketLoss > LOSS_THR) |
| { |
| estimatedTransRateDown = LOSS_RATE_FAC * estimatedTransRateDown; |
| } |
| |
| if ((avgTargetRate < estimatedTransRateDown ) || |
| (ratioBufferLow > MAX_BUFFER_LOW) |
| || (rateMisMatch > MAX_RATE_MM)) |
| { |
| |
| WebRtc_UWord8 spatialFact = 1; |
| WebRtc_UWord8 tempFact = 1; |
| |
| // Get the action |
| spatialFact = kSpatialAction[contentClass]; |
| tempFact = kTemporalAction[contentClass]; |
| |
| switch(spatialFact) |
| { |
| case 4: |
| _qm->spatialWidthFact = 2; |
| _qm->spatialHeightFact = 2; |
| break; |
| case 2: |
| //default is 1x2 (H) |
| _qm->spatialWidthFact = 2; |
| _qm->spatialHeightFact = 1; |
| // Select 1x2,2x1, or back to 2x2 |
| // Note: directional selection not used in this version |
| // SelectSpatialDirectionMode((float) estimatedTransRateDown); |
| break; |
| default: |
| _qm->spatialWidthFact = 1; |
| _qm->spatialHeightFact = 1; |
| break; |
| } |
| _qm->temporalFact = tempFact; |
| |
| // Sanity check on ST QM selection: |
| // override the settings for too small image size and frame rate |
| // Also check the limit on current down-sampling state |
| |
| // No spatial sampling if image size is too small (QCIF) |
| if ( (_width * _height) <= MIN_IMAGE_SIZE || |
| _stateDecFactorSpatial >= MAX_SPATIAL_DOWN_FACT) |
| { |
| _qm->spatialWidthFact = 1; |
| _qm->spatialHeightFact = 1; |
| } |
| |
| // No frame rate reduction below some point: |
| // use the (average) incoming frame rate |
| if ( avgIncomingFrameRate <= MIN_FRAME_RATE_QM || |
| _stateDecFactorTemp >= MAX_TEMP_DOWN_FACT) |
| { |
| _qm->temporalFact = 1; |
| } |
| |
| // No down-sampling if current downsampling state is above threshold |
| if (_stateDecFactorTemp * _stateDecFactorSpatial >= |
| MAX_SPATIAL_TEMP_DOWN_FACT) |
| { |
| _qm->spatialWidthFact = 1; |
| _qm->spatialHeightFact = 1; |
| _qm->temporalFact = 1; |
| } |
| // |
| // Done with sanity checks on ST QM selection |
| // |
| |
| // Update down-sampling states |
| _stateDecFactorSpatial = _stateDecFactorSpatial * _qm->spatialWidthFact |
| * _qm->spatialHeightFact; |
| _stateDecFactorTemp = _stateDecFactorTemp * _qm->temporalFact; |
| |
| if (_qm->spatialWidthFact != 1 || _qm->spatialHeightFact != 1 || |
| _qm->temporalFact != 1) |
| { |
| |
| WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, -1, |
| "Resolution reduction occurred" |
| "Content Metrics are: Motion = %d , Spatial = %d, " |
| "Rates are: Est. Trans. BR = %d, Avg.Target BR = %f", |
| _motion.level, _spatial.level, |
| estimatedTransRateDown, avgTargetRate); |
| } |
| |
| } |
| else |
| { |
| *qm = _qm; |
| return VCM_OK; |
| } |
| // Done with checking for resolution reduction |
| |
| *qm = _qm; |
| return VCM_OK; |
| |
| |
| } |
| |
| WebRtc_Word32 |
| VCMQmResolution::SelectSpatialDirectionMode(float transRate) |
| { |
| // Default is 1x2 (H) |
| |
| // For bit rates well below transitional rate, we select 2x2 |
| if ( _targetBitRate < transRate * RATE_RED_SPATIAL_2X2 ) |
| { |
| _qm->spatialWidthFact = 2; |
| _qm->spatialHeightFact = 2; |
| return VCM_OK; |
| } |
| |
| // Otherwise check prediction errors, aspect ratio, horizontalness |
| |
| float spatialErr = _contentMetrics->spatialPredErr; |
| float spatialErrH = _contentMetrics->spatialPredErrH; |
| float spatialErrV = _contentMetrics->spatialPredErrV; |
| |
| // Favor 1x2 if aspect_ratio is 16:9 |
| if (_aspectRatio >= 16.0f / 9.0f ) |
| { |
| //check if 1x2 has lowest prediction error |
| if (spatialErrH < spatialErr && spatialErrH < spatialErrV) |
| { |
| return VCM_OK; |
| } |
| } |
| |
| // Check for 2x2 selection: favor 2x2 over 1x2 and 2x1 |
| if (spatialErr < spatialErrH * (1.0f + SPATIAL_ERR_2X2_VS_H) && |
| spatialErr < spatialErrV * (1.0f + SPATIAL_ERR_2X2_VS_V)) |
| { |
| _qm->spatialWidthFact = 2; |
| _qm->spatialHeightFact = 2; |
| return VCM_OK; |
| } |
| |
| // Check for 2x1 selection: |
| if (spatialErrV < spatialErrH * (1.0f - SPATIAL_ERR_V_VS_H) && |
| spatialErrV < spatialErr * (1.0f - SPATIAL_ERR_2X2_VS_V)) |
| { |
| _qm->spatialWidthFact = 1; |
| _qm->spatialHeightFact = 2; |
| return VCM_OK; |
| } |
| |
| return VCM_OK; |
| } |
| |
| // DONE WITH RESOLUTION CLASS |
| |
| |
| // ROBUSTNESS CLASS |
| |
| VCMQmRobustness::VCMQmRobustness() |
| { |
| Reset(); |
| } |
| |
| VCMQmRobustness::~VCMQmRobustness() |
| { |
| |
| } |
| |
| void |
| VCMQmRobustness::Reset() |
| { |
| _prevTotalRate = 0.0f; |
| _prevRttTime = 0; |
| _prevPacketLoss = 0; |
| ResetQM(); |
| return; |
| } |
| |
| // Adjust the FEC rate based on the content and the network state |
| // (packet loss rate, total rate/bandwidth, round trip time). |
| // Note that packetLoss here is the filtered loss value. |
| float |
| VCMQmRobustness::AdjustFecFactor(WebRtc_UWord8 codeRateDelta, float totalRate, |
| float frameRate,WebRtc_UWord32 rttTime, |
| WebRtc_UWord8 packetLoss) |
| { |
| // Default: no adjustment |
| float adjustFec = 1.0f; |
| |
| if (_contentMetrics == NULL) |
| { |
| return adjustFec; |
| } |
| |
| // Compute class state of the content. |
| MotionNFD(); |
| Spatial(); |
| |
| // TODO (marpan): Set FEC adjustment factor |
| |
| // Keep track of previous values of network state: |
| // adjustment may be also based on pattern of changes in network state |
| _prevTotalRate = totalRate; |
| _prevRttTime = rttTime; |
| _prevPacketLoss = packetLoss; |
| |
| _prevCodeRateDelta = codeRateDelta; |
| |
| return adjustFec; |
| |
| } |
| |
| // Set the UEP (unequal-protection) on/off for the FEC |
| bool |
| VCMQmRobustness::SetUepProtection(WebRtc_UWord8 codeRateDelta, float totalRate, |
| WebRtc_UWord8 packetLoss, bool frameType) |
| { |
| // Default: |
| bool uepProtection = false; |
| |
| if (_contentMetrics == NULL) |
| { |
| return uepProtection; |
| } |
| |
| |
| return uepProtection; |
| } |
| |
| } // end of namespace |