/* * 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 "content_metrics_processing.h" #include "tick_time.h" #include "module_common_types.h" #include "video_coding_defines.h" #include namespace webrtc { ////////////////////////////////// /// VCMContentMetricsProcessing // ////////////////////////////////// VCMContentMetricsProcessing::VCMContentMetricsProcessing(): _frameRate(0), _recAvgFactor(1 / 150.0f), // matched to 30fps _frameCntRecursiveAvg(0), _frameCntUniformAvg(0), _avgMotionLevel(0.0f), _avgSpatialLevel(0.0f) { _recursiveAvg = new VideoContentMetrics(); _uniformAvg = new VideoContentMetrics(); } VCMContentMetricsProcessing::~VCMContentMetricsProcessing() { delete _recursiveAvg; delete _uniformAvg; } WebRtc_Word32 VCMContentMetricsProcessing::Reset() { _recursiveAvg->Reset(); _uniformAvg->Reset(); _frameRate = 0; _frameCntRecursiveAvg = 0; _frameCntUniformAvg = 0; _avgMotionLevel = 0.0f; _avgSpatialLevel = 0.0f; return VCM_OK; } void VCMContentMetricsProcessing::UpdateFrameRate(WebRtc_UWord32 frameRate) { _frameRate = frameRate; // Update factor for recursive averaging. _recAvgFactor = (float) 1000.0f / ((float)(_frameRate * kQmMinIntervalMs)); } VideoContentMetrics* VCMContentMetricsProcessing::LongTermAvgData() { if (_frameCntRecursiveAvg == 0) { return NULL; } return _recursiveAvg; } VideoContentMetrics* VCMContentMetricsProcessing::ShortTermAvgData() { if (_frameCntUniformAvg == 0) { return NULL; } // Two metrics are used: motion and spatial level. _uniformAvg->motionMagnitudeNZ = _avgMotionLevel / (float)(_frameCntUniformAvg); _uniformAvg->spatialPredErr = _avgSpatialLevel / (float)(_frameCntUniformAvg); return _uniformAvg; } void VCMContentMetricsProcessing::ResetShortTermAvgData() { // Reset _avgMotionLevel = 0.0f; _avgSpatialLevel = 0.0f; _frameCntUniformAvg = 0; } WebRtc_Word32 VCMContentMetricsProcessing::UpdateContentData(const VideoContentMetrics *contentMetrics) { if (contentMetrics == NULL) { return VCM_OK; } return ProcessContent(contentMetrics); } WebRtc_UWord32 VCMContentMetricsProcessing::ProcessContent(const VideoContentMetrics *contentMetrics) { // Update the recursive averaged metrics // average is over longer window of time: over QmMinIntervalMs ms. UpdateRecursiveAvg(contentMetrics); // Update the uniform averaged metrics: // average is over shorter window of time: based on ~RTCP reports. UpdateUniformAvg(contentMetrics); return VCM_OK; } void VCMContentMetricsProcessing::UpdateUniformAvg(const VideoContentMetrics *contentMetrics) { // Update frame counter _frameCntUniformAvg += 1; // Update averaged metrics: motion and spatial level are used. _avgMotionLevel += contentMetrics->motionMagnitudeNZ; _avgSpatialLevel += contentMetrics->spatialPredErr; return; } void VCMContentMetricsProcessing::UpdateRecursiveAvg(const VideoContentMetrics *contentMetrics) { // Threshold for size of zero motion cluster: // Use for updating 3 motion vector derived metrics: // motion magnitude, cluster distortion, and horizontalness. float nonZeroMvThr = 0.1f; float tmpRecAvgFactor = _recAvgFactor; // Take value as is for first frame (no motion search in frame zero). if (_frameCntRecursiveAvg < 1) { tmpRecAvgFactor = 1; } _recursiveAvg->motionPredErr = (1 - tmpRecAvgFactor) * _recursiveAvg->motionPredErr + tmpRecAvgFactor * contentMetrics->motionPredErr; _recursiveAvg->sizeZeroMotion = (1 - tmpRecAvgFactor) * _recursiveAvg->sizeZeroMotion + tmpRecAvgFactor * contentMetrics->sizeZeroMotion; _recursiveAvg->spatialPredErr = (1 - tmpRecAvgFactor) * _recursiveAvg->spatialPredErr + tmpRecAvgFactor * contentMetrics->spatialPredErr; _recursiveAvg->spatialPredErrH = (1 - tmpRecAvgFactor) * _recursiveAvg->spatialPredErrH + tmpRecAvgFactor * contentMetrics->spatialPredErrH; _recursiveAvg->spatialPredErrV = (1 - tmpRecAvgFactor) * _recursiveAvg->spatialPredErrV + tmpRecAvgFactor * contentMetrics->spatialPredErrV; // motionMag metric is derived from NFD (normalized frame difference). if (kNfdMetric == 1) { _recursiveAvg->motionMagnitudeNZ = (1 - tmpRecAvgFactor) * _recursiveAvg->motionMagnitudeNZ + tmpRecAvgFactor * contentMetrics->motionMagnitudeNZ; } if (contentMetrics->sizeZeroMotion > nonZeroMvThr) { _recursiveAvg->motionClusterDistortion = (1 - tmpRecAvgFactor) * _recursiveAvg->motionClusterDistortion + tmpRecAvgFactor *contentMetrics->motionClusterDistortion; _recursiveAvg->motionHorizontalness = (1 - _recAvgFactor) * _recursiveAvg->motionHorizontalness + tmpRecAvgFactor * contentMetrics->motionHorizontalness; // motionMag metric is derived from motion vectors. if (kNfdMetric == 0) { _recursiveAvg->motionMagnitudeNZ = (1 - tmpRecAvgFactor) * _recursiveAvg->motionMagnitudeNZ + tmpRecAvgFactor * contentMetrics->motionMagnitudeNZ; } } // Update native values: // TODO (marpan): we don't need to update this every frame. _recursiveAvg->nativeHeight = contentMetrics->nativeHeight; _recursiveAvg->nativeWidth = contentMetrics->nativeWidth; _recursiveAvg->nativeFrameRate = contentMetrics->nativeFrameRate; _frameCntRecursiveAvg++; return; } } //end of namespace