Remove remaining quality-analysis (QM).

This was never turned on, contains a lot of complexity and somehow
manages triggering a bug in a downstream project.

BUG=webrtc:5066
R=marpan@webrtc.org
TBR=mflodman@webrtc.org

Review URL: https://codereview.webrtc.org/1917323002 .

Cr-Commit-Position: refs/heads/master@{#12692}
This commit is contained in:
Peter Boström
2016-05-12 03:01:31 +02:00
parent 919288f6ba
commit ad6fc5a05c
34 changed files with 30 additions and 3991 deletions

View File

@ -13,8 +13,6 @@ build_video_processing_sse2 = current_cpu == "x86" || current_cpu == "x64"
source_set("video_processing") {
sources = [
"content_analysis.cc",
"content_analysis.h",
"frame_preprocessor.cc",
"frame_preprocessor.h",
"include/video_processing.h",
@ -63,7 +61,6 @@ source_set("video_processing") {
if (build_video_processing_sse2) {
source_set("video_processing_sse2") {
sources = [
"content_analysis_sse2.cc",
"util/denoiser_filter_sse2.cc",
"util/denoiser_filter_sse2.h",
]

View File

@ -1,280 +0,0 @@
/*
* Copyright (c) 2012 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 "webrtc/modules/video_processing/content_analysis.h"
#include <math.h>
#include <stdlib.h>
#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
namespace webrtc {
VPMContentAnalysis::VPMContentAnalysis(bool runtime_cpu_detection)
: orig_frame_(NULL),
prev_frame_(NULL),
width_(0),
height_(0),
skip_num_(1),
border_(8),
motion_magnitude_(0.0f),
spatial_pred_err_(0.0f),
spatial_pred_err_h_(0.0f),
spatial_pred_err_v_(0.0f),
first_frame_(true),
ca_Init_(false),
content_metrics_(NULL) {
ComputeSpatialMetrics = &VPMContentAnalysis::ComputeSpatialMetrics_C;
TemporalDiffMetric = &VPMContentAnalysis::TemporalDiffMetric_C;
if (runtime_cpu_detection) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
if (WebRtc_GetCPUInfo(kSSE2)) {
ComputeSpatialMetrics = &VPMContentAnalysis::ComputeSpatialMetrics_SSE2;
TemporalDiffMetric = &VPMContentAnalysis::TemporalDiffMetric_SSE2;
}
#endif
}
Release();
}
VPMContentAnalysis::~VPMContentAnalysis() {
Release();
}
VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics(
const VideoFrame& inputFrame) {
if (inputFrame.IsZeroSize())
return NULL;
// Init if needed (native dimension change).
if (width_ != inputFrame.width() || height_ != inputFrame.height()) {
if (VPM_OK != Initialize(inputFrame.width(), inputFrame.height()))
return NULL;
}
// Only interested in the Y plane.
orig_frame_ = inputFrame.buffer(kYPlane);
// Compute spatial metrics: 3 spatial prediction errors.
(this->*ComputeSpatialMetrics)();
// Compute motion metrics
if (first_frame_ == false)
ComputeMotionMetrics();
// Saving current frame as previous one: Y only.
memcpy(prev_frame_, orig_frame_, width_ * height_);
first_frame_ = false;
ca_Init_ = true;
return ContentMetrics();
}
int32_t VPMContentAnalysis::Release() {
if (content_metrics_ != NULL) {
delete content_metrics_;
content_metrics_ = NULL;
}
if (prev_frame_ != NULL) {
delete[] prev_frame_;
prev_frame_ = NULL;
}
width_ = 0;
height_ = 0;
first_frame_ = true;
return VPM_OK;
}
int32_t VPMContentAnalysis::Initialize(int width, int height) {
width_ = width;
height_ = height;
first_frame_ = true;
// skip parameter: # of skipped rows: for complexity reduction
// temporal also currently uses it for column reduction.
skip_num_ = 1;
// use skipNum = 2 for 4CIF, WHD
if ((height_ >= 576) && (width_ >= 704)) {
skip_num_ = 2;
}
// use skipNum = 4 for FULLL_HD images
if ((height_ >= 1080) && (width_ >= 1920)) {
skip_num_ = 4;
}
if (content_metrics_ != NULL) {
delete content_metrics_;
}
if (prev_frame_ != NULL) {
delete[] prev_frame_;
}
// Spatial Metrics don't work on a border of 8. Minimum processing
// block size is 16 pixels. So make sure the width and height support this.
if (width_ <= 32 || height_ <= 32) {
ca_Init_ = false;
return VPM_PARAMETER_ERROR;
}
content_metrics_ = new VideoContentMetrics();
if (content_metrics_ == NULL) {
return VPM_MEMORY;
}
prev_frame_ = new uint8_t[width_ * height_]; // Y only.
if (prev_frame_ == NULL)
return VPM_MEMORY;
return VPM_OK;
}
// Compute motion metrics: magnitude over non-zero motion vectors,
// and size of zero cluster
int32_t VPMContentAnalysis::ComputeMotionMetrics() {
// Motion metrics: only one is derived from normalized
// (MAD) temporal difference
(this->*TemporalDiffMetric)();
return VPM_OK;
}
// Normalized temporal difference (MAD): used as a motion level metric
// Normalize MAD by spatial contrast: images with more contrast
// (pixel variance) likely have larger temporal difference
// To reduce complexity, we compute the metric for a reduced set of points.
int32_t VPMContentAnalysis::TemporalDiffMetric_C() {
// size of original frame
int sizei = height_;
int sizej = width_;
uint32_t tempDiffSum = 0;
uint32_t pixelSum = 0;
uint64_t pixelSqSum = 0;
uint32_t num_pixels = 0; // Counter for # of pixels.
const int width_end = ((width_ - 2 * border_) & -16) + border_;
for (int i = border_; i < sizei - border_; i += skip_num_) {
for (int j = border_; j < width_end; j++) {
num_pixels += 1;
int ssn = i * sizej + j;
uint8_t currPixel = orig_frame_[ssn];
uint8_t prevPixel = prev_frame_[ssn];
tempDiffSum +=
static_cast<uint32_t>(abs((int16_t)(currPixel - prevPixel)));
pixelSum += static_cast<uint32_t>(currPixel);
pixelSqSum += static_cast<uint64_t>(currPixel * currPixel);
}
}
// Default.
motion_magnitude_ = 0.0f;
if (tempDiffSum == 0)
return VPM_OK;
// Normalize over all pixels.
float const tempDiffAvg =
static_cast<float>(tempDiffSum) / static_cast<float>(num_pixels);
float const pixelSumAvg =
static_cast<float>(pixelSum) / static_cast<float>(num_pixels);
float const pixelSqSumAvg =
static_cast<float>(pixelSqSum) / static_cast<float>(num_pixels);
float contrast = pixelSqSumAvg - (pixelSumAvg * pixelSumAvg);
if (contrast > 0.0) {
contrast = sqrt(contrast);
motion_magnitude_ = tempDiffAvg / contrast;
}
return VPM_OK;
}
// Compute spatial metrics:
// To reduce complexity, we compute the metric for a reduced set of points.
// The spatial metrics are rough estimates of the prediction error cost for
// each QM spatial mode: 2x2,1x2,2x1
// The metrics are a simple estimate of the up-sampling prediction error,
// estimated assuming sub-sampling for decimation (no filtering),
// and up-sampling back up with simple bilinear interpolation.
int32_t VPMContentAnalysis::ComputeSpatialMetrics_C() {
const int sizei = height_;
const int sizej = width_;
// Pixel mean square average: used to normalize the spatial metrics.
uint32_t pixelMSA = 0;
uint32_t spatialErrSum = 0;
uint32_t spatialErrVSum = 0;
uint32_t spatialErrHSum = 0;
// make sure work section is a multiple of 16
const int width_end = ((sizej - 2 * border_) & -16) + border_;
for (int i = border_; i < sizei - border_; i += skip_num_) {
for (int j = border_; j < width_end; j++) {
int ssn1 = i * sizej + j;
int ssn2 = (i + 1) * sizej + j; // bottom
int ssn3 = (i - 1) * sizej + j; // top
int ssn4 = i * sizej + j + 1; // right
int ssn5 = i * sizej + j - 1; // left
uint16_t refPixel1 = orig_frame_[ssn1] << 1;
uint16_t refPixel2 = orig_frame_[ssn1] << 2;
uint8_t bottPixel = orig_frame_[ssn2];
uint8_t topPixel = orig_frame_[ssn3];
uint8_t rightPixel = orig_frame_[ssn4];
uint8_t leftPixel = orig_frame_[ssn5];
spatialErrSum += static_cast<uint32_t>(abs(static_cast<int16_t>(
refPixel2 - static_cast<uint16_t>(bottPixel + topPixel + leftPixel +
rightPixel))));
spatialErrVSum += static_cast<uint32_t>(abs(static_cast<int16_t>(
refPixel1 - static_cast<uint16_t>(bottPixel + topPixel))));
spatialErrHSum += static_cast<uint32_t>(abs(static_cast<int16_t>(
refPixel1 - static_cast<uint16_t>(leftPixel + rightPixel))));
pixelMSA += orig_frame_[ssn1];
}
}
// Normalize over all pixels.
const float spatialErr = static_cast<float>(spatialErrSum >> 2);
const float spatialErrH = static_cast<float>(spatialErrHSum >> 1);
const float spatialErrV = static_cast<float>(spatialErrVSum >> 1);
const float norm = static_cast<float>(pixelMSA);
// 2X2:
spatial_pred_err_ = spatialErr / norm;
// 1X2:
spatial_pred_err_h_ = spatialErrH / norm;
// 2X1:
spatial_pred_err_v_ = spatialErrV / norm;
return VPM_OK;
}
VideoContentMetrics* VPMContentAnalysis::ContentMetrics() {
if (ca_Init_ == false)
return NULL;
content_metrics_->spatial_pred_err = spatial_pred_err_;
content_metrics_->spatial_pred_err_h = spatial_pred_err_h_;
content_metrics_->spatial_pred_err_v = spatial_pred_err_v_;
// Motion metric: normalized temporal difference (MAD).
content_metrics_->motion_magnitude = motion_magnitude_;
return content_metrics_;
}
} // namespace webrtc

View File

@ -1,87 +0,0 @@
/*
* Copyright (c) 2012 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.
*/
#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_CONTENT_ANALYSIS_H_
#define WEBRTC_MODULES_VIDEO_PROCESSING_CONTENT_ANALYSIS_H_
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/video_processing/include/video_processing_defines.h"
#include "webrtc/typedefs.h"
#include "webrtc/video_frame.h"
namespace webrtc {
class VPMContentAnalysis {
public:
// When |runtime_cpu_detection| is true, runtime selection of an optimized
// code path is allowed.
explicit VPMContentAnalysis(bool runtime_cpu_detection);
~VPMContentAnalysis();
// Initialize ContentAnalysis - should be called prior to
// extractContentFeature
// Inputs: width, height
// Return value: 0 if OK, negative value upon error
int32_t Initialize(int width, int height);
// Extract content Feature - main function of ContentAnalysis
// Input: new frame
// Return value: pointer to structure containing content Analysis
// metrics or NULL value upon error
VideoContentMetrics* ComputeContentMetrics(const VideoFrame& inputFrame);
// Release all allocated memory
// Output: 0 if OK, negative value upon error
int32_t Release();
private:
// return motion metrics
VideoContentMetrics* ContentMetrics();
// Normalized temporal difference metric: for motion magnitude
typedef int32_t (VPMContentAnalysis::*TemporalDiffMetricFunc)();
TemporalDiffMetricFunc TemporalDiffMetric;
int32_t TemporalDiffMetric_C();
// Motion metric method: call 2 metrics (magnitude and size)
int32_t ComputeMotionMetrics();
// Spatial metric method: computes the 3 frame-average spatial
// prediction errors (1x2,2x1,2x2)
typedef int32_t (VPMContentAnalysis::*ComputeSpatialMetricsFunc)();
ComputeSpatialMetricsFunc ComputeSpatialMetrics;
int32_t ComputeSpatialMetrics_C();
#if defined(WEBRTC_ARCH_X86_FAMILY)
int32_t ComputeSpatialMetrics_SSE2();
int32_t TemporalDiffMetric_SSE2();
#endif
const uint8_t* orig_frame_;
uint8_t* prev_frame_;
int width_;
int height_;
int skip_num_;
int border_;
// Content Metrics: Stores the local average of the metrics.
float motion_magnitude_; // motion class
float spatial_pred_err_; // spatial class
float spatial_pred_err_h_; // spatial class
float spatial_pred_err_v_; // spatial class
bool first_frame_;
bool ca_Init_;
VideoContentMetrics* content_metrics_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_CONTENT_ANALYSIS_H_

View File

@ -1,271 +0,0 @@
/*
* Copyright (c) 2012 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 "webrtc/modules/video_processing/content_analysis.h"
#include <emmintrin.h>
#include <math.h>
namespace webrtc {
int32_t VPMContentAnalysis::TemporalDiffMetric_SSE2() {
uint32_t num_pixels = 0; // counter for # of pixels
const uint8_t* imgBufO = orig_frame_ + border_ * width_ + border_;
const uint8_t* imgBufP = prev_frame_ + border_ * width_ + border_;
const int32_t width_end = ((width_ - 2 * border_) & -16) + border_;
__m128i sad_64 = _mm_setzero_si128();
__m128i sum_64 = _mm_setzero_si128();
__m128i sqsum_64 = _mm_setzero_si128();
const __m128i z = _mm_setzero_si128();
for (uint16_t i = 0; i < (height_ - 2 * border_); i += skip_num_) {
__m128i sqsum_32 = _mm_setzero_si128();
const uint8_t* lineO = imgBufO;
const uint8_t* lineP = imgBufP;
// Work on 16 pixels at a time. For HD content with a width of 1920
// this loop will run ~67 times (depending on border). Maximum for
// abs(o-p) and sum(o) will be 255. _mm_sad_epu8 produces 2 64 bit
// results which are then accumulated. There is no chance of
// rollover for these two accumulators.
// o*o will have a maximum of 255*255 = 65025. This will roll over
// a 16 bit accumulator as 67*65025 > 65535, but will fit in a
// 32 bit accumulator.
for (uint16_t j = 0; j < width_end - border_; j += 16) {
const __m128i o = _mm_loadu_si128((__m128i*)(lineO));
const __m128i p = _mm_loadu_si128((__m128i*)(lineP));
lineO += 16;
lineP += 16;
// Abs pixel difference between frames.
sad_64 = _mm_add_epi64(sad_64, _mm_sad_epu8(o, p));
// sum of all pixels in frame
sum_64 = _mm_add_epi64(sum_64, _mm_sad_epu8(o, z));
// Squared sum of all pixels in frame.
const __m128i olo = _mm_unpacklo_epi8(o, z);
const __m128i ohi = _mm_unpackhi_epi8(o, z);
const __m128i sqsum_32_lo = _mm_madd_epi16(olo, olo);
const __m128i sqsum_32_hi = _mm_madd_epi16(ohi, ohi);
sqsum_32 = _mm_add_epi32(sqsum_32, sqsum_32_lo);
sqsum_32 = _mm_add_epi32(sqsum_32, sqsum_32_hi);
}
// Add to 64 bit running sum as to not roll over.
sqsum_64 =
_mm_add_epi64(sqsum_64, _mm_add_epi64(_mm_unpackhi_epi32(sqsum_32, z),
_mm_unpacklo_epi32(sqsum_32, z)));
imgBufO += width_ * skip_num_;
imgBufP += width_ * skip_num_;
num_pixels += (width_end - border_);
}
__m128i sad_final_128;
__m128i sum_final_128;
__m128i sqsum_final_128;
// Bring sums out of vector registers and into integer register
// domain, summing them along the way.
_mm_store_si128(&sad_final_128, sad_64);
_mm_store_si128(&sum_final_128, sum_64);
_mm_store_si128(&sqsum_final_128, sqsum_64);
uint64_t* sad_final_64 = reinterpret_cast<uint64_t*>(&sad_final_128);
uint64_t* sum_final_64 = reinterpret_cast<uint64_t*>(&sum_final_128);
uint64_t* sqsum_final_64 = reinterpret_cast<uint64_t*>(&sqsum_final_128);
const uint32_t pixelSum = sum_final_64[0] + sum_final_64[1];
const uint64_t pixelSqSum = sqsum_final_64[0] + sqsum_final_64[1];
const uint32_t tempDiffSum = sad_final_64[0] + sad_final_64[1];
// Default.
motion_magnitude_ = 0.0f;
if (tempDiffSum == 0)
return VPM_OK;
// Normalize over all pixels.
const float tempDiffAvg =
static_cast<float>(tempDiffSum) / static_cast<float>(num_pixels);
const float pixelSumAvg =
static_cast<float>(pixelSum) / static_cast<float>(num_pixels);
const float pixelSqSumAvg =
static_cast<float>(pixelSqSum) / static_cast<float>(num_pixels);
float contrast = pixelSqSumAvg - (pixelSumAvg * pixelSumAvg);
if (contrast > 0.0) {
contrast = sqrt(contrast);
motion_magnitude_ = tempDiffAvg / contrast;
}
return VPM_OK;
}
int32_t VPMContentAnalysis::ComputeSpatialMetrics_SSE2() {
const uint8_t* imgBuf = orig_frame_ + border_ * width_;
const int32_t width_end = ((width_ - 2 * border_) & -16) + border_;
__m128i se_32 = _mm_setzero_si128();
__m128i sev_32 = _mm_setzero_si128();
__m128i seh_32 = _mm_setzero_si128();
__m128i msa_32 = _mm_setzero_si128();
const __m128i z = _mm_setzero_si128();
// Error is accumulated as a 32 bit value. Looking at HD content with a
// height of 1080 lines, or about 67 macro blocks. If the 16 bit row
// value is maxed out at 65529 for every row, 65529*1080 = 70777800, which
// will not roll over a 32 bit accumulator.
// skip_num_ is also used to reduce the number of rows
for (int32_t i = 0; i < (height_ - 2 * border_); i += skip_num_) {
__m128i se_16 = _mm_setzero_si128();
__m128i sev_16 = _mm_setzero_si128();
__m128i seh_16 = _mm_setzero_si128();
__m128i msa_16 = _mm_setzero_si128();
// Row error is accumulated as a 16 bit value. There are 8
// accumulators. Max value of a 16 bit number is 65529. Looking
// at HD content, 1080p, has a width of 1920, 120 macro blocks.
// A mb at a time is processed at a time. Absolute max error at
// a point would be abs(0-255+255+255+255) which equals 1020.
// 120*1020 = 122400. The probability of hitting this is quite low
// on well behaved content. A specially crafted image could roll over.
// border_ could also be adjusted to concentrate on just the center of
// the images for an HD capture in order to reduce the possiblity of
// rollover.
const uint8_t* lineTop = imgBuf - width_ + border_;
const uint8_t* lineCen = imgBuf + border_;
const uint8_t* lineBot = imgBuf + width_ + border_;
for (int32_t j = 0; j < width_end - border_; j += 16) {
const __m128i t = _mm_loadu_si128((__m128i*)(lineTop));
const __m128i l = _mm_loadu_si128((__m128i*)(lineCen - 1));
const __m128i c = _mm_loadu_si128((__m128i*)(lineCen));
const __m128i r = _mm_loadu_si128((__m128i*)(lineCen + 1));
const __m128i b = _mm_loadu_si128((__m128i*)(lineBot));
lineTop += 16;
lineCen += 16;
lineBot += 16;
// center pixel unpacked
__m128i clo = _mm_unpacklo_epi8(c, z);
__m128i chi = _mm_unpackhi_epi8(c, z);
// left right pixels unpacked and added together
const __m128i lrlo =
_mm_add_epi16(_mm_unpacklo_epi8(l, z), _mm_unpacklo_epi8(r, z));
const __m128i lrhi =
_mm_add_epi16(_mm_unpackhi_epi8(l, z), _mm_unpackhi_epi8(r, z));
// top & bottom pixels unpacked and added together
const __m128i tblo =
_mm_add_epi16(_mm_unpacklo_epi8(t, z), _mm_unpacklo_epi8(b, z));
const __m128i tbhi =
_mm_add_epi16(_mm_unpackhi_epi8(t, z), _mm_unpackhi_epi8(b, z));
// running sum of all pixels
msa_16 = _mm_add_epi16(msa_16, _mm_add_epi16(chi, clo));
clo = _mm_slli_epi16(clo, 1);
chi = _mm_slli_epi16(chi, 1);
const __m128i sevtlo = _mm_subs_epi16(clo, tblo);
const __m128i sevthi = _mm_subs_epi16(chi, tbhi);
const __m128i sehtlo = _mm_subs_epi16(clo, lrlo);
const __m128i sehthi = _mm_subs_epi16(chi, lrhi);
clo = _mm_slli_epi16(clo, 1);
chi = _mm_slli_epi16(chi, 1);
const __m128i setlo = _mm_subs_epi16(clo, _mm_add_epi16(lrlo, tblo));
const __m128i sethi = _mm_subs_epi16(chi, _mm_add_epi16(lrhi, tbhi));
// Add to 16 bit running sum
se_16 =
_mm_add_epi16(se_16, _mm_max_epi16(setlo, _mm_subs_epi16(z, setlo)));
se_16 =
_mm_add_epi16(se_16, _mm_max_epi16(sethi, _mm_subs_epi16(z, sethi)));
sev_16 = _mm_add_epi16(sev_16,
_mm_max_epi16(sevtlo, _mm_subs_epi16(z, sevtlo)));
sev_16 = _mm_add_epi16(sev_16,
_mm_max_epi16(sevthi, _mm_subs_epi16(z, sevthi)));
seh_16 = _mm_add_epi16(seh_16,
_mm_max_epi16(sehtlo, _mm_subs_epi16(z, sehtlo)));
seh_16 = _mm_add_epi16(seh_16,
_mm_max_epi16(sehthi, _mm_subs_epi16(z, sehthi)));
}
// Add to 32 bit running sum as to not roll over.
se_32 = _mm_add_epi32(se_32, _mm_add_epi32(_mm_unpackhi_epi16(se_16, z),
_mm_unpacklo_epi16(se_16, z)));
sev_32 =
_mm_add_epi32(sev_32, _mm_add_epi32(_mm_unpackhi_epi16(sev_16, z),
_mm_unpacklo_epi16(sev_16, z)));
seh_32 =
_mm_add_epi32(seh_32, _mm_add_epi32(_mm_unpackhi_epi16(seh_16, z),
_mm_unpacklo_epi16(seh_16, z)));
msa_32 =
_mm_add_epi32(msa_32, _mm_add_epi32(_mm_unpackhi_epi16(msa_16, z),
_mm_unpacklo_epi16(msa_16, z)));
imgBuf += width_ * skip_num_;
}
__m128i se_128;
__m128i sev_128;
__m128i seh_128;
__m128i msa_128;
// Bring sums out of vector registers and into integer register
// domain, summing them along the way.
_mm_store_si128(&se_128, _mm_add_epi64(_mm_unpackhi_epi32(se_32, z),
_mm_unpacklo_epi32(se_32, z)));
_mm_store_si128(&sev_128, _mm_add_epi64(_mm_unpackhi_epi32(sev_32, z),
_mm_unpacklo_epi32(sev_32, z)));
_mm_store_si128(&seh_128, _mm_add_epi64(_mm_unpackhi_epi32(seh_32, z),
_mm_unpacklo_epi32(seh_32, z)));
_mm_store_si128(&msa_128, _mm_add_epi64(_mm_unpackhi_epi32(msa_32, z),
_mm_unpacklo_epi32(msa_32, z)));
uint64_t* se_64 = reinterpret_cast<uint64_t*>(&se_128);
uint64_t* sev_64 = reinterpret_cast<uint64_t*>(&sev_128);
uint64_t* seh_64 = reinterpret_cast<uint64_t*>(&seh_128);
uint64_t* msa_64 = reinterpret_cast<uint64_t*>(&msa_128);
const uint32_t spatialErrSum = se_64[0] + se_64[1];
const uint32_t spatialErrVSum = sev_64[0] + sev_64[1];
const uint32_t spatialErrHSum = seh_64[0] + seh_64[1];
const uint32_t pixelMSA = msa_64[0] + msa_64[1];
// Normalize over all pixels.
const float spatialErr = static_cast<float>(spatialErrSum >> 2);
const float spatialErrH = static_cast<float>(spatialErrHSum >> 1);
const float spatialErrV = static_cast<float>(spatialErrVSum >> 1);
const float norm = static_cast<float>(pixelMSA);
// 2X2:
spatial_pred_err_ = spatialErr / norm;
// 1X2:
spatial_pred_err_h_ = spatialErrH / norm;
// 2X1:
spatial_pred_err_v_ = spatialErrV / norm;
return VPM_OK;
}
} // namespace webrtc

View File

@ -15,12 +15,8 @@
namespace webrtc {
VPMFramePreprocessor::VPMFramePreprocessor()
: content_metrics_(nullptr),
resampled_frame_(),
enable_ca_(false),
frame_cnt_(0) {
: resampled_frame_(), frame_cnt_(0) {
spatial_resampler_ = new VPMSimpleSpatialResampler();
ca_ = new VPMContentAnalysis(true);
vd_ = new VPMVideoDecimator();
EnableDenoising(false);
denoised_frame_toggle_ = 0;
@ -28,17 +24,13 @@ VPMFramePreprocessor::VPMFramePreprocessor()
VPMFramePreprocessor::~VPMFramePreprocessor() {
Reset();
delete ca_;
delete vd_;
delete spatial_resampler_;
}
void VPMFramePreprocessor::Reset() {
ca_->Release();
vd_->Reset();
content_metrics_ = nullptr;
spatial_resampler_->Reset();
enable_ca_ = false;
frame_cnt_ = 0;
}
@ -46,10 +38,6 @@ void VPMFramePreprocessor::EnableTemporalDecimation(bool enable) {
vd_->EnableTemporalDecimation(enable);
}
void VPMFramePreprocessor::EnableContentAnalysis(bool enable) {
enable_ca_ = enable;
}
void VPMFramePreprocessor::SetInputFrameResampleMode(
VideoFrameResampling resampling_mode) {
spatial_resampler_->SetInputFrameResampleMode(resampling_mode);
@ -131,18 +119,8 @@ const VideoFrame* VPMFramePreprocessor::PreprocessFrame(
current_frame = &resampled_frame_;
}
// Perform content analysis on the frame to be encoded.
if (enable_ca_ && frame_cnt_ % kSkipFrameCA == 0) {
// Compute new metrics every |kSkipFramesCA| frames, starting with
// the first frame.
content_metrics_ = ca_->ComputeContentMetrics(*current_frame);
}
++frame_cnt_;
return current_frame;
}
VideoContentMetrics* VPMFramePreprocessor::GetContentMetrics() const {
return content_metrics_;
}
} // namespace webrtc

View File

@ -14,7 +14,6 @@
#include <memory>
#include "webrtc/modules/video_processing/include/video_processing.h"
#include "webrtc/modules/video_processing/content_analysis.h"
#include "webrtc/modules/video_processing/spatial_resampler.h"
#include "webrtc/modules/video_processing/video_decimator.h"
#include "webrtc/typedefs.h"
@ -38,9 +37,6 @@ class VPMFramePreprocessor {
void SetInputFrameResampleMode(VideoFrameResampling resampling_mode);
// Enable content analysis.
void EnableContentAnalysis(bool enable);
// Set target resolution: frame rate and dimension.
int32_t SetTargetResolution(uint32_t width,
uint32_t height,
@ -59,21 +55,17 @@ class VPMFramePreprocessor {
// Preprocess output:
void EnableDenoising(bool enable);
const VideoFrame* PreprocessFrame(const VideoFrame& frame);
VideoContentMetrics* GetContentMetrics() const;
private:
// The content does not change so much every frame, so to reduce complexity
// we can compute new content metrics every |kSkipFrameCA| frames.
enum { kSkipFrameCA = 2 };
VideoContentMetrics* content_metrics_;
VideoFrame denoised_frame_[2];
VideoFrame resampled_frame_;
VPMSpatialResampler* spatial_resampler_;
VPMContentAnalysis* ca_;
VPMVideoDecimator* vd_;
std::unique_ptr<VideoDenoiser> denoiser_;
bool enable_ca_;
uint8_t denoised_frame_toggle_;
uint32_t frame_cnt_;
};

View File

@ -53,9 +53,6 @@ class VideoProcessing {
virtual void EnableDenoising(bool enable) = 0;
virtual const VideoFrame* PreprocessFrame(const VideoFrame& frame) = 0;
virtual VideoContentMetrics* GetContentMetrics() const = 0;
virtual void EnableContentAnalysis(bool enable) = 0;
};
} // namespace webrtc

View File

@ -1,50 +0,0 @@
/*
* 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 <memory>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/modules/video_processing/include/video_processing.h"
#include "webrtc/modules/video_processing/content_analysis.h"
#include "webrtc/modules/video_processing/test/video_processing_unittest.h"
namespace webrtc {
#if defined(WEBRTC_IOS)
TEST_F(VideoProcessingTest, DISABLED_ContentAnalysis) {
#else
TEST_F(VideoProcessingTest, ContentAnalysis) {
#endif
VPMContentAnalysis ca__c(false);
VPMContentAnalysis ca__sse(true);
VideoContentMetrics* _cM_c;
VideoContentMetrics* _cM_SSE;
ca__c.Initialize(width_, height_);
ca__sse.Initialize(width_, height_);
std::unique_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
frame_length_) {
// Using ConvertToI420 to add stride to the image.
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
0, kVideoRotation_0, &video_frame_));
_cM_c = ca__c.ComputeContentMetrics(video_frame_);
_cM_SSE = ca__sse.ComputeContentMetrics(video_frame_);
ASSERT_EQ(_cM_c->spatial_pred_err, _cM_SSE->spatial_pred_err);
ASSERT_EQ(_cM_c->spatial_pred_err_v, _cM_SSE->spatial_pred_err_v);
ASSERT_EQ(_cM_c->spatial_pred_err_h, _cM_SSE->spatial_pred_err_h);
ASSERT_EQ(_cM_c->motion_magnitude, _cM_SSE->motion_magnitude);
}
ASSERT_NE(0, feof(source_file_)) << "Error reading source file";
}
} // namespace webrtc

View File

@ -126,8 +126,6 @@ TEST_F(VideoProcessingTest, Resampler) {
rewind(source_file_);
ASSERT_TRUE(source_file_ != NULL) << "Cannot read input file \n";
// CA not needed here
vp_->EnableContentAnalysis(false);
// no temporal decimation
vp_->EnableTemporalDecimation(false);

View File

@ -20,8 +20,6 @@
'sources': [
'include/video_processing.h',
'include/video_processing_defines.h',
'content_analysis.cc',
'content_analysis.h',
'frame_preprocessor.cc',
'frame_preprocessor.h',
'spatial_resampler.cc',
@ -58,7 +56,6 @@
'target_name': 'video_processing_sse2',
'type': 'static_library',
'sources': [
'content_analysis_sse2.cc',
'util/denoiser_filter_sse2.cc',
'util/denoiser_filter_sse2.h',
],

View File

@ -69,14 +69,4 @@ const VideoFrame* VideoProcessingImpl::PreprocessFrame(
return frame_pre_processor_.PreprocessFrame(frame);
}
VideoContentMetrics* VideoProcessingImpl::GetContentMetrics() const {
rtc::CritScope mutex(&mutex_);
return frame_pre_processor_.GetContentMetrics();
}
void VideoProcessingImpl::EnableContentAnalysis(bool enable) {
rtc::CritScope mutex(&mutex_);
frame_pre_processor_.EnableContentAnalysis(enable);
}
} // namespace webrtc

View File

@ -26,7 +26,6 @@ class VideoProcessingImpl : public VideoProcessing {
// Implements VideoProcessing.
void EnableTemporalDecimation(bool enable) override;
void SetInputFrameResampleMode(VideoFrameResampling resampling_mode) override;
void EnableContentAnalysis(bool enable) override;
int32_t SetTargetResolution(uint32_t width,
uint32_t height,
uint32_t frame_rate) override;
@ -35,7 +34,6 @@ class VideoProcessingImpl : public VideoProcessing {
uint32_t GetDecimatedHeight() const override;
void EnableDenoising(bool enable) override;
const VideoFrame* PreprocessFrame(const VideoFrame& frame) override;
VideoContentMetrics* GetContentMetrics() const override;
private:
rtc::CriticalSection mutex_;