Initial VideoProcessing refactoring.

This CL is the first in a series of CLs to refactor
VideoProcessing(Module) to follow Google C++ style guide and make the
code more readable.

This CL removed inheritance from Module, renames variables and makes
VideoProcessingImpl::PreprocessFrame return a frame pointer if there
is a frame to send, nullptr otherwise. The affected CLs also passes git
cl lint.

BUG=webrtc:5259

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

Cr-Commit-Position: refs/heads/master@{#10907}
This commit is contained in:
mflodman
2015-12-07 01:09:52 -08:00
committed by Commit bot
parent 2512f44397
commit a8565425bc
22 changed files with 362 additions and 642 deletions

View File

@ -13,8 +13,6 @@ build_video_processing_sse2 = current_cpu == "x86" || current_cpu == "x64"
source_set("video_processing") {
sources = [
"brighten.cc",
"brighten.h",
"brightness_detection.cc",
"brightness_detection.h",
"content_analysis.cc",

View File

@ -1,45 +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 "webrtc/modules/video_processing/brighten.h"
#include <stdlib.h>
namespace webrtc {
namespace VideoProcessing {
int32_t Brighten(VideoFrame* frame, int delta) {
assert(frame);
if (frame->IsZeroSize()) {
return VPM_PARAMETER_ERROR;
}
if (frame->width() <= 0 || frame->height() <= 0) {
return VPM_PARAMETER_ERROR;
}
int num_pixels = frame->width() * frame->height();
int look_up[256];
for (int i = 0; i < 256; i++) {
int val = i + delta;
look_up[i] = ((((val < 0) ? 0 : val) > 255) ? 255 : val);
}
uint8_t* temp_ptr = frame->buffer(kYPlane);
for (int i = 0; i < num_pixels; i++) {
*temp_ptr = static_cast<uint8_t>(look_up[*temp_ptr]);
temp_ptr++;
}
return VPM_OK;
}
} // namespace VideoProcessing
} // namespace webrtc

View File

@ -1,25 +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.
*/
#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_BRIGHTEN_H_
#define WEBRTC_MODULES_VIDEO_PROCESSING_BRIGHTEN_H_
#include "webrtc/modules/video_processing/include/video_processing.h"
#include "webrtc/typedefs.h"
namespace webrtc {
namespace VideoProcessing {
int32_t Brighten(VideoFrame* frame, int delta);
} // namespace VideoProcessing
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_BRIGHTEN_H_

View File

@ -8,11 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/video_processing/include/video_processing.h"
#include "webrtc/modules/video_processing/brightness_detection.h"
#include <math.h>
#include "webrtc/modules/video_processing/include/video_processing.h"
namespace webrtc {
VPMBrightnessDetection::VPMBrightnessDetection() {
@ -28,14 +29,14 @@ void VPMBrightnessDetection::Reset() {
int32_t VPMBrightnessDetection::ProcessFrame(
const VideoFrame& frame,
const VideoProcessingModule::FrameStats& stats) {
const VideoProcessing::FrameStats& stats) {
if (frame.IsZeroSize()) {
return VPM_PARAMETER_ERROR;
}
int width = frame.width();
int height = frame.height();
if (!VideoProcessingModule::ValidFrameStats(stats)) {
if (!VideoProcessing::ValidFrameStats(stats)) {
return VPM_PARAMETER_ERROR;
}
@ -62,9 +63,9 @@ int32_t VPMBrightnessDetection::ProcessFrame(
// Standard deviation of Y
const uint8_t* buffer = frame.buffer(kYPlane);
float std_y = 0;
for (int h = 0; h < height; h += (1 << stats.subSamplHeight)) {
for (int h = 0; h < height; h += (1 << stats.sub_sampling_factor)) {
int row = h*width;
for (int w = 0; w < width; w += (1 << stats.subSamplWidth)) {
for (int w = 0; w < width; w += (1 << stats.sub_sampling_factor)) {
std_y += (buffer[w + row] - stats.mean) * (buffer[w + row] -
stats.mean);
}
@ -122,11 +123,11 @@ int32_t VPMBrightnessDetection::ProcessFrame(
}
if (frame_cnt_dark_ > frame_cnt_alarm) {
return VideoProcessingModule::kDarkWarning;
return VideoProcessing::kDarkWarning;
} else if (frame_cnt_bright_ > frame_cnt_alarm) {
return VideoProcessingModule::kBrightWarning;
return VideoProcessing::kBrightWarning;
} else {
return VideoProcessingModule::kNoWarning;
return VideoProcessing::kNoWarning;
}
}

View File

@ -23,7 +23,7 @@ class VPMBrightnessDetection {
void Reset();
int32_t ProcessFrame(const VideoFrame& frame,
const VideoProcessingModule::FrameStats& stats);
const VideoProcessing::FrameStats& stats);
private:
uint32_t frame_cnt_bright_;
@ -32,4 +32,4 @@ class VPMBrightnessDetection {
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_BRIGHTNESS_DETECTION_H_
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_BRIGHTNESS_DETECTION_H_

View File

@ -41,7 +41,7 @@ enum { kLog2OfDownsamplingFactor = 3 };
// Resolution reduced to avoid overflow when multiplying with the
// (potentially) large number of pixels.
const uint16_t VPMDeflickering::prob_uw16_[kNumProbs] = {102, 205, 410, 614,
819, 1024, 1229, 1434, 1638, 1843, 1946, 1987}; // <Q11>
819, 1024, 1229, 1434, 1638, 1843, 1946, 1987}; // <Q11>
// To generate in Matlab:
// >> numQuants = 14; maxOnlyLength = 5;
@ -49,7 +49,7 @@ const uint16_t VPMDeflickering::prob_uw16_[kNumProbs] = {102, 205, 410, 614,
// [linspace(0.5, 1.0, numQuants - maxOnlyLength)]);
// >> fprintf('%d, %d,\n ', weightUW16);
const uint16_t VPMDeflickering::weight_uw16_[kNumQuants - kMaxOnlyLength] =
{16384, 18432, 20480, 22528, 24576, 26624, 28672, 30720, 32768}; // <Q15>
{16384, 18432, 20480, 22528, 24576, 26624, 28672, 30720, 32768}; // <Q15>
VPMDeflickering::VPMDeflickering() {
Reset();
@ -82,7 +82,7 @@ void VPMDeflickering::Reset() {
int32_t VPMDeflickering::ProcessFrame(
VideoFrame* frame,
VideoProcessingModule::FrameStats* stats) {
VideoProcessing::FrameStats* stats) {
assert(frame);
uint32_t frame_memory;
uint8_t quant_uw8[kNumQuants];
@ -107,7 +107,7 @@ int32_t VPMDeflickering::ProcessFrame(
return VPM_GENERAL_ERROR;
}
if (!VideoProcessingModule::ValidFrameStats(*stats)) {
if (!VideoProcessing::ValidFrameStats(*stats)) {
return VPM_GENERAL_ERROR;
}
@ -209,7 +209,7 @@ int32_t VPMDeflickering::ProcessFrame(
if (tmp_uw16 > 0) {
increment_uw16 = static_cast<uint16_t>(WebRtcSpl_DivU32U16(tmp_uw32,
tmp_uw16)); // <Q7>
tmp_uw16)); // <Q7>
} else {
// The value is irrelevant; the loop below will only iterate once.
increment_uw16 = 0;
@ -230,7 +230,7 @@ int32_t VPMDeflickering::ProcessFrame(
}
// Frame was altered, so reset stats.
VideoProcessingModule::ClearFrameStats(stats);
VideoProcessing::ClearFrameStats(stats);
return VPM_OK;
}
@ -248,7 +248,7 @@ int32_t VPMDeflickering::ProcessFrame(
-1: Error
*/
int32_t VPMDeflickering::PreDetection(const uint32_t timestamp,
const VideoProcessingModule::FrameStats& stats) {
const VideoProcessing::FrameStats& stats) {
int32_t mean_val; // Mean value of frame (Q4)
uint32_t frame_rate = 0;
int32_t meanBufferLength; // Temp variable.
@ -371,7 +371,7 @@ int32_t VPMDeflickering::DetectFlicker() {
int32_t freqAlias = freqEst;
if (freqEst > kMinFrequencyToDetect) {
uint8_t aliasState = 1;
while(freqState == 0) {
while (freqState == 0) {
/* Increase frequency */
freqAlias += (aliasState * frame_rate_);
freqAlias += ((freqEst << 1) * (1 - (aliasState << 1)));

View File

@ -24,12 +24,11 @@ class VPMDeflickering {
~VPMDeflickering();
void Reset();
int32_t ProcessFrame(VideoFrame* frame,
VideoProcessingModule::FrameStats* stats);
int32_t ProcessFrame(VideoFrame* frame, VideoProcessing::FrameStats* stats);
private:
int32_t PreDetection(uint32_t timestamp,
const VideoProcessingModule::FrameStats& stats);
const VideoProcessing::FrameStats& stats);
int32_t DetectFlicker();
@ -53,4 +52,4 @@ class VPMDeflickering {
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_DEFLICKERING_H_
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_DEFLICKERING_H_

View File

@ -10,30 +10,24 @@
#include "webrtc/modules/video_processing/frame_preprocessor.h"
#include "webrtc/modules/video_processing/video_denoiser.h"
namespace webrtc {
VPMFramePreprocessor::VPMFramePreprocessor()
: content_metrics_(nullptr),
resampled_frame_(),
enable_ca_(false),
enable_denoising_(false),
frame_cnt_(0) {
spatial_resampler_ = new VPMSimpleSpatialResampler();
ca_ = new VPMContentAnalysis(true);
vd_ = new VPMVideoDecimator();
if (enable_denoising_) {
denoiser_ = new VideoDenoiser();
} else {
denoiser_ = nullptr;
}
}
VPMFramePreprocessor::~VPMFramePreprocessor() {
Reset();
delete ca_;
delete vd_;
if (enable_denoising_)
delete denoiser_;
delete spatial_resampler_;
}
@ -61,7 +55,7 @@ void VPMFramePreprocessor::SetInputFrameResampleMode(
int32_t VPMFramePreprocessor::SetTargetResolution(
uint32_t width, uint32_t height, uint32_t frame_rate) {
if ( (width == 0) || (height == 0) || (frame_rate == 0)) {
if ((width == 0) || (height == 0) || (frame_rate == 0)) {
return VPM_PARAMETER_ERROR;
}
int32_t ret_val = 0;
@ -86,70 +80,62 @@ void VPMFramePreprocessor::UpdateIncomingframe_rate() {
vd_->UpdateIncomingframe_rate();
}
uint32_t VPMFramePreprocessor::Decimatedframe_rate() {
return vd_->Decimatedframe_rate();
uint32_t VPMFramePreprocessor::GetDecimatedFrameRate() {
return vd_->GetDecimatedFrameRate();
}
uint32_t VPMFramePreprocessor::DecimatedWidth() const {
uint32_t VPMFramePreprocessor::GetDecimatedWidth() const {
return spatial_resampler_->TargetWidth();
}
uint32_t VPMFramePreprocessor::DecimatedHeight() const {
uint32_t VPMFramePreprocessor::GetDecimatedHeight() const {
return spatial_resampler_->TargetHeight();
}
int32_t VPMFramePreprocessor::PreprocessFrame(const VideoFrame& frame,
VideoFrame** processed_frame) {
void VPMFramePreprocessor::EnableDenosing(bool enable) {
denoiser_.reset(new VideoDenoiser());
}
const VideoFrame* VPMFramePreprocessor::PreprocessFrame(
const VideoFrame& frame) {
if (frame.IsZeroSize()) {
return VPM_PARAMETER_ERROR;
return nullptr;
}
vd_->UpdateIncomingframe_rate();
if (vd_->DropFrame()) {
return 1; // drop 1 frame
return nullptr;
}
// Resizing incoming frame if needed. Otherwise, remains nullptr.
// We are not allowed to resample the input frame (must make a copy of it).
*processed_frame = nullptr;
if (denoiser_ != nullptr) {
denoiser_->DenoiseFrame(frame, &denoised_frame_);
*processed_frame = &denoised_frame_;
const VideoFrame* current_frame = &frame;
if (denoiser_) {
denoiser_->DenoiseFrame(*current_frame, &denoised_frame_);
current_frame = &denoised_frame_;
}
if (spatial_resampler_->ApplyResample(frame.width(), frame.height())) {
int32_t ret;
if (enable_denoising_) {
ret = spatial_resampler_->ResampleFrame(denoised_frame_,
&resampled_frame_);
} else {
ret = spatial_resampler_->ResampleFrame(frame, &resampled_frame_);
if (spatial_resampler_->ApplyResample(current_frame->width(),
current_frame->height())) {
if (spatial_resampler_->ResampleFrame(*current_frame, &resampled_frame_) !=
VPM_OK) {
return nullptr;
}
if (ret != VPM_OK) return ret;
*processed_frame = &resampled_frame_;
current_frame = &resampled_frame_;
}
// Perform content analysis on the frame to be encoded.
if (enable_ca_) {
if (enable_ca_ && frame_cnt_ % kSkipFrameCA == 0) {
// Compute new metrics every |kSkipFramesCA| frames, starting with
// the first frame.
if (frame_cnt_ % kSkipFrameCA == 0) {
if (*processed_frame == nullptr) {
content_metrics_ = ca_->ComputeContentMetrics(frame);
} else {
content_metrics_ = ca_->ComputeContentMetrics(**processed_frame);
}
}
content_metrics_ = ca_->ComputeContentMetrics(*current_frame);
}
++frame_cnt_;
return VPM_OK;
return current_frame;
}
VideoContentMetrics* VPMFramePreprocessor::ContentMetrics() const {
VideoContentMetrics* VPMFramePreprocessor::GetContentMetrics() const {
return content_metrics_;
}
} // namespace
} // namespace webrtc

View File

@ -8,22 +8,23 @@
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* frame_preprocessor.h
*/
#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_FRAME_PREPROCESSOR_H_
#define WEBRTC_MODULES_VIDEO_PROCESSING_FRAME_PREPROCESSOR_H_
#include "webrtc/base/scoped_ptr.h"
#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/modules/video_processing/video_denoiser.h"
#include "webrtc/typedefs.h"
#include "webrtc/video_frame.h"
namespace webrtc {
class VideoDenoiser;
// All pointers/members in this class are assumed to be protected by the class
// owner.
class VPMFramePreprocessor {
public:
VPMFramePreprocessor();
@ -52,14 +53,14 @@ class VPMFramePreprocessor {
int32_t updateIncomingFrameSize(uint32_t width, uint32_t height);
// Set decimated values: frame rate/dimension.
uint32_t Decimatedframe_rate();
uint32_t DecimatedWidth() const;
uint32_t DecimatedHeight() const;
uint32_t GetDecimatedFrameRate();
uint32_t GetDecimatedWidth() const;
uint32_t GetDecimatedHeight() const;
// Preprocess output:
int32_t PreprocessFrame(const VideoFrame& frame,
VideoFrame** processed_frame);
VideoContentMetrics* ContentMetrics() const;
void EnableDenosing(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
@ -72,13 +73,11 @@ class VPMFramePreprocessor {
VPMSpatialResampler* spatial_resampler_;
VPMContentAnalysis* ca_;
VPMVideoDecimator* vd_;
VideoDenoiser* denoiser_;
rtc::scoped_ptr<VideoDenoiser> denoiser_;
bool enable_ca_;
bool enable_denoising_;
int frame_cnt_;
uint32_t frame_cnt_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_FRAME_PREPROCESSOR_H_
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_FRAME_PREPROCESSOR_H_

View File

@ -18,250 +18,93 @@
#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_INCLUDE_VIDEO_PROCESSING_H_
#define WEBRTC_MODULES_VIDEO_PROCESSING_INCLUDE_VIDEO_PROCESSING_H_
#include "webrtc/modules/include/module.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/video_processing/include/video_processing_defines.h"
#include "webrtc/video_frame.h"
/**
The module is largely intended to process video streams, except functionality
provided by static functions which operate independent of previous frames. It
is recommended, but not required that a unique instance be used for each
concurrently processed stream. Similarly, it is recommended to call Reset()
before switching to a new stream, but this is not absolutely required.
The module provides basic thread safety by permitting only a single function
to execute concurrently.
*/
// The module is largely intended to process video streams, except functionality
// provided by static functions which operate independent of previous frames. It
// is recommended, but not required that a unique instance be used for each
// concurrently processed stream. Similarly, it is recommended to call Reset()
// before switching to a new stream, but this is not absolutely required.
//
// The module provides basic thread safety by permitting only a single function
// to execute concurrently.
namespace webrtc {
class VideoProcessingModule : public Module {
class VideoProcessing {
public:
/**
Structure to hold frame statistics. Populate it with GetFrameStats().
*/
struct FrameStats {
FrameStats() :
mean(0),
sum(0),
num_pixels(0),
subSamplWidth(0),
subSamplHeight(0) {
memset(hist, 0, sizeof(hist));
}
uint32_t hist[256]; // FRame histogram.
uint32_t mean; // Frame Mean value.
uint32_t sum; // Sum of frame.
uint32_t num_pixels; // Number of pixels.
uint8_t subSamplWidth; // Subsampling rate of width in powers of 2.
uint8_t subSamplHeight; // Subsampling rate of height in powers of 2.
};
/**
Specifies the warning types returned by BrightnessDetection().
*/
enum BrightnessWarning {
kNoWarning, // Frame has acceptable brightness.
kDarkWarning, // Frame is too dark.
kBrightWarning // Frame is too bright.
uint32_t hist[256]; // Frame histogram.
uint32_t mean;
uint32_t sum;
uint32_t num_pixels;
uint32_t sub_sampling_factor; // Sub-sampling factor, in powers of 2.
};
/*
Creates a VPM object.
enum BrightnessWarning {
kNoWarning,
kDarkWarning,
kBrightWarning
};
\param[in] id
Unique identifier of this object.
static VideoProcessing* Create();
virtual ~VideoProcessing() {}
\return Pointer to a VPM object.
*/
static VideoProcessingModule* Create();
// Retrieves statistics for the input frame. This function must be used to
// prepare a FrameStats struct for use in certain VPM functions.
static void GetFrameStats(const VideoFrame& frame, FrameStats* stats);
/**
Destroys a VPM object.
\param[in] module
Pointer to the VPM object to destroy.
*/
static void Destroy(VideoProcessingModule* module);
/**
Not supported.
*/
int64_t TimeUntilNextProcess() override { return -1; }
/**
Not supported.
*/
int32_t Process() override { return -1; }
/**
Resets all processing components to their initial states. This should be
called whenever a new video stream is started.
*/
virtual void Reset() = 0;
/**
Retrieves statistics for the input frame. This function must be used to
prepare a FrameStats struct for use in certain VPM functions.
\param[out] stats
The frame statistics will be stored here on return.
\param[in] frame
Reference to the video frame.
\return 0 on success, -1 on failure.
*/
static int32_t GetFrameStats(FrameStats* stats, const VideoFrame& frame);
/**
Checks the validity of a FrameStats struct. Currently, valid implies only
that is had changed from its initialized state.
\param[in] stats
Frame statistics.
\return True on valid stats, false on invalid stats.
*/
// Checks the validity of a FrameStats struct. Currently, valid implies only
// that is had changed from its initialized state.
static bool ValidFrameStats(const FrameStats& stats);
/**
Returns a FrameStats struct to its intialized state.
\param[in,out] stats
Frame statistics.
*/
static void ClearFrameStats(FrameStats* stats);
/**
Increases/decreases the luminance value.
// Increases/decreases the luminance value. 'delta' can be in the range {}
static void Brighten(int delta, VideoFrame* frame);
\param[in,out] frame
Pointer to the video frame.
\param[in] delta
The amount to change the chrominance value of every single pixel.
Can be < 0 also.
\return 0 on success, -1 on failure.
*/
static int32_t Brighten(VideoFrame* frame, int delta);
/**
Detects and removes camera flicker from a video stream. Every frame from
the stream must be passed in. A frame will only be altered if flicker has
been detected. Has a fixed-point implementation.
\param[in,out] frame
Pointer to the video frame.
\param[in,out] stats
Frame statistics provided by GetFrameStats(). On return the stats will
be reset to zero if the frame was altered. Call GetFrameStats() again
if the statistics for the altered frame are required.
\return 0 on success, -1 on failure.
*/
// Detects and removes camera flicker from a video stream. Every frame from
// the stream must be passed in. A frame will only be altered if flicker has
// been detected. Has a fixed-point implementation.
// Frame statistics provided by GetFrameStats(). On return the stats will
// be reset to zero if the frame was altered. Call GetFrameStats() again
// if the statistics for the altered frame are required.
virtual int32_t Deflickering(VideoFrame* frame, FrameStats* stats) = 0;
/**
Detects if a video frame is excessively bright or dark. Returns a
warning if this is the case. Multiple frames should be passed in before
expecting a warning. Has a floating-point implementation.
\param[in] frame
Pointer to the video frame.
\param[in] stats
Frame statistics provided by GetFrameStats().
\return A member of BrightnessWarning on success, -1 on error
*/
// Detects if a video frame is excessively bright or dark. Returns a
// warning if this is the case. Multiple frames should be passed in before
// expecting a warning. Has a floating-point implementation.
virtual int32_t BrightnessDetection(const VideoFrame& frame,
const FrameStats& stats) = 0;
/**
The following functions refer to the pre-processor unit within VPM. The
pre-processor perfoms spatial/temporal decimation and content analysis on
the frames prior to encoding.
*/
// The following functions refer to the pre-processor unit within VPM. The
// pre-processor perfoms spatial/temporal decimation and content analysis on
// the frames prior to encoding.
/**
Enable/disable temporal decimation
\param[in] enable when true, temporal decimation is enabled
*/
// Enable/disable temporal decimation
virtual void EnableTemporalDecimation(bool enable) = 0;
/**
Set target resolution
\param[in] width
Target width
\param[in] height
Target height
\param[in] frame_rate
Target frame_rate
\return VPM_OK on success, a negative value on error (see error codes)
*/
virtual int32_t SetTargetResolution(uint32_t width,
uint32_t height,
uint32_t frame_rate) = 0;
virtual void SetTargetFramerate(int frame_rate) {}
virtual void SetTargetFramerate(int frame_rate) = 0;
/**
Get decimated(target) frame rate
*/
virtual uint32_t Decimatedframe_rate() = 0;
virtual uint32_t GetDecimatedFrameRate() = 0;
virtual uint32_t GetDecimatedWidth() const = 0;
virtual uint32_t GetDecimatedHeight() const = 0;
/**
Get decimated(target) frame width
*/
virtual uint32_t DecimatedWidth() const = 0;
// Set the spatial resampling settings of the VPM according to
// VideoFrameResampling.
virtual void SetInputFrameResampleMode(
VideoFrameResampling resampling_mode) = 0;
/**
Get decimated(target) frame height
*/
virtual uint32_t DecimatedHeight() const = 0 ;
virtual void EnableDenosing(bool enable) = 0;
virtual const VideoFrame* PreprocessFrame(const VideoFrame& frame) = 0;
/**
Set the spatial resampling settings of the VPM: The resampler may either be
disabled or one of the following:
scaling to a close to target dimension followed by crop/pad
\param[in] resampling_mode
Set resampling mode (a member of VideoFrameResampling)
*/
virtual void SetInputFrameResampleMode(VideoFrameResampling
resampling_mode) = 0;
/**
Get Processed (decimated) frame
\param[in] frame pointer to the video frame.
\param[in] processed_frame pointer (double) to the processed frame. If no
processing is required, processed_frame will be NULL.
\return VPM_OK on success, a negative value on error (see error codes)
*/
virtual int32_t PreprocessFrame(const VideoFrame& frame,
VideoFrame** processed_frame) = 0;
/**
Return content metrics for the last processed frame
*/
virtual VideoContentMetrics* ContentMetrics() const = 0 ;
/**
Enable content analysis
*/
virtual VideoContentMetrics* GetContentMetrics() const = 0;
virtual void EnableContentAnalysis(bool enable) = 0;
};

View File

@ -13,26 +13,24 @@
#include "webrtc/modules/video_processing/test/video_processing_unittest.h"
#include "webrtc/test/testsupport/gtest_disable.h"
using namespace webrtc;
namespace webrtc {
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(BrightnessDetection))
{
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(BrightnessDetection)) {
uint32_t frameNum = 0;
int32_t brightnessWarning = 0;
uint32_t warningCount = 0;
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
frame_length_)
{
frame_length_) {
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_,
height_, 0, kVideoRotation_0, &video_frame_));
frameNum++;
VideoProcessingModule::FrameStats stats;
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
ASSERT_GE(brightnessWarning = vpm_->BrightnessDetection(video_frame_,
VideoProcessing::FrameStats stats;
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
ASSERT_GE(brightnessWarning = vp_->BrightnessDetection(video_frame_,
stats), 0);
if (brightnessWarning != VideoProcessingModule::kNoWarning)
{
if (brightnessWarning != VideoProcessing::kNoWarning) {
warningCount++;
}
}
@ -49,31 +47,28 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(BrightnessDetection))
warningCount = 0;
while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
frame_length_ &&
frameNum < 300)
{
frameNum < 300) {
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_,
height_, 0, kVideoRotation_0, &video_frame_));
frameNum++;
uint8_t* frame = video_frame_.buffer(kYPlane);
uint32_t yTmp = 0;
for (int yIdx = 0; yIdx < width_ * height_; yIdx++)
{
for (int yIdx = 0; yIdx < width_ * height_; yIdx++) {
yTmp = frame[yIdx] << 1;
if (yTmp > 255)
{
if (yTmp > 255) {
yTmp = 255;
}
frame[yIdx] = static_cast<uint8_t>(yTmp);
}
VideoProcessingModule::FrameStats stats;
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
ASSERT_GE(brightnessWarning = vpm_->BrightnessDetection(video_frame_,
VideoProcessing::FrameStats stats;
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
ASSERT_GE(brightnessWarning = vp_->BrightnessDetection(video_frame_,
stats), 0);
EXPECT_NE(VideoProcessingModule::kDarkWarning, brightnessWarning);
if (brightnessWarning == VideoProcessingModule::kBrightWarning)
{
EXPECT_NE(VideoProcessing::kDarkWarning, brightnessWarning);
if (brightnessWarning == VideoProcessing::kBrightWarning) {
warningCount++;
}
}
@ -88,27 +83,25 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(BrightnessDetection))
frameNum = 0;
warningCount = 0;
while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
frame_length_ && frameNum < 300)
{
frame_length_ && frameNum < 300) {
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_,
height_, 0, kVideoRotation_0, &video_frame_));
frameNum++;
uint8_t* y_plane = video_frame_.buffer(kYPlane);
int32_t yTmp = 0;
for (int yIdx = 0; yIdx < width_ * height_; yIdx++)
{
for (int yIdx = 0; yIdx < width_ * height_; yIdx++) {
yTmp = y_plane[yIdx] >> 1;
y_plane[yIdx] = static_cast<uint8_t>(yTmp);
}
VideoProcessingModule::FrameStats stats;
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
ASSERT_GE(brightnessWarning = vpm_->BrightnessDetection(video_frame_,
VideoProcessing::FrameStats stats;
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
ASSERT_GE(brightnessWarning = vp_->BrightnessDetection(video_frame_,
stats), 0);
EXPECT_NE(VideoProcessingModule::kBrightWarning, brightnessWarning);
if (brightnessWarning == VideoProcessingModule::kDarkWarning)
{
EXPECT_NE(VideoProcessing::kBrightWarning, brightnessWarning);
if (brightnessWarning == VideoProcessing::kDarkWarning) {
warningCount++;
}
}
@ -119,3 +112,4 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(BrightnessDetection))
printf("Dark foreman: %.1f %%\n\n", warningProportion);
EXPECT_GT(warningProportion, 90);
}
} // namespace webrtc

View File

@ -16,13 +16,14 @@
namespace webrtc {
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(ContentAnalysis)) {
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(ContentAnalysis)) {
VPMContentAnalysis ca__c(false);
VPMContentAnalysis ca__sse(true);
VideoContentMetrics *_cM_c, *_cM_SSE;
VideoContentMetrics* _cM_c;
VideoContentMetrics* _cM_SSE;
ca__c.Initialize(width_,height_);
ca__sse.Initialize(width_,height_);
ca__c.Initialize(width_, height_);
ca__sse.Initialize(width_, height_);
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
while (fread(video_buffer.get(), 1, frame_length_, source_file_)

View File

@ -20,8 +20,7 @@
namespace webrtc {
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Deflickering))
{
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(Deflickering)) {
enum { NumRuns = 30 };
uint32_t frameNum = 0;
const uint32_t frame_rate = 15;
@ -45,8 +44,7 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Deflickering))
printf("\nRun time [us / frame]:\n");
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
for (uint32_t run_idx = 0; run_idx < NumRuns; run_idx++)
{
for (uint32_t run_idx = 0; run_idx < NumRuns; run_idx++) {
TickTime t0;
TickTime t1;
TickInterval acc_ticks;
@ -54,8 +52,7 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Deflickering))
frameNum = 0;
while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
frame_length_)
{
frame_length_) {
frameNum++;
EXPECT_EQ(
0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_,
@ -63,14 +60,14 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Deflickering))
video_frame_.set_timestamp(timeStamp);
t0 = TickTime::Now();
VideoProcessingModule::FrameStats stats;
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
ASSERT_EQ(0, vpm_->Deflickering(&video_frame_, &stats));
VideoProcessing::FrameStats stats;
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
ASSERT_EQ(0, vp_->Deflickering(&video_frame_, &stats));
t1 = TickTime::Now();
acc_ticks += (t1 - t0);
if (run_idx == 0)
{
if (run_idx == 0) {
if (PrintVideoFrame(video_frame_, deflickerFile) < 0) {
return;
}
@ -80,8 +77,7 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Deflickering))
ASSERT_NE(0, feof(source_file_)) << "Error reading source file";
printf("%u\n", static_cast<int>(acc_ticks.Microseconds() / frameNum));
if (acc_ticks.Microseconds() < min_runtime || run_idx == 0)
{
if (acc_ticks.Microseconds() < min_runtime || run_idx == 0) {
min_runtime = acc_ticks.Microseconds();
}
avg_runtime += acc_ticks.Microseconds();

View File

@ -10,9 +10,10 @@
#include "webrtc/modules/video_processing/test/video_processing_unittest.h"
#include <gflags/gflags.h>
#include <string>
#include <gflags/gflags.h>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#include "webrtc/test/testsupport/fileutils.h"
@ -30,8 +31,8 @@ DEFINE_bool(gen_files, false, "Output files for visual inspection.");
static void PreprocessFrameAndVerify(const VideoFrame& source,
int target_width,
int target_height,
VideoProcessingModule* vpm,
VideoFrame** out_frame);
VideoProcessing* vpm,
const VideoFrame* out_frame);
static void CropFrame(const uint8_t* source_data,
int source_width,
int source_height,
@ -49,14 +50,14 @@ static void TestSize(const VideoFrame& source_frame,
int target_width,
int target_height,
double expected_psnr,
VideoProcessingModule* vpm);
VideoProcessing* vpm);
static bool CompareFrames(const webrtc::VideoFrame& frame1,
const webrtc::VideoFrame& frame2);
static void WriteProcessedFrameForVisualInspection(const VideoFrame& source,
const VideoFrame& processed);
VideoProcessingModuleTest::VideoProcessingModuleTest()
: vpm_(NULL),
VideoProcessingTest::VideoProcessingTest()
: vp_(NULL),
source_file_(NULL),
width_(352),
half_width_((width_ + 1) / 2),
@ -65,9 +66,9 @@ VideoProcessingModuleTest::VideoProcessingModuleTest()
size_uv_(half_width_ * ((height_ + 1) / 2)),
frame_length_(CalcBufferSize(kI420, width_, height_)) {}
void VideoProcessingModuleTest::SetUp() {
vpm_ = VideoProcessingModule::Create();
ASSERT_TRUE(vpm_ != NULL);
void VideoProcessingTest::SetUp() {
vp_ = VideoProcessing::Create();
ASSERT_TRUE(vp_ != NULL);
ASSERT_EQ(0, video_frame_.CreateEmptyFrame(width_, height_, width_,
half_width_, half_width_));
@ -77,125 +78,126 @@ void VideoProcessingModuleTest::SetUp() {
memset(video_frame_.buffer(kVPlane), 0, video_frame_.allocated_size(kVPlane));
const std::string video_file =
webrtc::test::ResourcePath("foreman_cif", "yuv");
source_file_ = fopen(video_file.c_str(),"rb");
source_file_ = fopen(video_file.c_str(), "rb");
ASSERT_TRUE(source_file_ != NULL) <<
"Cannot read source file: " + video_file + "\n";
}
void VideoProcessingModuleTest::TearDown() {
void VideoProcessingTest::TearDown() {
if (source_file_ != NULL) {
ASSERT_EQ(0, fclose(source_file_));
}
source_file_ = NULL;
if (vpm_ != NULL) {
VideoProcessingModule::Destroy(vpm_);
}
vpm_ = NULL;
delete vp_;
vp_ = NULL;
}
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(HandleNullBuffer)) {
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(HandleNullBuffer)) {
// TODO(mikhal/stefan): Do we need this one?
VideoProcessingModule::FrameStats stats;
VideoProcessing::FrameStats stats;
// Video frame with unallocated buffer.
VideoFrame videoFrame;
EXPECT_EQ(-3, vpm_->GetFrameStats(&stats, videoFrame));
vp_->GetFrameStats(videoFrame, &stats);
EXPECT_EQ(stats.num_pixels, 0u);
EXPECT_EQ(-1, vpm_->Deflickering(&videoFrame, &stats));
EXPECT_EQ(-1, vp_->Deflickering(&videoFrame, &stats));
EXPECT_EQ(-3, vpm_->BrightnessDetection(videoFrame, stats));
EXPECT_EQ(-3, vp_->BrightnessDetection(videoFrame, stats));
}
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(HandleBadStats)) {
VideoProcessingModule::FrameStats stats;
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(HandleBadStats)) {
VideoProcessing::FrameStats stats;
vp_->ClearFrameStats(&stats);
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
ASSERT_EQ(frame_length_, fread(video_buffer.get(), 1, frame_length_,
source_file_));
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
0, kVideoRotation_0, &video_frame_));
EXPECT_EQ(-1, vpm_->Deflickering(&video_frame_, &stats));
EXPECT_EQ(-1, vp_->Deflickering(&video_frame_, &stats));
EXPECT_EQ(-3, vpm_->BrightnessDetection(video_frame_, stats));
EXPECT_EQ(-3, vp_->BrightnessDetection(video_frame_, stats));
}
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(IdenticalResultsAfterReset)) {
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(IdenticalResultsAfterReset)) {
VideoFrame video_frame2;
VideoProcessingModule::FrameStats stats;
VideoProcessing::FrameStats stats;
// Only testing non-static functions here.
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
ASSERT_EQ(frame_length_, fread(video_buffer.get(), 1, frame_length_,
source_file_));
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
0, kVideoRotation_0, &video_frame_));
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
ASSERT_EQ(0, video_frame2.CopyFrame(video_frame_));
ASSERT_EQ(0, vpm_->Deflickering(&video_frame_, &stats));
vpm_->Reset();
ASSERT_EQ(0, vp_->Deflickering(&video_frame_, &stats));
// Retrieve frame stats again in case Deflickering() has zeroed them.
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame2));
ASSERT_EQ(0, vpm_->Deflickering(&video_frame2, &stats));
vp_->GetFrameStats(video_frame2, &stats);
EXPECT_GT(stats.num_pixels, 0u);
ASSERT_EQ(0, vp_->Deflickering(&video_frame2, &stats));
EXPECT_TRUE(CompareFrames(video_frame_, video_frame2));
ASSERT_EQ(frame_length_, fread(video_buffer.get(), 1, frame_length_,
source_file_));
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
0, kVideoRotation_0, &video_frame_));
ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
video_frame2.CopyFrame(video_frame_);
ASSERT_EQ(0, vpm_->BrightnessDetection(video_frame_, stats));
vpm_->Reset();
ASSERT_EQ(0, vpm_->BrightnessDetection(video_frame2, stats));
ASSERT_EQ(0, vp_->BrightnessDetection(video_frame_, stats));
ASSERT_EQ(0, vp_->BrightnessDetection(video_frame2, stats));
EXPECT_TRUE(CompareFrames(video_frame_, video_frame2));
}
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(FrameStats)) {
VideoProcessingModule::FrameStats stats;
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(FrameStats)) {
VideoProcessing::FrameStats stats;
vp_->ClearFrameStats(&stats);
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
ASSERT_EQ(frame_length_, fread(video_buffer.get(), 1, frame_length_,
source_file_));
EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
0, kVideoRotation_0, &video_frame_));
EXPECT_FALSE(vpm_->ValidFrameStats(stats));
EXPECT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_));
EXPECT_TRUE(vpm_->ValidFrameStats(stats));
EXPECT_FALSE(vp_->ValidFrameStats(stats));
vp_->GetFrameStats(video_frame_, &stats);
EXPECT_GT(stats.num_pixels, 0u);
EXPECT_TRUE(vp_->ValidFrameStats(stats));
printf("\nFrameStats\n");
printf("mean: %u\nnum_pixels: %u\nsubSamplWidth: "
"%u\nsumSamplHeight: %u\nsum: %u\n\n",
printf("mean: %u\nnum_pixels: %u\nsubSamplFactor: %u\nsum: %u\n\n",
static_cast<unsigned int>(stats.mean),
static_cast<unsigned int>(stats.num_pixels),
static_cast<unsigned int>(stats.subSamplHeight),
static_cast<unsigned int>(stats.subSamplWidth),
static_cast<unsigned int>(stats.sub_sampling_factor),
static_cast<unsigned int>(stats.sum));
vpm_->ClearFrameStats(&stats);
EXPECT_FALSE(vpm_->ValidFrameStats(stats));
vp_->ClearFrameStats(&stats);
EXPECT_FALSE(vp_->ValidFrameStats(stats));
}
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(PreprocessorLogic)) {
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(PreprocessorLogic)) {
// Disable temporal sampling (frame dropping).
vpm_->EnableTemporalDecimation(false);
vp_->EnableTemporalDecimation(false);
int resolution = 100;
EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 15));
EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 30));
EXPECT_EQ(VPM_OK, vp_->SetTargetResolution(resolution, resolution, 15));
EXPECT_EQ(VPM_OK, vp_->SetTargetResolution(resolution, resolution, 30));
// Disable spatial sampling.
vpm_->SetInputFrameResampleMode(kNoRescaling);
EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 30));
vp_->SetInputFrameResampleMode(kNoRescaling);
EXPECT_EQ(VPM_OK, vp_->SetTargetResolution(resolution, resolution, 30));
VideoFrame* out_frame = NULL;
// Set rescaling => output frame != NULL.
vpm_->SetInputFrameResampleMode(kFastRescaling);
PreprocessFrameAndVerify(video_frame_, resolution, resolution, vpm_,
&out_frame);
vp_->SetInputFrameResampleMode(kFastRescaling);
PreprocessFrameAndVerify(video_frame_, resolution, resolution, vp_,
out_frame);
// No rescaling=> output frame = NULL.
vpm_->SetInputFrameResampleMode(kNoRescaling);
EXPECT_EQ(VPM_OK, vpm_->PreprocessFrame(video_frame_, &out_frame));
EXPECT_TRUE(out_frame == NULL);
vp_->SetInputFrameResampleMode(kNoRescaling);
EXPECT_TRUE(vp_->PreprocessFrame(video_frame_) != nullptr);
}
TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Resampler)) {
TEST_F(VideoProcessingTest, DISABLED_ON_IOS(Resampler)) {
enum { NumRuns = 1 };
int64_t min_runtime = 0;
@ -206,9 +208,9 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Resampler)) {
"Cannot read input file \n";
// CA not needed here
vpm_->EnableContentAnalysis(false);
vp_->EnableContentAnalysis(false);
// no temporal decimation
vpm_->EnableTemporalDecimation(false);
vp_->EnableTemporalDecimation(false);
// Reading test frame
rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
@ -231,43 +233,43 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Resampler)) {
// Test scaling to different sizes: source is of |width|/|height| = 352/288.
// Pure scaling:
TestSize(video_frame_, video_frame_, width_ / 4, height_ / 4, 25.2, vpm_);
TestSize(video_frame_, video_frame_, width_ / 2, height_ / 2, 28.1, vpm_);
TestSize(video_frame_, video_frame_, width_ / 4, height_ / 4, 25.2, vp_);
TestSize(video_frame_, video_frame_, width_ / 2, height_ / 2, 28.1, vp_);
// No resampling:
TestSize(video_frame_, video_frame_, width_, height_, -1, vpm_);
TestSize(video_frame_, video_frame_, 2 * width_, 2 * height_, 32.2, vpm_);
TestSize(video_frame_, video_frame_, width_, height_, -1, vp_);
TestSize(video_frame_, video_frame_, 2 * width_, 2 * height_, 32.2, vp_);
// Scaling and cropping. The cropped source frame is the largest center
// aligned region that can be used from the source while preserving aspect
// ratio.
CropFrame(video_buffer.get(), width_, height_, 0, 56, 352, 176,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 100, 50, 24.0, vpm_);
TestSize(video_frame_, cropped_source_frame, 100, 50, 24.0, vp_);
CropFrame(video_buffer.get(), width_, height_, 0, 30, 352, 225,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 400, 256, 31.3, vpm_);
TestSize(video_frame_, cropped_source_frame, 400, 256, 31.3, vp_);
CropFrame(video_buffer.get(), width_, height_, 68, 0, 216, 288,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 480, 640, 32.15, vpm_);
TestSize(video_frame_, cropped_source_frame, 480, 640, 32.15, vp_);
CropFrame(video_buffer.get(), width_, height_, 0, 12, 352, 264,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 960, 720, 32.2, vpm_);
TestSize(video_frame_, cropped_source_frame, 960, 720, 32.2, vp_);
CropFrame(video_buffer.get(), width_, height_, 0, 44, 352, 198,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 1280, 720, 32.15, vpm_);
TestSize(video_frame_, cropped_source_frame, 1280, 720, 32.15, vp_);
// Upsampling to odd size.
CropFrame(video_buffer.get(), width_, height_, 0, 26, 352, 233,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 501, 333, 32.05, vpm_);
TestSize(video_frame_, cropped_source_frame, 501, 333, 32.05, vp_);
// Downsample to odd size.
CropFrame(video_buffer.get(), width_, height_, 0, 34, 352, 219,
&cropped_source_frame);
TestSize(video_frame_, cropped_source_frame, 281, 175, 29.3, vpm_);
TestSize(video_frame_, cropped_source_frame, 281, 175, 29.3, vp_);
// Stop timer.
const int64_t runtime = (TickTime::Now() - time_start).Microseconds();
@ -286,23 +288,24 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_IOS(Resampler)) {
void PreprocessFrameAndVerify(const VideoFrame& source,
int target_width,
int target_height,
VideoProcessingModule* vpm,
VideoFrame** out_frame) {
VideoProcessing* vpm,
const VideoFrame* out_frame) {
ASSERT_EQ(VPM_OK, vpm->SetTargetResolution(target_width, target_height, 30));
ASSERT_EQ(VPM_OK, vpm->PreprocessFrame(source, out_frame));
out_frame = vpm->PreprocessFrame(source);
EXPECT_TRUE(out_frame != nullptr);
// If no resizing is needed, expect NULL.
// If no resizing is needed, expect the original frame.
if (target_width == source.width() && target_height == source.height()) {
EXPECT_EQ(NULL, *out_frame);
EXPECT_EQ(&source, out_frame);
return;
}
// Verify the resampled frame.
EXPECT_TRUE(*out_frame != NULL);
EXPECT_EQ(source.render_time_ms(), (*out_frame)->render_time_ms());
EXPECT_EQ(source.timestamp(), (*out_frame)->timestamp());
EXPECT_EQ(target_width, (*out_frame)->width());
EXPECT_EQ(target_height, (*out_frame)->height());
EXPECT_TRUE(out_frame != NULL);
EXPECT_EQ(source.render_time_ms(), (out_frame)->render_time_ms());
EXPECT_EQ(source.timestamp(), (out_frame)->timestamp());
EXPECT_EQ(target_width, (out_frame)->width());
EXPECT_EQ(target_height, (out_frame)->height());
}
void CropFrame(const uint8_t* source_data,
@ -326,12 +329,12 @@ void TestSize(const VideoFrame& source_frame,
int target_width,
int target_height,
double expected_psnr,
VideoProcessingModule* vpm) {
VideoProcessing* vpm) {
// Resample source_frame to out_frame.
VideoFrame* out_frame = NULL;
vpm->SetInputFrameResampleMode(kBox);
PreprocessFrameAndVerify(source_frame, target_width, target_height, vpm,
&out_frame);
out_frame);
if (out_frame == NULL)
return;
WriteProcessedFrameForVisualInspection(source_frame, *out_frame);
@ -340,7 +343,7 @@ void TestSize(const VideoFrame& source_frame,
VideoFrame resampled_source_frame;
resampled_source_frame.CopyFrame(*out_frame);
PreprocessFrameAndVerify(resampled_source_frame, cropped_source_frame.width(),
cropped_source_frame.height(), vpm, &out_frame);
cropped_source_frame.height(), vpm, out_frame);
WriteProcessedFrameForVisualInspection(resampled_source_frame, *out_frame);
// Compute PSNR against the cropped source frame and check expectation.

View File

@ -11,6 +11,8 @@
#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_TEST_VIDEO_PROCESSING_UNITTEST_H_
#define WEBRTC_MODULES_VIDEO_PROCESSING_TEST_VIDEO_PROCESSING_UNITTEST_H_
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/video_processing/include/video_processing.h"
#include "webrtc/system_wrappers/include/trace.h"
@ -18,9 +20,9 @@
namespace webrtc {
class VideoProcessingModuleTest : public ::testing::Test {
class VideoProcessingTest : public ::testing::Test {
protected:
VideoProcessingModuleTest();
VideoProcessingTest();
virtual void SetUp();
virtual void TearDown();
static void SetUpTestCase() {
@ -31,7 +33,7 @@ class VideoProcessingModuleTest : public ::testing::Test {
static void TearDownTestCase() {
Trace::ReturnTrace();
}
VideoProcessingModule* vpm_;
VideoProcessing* vp_;
FILE* source_file_;
VideoFrame video_frame_;
const int width_;

View File

@ -92,7 +92,7 @@ bool VPMVideoDecimator::DropFrame() {
}
uint32_t VPMVideoDecimator::Decimatedframe_rate() {
uint32_t VPMVideoDecimator::GetDecimatedFrameRate() {
ProcessIncomingframe_rate(TickTime::MillisecondTimestamp());
if (!enable_temporal_decimation_) {
return static_cast<uint32_t>(incoming_frame_rate_ + 0.5f);

View File

@ -32,7 +32,7 @@ class VPMVideoDecimator {
void UpdateIncomingframe_rate();
// Get Decimated Frame Rate/Dimensions.
uint32_t Decimatedframe_rate();
uint32_t GetDecimatedFrameRate();
// Get input frame rate.
uint32_t Inputframe_rate();

View File

@ -20,8 +20,6 @@
'sources': [
'include/video_processing.h',
'include/video_processing_defines.h',
'brighten.cc',
'brighten.h',
'brightness_detection.cc',
'brightness_detection.h',
'content_analysis.cc',

View File

@ -7,87 +7,70 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/base/logging.h"
#include "webrtc/modules/video_processing/video_processing_impl.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
#include <assert.h>
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
namespace webrtc {
namespace {
void SetSubSampling(VideoProcessingModule::FrameStats* stats,
const int32_t width,
const int32_t height) {
int GetSubSamplingFactor(int width, int height) {
if (width * height >= 640 * 480) {
stats->subSamplWidth = 3;
stats->subSamplHeight = 3;
return 3;
} else if (width * height >= 352 * 288) {
stats->subSamplWidth = 2;
stats->subSamplHeight = 2;
return 2;
} else if (width * height >= 176 * 144) {
stats->subSamplWidth = 1;
stats->subSamplHeight = 1;
return 1;
} else {
stats->subSamplWidth = 0;
stats->subSamplHeight = 0;
return 0;
}
}
} // namespace
VideoProcessingModule* VideoProcessingModule::Create() {
return new VideoProcessingModuleImpl();
VideoProcessing* VideoProcessing::Create() {
return new VideoProcessingImpl();
}
void VideoProcessingModule::Destroy(VideoProcessingModule* module) {
if (module)
delete static_cast<VideoProcessingModuleImpl*>(module);
}
VideoProcessingImpl::VideoProcessingImpl() {}
VideoProcessingImpl::~VideoProcessingImpl() {}
VideoProcessingModuleImpl::VideoProcessingModuleImpl() {}
VideoProcessingModuleImpl::~VideoProcessingModuleImpl() {}
void VideoProcessingModuleImpl::Reset() {
rtc::CritScope mutex(&mutex_);
deflickering_.Reset();
brightness_detection_.Reset();
frame_pre_processor_.Reset();
}
int32_t VideoProcessingModule::GetFrameStats(FrameStats* stats,
const VideoFrame& frame) {
void VideoProcessing::GetFrameStats(const VideoFrame& frame,
FrameStats* stats) {
ClearFrameStats(stats); // The histogram needs to be zeroed out.
if (frame.IsZeroSize()) {
LOG(LS_ERROR) << "Zero size frame.";
return VPM_PARAMETER_ERROR;
return;
}
int width = frame.width();
int height = frame.height();
ClearFrameStats(stats); // The histogram needs to be zeroed out.
SetSubSampling(stats, width, height);
stats->sub_sampling_factor = GetSubSamplingFactor(width, height);
const uint8_t* buffer = frame.buffer(kYPlane);
// Compute histogram and sum of frame
for (int i = 0; i < height; i += (1 << stats->subSamplHeight)) {
for (int i = 0; i < height; i += (1 << stats->sub_sampling_factor)) {
int k = i * width;
for (int j = 0; j < width; j += (1 << stats->subSamplWidth)) {
for (int j = 0; j < width; j += (1 << stats->sub_sampling_factor)) {
stats->hist[buffer[k + j]]++;
stats->sum += buffer[k + j];
}
}
stats->num_pixels = (width * height) / ((1 << stats->subSamplWidth) *
(1 << stats->subSamplHeight));
stats->num_pixels = (width * height) /
((1 << stats->sub_sampling_factor) * (1 << stats->sub_sampling_factor));
assert(stats->num_pixels > 0);
// Compute mean value of frame
stats->mean = stats->sum / stats->num_pixels;
return VPM_OK;
}
bool VideoProcessingModule::ValidFrameStats(const FrameStats& stats) {
bool VideoProcessing::ValidFrameStats(const FrameStats& stats) {
if (stats.num_pixels == 0) {
LOG(LS_WARNING) << "Invalid frame stats.";
return false;
@ -95,26 +78,41 @@ bool VideoProcessingModule::ValidFrameStats(const FrameStats& stats) {
return true;
}
void VideoProcessingModule::ClearFrameStats(FrameStats* stats) {
void VideoProcessing::ClearFrameStats(FrameStats* stats) {
stats->mean = 0;
stats->sum = 0;
stats->num_pixels = 0;
stats->subSamplWidth = 0;
stats->subSamplHeight = 0;
stats->sub_sampling_factor = 0;
memset(stats->hist, 0, sizeof(stats->hist));
}
int32_t VideoProcessingModule::Brighten(VideoFrame* frame, int delta) {
return VideoProcessing::Brighten(frame, delta);
void VideoProcessing::Brighten(int delta, VideoFrame* frame) {
RTC_DCHECK(!frame->IsZeroSize());
RTC_DCHECK(frame->width() > 0);
RTC_DCHECK(frame->height() > 0);
int num_pixels = frame->width() * frame->height();
int look_up[256];
for (int i = 0; i < 256; i++) {
int val = i + delta;
look_up[i] = ((((val < 0) ? 0 : val) > 255) ? 255 : val);
}
uint8_t* temp_ptr = frame->buffer(kYPlane);
for (int i = 0; i < num_pixels; i++) {
*temp_ptr = static_cast<uint8_t>(look_up[*temp_ptr]);
temp_ptr++;
}
}
int32_t VideoProcessingModuleImpl::Deflickering(VideoFrame* frame,
FrameStats* stats) {
int32_t VideoProcessingImpl::Deflickering(VideoFrame* frame,
FrameStats* stats) {
rtc::CritScope mutex(&mutex_);
return deflickering_.ProcessFrame(frame, stats);
}
int32_t VideoProcessingModuleImpl::BrightnessDetection(
int32_t VideoProcessingImpl::BrightnessDetection(
const VideoFrame& frame,
const FrameStats& stats) {
rtc::CritScope mutex(&mutex_);
@ -122,58 +120,62 @@ int32_t VideoProcessingModuleImpl::BrightnessDetection(
}
void VideoProcessingModuleImpl::EnableTemporalDecimation(bool enable) {
void VideoProcessingImpl::EnableTemporalDecimation(bool enable) {
rtc::CritScope mutex(&mutex_);
frame_pre_processor_.EnableTemporalDecimation(enable);
}
void VideoProcessingModuleImpl::SetInputFrameResampleMode(VideoFrameResampling
resampling_mode) {
void VideoProcessingImpl::SetInputFrameResampleMode(VideoFrameResampling
resampling_mode) {
rtc::CritScope cs(&mutex_);
frame_pre_processor_.SetInputFrameResampleMode(resampling_mode);
}
int32_t VideoProcessingModuleImpl::SetTargetResolution(uint32_t width,
uint32_t height,
uint32_t frame_rate) {
int32_t VideoProcessingImpl::SetTargetResolution(uint32_t width,
uint32_t height,
uint32_t frame_rate) {
rtc::CritScope cs(&mutex_);
return frame_pre_processor_.SetTargetResolution(width, height, frame_rate);
}
void VideoProcessingModuleImpl::SetTargetFramerate(int frame_rate) {
void VideoProcessingImpl::SetTargetFramerate(int frame_rate) {
rtc::CritScope cs(&mutex_);
frame_pre_processor_.SetTargetFramerate(frame_rate);
}
uint32_t VideoProcessingModuleImpl::Decimatedframe_rate() {
uint32_t VideoProcessingImpl::GetDecimatedFrameRate() {
rtc::CritScope cs(&mutex_);
return frame_pre_processor_.Decimatedframe_rate();
return frame_pre_processor_.GetDecimatedFrameRate();
}
uint32_t VideoProcessingModuleImpl::DecimatedWidth() const {
uint32_t VideoProcessingImpl::GetDecimatedWidth() const {
rtc::CritScope cs(&mutex_);
return frame_pre_processor_.DecimatedWidth();
return frame_pre_processor_.GetDecimatedWidth();
}
uint32_t VideoProcessingModuleImpl::DecimatedHeight() const {
uint32_t VideoProcessingImpl::GetDecimatedHeight() const {
rtc::CritScope cs(&mutex_);
return frame_pre_processor_.DecimatedHeight();
return frame_pre_processor_.GetDecimatedHeight();
}
int32_t VideoProcessingModuleImpl::PreprocessFrame(
const VideoFrame& frame,
VideoFrame** processed_frame) {
void VideoProcessingImpl::EnableDenosing(bool enable) {
rtc::CritScope cs(&mutex_);
frame_pre_processor_.EnableDenosing(enable);
}
const VideoFrame* VideoProcessingImpl::PreprocessFrame(
const VideoFrame& frame) {
rtc::CritScope mutex(&mutex_);
return frame_pre_processor_.PreprocessFrame(frame, processed_frame);
return frame_pre_processor_.PreprocessFrame(frame);
}
VideoContentMetrics* VideoProcessingModuleImpl::ContentMetrics() const {
VideoContentMetrics* VideoProcessingImpl::GetContentMetrics() const {
rtc::CritScope mutex(&mutex_);
return frame_pre_processor_.ContentMetrics();
return frame_pre_processor_.GetContentMetrics();
}
void VideoProcessingModuleImpl::EnableContentAnalysis(bool enable) {
void VideoProcessingImpl::EnableContentAnalysis(bool enable) {
rtc::CritScope mutex(&mutex_);
frame_pre_processor_.EnableContentAnalysis(enable);
}

View File

@ -13,7 +13,6 @@
#include "webrtc/base/criticalsection.h"
#include "webrtc/modules/video_processing/include/video_processing.h"
#include "webrtc/modules/video_processing/brighten.h"
#include "webrtc/modules/video_processing/brightness_detection.h"
#include "webrtc/modules/video_processing/deflickering.h"
#include "webrtc/modules/video_processing/frame_preprocessor.h"
@ -21,47 +20,28 @@
namespace webrtc {
class CriticalSectionWrapper;
class VideoProcessingModuleImpl : public VideoProcessingModule {
class VideoProcessingImpl : public VideoProcessing {
public:
VideoProcessingModuleImpl();
~VideoProcessingModuleImpl() override;
void Reset() override;
VideoProcessingImpl();
~VideoProcessingImpl() override;
// Implements VideoProcessing.
int32_t Deflickering(VideoFrame* frame, FrameStats* stats) override;
int32_t BrightnessDetection(const VideoFrame& frame,
const FrameStats& stats) override;
// Frame pre-processor functions
// Enable temporal decimation
void EnableTemporalDecimation(bool enable) override;
void SetInputFrameResampleMode(VideoFrameResampling resampling_mode) override;
// Enable content analysis
void EnableContentAnalysis(bool enable) override;
// Set Target Resolution: frame rate and dimension
int32_t SetTargetResolution(uint32_t width,
uint32_t height,
uint32_t frame_rate) override;
void SetTargetFramerate(int frame_rate) override;
// Get decimated values: frame rate/dimension
uint32_t Decimatedframe_rate() override;
uint32_t DecimatedWidth() const override;
uint32_t DecimatedHeight() const override;
// Preprocess:
// Pre-process incoming frame: Sample when needed and compute content
// metrics when enabled.
// If no resampling takes place - processed_frame is set to NULL.
int32_t PreprocessFrame(const VideoFrame& frame,
VideoFrame** processed_frame) override;
VideoContentMetrics* ContentMetrics() const override;
uint32_t GetDecimatedFrameRate() override;
uint32_t GetDecimatedWidth() const override;
uint32_t GetDecimatedHeight() const override;
void EnableDenosing(bool enable) override;
const VideoFrame* PreprocessFrame(const VideoFrame& frame) override;
VideoContentMetrics* GetContentMetrics() const override;
private:
mutable rtc::CriticalSection mutex_;
@ -70,6 +50,6 @@ class VideoProcessingModuleImpl : public VideoProcessingModule {
VPMFramePreprocessor frame_pre_processor_;
};
} // namespace
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_PROCESSING_VIDEO_PROCESSING_IMPL_H_

View File

@ -72,7 +72,7 @@ std::vector<uint32_t> AllocateStreamBitrates(
class QMVideoSettingsCallback : public VCMQMSettingsCallback {
public:
explicit QMVideoSettingsCallback(VideoProcessingModule* vpm);
explicit QMVideoSettingsCallback(VideoProcessing* vpm);
~QMVideoSettingsCallback();
@ -85,7 +85,7 @@ class QMVideoSettingsCallback : public VCMQMSettingsCallback {
void SetTargetFramerate(int frame_rate);
private:
VideoProcessingModule* vpm_;
VideoProcessing* vp_;
};
class ViEBitrateObserver : public BitrateObserver {
@ -111,8 +111,8 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
PacedSender* pacer,
BitrateAllocator* bitrate_allocator)
: number_of_cores_(number_of_cores),
vpm_(VideoProcessingModule::Create()),
qm_callback_(new QMVideoSettingsCallback(vpm_.get())),
vp_(VideoProcessing::Create()),
qm_callback_(new QMVideoSettingsCallback(vp_.get())),
vcm_(VideoCodingModule::Create(Clock::GetRealTimeClock(),
this,
qm_callback_.get())),
@ -140,10 +140,10 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
}
bool ViEEncoder::Init() {
vpm_->EnableTemporalDecimation(true);
vp_->EnableTemporalDecimation(true);
// Enable/disable content analysis: off by default for now.
vpm_->EnableContentAnalysis(false);
vp_->EnableContentAnalysis(false);
if (vcm_->RegisterTransportCallback(this) != 0) {
return false;
@ -168,7 +168,6 @@ void ViEEncoder::StopThreadsAndRemoveSharedMembers() {
if (bitrate_allocator_)
bitrate_allocator_->RemoveBitrateObserver(bitrate_observer_.get());
module_process_thread_->DeRegisterModule(vcm_.get());
module_process_thread_->DeRegisterModule(vpm_.get());
}
ViEEncoder::~ViEEncoder() {
@ -211,8 +210,8 @@ int32_t ViEEncoder::DeRegisterExternalEncoder(uint8_t pl_type) {
int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
RTC_DCHECK(send_payload_router_ != NULL);
// Setting target width and height for VPM.
if (vpm_->SetTargetResolution(video_codec.width, video_codec.height,
video_codec.maxFramerate) != VPM_OK) {
if (vp_->SetTargetResolution(video_codec.width, video_codec.height,
video_codec.maxFramerate) != VPM_OK) {
return -1;
}
@ -358,16 +357,13 @@ void ViEEncoder::DeliverFrame(VideoFrame video_frame) {
TRACE_EVENT_ASYNC_STEP0("webrtc", "Video", video_frame.render_time_ms(),
"Encode");
VideoFrame* decimated_frame = NULL;
const VideoFrame* frame_to_send = &video_frame;
// TODO(wuchengli): support texture frames.
if (video_frame.native_handle() == NULL) {
// Pass frame via preprocessor.
const int ret = vpm_->PreprocessFrame(video_frame, &decimated_frame);
if (ret == 1) {
// Drop this frame.
return;
}
if (ret != VPM_OK) {
frame_to_send = vp_->PreprocessFrame(video_frame);
if (!frame_to_send) {
// Drop this frame, or there was an error processing it.
return;
}
}
@ -376,19 +372,11 @@ void ViEEncoder::DeliverFrame(VideoFrame video_frame) {
// make a deep copy of |video_frame|.
VideoFrame copied_frame;
if (pre_encode_callback_) {
// If the frame was not resampled or scaled => use copy of original.
if (decimated_frame == NULL) {
copied_frame.CopyFrame(video_frame);
decimated_frame = &copied_frame;
}
pre_encode_callback_->FrameCallback(decimated_frame);
copied_frame.CopyFrame(*frame_to_send);
pre_encode_callback_->FrameCallback(&copied_frame);
frame_to_send = &copied_frame;
}
// If the frame was not resampled, scaled, or touched by FrameCallback => use
// original. The frame is const from here.
const VideoFrame* output_frame =
(decimated_frame != NULL) ? decimated_frame : &video_frame;
if (codec_type == webrtc::kVideoCodecVP8) {
webrtc::CodecSpecificInfo codec_specific_info;
codec_specific_info.codecType = webrtc::kVideoCodecVP8;
@ -406,11 +394,11 @@ void ViEEncoder::DeliverFrame(VideoFrame video_frame) {
has_received_rpsi_ = false;
}
vcm_->AddVideoFrame(*output_frame, vpm_->ContentMetrics(),
vcm_->AddVideoFrame(*frame_to_send, vp_->GetContentMetrics(),
&codec_specific_info);
return;
}
vcm_->AddVideoFrame(*output_frame);
vcm_->AddVideoFrame(*frame_to_send);
}
int ViEEncoder::SendKeyFrame() {
@ -448,10 +436,10 @@ void ViEEncoder::SetSenderBufferingMode(int target_delay_ms) {
if (target_delay_ms > 0) {
// Disable external frame-droppers.
vcm_->EnableFrameDropper(false);
vpm_->EnableTemporalDecimation(false);
vp_->EnableTemporalDecimation(false);
} else {
// Real-time mode - enable frame droppers.
vpm_->EnableTemporalDecimation(true);
vp_->EnableTemporalDecimation(true);
vcm_->EnableFrameDropper(true);
}
}
@ -619,8 +607,8 @@ void ViEEncoder::RegisterPostEncodeImageCallback(
vcm_->RegisterPostEncodeImageCallback(post_encode_callback);
}
QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessingModule* vpm)
: vpm_(vpm) {
QMVideoSettingsCallback::QMVideoSettingsCallback(VideoProcessing* vpm)
: vp_(vpm) {
}
QMVideoSettingsCallback::~QMVideoSettingsCallback() {
@ -630,11 +618,11 @@ int32_t QMVideoSettingsCallback::SetVideoQMSettings(
const uint32_t frame_rate,
const uint32_t width,
const uint32_t height) {
return vpm_->SetTargetResolution(width, height, frame_rate);
return vp_->SetTargetResolution(width, height, frame_rate);
}
void QMVideoSettingsCallback::SetTargetFramerate(int frame_rate) {
vpm_->SetTargetFramerate(frame_rate);
vp_->SetTargetFramerate(frame_rate);
}
} // namespace webrtc

View File

@ -152,7 +152,7 @@ class ViEEncoder : public RtcpIntraFrameObserver,
const uint32_t number_of_cores_;
const rtc::scoped_ptr<VideoProcessingModule> vpm_;
const rtc::scoped_ptr<VideoProcessing> vp_;
const rtc::scoped_ptr<QMVideoSettingsCallback> qm_callback_;
const rtc::scoped_ptr<VideoCodingModule> vcm_;
rtc::scoped_refptr<PayloadRouter> send_payload_router_;