diff --git a/webrtc/modules/video_coding/main/test/quality_modes_test.cc b/webrtc/modules/video_coding/main/test/quality_modes_test.cc index 31242774b..0dbf6fdfe 100644 --- a/webrtc/modules/video_coding/main/test/quality_modes_test.cc +++ b/webrtc/modules/video_coding/main/test/quality_modes_test.cc @@ -249,7 +249,7 @@ QualityModesTest::Perform(const CmdArgs& args) VideoContentMetrics* contentMetrics = NULL; // setting user frame rate - _vpm->SetMaxFrameRate((uint32_t)(_nativeFrameRate+ 0.5f)); + _vpm->SetMaxFramerate((uint32_t)(_nativeFrameRate+ 0.5f)); // for starters: keeping native values: _vpm->SetTargetResolution(_width, _height, (uint32_t)(_frameRate+ 0.5f)); diff --git a/webrtc/modules/video_processing/main/interface/video_processing.h b/webrtc/modules/video_processing/main/interface/video_processing.h index 094900d86..b3e0483d0 100644 --- a/webrtc/modules/video_processing/main/interface/video_processing.h +++ b/webrtc/modules/video_processing/main/interface/video_processing.h @@ -24,281 +24,274 @@ #include "webrtc/modules/video_processing/main/interface/video_processing_defines.h" /** - The module is largely intended to process video streams, except functionality + 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 + 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 -{ -public: - /** - Structure to hold frame statistics. Populate it with GetFrameStats(). - */ - struct FrameStats - { - FrameStats() : - mean(0), - sum(0), - numPixels(0), - subSamplWidth(0), - subSamplHeight(0) - { - memset(hist, 0, sizeof(hist)); - } - - uint32_t hist[256]; /**< Histogram of frame */ - uint32_t mean; /**< Mean value of frame */ - uint32_t sum; /**< Sum of frame */ - uint32_t numPixels; /**< 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 */ - }; - - /* - Creates a VPM object. - - \param[in] id - Unique identifier of this object. - - \return Pointer to a VPM object. - */ - static VideoProcessingModule* Create(int32_t id); - - /** - Destroys a VPM object. - - \param[in] module - Pointer to the VPM object to destroy. - */ - static void Destroy(VideoProcessingModule* module); - - /** - Not supported. - */ - virtual int32_t TimeUntilNextProcess() { return -1; } - - /** - Not supported. - */ - virtual int32_t Process() { 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 I420VideoFrame& 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. - */ - 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); - - /** - Enhances the color of an image through a constant mapping. Only the - chrominance is altered. Has a fixed-point implementation. - - \param[in,out] frame - Pointer to the video frame. - */ - static int32_t ColorEnhancement(I420VideoFrame* frame); - - /** - Increases/decreases the luminance value. - - \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(I420VideoFrame* 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. - */ - virtual int32_t Deflickering(I420VideoFrame* frame, FrameStats* stats) = 0; - - /** - Denoises a video frame. Every frame from the stream should be passed in. - Has a fixed-point implementation. - - \param[in,out] frame - Pointer to the video frame. - - \return The number of modified pixels on success, -1 on failure. - */ - virtual int32_t Denoising(I420VideoFrame* frame) = 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 - */ - virtual int32_t BrightnessDetection(const I420VideoFrame& 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. - */ - - /** - Enable/disable temporal decimation - - \param[in] enable when true, temporal decimation is enabled - */ - virtual void EnableTemporalDecimation(bool enable) = 0; - - /** - Set target resolution - - \param[in] width - Target width - - \param[in] height - Target height - - \param[in] frameRate - Target frameRate - - \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 frameRate) = 0; - - /** - Set max frame rate - \param[in] maxFrameRate: maximum frame rate (limited to native frame rate) - - \return VPM_OK on success, a negative value on error (see error codes) - */ - virtual int32_t SetMaxFrameRate(uint32_t maxFrameRate) = 0; - - /** - Get decimated(target) frame rate - */ - virtual uint32_t DecimatedFrameRate() = 0; - - /** - Get decimated(target) frame width - */ - virtual uint32_t DecimatedWidth() const = 0; - - /** - Get decimated(target) frame height - */ - virtual uint32_t DecimatedHeight() const = 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] resamplingMode - Set resampling mode (a member of VideoFrameResampling) - */ - virtual void SetInputFrameResampleMode(VideoFrameResampling - resamplingMode) = 0; - - /** - Get Processed (decimated) frame - - \param[in] frame pointer to the video frame. - \param[in] processedFrame pointer (double) to the processed frame. If no - processing is required, processedFrame will be NULL. - - \return VPM_OK on success, a negative value on error (see error codes) - */ - virtual int32_t PreprocessFrame(const I420VideoFrame& frame, - I420VideoFrame** processedFrame) = 0; - - /** - Return content metrics for the last processed frame - */ - virtual VideoContentMetrics* ContentMetrics() const = 0 ; - - /** - Enable content analysis - */ - virtual void EnableContentAnalysis(bool enable) = 0; +class VideoProcessingModule : public Module { + 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. }; -} // namespace + /** + Specifies the warning types returned by BrightnessDetection(). + */ + enum BrightnessWarning { + kNoWarning, // Frame has acceptable brightness. + kDarkWarning, // Frame is too dark. + kBrightWarning // Frame is too bright. + }; -#endif + /* + Creates a VPM object. + + \param[in] id + Unique identifier of this object. + + \return Pointer to a VPM object. + */ + static VideoProcessingModule* Create(int32_t id); + + /** + Destroys a VPM object. + + \param[in] module + Pointer to the VPM object to destroy. + */ + static void Destroy(VideoProcessingModule* module); + + /** + Not supported. + */ + virtual int32_t TimeUntilNextProcess() { return -1; } + + /** + Not supported. + */ + virtual int32_t Process() { 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 I420VideoFrame& 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. + */ + 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); + + /** + Enhances the color of an image through a constant mapping. Only the + chrominance is altered. Has a fixed-point implementation. + + \param[in,out] frame + Pointer to the video frame. + */ + static int32_t ColorEnhancement(I420VideoFrame* frame); + + /** + Increases/decreases the luminance value. + + \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(I420VideoFrame* 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. + */ + virtual int32_t Deflickering(I420VideoFrame* frame, FrameStats* stats) = 0; + + /** + Denoises a video frame. Every frame from the stream should be passed in. + Has a fixed-point implementation. + + \param[in,out] frame + Pointer to the video frame. + + \return The number of modified pixels on success, -1 on failure. + */ + virtual int32_t Denoising(I420VideoFrame* frame) = 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 + */ + virtual int32_t BrightnessDetection(const I420VideoFrame& 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. + */ + + /** + Enable/disable temporal decimation + + \param[in] enable when true, temporal decimation is enabled + */ + 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; + + /** + Set max frame rate + \param[in] max_frame_rate: maximum frame rate (limited to native frame rate) + + \return VPM_OK on success, a negative value on error (see error codes) + */ + virtual int32_t SetMaxFramerate(uint32_t max_frame_rate) = 0; + + /** + Get decimated(target) frame rate + */ + virtual uint32_t Decimatedframe_rate() = 0; + + /** + Get decimated(target) frame width + */ + virtual uint32_t DecimatedWidth() const = 0; + + /** + Get decimated(target) frame height + */ + virtual uint32_t DecimatedHeight() const = 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 I420VideoFrame& frame, + I420VideoFrame** processed_frame) = 0; + + /** + Return content metrics for the last processed frame + */ + virtual VideoContentMetrics* ContentMetrics() const = 0 ; + + /** + Enable content analysis + */ + virtual void EnableContentAnalysis(bool enable) = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_INTERFACE_VIDEO_PROCESSING_H diff --git a/webrtc/modules/video_processing/main/interface/video_processing_defines.h b/webrtc/modules/video_processing/main/interface/video_processing_defines.h index 7a3536c72..93a065896 100644 --- a/webrtc/modules/video_processing/main/interface/video_processing_defines.h +++ b/webrtc/modules/video_processing/main/interface/video_processing_defines.h @@ -29,15 +29,13 @@ namespace webrtc { #define VPM_UNINITIALIZED -5 #define VPM_UNIMPLEMENTED -6 -enum VideoFrameResampling -{ - // TODO: Do we still need crop/pad? - kNoRescaling, // disables rescaling - kFastRescaling, // point - kBiLinear, // bi-linear interpolation - kBox, // Box inteprolation +enum VideoFrameResampling { + kNoRescaling, // Disables rescaling. + kFastRescaling, // Point filter. + kBiLinear, // Bi-linear interpolation. + kBox, // Box inteprolation. }; -} // namespace +} // namespace webrtc -#endif +#endif // WEBRTC_MODULES_INTERFACE_VIDEO_PROCESSING_DEFINES_H diff --git a/webrtc/modules/video_processing/main/source/brighten.cc b/webrtc/modules/video_processing/main/source/brighten.cc index 8fa23c275..ffabbf7ff 100644 --- a/webrtc/modules/video_processing/main/source/brighten.cc +++ b/webrtc/modules/video_processing/main/source/brighten.cc @@ -31,19 +31,19 @@ int32_t Brighten(I420VideoFrame* frame, int delta) { return VPM_PARAMETER_ERROR; } - int numPixels = frame->width() * frame->height(); + int num_pixels = frame->width() * frame->height(); - int lookUp[256]; + int look_up[256]; for (int i = 0; i < 256; i++) { int val = i + delta; - lookUp[i] = ((((val < 0) ? 0 : val) > 255) ? 255 : val); + look_up[i] = ((((val < 0) ? 0 : val) > 255) ? 255 : val); } - uint8_t* tempPtr = frame->buffer(kYPlane); + uint8_t* temp_ptr = frame->buffer(kYPlane); - for (int i = 0; i < numPixels; i++) { - *tempPtr = static_cast(lookUp[*tempPtr]); - tempPtr++; + for (int i = 0; i < num_pixels; i++) { + *temp_ptr = static_cast(look_up[*temp_ptr]); + temp_ptr++; } return VPM_OK; } diff --git a/webrtc/modules/video_processing/main/source/brightness_detection.cc b/webrtc/modules/video_processing/main/source/brightness_detection.cc index 1e7e939db..8817bac43 100644 --- a/webrtc/modules/video_processing/main/source/brightness_detection.cc +++ b/webrtc/modules/video_processing/main/source/brightness_detection.cc @@ -17,180 +17,128 @@ namespace webrtc { VPMBrightnessDetection::VPMBrightnessDetection() : - _id(0) -{ - Reset(); + id_(0) { + Reset(); } -VPMBrightnessDetection::~VPMBrightnessDetection() -{ +VPMBrightnessDetection::~VPMBrightnessDetection() {} + +int32_t VPMBrightnessDetection::ChangeUniqueId(const int32_t id) { + id_ = id; + return VPM_OK; } -int32_t -VPMBrightnessDetection::ChangeUniqueId(const int32_t id) -{ - _id = id; - return VPM_OK; +void VPMBrightnessDetection::Reset() { + frame_cnt_bright_ = 0; + frame_cnt_dark_ = 0; } -void -VPMBrightnessDetection::Reset() -{ - _frameCntBright = 0; - _frameCntDark = 0; -} +int32_t VPMBrightnessDetection::ProcessFrame( + const I420VideoFrame& frame, + const VideoProcessingModule::FrameStats& stats) { + if (frame.IsZeroSize()) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "Null frame pointer"); + return VPM_PARAMETER_ERROR; + } + int width = frame.width(); + int height = frame.height(); -int32_t -VPMBrightnessDetection::ProcessFrame(const I420VideoFrame& frame, - const VideoProcessingModule::FrameStats& - stats) -{ - if (frame.IsZeroSize()) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "Null frame pointer"); - return VPM_PARAMETER_ERROR; - } - int width = frame.width(); - int height = frame.height(); + if (!VideoProcessingModule::ValidFrameStats(stats)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "Invalid frame stats"); + return VPM_PARAMETER_ERROR; + } - if (!VideoProcessingModule::ValidFrameStats(stats)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "Invalid frame stats"); - return VPM_PARAMETER_ERROR; - } + const uint8_t frame_cnt_alarm = 2; - const uint8_t frameCntAlarm = 2; + // Get proportion in lowest bins. + uint8_t low_th = 20; + float prop_low = 0; + for (uint32_t i = 0; i < low_th; i++) { + prop_low += stats.hist[i]; + } +prop_low /= stats.num_pixels; - // Get proportion in lowest bins - uint8_t lowTh = 20; - float propLow = 0; - for (uint32_t i = 0; i < lowTh; i++) - { - propLow += stats.hist[i]; - } - propLow /= stats.numPixels; + // Get proportion in highest bins. + unsigned char high_th = 230; + float prop_high = 0; + for (uint32_t i = high_th; i < 256; i++) { + prop_high += stats.hist[i]; + } + prop_high /= stats.num_pixels; - // Get proportion in highest bins - unsigned char highTh = 230; - float propHigh = 0; - for (uint32_t i = highTh; i < 256; i++) - { - propHigh += stats.hist[i]; - } - propHigh /= stats.numPixels; + if (prop_high < 0.4) { + if (stats.mean < 90 || stats.mean > 170) { + // 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)) { + int row = h*width; + for (int w = 0; w < width; w += (1 << stats.subSamplWidth)) { + std_y += (buffer[w + row] - stats.mean) * (buffer[w + row] - + stats.mean); + } + } + std_y = sqrt(std_y / stats.num_pixels); - if(propHigh < 0.4) - { - if (stats.mean < 90 || stats.mean > 170) - { - // Standard deviation of Y - const uint8_t* buffer = frame.buffer(kYPlane); - float stdY = 0; - for (int h = 0; h < height; h += (1 << stats.subSamplHeight)) - { - int row = h*width; - for (int w = 0; w < width; w += (1 << stats.subSamplWidth)) - { - stdY += (buffer[w + row] - stats.mean) * (buffer[w + row] - - stats.mean); - } - } - stdY = sqrt(stdY / stats.numPixels); - - // Get percentiles - uint32_t sum = 0; - uint32_t medianY = 140; - uint32_t perc05 = 0; - uint32_t perc95 = 255; - float posPerc05 = stats.numPixels * 0.05f; - float posMedian = stats.numPixels * 0.5f; - float posPerc95 = stats.numPixels * 0.95f; - for (uint32_t i = 0; i < 256; i++) - { - sum += stats.hist[i]; - - if (sum < posPerc05) - { - perc05 = i; // 5th perc - } - if (sum < posMedian) - { - medianY = i; // 50th perc - } - if (sum < posPerc95) - { - perc95 = i; // 95th perc - } - else - { - break; - } - } - - // Check if image is too dark - if ((stdY < 55) && (perc05 < 50)) - { - if (medianY < 60 || stats.mean < 80 || perc95 < 130 || - propLow > 0.20) - { - _frameCntDark++; - } - else - { - _frameCntDark = 0; - } - } - else - { - _frameCntDark = 0; - } - - // Check if image is too bright - if ((stdY < 52) && (perc95 > 200) && (medianY > 160)) - { - if (medianY > 185 || stats.mean > 185 || perc05 > 140 || - propHigh > 0.25) - { - _frameCntBright++; - } - else - { - _frameCntBright = 0; - } - } - else - { - _frameCntBright = 0; - } - - } + // Get percentiles. + uint32_t sum = 0; + uint32_t median_y = 140; + uint32_t perc05 = 0; + uint32_t perc95 = 255; + float pos_perc05 = stats.num_pixels * 0.05f; + float pos_median = stats.num_pixels * 0.5f; + float posPerc95 = stats.num_pixels * 0.95f; + for (uint32_t i = 0; i < 256; i++) { + sum += stats.hist[i]; + if (sum < pos_perc05) perc05 = i; // 5th perc. + if (sum < pos_median) median_y = i; // 50th perc. + if (sum < posPerc95) + perc95 = i; // 95th perc. else - { - _frameCntDark = 0; - _frameCntBright = 0; + break; + } + + // Check if image is too dark + if ((std_y < 55) && (perc05 < 50)) { + if (median_y < 60 || stats.mean < 80 || perc95 < 130 || + prop_low > 0.20) { + frame_cnt_dark_++; + } else { + frame_cnt_dark_ = 0; + } + } else { + frame_cnt_dark_ = 0; } - } - else - { - _frameCntBright++; - _frameCntDark = 0; - } - - if (_frameCntDark > frameCntAlarm) - { - return VideoProcessingModule::kDarkWarning; - } - else if (_frameCntBright > frameCntAlarm) - { - return VideoProcessingModule::kBrightWarning; - } - else - { - return VideoProcessingModule::kNoWarning; + // Check if image is too bright + if ((std_y < 52) && (perc95 > 200) && (median_y > 160)) { + if (median_y > 185 || stats.mean > 185 || perc05 > 140 || + prop_high > 0.25) { + frame_cnt_bright_++; + } else { + frame_cnt_bright_ = 0; + } + } else { + frame_cnt_bright_ = 0; + } + } else { + frame_cnt_dark_ = 0; + frame_cnt_bright_ = 0; } + } else { + frame_cnt_bright_++; + frame_cnt_dark_ = 0; + } + + if (frame_cnt_dark_ > frame_cnt_alarm) { + return VideoProcessingModule::kDarkWarning; + } else if (frame_cnt_bright_ > frame_cnt_alarm) { + return VideoProcessingModule::kBrightWarning; + } else { + return VideoProcessingModule::kNoWarning; + } } -} // namespace +} // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/brightness_detection.h b/webrtc/modules/video_processing/main/source/brightness_detection.h index 22248d60c..dcb366b8b 100644 --- a/webrtc/modules/video_processing/main/source/brightness_detection.h +++ b/webrtc/modules/video_processing/main/source/brightness_detection.h @@ -11,34 +11,30 @@ /* * brightness_detection.h */ -#ifndef VPM_BRIGHTNESS_DETECTION_H -#define VPM_BRIGHTNESS_DETECTION_H - +#ifndef MODULES_VIDEO_PROCESSING_MAIN_SOURCE_BRIGHTNESS_DETECTION_H +#define MODULES_VIDEO_PROCESSING_MAIN_SOURCE_BRIGHTNESS_DETECTION_H #include "webrtc/modules/video_processing/main/interface/video_processing.h" #include "webrtc/typedefs.h" namespace webrtc { -class VPMBrightnessDetection -{ -public: - VPMBrightnessDetection(); - ~VPMBrightnessDetection(); +class VPMBrightnessDetection { + public: + VPMBrightnessDetection(); + ~VPMBrightnessDetection(); + int32_t ChangeUniqueId(int32_t id); - int32_t ChangeUniqueId(int32_t id); + void Reset(); + int32_t ProcessFrame(const I420VideoFrame& frame, + const VideoProcessingModule::FrameStats& stats); - void Reset(); + private: + int32_t id_; - int32_t ProcessFrame(const I420VideoFrame& frame, - const VideoProcessingModule::FrameStats& stats); - -private: - int32_t _id; - - uint32_t _frameCntBright; - uint32_t _frameCntDark; + uint32_t frame_cnt_bright_; + uint32_t frame_cnt_dark_; }; -} // namespace +} // namespace webrtc -#endif // VPM_BRIGHTNESS_DETECTION_H +#endif // MODULES_VIDEO_PROCESSING_MAIN_SOURCE_BRIGHTNESS_DETECTION_H diff --git a/webrtc/modules/video_processing/main/source/color_enhancement.cc b/webrtc/modules/video_processing/main/source/color_enhancement.cc index 87a594b61..bbe23793a 100644 --- a/webrtc/modules/video_processing/main/source/color_enhancement.cc +++ b/webrtc/modules/video_processing/main/source/color_enhancement.cc @@ -16,50 +16,42 @@ namespace webrtc { -namespace VideoProcessing -{ - int32_t - ColorEnhancement(I420VideoFrame* frame) - { - assert(frame); - // pointers to U and V color pixels - uint8_t* ptrU; - uint8_t* ptrV; - uint8_t tempChroma; +namespace VideoProcessing { + int32_t ColorEnhancement(I420VideoFrame* frame) { + assert(frame); + // Pointers to U and V color pixels. + uint8_t* ptr_u; + uint8_t* ptr_v; + uint8_t temp_chroma; + if (frame->IsZeroSize()) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, + -1, "Null frame pointer"); + return VPM_GENERAL_ERROR; + } - if (frame->IsZeroSize()) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, - -1, "Null frame pointer"); - return VPM_GENERAL_ERROR; - } + if (frame->width() == 0 || frame->height() == 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, + -1, "Invalid frame size"); + return VPM_GENERAL_ERROR; + } - if (frame->width() == 0 || frame->height() == 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, - -1, "Invalid frame size"); - return VPM_GENERAL_ERROR; - } + // set pointers to first U and V pixels (skip luminance) + ptr_u = frame->buffer(kUPlane); + ptr_v = frame->buffer(kVPlane); + int size_uv = ((frame->width() + 1) / 2) * ((frame->height() + 1) / 2); - // set pointers to first U and V pixels (skip luminance) - ptrU = frame->buffer(kUPlane); - ptrV = frame->buffer(kVPlane); - int size_uv = ((frame->width() + 1) / 2) * ((frame->height() + 1) / 2); + // Loop through all chrominance pixels and modify color + for (int ix = 0; ix < size_uv; ix++) { + temp_chroma = colorTable[*ptr_u][*ptr_v]; + *ptr_v = colorTable[*ptr_v][*ptr_u]; + *ptr_u = temp_chroma; - // loop through all chrominance pixels and modify color - for (int ix = 0; ix < size_uv; ix++) - { - tempChroma = colorTable[*ptrU][*ptrV]; - *ptrV = colorTable[*ptrV][*ptrU]; - *ptrU = tempChroma; - - // increment pointers - ptrU++; - ptrV++; - } - return VPM_OK; - } + ptr_u++; + ptr_v++; + } + return VPM_OK; +} -} // namespace +} // namespace VideoProcessing } // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/color_enhancement.h b/webrtc/modules/video_processing/main/source/color_enhancement.h index f8baaa770..9bf4ee984 100644 --- a/webrtc/modules/video_processing/main/source/color_enhancement.h +++ b/webrtc/modules/video_processing/main/source/color_enhancement.h @@ -11,19 +11,18 @@ /* * color_enhancement.h */ -#ifndef VPM_COLOR_ENHANCEMENT_H -#define VPM_COLOR_ENHANCEMENT_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_COLOR_ENHANCEMENT_H +#define WEBRTC_MODULES_VIDEO_PROCESSING_COLOR_ENHANCEMENT_H #include "webrtc/modules/video_processing/main/interface/video_processing.h" #include "webrtc/typedefs.h" namespace webrtc { -namespace VideoProcessing -{ - int32_t ColorEnhancement(I420VideoFrame* frame); +namespace VideoProcessing { + int32_t ColorEnhancement(I420VideoFrame* frame); } -} // namespace +} // namespace webrtc -#endif // VPM_COLOR_ENHANCEMENT_H +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_COLOR_ENHANCEMENT_H diff --git a/webrtc/modules/video_processing/main/source/color_enhancement_private.h b/webrtc/modules/video_processing/main/source/color_enhancement_private.h index d4aadfcab..0b4891572 100644 --- a/webrtc/modules/video_processing/main/source/color_enhancement_private.h +++ b/webrtc/modules/video_processing/main/source/color_enhancement_private.h @@ -1,3 +1,13 @@ +/* + * 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 VPM_COLOR_ENHANCEMENT_PRIVATE_H #define VPM_COLOR_ENHANCEMENT_PRIVATE_H @@ -270,4 +280,4 @@ static const uint8_t colorTable[256][256] = { } // namespace -#endif // VPM_COLOR_ENHANCEMENT_PRIVATE_H +#endif // VPM_COLOR_ENHANCEMENT_PRIVATE_H \ No newline at end of file diff --git a/webrtc/modules/video_processing/main/source/content_analysis.cc b/webrtc/modules/video_processing/main/source/content_analysis.cc index a500991d5..25fcb5431 100644 --- a/webrtc/modules/video_processing/main/source/content_analysis.cc +++ b/webrtc/modules/video_processing/main/source/content_analysis.cc @@ -17,229 +17,185 @@ namespace webrtc { -VPMContentAnalysis::VPMContentAnalysis(bool runtime_cpu_detection): -_origFrame(NULL), -_prevFrame(NULL), -_width(0), -_height(0), -_skipNum(1), -_border(8), -_motionMagnitude(0.0f), -_spatialPredErr(0.0f), -_spatialPredErrH(0.0f), -_spatialPredErrV(0.0f), -_firstFrame(true), -_CAInit(false), -_cMetrics(NULL) -{ - ComputeSpatialMetrics = &VPMContentAnalysis::ComputeSpatialMetrics_C; - TemporalDiffMetric = &VPMContentAnalysis::TemporalDiffMetric_C; +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 (runtime_cpu_detection) { #if defined(WEBRTC_ARCH_X86_FAMILY) - if (WebRtc_GetCPUInfo(kSSE2)) - { - ComputeSpatialMetrics = - &VPMContentAnalysis::ComputeSpatialMetrics_SSE2; - TemporalDiffMetric = &VPMContentAnalysis::TemporalDiffMetric_SSE2; - } + if (WebRtc_GetCPUInfo(kSSE2)) { + ComputeSpatialMetrics = &VPMContentAnalysis::ComputeSpatialMetrics_SSE2; + TemporalDiffMetric = &VPMContentAnalysis::TemporalDiffMetric_SSE2; + } #endif - } - - Release(); + } + Release(); } -VPMContentAnalysis::~VPMContentAnalysis() -{ - Release(); +VPMContentAnalysis::~VPMContentAnalysis() { + Release(); } -VideoContentMetrics* -VPMContentAnalysis::ComputeContentMetrics(const I420VideoFrame& inputFrame) -{ - if (inputFrame.IsZeroSize()) - { - return NULL; - } +VideoContentMetrics* VPMContentAnalysis::ComputeContentMetrics( + const I420VideoFrame& 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. - _origFrame = inputFrame.buffer(kYPlane); + // 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 spatial metrics: 3 spatial prediction errors. + (this->*ComputeSpatialMetrics)(); - // compute motion metrics - if (_firstFrame == false) - ComputeMotionMetrics(); + // Compute motion metrics + if (first_frame_ == false) + ComputeMotionMetrics(); - // saving current frame as previous one: Y only - memcpy(_prevFrame, _origFrame, _width * _height); + // Saving current frame as previous one: Y only. + memcpy(prev_frame_, orig_frame_, width_ * height_); - _firstFrame = false; - _CAInit = true; + first_frame_ = false; + ca_Init_ = true; - return ContentMetrics(); + return ContentMetrics(); } -int32_t -VPMContentAnalysis::Release() -{ - if (_cMetrics != NULL) - { - delete _cMetrics; - _cMetrics = NULL; - } +int32_t VPMContentAnalysis::Release() { + if (content_metrics_ != NULL) { + delete content_metrics_; + content_metrics_ = NULL; + } - if (_prevFrame != NULL) - { - delete [] _prevFrame; - _prevFrame = NULL; - } + if (prev_frame_ != NULL) { + delete [] prev_frame_; + prev_frame_ = NULL; + } - _width = 0; - _height = 0; - _firstFrame = true; + width_ = 0; + height_ = 0; + first_frame_ = true; - return VPM_OK; + return VPM_OK; } -int32_t -VPMContentAnalysis::Initialize(int width, int height) -{ - _width = width; - _height = height; - _firstFrame = true; +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. - _skipNum = 1; + // 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) ) - { - _skipNum = 2; - } - // use skipNum = 4 for FULLL_HD images - if ( (_height >= 1080) && (_width >= 1920) ) - { - _skipNum = 4; - } + // 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 (_cMetrics != NULL) - { - delete _cMetrics; - } + if (content_metrics_ != NULL) { + delete content_metrics_; + } - if (_prevFrame != NULL) - { - delete [] _prevFrame; - } + 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) - { - _CAInit = false; - return VPM_PARAMETER_ERROR; - } + // 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; + } - _cMetrics = new VideoContentMetrics(); - if (_cMetrics == NULL) - { - return VPM_MEMORY; - } + content_metrics_ = new VideoContentMetrics(); + if (content_metrics_ == NULL) { + return VPM_MEMORY; + } - _prevFrame = new uint8_t[_width * _height] ; // Y only - if (_prevFrame == NULL) - { - return VPM_MEMORY; - } + prev_frame_ = new uint8_t[width_ * height_]; // Y only. + if (prev_frame_ == NULL) return VPM_MEMORY; - return VPM_OK; + 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; +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; +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 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_; - uint32_t numPixels = 0; // counter for # of pixels + 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; - const int width_end = ((_width - 2*_border) & -16) + _border; + uint8_t currPixel = orig_frame_[ssn]; + uint8_t prevPixel = prev_frame_[ssn]; - for(int i = _border; i < sizei - _border; i += _skipNum) - { - for(int j = _border; j < width_end; j++) - { - numPixels += 1; - int ssn = i * sizej + j; - - uint8_t currPixel = _origFrame[ssn]; - uint8_t prevPixel = _prevFrame[ssn]; - - tempDiffSum += (uint32_t) - abs((int16_t)(currPixel - prevPixel)); - pixelSum += (uint32_t) currPixel; - pixelSqSum += (uint64_t) (currPixel * currPixel); - } + tempDiffSum += (uint32_t)abs((int16_t)(currPixel - prevPixel)); + pixelSum += (uint32_t) currPixel; + pixelSqSum += (uint64_t) (currPixel * currPixel); } + } - // default - _motionMagnitude = 0.0f; + // Default. + motion_magnitude_ = 0.0f; - if (tempDiffSum == 0) - { - return VPM_OK; - } + if (tempDiffSum == 0) return VPM_OK; - // normalize over all pixels - float const tempDiffAvg = (float)tempDiffSum / (float)(numPixels); - float const pixelSumAvg = (float)pixelSum / (float)(numPixels); - float const pixelSqSumAvg = (float)pixelSqSum / (float)(numPixels); - float contrast = pixelSqSumAvg - (pixelSumAvg * pixelSumAvg); - - if (contrast > 0.0) - { - contrast = sqrt(contrast); - _motionMagnitude = tempDiffAvg/contrast; - } - - return VPM_OK; + // Normalize over all pixels. + float const tempDiffAvg = (float)tempDiffSum / (float)(num_pixels); + float const pixelSumAvg = (float)pixelSum / (float)(num_pixels); + float const pixelSqSumAvg = (float)pixelSqSum / (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: @@ -249,88 +205,71 @@ VPMContentAnalysis::TemporalDiffMetric_C() // 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() -{ - //size of original frame - const int sizei = _height; - const int sizej = _width; +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; + // 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; + 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; + // 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 += _skipNum) - { - for(int j = _border; j < width_end; j++) - { + 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 - 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; - uint16_t refPixel1 = _origFrame[ssn1] << 1; - uint16_t refPixel2 = _origFrame[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]; - uint8_t bottPixel = _origFrame[ssn2]; - uint8_t topPixel = _origFrame[ssn3]; - uint8_t rightPixel = _origFrame[ssn4]; - uint8_t leftPixel = _origFrame[ssn5]; - - spatialErrSum += (uint32_t) abs((int16_t)(refPixel2 - - (uint16_t)(bottPixel + topPixel - + leftPixel + rightPixel))); - spatialErrVSum += (uint32_t) abs((int16_t)(refPixel1 - - (uint16_t)(bottPixel + topPixel))); - spatialErrHSum += (uint32_t) abs((int16_t)(refPixel1 - - (uint16_t)(leftPixel + rightPixel))); - - pixelMSA += _origFrame[ssn1]; - } + spatialErrSum += (uint32_t) abs((int16_t)(refPixel2 + - (uint16_t)(bottPixel + topPixel + leftPixel + rightPixel))); + spatialErrVSum += (uint32_t) abs((int16_t)(refPixel1 + - (uint16_t)(bottPixel + topPixel))); + spatialErrHSum += (uint32_t) abs((int16_t)(refPixel1 + - (uint16_t)(leftPixel + rightPixel))); + pixelMSA += orig_frame_[ssn1]; } + } - // normalize over all pixels - const float spatialErr = (float)(spatialErrSum >> 2); - const float spatialErrH = (float)(spatialErrHSum >> 1); - const float spatialErrV = (float)(spatialErrVSum >> 1); - const float norm = (float)pixelMSA; + // Normalize over all pixels. + const float spatialErr = (float)(spatialErrSum >> 2); + const float spatialErrH = (float)(spatialErrHSum >> 1); + const float spatialErrV = (float)(spatialErrVSum >> 1); + const float norm = (float)pixelMSA; - // 2X2: - _spatialPredErr = spatialErr / norm; - - // 1X2: - _spatialPredErrH = spatialErrH / norm; - - // 2X1: - _spatialPredErrV = spatialErrV / norm; - - return VPM_OK; + // 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 (_CAInit == false) - { - return NULL; - } +VideoContentMetrics* VPMContentAnalysis::ContentMetrics() { + if (ca_Init_ == false) return NULL; - _cMetrics->spatial_pred_err = _spatialPredErr; - _cMetrics->spatial_pred_err_h = _spatialPredErrH; - _cMetrics->spatial_pred_err_v = _spatialPredErrV; - // Motion metric: normalized temporal difference (MAD) - _cMetrics->motion_magnitude = _motionMagnitude; - - return _cMetrics; + 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 +} // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/content_analysis.h b/webrtc/modules/video_processing/main/source/content_analysis.h index a1e485f1c..54b5b45c4 100644 --- a/webrtc/modules/video_processing/main/source/content_analysis.h +++ b/webrtc/modules/video_processing/main/source/content_analysis.h @@ -8,8 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef VPM_CONTENT_ANALYSIS_H -#define VPM_CONTENT_ANALYSIS_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_CONTENT_ANALYSIS_H +#define WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_CONTENT_ANALYSIS_H #include "webrtc/common_video/interface/i420_video_frame.h" #include "webrtc/modules/interface/module_common_types.h" @@ -18,75 +18,71 @@ namespace webrtc { -class VPMContentAnalysis -{ -public: - // When |runtime_cpu_detection| is true, runtime selection of an optimized - // code path is allowed. - VPMContentAnalysis(bool runtime_cpu_detection); - ~VPMContentAnalysis(); +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); + // 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 I420VideoFrame& - inputFrame); + // 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 I420VideoFrame& + inputFrame); - // Release all allocated memory - // Output: 0 if OK, negative value upon error - int32_t Release(); + // Release all allocated memory + // Output: 0 if OK, negative value upon error + int32_t Release(); -private: + private: + // return motion metrics + VideoContentMetrics* ContentMetrics(); - // return motion metrics - VideoContentMetrics* ContentMetrics(); + // Normalized temporal difference metric: for motion magnitude + typedef int32_t (VPMContentAnalysis::*TemporalDiffMetricFunc)(); + TemporalDiffMetricFunc TemporalDiffMetric; + int32_t TemporalDiffMetric_C(); - // 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(); - // 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(); + // 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(); + int32_t ComputeSpatialMetrics_SSE2(); + int32_t TemporalDiffMetric_SSE2(); #endif - const uint8_t* _origFrame; - uint8_t* _prevFrame; - int _width; - int _height; - int _skipNum; - int _border; + 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 _motionMagnitude; // motion class - float _spatialPredErr; // spatial class - float _spatialPredErrH; // spatial class - float _spatialPredErrV; // spatial class - bool _firstFrame; - bool _CAInit; + // 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* _cMetrics; + VideoContentMetrics* content_metrics_; +}; -}; // end of VPMContentAnalysis class definition +} // namespace webrtc -} // namespace - -#endif +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_CONTENT_ANALYSIS_H diff --git a/webrtc/modules/video_processing/main/source/content_analysis_sse2.cc b/webrtc/modules/video_processing/main/source/content_analysis_sse2.cc index 565312bc0..17b64ff28 100644 --- a/webrtc/modules/video_processing/main/source/content_analysis_sse2.cc +++ b/webrtc/modules/video_processing/main/source/content_analysis_sse2.cc @@ -15,284 +15,248 @@ namespace webrtc { -int32_t -VPMContentAnalysis::TemporalDiffMetric_SSE2() -{ - uint32_t numPixels = 0; // counter for # of pixels +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 uint8_t* imgBufO = _origFrame + _border*_width + _border; - const uint8_t* imgBufP = _prevFrame + _border*_width + _border; + const int32_t width_end = ((width_ - 2*border_) & -16) + 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(); - __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(); - for(uint16_t i = 0; i < (_height - 2*_border); i += _skipNum) - { - __m128i sqsum_32 = _mm_setzero_si128(); + const uint8_t *lineO = imgBufO; + const uint8_t *lineP = imgBufP; - 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)); - // 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; - lineO += 16; - lineP += 16; + // Abs pixel difference between frames. + sad_64 = _mm_add_epi64 (sad_64, _mm_sad_epu8(o, p)); - // 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)); - // 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); - // 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); - 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 * _skipNum; - imgBufP += _width * _skipNum; - numPixels += (width_end - _border); + sqsum_32 = _mm_add_epi32(sqsum_32, sqsum_32_lo); + sqsum_32 = _mm_add_epi32(sqsum_32, sqsum_32_hi); } - __m128i sad_final_128; - __m128i sum_final_128; - __m128i sqsum_final_128; + // 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))); - // 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); + imgBufO += width_ * skip_num_; + imgBufP += width_ * skip_num_; + num_pixels += (width_end - border_); + } - uint64_t *sad_final_64 = - reinterpret_cast(&sad_final_128); - uint64_t *sum_final_64 = - reinterpret_cast(&sum_final_128); - uint64_t *sqsum_final_64 = - reinterpret_cast(&sqsum_final_128); + __m128i sad_final_128; + __m128i sum_final_128; + __m128i 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]; + // 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); - // default - _motionMagnitude = 0.0f; + uint64_t *sad_final_64 = reinterpret_cast(&sad_final_128); + uint64_t *sum_final_64 = reinterpret_cast(&sum_final_128); + uint64_t *sqsum_final_64 = reinterpret_cast(&sqsum_final_128); - if (tempDiffSum == 0) - { - return VPM_OK; - } + 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]; - // normalize over all pixels - const float tempDiffAvg = (float)tempDiffSum / (float)(numPixels); - const float pixelSumAvg = (float)pixelSum / (float)(numPixels); - const float pixelSqSumAvg = (float)pixelSqSum / (float)(numPixels); - float contrast = pixelSqSumAvg - (pixelSumAvg * pixelSumAvg); + // Default. + motion_magnitude_ = 0.0f; - if (contrast > 0.0) - { - contrast = sqrt(contrast); - _motionMagnitude = tempDiffAvg/contrast; - } + if (tempDiffSum == 0) return VPM_OK; - return VPM_OK; + // Normalize over all pixels. + const float tempDiffAvg = (float)tempDiffSum / (float)(num_pixels); + const float pixelSumAvg = (float)pixelSum / (float)(num_pixels); + const float pixelSqSumAvg = (float)pixelSqSum / (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 = _origFrame + _border*_width; - const int32_t width_end = ((_width - 2*_border) & -16) + _border; +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(); + __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. - // _skipNum is also used to reduce the number of rows - for(int32_t i = 0; i < (_height - 2*_border); i += _skipNum) - { - __m128i se_16 = _mm_setzero_si128(); - __m128i sev_16 = _mm_setzero_si128(); - __m128i seh_16 = _mm_setzero_si128(); - __m128i msa_16 = _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; + // 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)); + 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; + lineTop += 16; + lineCen += 16; + lineBot += 16; - // center pixel unpacked - __m128i clo = _mm_unpacklo_epi8(c,z); - __m128i chi = _mm_unpackhi_epi8(c,z); + // 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)); + // 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)); + // 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)); + // 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 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)); + 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 * _skipNum; + // 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))); } - __m128i se_128; - __m128i sev_128; - __m128i seh_128; - __m128i msa_128; + // 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))); - // 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))); + imgBuf += width_ * skip_num_; + } - uint64_t *se_64 = - reinterpret_cast(&se_128); - uint64_t *sev_64 = - reinterpret_cast(&sev_128); - uint64_t *seh_64 = - reinterpret_cast(&seh_128); - uint64_t *msa_64 = - reinterpret_cast(&msa_128); + __m128i se_128; + __m128i sev_128; + __m128i seh_128; + __m128i 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]; + // 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))); - // normalize over all pixels - const float spatialErr = (float)(spatialErrSum >> 2); - const float spatialErrH = (float)(spatialErrHSum >> 1); - const float spatialErrV = (float)(spatialErrVSum >> 1); - const float norm = (float)pixelMSA; + uint64_t *se_64 = reinterpret_cast(&se_128); + uint64_t *sev_64 = reinterpret_cast(&sev_128); + uint64_t *seh_64 = reinterpret_cast(&seh_128); + uint64_t *msa_64 = reinterpret_cast(&msa_128); - // 2X2: - _spatialPredErr = spatialErr / norm; + 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]; - // 1X2: - _spatialPredErrH = spatialErrH / norm; + // Normalize over all pixels. + const float spatialErr = (float)(spatialErrSum >> 2); + const float spatialErrH = (float)(spatialErrHSum >> 1); + const float spatialErrV = (float)(spatialErrVSum >> 1); + const float norm = (float)pixelMSA; - // 2X1: - _spatialPredErrV = spatialErrV / norm; + // 2X2: + spatial_pred_err_ = spatialErr / norm; + + // 1X2: + spatial_pred_err_h_ = spatialErrH / norm; + + // 2X1: + spatial_pred_err_v_ = spatialErrV / norm; return VPM_OK; } diff --git a/webrtc/modules/video_processing/main/source/deflickering.cc b/webrtc/modules/video_processing/main/source/deflickering.cc index a4b55c1c1..898fd80f4 100644 --- a/webrtc/modules/video_processing/main/source/deflickering.cc +++ b/webrtc/modules/video_processing/main/source/deflickering.cc @@ -20,431 +20,386 @@ namespace webrtc { // Detection constants -enum { kFrequencyDeviation = 39 }; // (Q4) Maximum allowed deviation for detection -enum { kMinFrequencyToDetect = 32 }; // (Q4) Minimum frequency that can be detected -enum { kNumFlickerBeforeDetect = 2 }; // Number of flickers before we accept detection -enum { kMeanValueScaling = 4 }; // (Q4) In power of 2 -enum { kZeroCrossingDeadzone = 10 }; // Deadzone region in terms of pixel values - -// Deflickering constants +// (Q4) Maximum allowed deviation for detection. +enum { kFrequencyDeviation = 39 }; +// (Q4) Minimum frequency that can be detected. +enum { kMinFrequencyToDetect = 32 }; +// Number of flickers before we accept detection +enum { kNumFlickerBeforeDetect = 2 }; +enum { kmean_valueScaling = 4 }; // (Q4) In power of 2 +// Dead-zone region in terms of pixel values +enum { kZeroCrossingDeadzone = 10 }; +// Deflickering constants. // Compute the quantiles over 1 / DownsamplingFactor of the image. enum { kDownsamplingFactor = 8 }; enum { kLog2OfDownsamplingFactor = 3 }; // To generate in Matlab: -// >> probUW16 = round(2^11 * [0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.97]); +// >> probUW16 = round(2^11 * +// [0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.97]); // >> fprintf('%d, ', probUW16) -// Resolution reduced to avoid overflow when multiplying with the (potentially) large -// number of pixels. -const uint16_t VPMDeflickering::_probUW16[kNumProbs] = - {102, 205, 410, 614, 819, 1024, 1229, 1434, 1638, 1843, 1946, 1987}; // +// 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}; // // To generate in Matlab: // >> numQuants = 14; maxOnlyLength = 5; -// >> weightUW16 = round(2^15 * [linspace(0.5, 1.0, numQuants - maxOnlyLength)]); +// >> weightUW16 = round(2^15 * +// [linspace(0.5, 1.0, numQuants - maxOnlyLength)]); // >> fprintf('%d, %d,\n ', weightUW16); -const uint16_t VPMDeflickering::_weightUW16[kNumQuants - kMaxOnlyLength] = +const uint16_t VPMDeflickering::weight_uw16_[kNumQuants - kMaxOnlyLength] = {16384, 18432, 20480, 22528, 24576, 26624, 28672, 30720, 32768}; // - -VPMDeflickering::VPMDeflickering() : - _id(0) -{ - Reset(); + +VPMDeflickering::VPMDeflickering() + : id_(0) { + Reset(); } -VPMDeflickering::~VPMDeflickering() -{ +VPMDeflickering::~VPMDeflickering() {} + +int32_t VPMDeflickering::ChangeUniqueId(const int32_t id) { + id_ = id; + return 0; } -int32_t -VPMDeflickering::ChangeUniqueId(const int32_t id) -{ - _id = id; +void VPMDeflickering::Reset() { + mean_buffer_length_ = 0; + detection_state_ = 0; + frame_rate_ = 0; + + memset(mean_buffer_, 0, sizeof(int32_t) * kMeanBufferLength); + memset(timestamp_buffer_, 0, sizeof(int32_t) * kMeanBufferLength); + + // Initialize the history with a uniformly distributed histogram. + quant_hist_uw8_[0][0] = 0; + quant_hist_uw8_[0][kNumQuants - 1] = 255; + for (int32_t i = 0; i < kNumProbs; i++) { + quant_hist_uw8_[0][i + 1] = static_cast((WEBRTC_SPL_UMUL_16_16( + prob_uw16_[i], 255) + (1 << 10)) >> 11); // Unsigned round. + } + + for (int32_t i = 1; i < kFrameHistory_size; i++) { + memcpy(quant_hist_uw8_[i], quant_hist_uw8_[0], + sizeof(uint8_t) * kNumQuants); + } +} + +int32_t VPMDeflickering::ProcessFrame(I420VideoFrame* frame, + VideoProcessingModule::FrameStats* stats) { + assert(frame); + uint32_t frame_memory; + uint8_t quant_uw8[kNumQuants]; + uint8_t maxquant_uw8[kNumQuants]; + uint8_t minquant_uw8[kNumQuants]; + uint16_t target_quant_uw16[kNumQuants]; + uint16_t increment_uw16; + uint8_t map_uw8[256]; + + uint16_t tmp_uw16; + uint32_t tmp_uw32; + int width = frame->width(); + int height = frame->height(); + + if (frame->IsZeroSize()) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "Null frame pointer"); + return VPM_GENERAL_ERROR; + } + + // Stricter height check due to subsampling size calculation below. + if (height < 2) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "Invalid frame size"); + return VPM_GENERAL_ERROR; + } + + if (!VideoProcessingModule::ValidFrameStats(*stats)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "Invalid frame stats"); + return VPM_GENERAL_ERROR; + } + + if (PreDetection(frame->timestamp(), *stats) == -1) return VPM_GENERAL_ERROR; + + // Flicker detection + int32_t det_flicker = DetectFlicker(); + if (det_flicker < 0) { + return VPM_GENERAL_ERROR; + } else if (det_flicker != 1) { return 0; -} + } -void -VPMDeflickering::Reset() -{ - _meanBufferLength = 0; - _detectionState = 0; - _frameRate = 0; + // Size of luminance component. + const uint32_t y_size = height * width; - memset(_meanBuffer, 0, sizeof(int32_t) * kMeanBufferLength); - memset(_timestampBuffer, 0, sizeof(int32_t) * kMeanBufferLength); + const uint32_t y_sub_size = width * (((height - 1) >> + kLog2OfDownsamplingFactor) + 1); + uint8_t* y_sorted = new uint8_t[y_sub_size]; + uint32_t sort_row_idx = 0; + for (int i = 0; i < height; i += kDownsamplingFactor) { + memcpy(y_sorted + sort_row_idx * width, + frame->buffer(kYPlane) + i * width, width); + sort_row_idx++; + } - // Initialize the history with a uniformly distributed histogram - _quantHistUW8[0][0] = 0; - _quantHistUW8[0][kNumQuants - 1] = 255; - for (int32_t i = 0; i < kNumProbs; i++) - { - _quantHistUW8[0][i + 1] = static_cast((WEBRTC_SPL_UMUL_16_16( - _probUW16[i], 255) + (1 << 10)) >> 11); // Unsigned round. + webrtc::Sort(y_sorted, y_sub_size, webrtc::TYPE_UWord8); + + uint32_t prob_idx_uw32 = 0; + quant_uw8[0] = 0; + quant_uw8[kNumQuants - 1] = 255; + + // Ensure we won't get an overflow below. + // In practice, the number of subsampled pixels will not become this large. + if (y_sub_size > (1 << 21) - 1) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "Subsampled number of pixels too large"); + return -1; + } + + for (int32_t i = 0; i < kNumProbs; i++) { + // . + prob_idx_uw32 = WEBRTC_SPL_UMUL_32_16(y_sub_size, prob_uw16_[i]) >> 11; + quant_uw8[i + 1] = y_sorted[prob_idx_uw32]; + } + + delete [] y_sorted; + y_sorted = NULL; + + // Shift history for new frame. + memmove(quant_hist_uw8_[1], quant_hist_uw8_[0], + (kFrameHistory_size - 1) * kNumQuants * sizeof(uint8_t)); + // Store current frame in history. + memcpy(quant_hist_uw8_[0], quant_uw8, kNumQuants * sizeof(uint8_t)); + + // We use a frame memory equal to the ceiling of half the frame rate to + // ensure we capture an entire period of flicker. + frame_memory = (frame_rate_ + (1 << 5)) >> 5; // Unsigned ceiling. + // frame_rate_ in Q4. + if (frame_memory > kFrameHistory_size) { + frame_memory = kFrameHistory_size; + } + + // Get maximum and minimum. + for (int32_t i = 0; i < kNumQuants; i++) { + maxquant_uw8[i] = 0; + minquant_uw8[i] = 255; + for (uint32_t j = 0; j < frame_memory; j++) { + if (quant_hist_uw8_[j][i] > maxquant_uw8[i]) { + maxquant_uw8[i] = quant_hist_uw8_[j][i]; + } + + if (quant_hist_uw8_[j][i] < minquant_uw8[i]) { + minquant_uw8[i] = quant_hist_uw8_[j][i]; + } } - - for (int32_t i = 1; i < kFrameHistorySize; i++) - { - memcpy(_quantHistUW8[i], _quantHistUW8[0], sizeof(uint8_t) * kNumQuants); - } -} + } -int32_t -VPMDeflickering::ProcessFrame(I420VideoFrame* frame, - VideoProcessingModule::FrameStats* stats) -{ - assert(frame); - uint32_t frameMemory; - uint8_t quantUW8[kNumQuants]; - uint8_t maxQuantUW8[kNumQuants]; - uint8_t minQuantUW8[kNumQuants]; - uint16_t targetQuantUW16[kNumQuants]; - uint16_t incrementUW16; - uint8_t mapUW8[256]; + // Get target quantiles. + for (int32_t i = 0; i < kNumQuants - kMaxOnlyLength; i++) { + target_quant_uw16[i] = static_cast((WEBRTC_SPL_UMUL_16_16( + weight_uw16_[i], maxquant_uw8[i]) + WEBRTC_SPL_UMUL_16_16((1 << 15) - + weight_uw16_[i], minquant_uw8[i])) >> 8); // + } - uint16_t tmpUW16; - uint32_t tmpUW32; - int width = frame->width(); - int height = frame->height(); + for (int32_t i = kNumQuants - kMaxOnlyLength; i < kNumQuants; i++) { + target_quant_uw16[i] = ((uint16_t)maxquant_uw8[i]) << 7; + } - if (frame->IsZeroSize()) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "Null frame pointer"); - return VPM_GENERAL_ERROR; + // Compute the map from input to output pixels. + uint16_t mapUW16; // + for (int32_t i = 1; i < kNumQuants; i++) { + // As quant and targetQuant are limited to UWord8, it's safe to use Q7 here. + tmp_uw32 = static_cast(target_quant_uw16[i] - + target_quant_uw16[i - 1]); + tmp_uw16 = static_cast(quant_uw8[i] - quant_uw8[i - 1]); // + + if (tmp_uw16 > 0) { + increment_uw16 = static_cast(WebRtcSpl_DivU32U16(tmp_uw32, + tmp_uw16)); // + } else { + // The value is irrelevant; the loop below will only iterate once. + increment_uw16 = 0; } - // Stricter height check due to subsampling size calculation below. - if (height < 2) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "Invalid frame size"); - return VPM_GENERAL_ERROR; + mapUW16 = target_quant_uw16[i - 1]; + for (uint32_t j = quant_uw8[i - 1]; j < (uint32_t)(quant_uw8[i] + 1); j++) { + // Unsigned round. + map_uw8[j] = (uint8_t)((mapUW16 + (1 << 6)) >> 7); + mapUW16 += increment_uw16; } + } - if (!VideoProcessingModule::ValidFrameStats(*stats)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "Invalid frame stats"); - return VPM_GENERAL_ERROR; - } + // Map to the output frame. + uint8_t* buffer = frame->buffer(kYPlane); + for (uint32_t i = 0; i < y_size; i++) { + buffer[i] = map_uw8[buffer[i]]; + } - if (PreDetection(frame->timestamp(), *stats) == -1) - { - return VPM_GENERAL_ERROR; - } + // Frame was altered, so reset stats. + VideoProcessingModule::ClearFrameStats(stats); - // Flicker detection - int32_t detFlicker = DetectFlicker(); - if (detFlicker < 0) - { // Error - return VPM_GENERAL_ERROR; - } - else if (detFlicker != 1) - { - return 0; - } - - // Size of luminance component - const uint32_t ySize = height * width; - - const uint32_t ySubSize = width * (((height - 1) >> - kLog2OfDownsamplingFactor) + 1); - uint8_t* ySorted = new uint8_t[ySubSize]; - uint32_t sortRowIdx = 0; - for (int i = 0; i < height; i += kDownsamplingFactor) - { - memcpy(ySorted + sortRowIdx * width, - frame->buffer(kYPlane) + i * width, width); - sortRowIdx++; - } - - webrtc::Sort(ySorted, ySubSize, webrtc::TYPE_UWord8); - - uint32_t probIdxUW32 = 0; - quantUW8[0] = 0; - quantUW8[kNumQuants - 1] = 255; - - // Ensure we won't get an overflow below. - // In practice, the number of subsampled pixels will not become this large. - if (ySubSize > (1 << 21) - 1) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "Subsampled number of pixels too large"); - return -1; - } - - for (int32_t i = 0; i < kNumProbs; i++) - { - probIdxUW32 = WEBRTC_SPL_UMUL_32_16(ySubSize, _probUW16[i]) >> 11; // - quantUW8[i + 1] = ySorted[probIdxUW32]; - } - - delete [] ySorted; - ySorted = NULL; - - // Shift history for new frame. - memmove(_quantHistUW8[1], _quantHistUW8[0], (kFrameHistorySize - 1) * kNumQuants * - sizeof(uint8_t)); - // Store current frame in history. - memcpy(_quantHistUW8[0], quantUW8, kNumQuants * sizeof(uint8_t)); - - // We use a frame memory equal to the ceiling of half the frame rate to ensure we - // capture an entire period of flicker. - frameMemory = (_frameRate + (1 << 5)) >> 5; // Unsigned ceiling. - // _frameRate in Q4. - if (frameMemory > kFrameHistorySize) - { - frameMemory = kFrameHistorySize; - } - - // Get maximum and minimum. - for (int32_t i = 0; i < kNumQuants; i++) - { - maxQuantUW8[i] = 0; - minQuantUW8[i] = 255; - for (uint32_t j = 0; j < frameMemory; j++) - { - if (_quantHistUW8[j][i] > maxQuantUW8[i]) - { - maxQuantUW8[i] = _quantHistUW8[j][i]; - } - - if (_quantHistUW8[j][i] < minQuantUW8[i]) - { - minQuantUW8[i] = _quantHistUW8[j][i]; - } - } - } - - // Get target quantiles. - for (int32_t i = 0; i < kNumQuants - kMaxOnlyLength; i++) - { - targetQuantUW16[i] = static_cast((WEBRTC_SPL_UMUL_16_16( - _weightUW16[i], maxQuantUW8[i]) + WEBRTC_SPL_UMUL_16_16((1 << 15) - - _weightUW16[i], minQuantUW8[i])) >> 8); // - } - - for (int32_t i = kNumQuants - kMaxOnlyLength; i < kNumQuants; i++) - { - targetQuantUW16[i] = ((uint16_t)maxQuantUW8[i]) << 7; - } - - // Compute the map from input to output pixels. - uint16_t mapUW16; // - for (int32_t i = 1; i < kNumQuants; i++) - { - // As quant and targetQuant are limited to UWord8, we're safe to use Q7 here. - tmpUW32 = static_cast(targetQuantUW16[i] - - targetQuantUW16[i - 1]); // - tmpUW16 = static_cast(quantUW8[i] - quantUW8[i - 1]); // - - if (tmpUW16 > 0) - { - incrementUW16 = static_cast(WebRtcSpl_DivU32U16(tmpUW32, - tmpUW16)); // - } - else - { - // The value is irrelevant; the loop below will only iterate once. - incrementUW16 = 0; - } - - mapUW16 = targetQuantUW16[i - 1]; - for (uint32_t j = quantUW8[i - 1]; j < (uint32_t)(quantUW8[i] + 1); j++) - { - mapUW8[j] = (uint8_t)((mapUW16 + (1 << 6)) >> 7); // Unsigned round. - mapUW16 += incrementUW16; - } - } - - // Map to the output frame. - uint8_t* buffer = frame->buffer(kYPlane); - for (uint32_t i = 0; i < ySize; i++) - { - buffer[i] = mapUW8[buffer[i]]; - } - - // Frame was altered, so reset stats. - VideoProcessingModule::ClearFrameStats(stats); - - return 0; + return VPM_OK; } /** - Performs some pre-detection operations. Must be called before + Performs some pre-detection operations. Must be called before DetectFlicker(). \param[in] timestamp Timestamp of the current frame. \param[in] stats Statistics of the current frame. - + \return 0: Success\n 2: Detection not possible due to flickering frequency too close to zero.\n -1: Error */ -int32_t -VPMDeflickering::PreDetection(const uint32_t timestamp, - const VideoProcessingModule::FrameStats& stats) -{ - int32_t meanVal; // Mean value of frame (Q4) - uint32_t frameRate = 0; - int32_t meanBufferLength; // Temp variable +int32_t VPMDeflickering::PreDetection(const uint32_t timestamp, + const VideoProcessingModule::FrameStats& stats) { + int32_t mean_val; // Mean value of frame (Q4) + uint32_t frame_rate = 0; + int32_t meanBufferLength; // Temp variable. - meanVal = ((stats.sum << kMeanValueScaling) / stats.numPixels); - /* Update mean value buffer. - * This should be done even though we might end up in an unreliable detection. + mean_val = ((stats.sum << kmean_valueScaling) / stats.num_pixels); + // Update mean value buffer. + // This should be done even though we might end up in an unreliable detection. + memmove(mean_buffer_ + 1, mean_buffer_, + (kMeanBufferLength - 1) * sizeof(int32_t)); + mean_buffer_[0] = mean_val; + + // Update timestamp buffer. + // This should be done even though we might end up in an unreliable detection. + memmove(timestamp_buffer_ + 1, timestamp_buffer_, (kMeanBufferLength - 1) * + sizeof(uint32_t)); + timestamp_buffer_[0] = timestamp; + +/* Compute current frame rate (Q4) */ + if (timestamp_buffer_[kMeanBufferLength - 1] != 0) { + frame_rate = ((90000 << 4) * (kMeanBufferLength - 1)); + frame_rate /= + (timestamp_buffer_[0] - timestamp_buffer_[kMeanBufferLength - 1]); + } else if (timestamp_buffer_[1] != 0) { + frame_rate = (90000 << 4) / (timestamp_buffer_[0] - timestamp_buffer_[1]); + } + + /* Determine required size of mean value buffer (mean_buffer_length_) */ + if (frame_rate == 0) { + meanBufferLength = 1; + } else { + meanBufferLength = + (kNumFlickerBeforeDetect * frame_rate) / kMinFrequencyToDetect; + } + /* Sanity check of buffer length */ + if (meanBufferLength >= kMeanBufferLength) { + /* Too long buffer. The flickering frequency is too close to zero, which + * makes the estimation unreliable. */ - memmove(_meanBuffer + 1, _meanBuffer, (kMeanBufferLength - 1) * sizeof(int32_t)); - _meanBuffer[0] = meanVal; + mean_buffer_length_ = 0; + return 2; + } + mean_buffer_length_ = meanBufferLength; - /* Update timestamp buffer. - * This should be done even though we might end up in an unreliable detection. - */ - memmove(_timestampBuffer + 1, _timestampBuffer, (kMeanBufferLength - 1) * - sizeof(uint32_t)); - _timestampBuffer[0] = timestamp; + if ((timestamp_buffer_[mean_buffer_length_ - 1] != 0) && + (mean_buffer_length_ != 1)) { + frame_rate = ((90000 << 4) * (mean_buffer_length_ - 1)); + frame_rate /= + (timestamp_buffer_[0] - timestamp_buffer_[mean_buffer_length_ - 1]); + } else if (timestamp_buffer_[1] != 0) { + frame_rate = (90000 << 4) / (timestamp_buffer_[0] - timestamp_buffer_[1]); + } + frame_rate_ = frame_rate; - /* Compute current frame rate (Q4) */ - if (_timestampBuffer[kMeanBufferLength - 1] != 0) - { - frameRate = ((90000 << 4) * (kMeanBufferLength - 1)); - frameRate /= (_timestampBuffer[0] - _timestampBuffer[kMeanBufferLength - 1]); - }else if (_timestampBuffer[1] != 0) - { - frameRate = (90000 << 4) / (_timestampBuffer[0] - _timestampBuffer[1]); - } - - /* Determine required size of mean value buffer (_meanBufferLength) */ - if (frameRate == 0) { - meanBufferLength = 1; - } - else { - meanBufferLength = (kNumFlickerBeforeDetect * frameRate) / kMinFrequencyToDetect; - } - /* Sanity check of buffer length */ - if (meanBufferLength >= kMeanBufferLength) - { - /* Too long buffer. The flickering frequency is too close to zero, which - * makes the estimation unreliable. - */ - _meanBufferLength = 0; - return 2; - } - _meanBufferLength = meanBufferLength; - - if ((_timestampBuffer[_meanBufferLength - 1] != 0) && (_meanBufferLength != 1)) - { - frameRate = ((90000 << 4) * (_meanBufferLength - 1)); - frameRate /= (_timestampBuffer[0] - _timestampBuffer[_meanBufferLength - 1]); - }else if (_timestampBuffer[1] != 0) - { - frameRate = (90000 << 4) / (_timestampBuffer[0] - _timestampBuffer[1]); - } - _frameRate = frameRate; - - return 0; + return VPM_OK; } /** - This function detects flicker in the video stream. As a side effect the mean value - buffer is updated with the new mean value. - + This function detects flicker in the video stream. As a side effect the + mean value buffer is updated with the new mean value. + \return 0: No flickering detected\n 1: Flickering detected\n 2: Detection not possible due to unreliable frequency interval -1: Error */ -int32_t VPMDeflickering::DetectFlicker() -{ - /* Local variables */ - uint32_t i; - int32_t freqEst; // (Q4) Frequency estimate to base detection upon - int32_t retVal = -1; +int32_t VPMDeflickering::DetectFlicker() { + uint32_t i; + int32_t freqEst; // (Q4) Frequency estimate to base detection upon + int32_t ret_val = -1; - /* Sanity check for _meanBufferLength */ - if (_meanBufferLength < 2) - { - /* Not possible to estimate frequency */ - return(2); - } - /* Count zero crossings with a dead zone to be robust against noise. - * If the noise std is 2 pixel this corresponds to about 95% confidence interval. - */ - int32_t deadzone = (kZeroCrossingDeadzone << kMeanValueScaling); // Q4 - int32_t meanOfBuffer = 0; // Mean value of mean value buffer - int32_t numZeros = 0; // Number of zeros that cross the deadzone - int32_t cntState = 0; // State variable for zero crossing regions - int32_t cntStateOld = 0; // Previous state variable for zero crossing regions + /* Sanity check for mean_buffer_length_ */ + if (mean_buffer_length_ < 2) { + /* Not possible to estimate frequency */ + return(2); + } + // Count zero crossings with a dead zone to be robust against noise. If the + // noise std is 2 pixel this corresponds to about 95% confidence interval. + int32_t deadzone = (kZeroCrossingDeadzone << kmean_valueScaling); // Q4 + int32_t meanOfBuffer = 0; // Mean value of mean value buffer. + int32_t numZeros = 0; // Number of zeros that cross the dead-zone. + int32_t cntState = 0; // State variable for zero crossing regions. + int32_t cntStateOld = 0; // Previous state for zero crossing regions. - for (i = 0; i < _meanBufferLength; i++) - { - meanOfBuffer += _meanBuffer[i]; - } - meanOfBuffer += (_meanBufferLength >> 1); // Rounding, not truncation - meanOfBuffer /= _meanBufferLength; + for (i = 0; i < mean_buffer_length_; i++) { + meanOfBuffer += mean_buffer_[i]; + } + meanOfBuffer += (mean_buffer_length_ >> 1); // Rounding, not truncation. + meanOfBuffer /= mean_buffer_length_; - /* Count zero crossings */ - cntStateOld = (_meanBuffer[0] >= (meanOfBuffer + deadzone)); - cntStateOld -= (_meanBuffer[0] <= (meanOfBuffer - deadzone)); - for (i = 1; i < _meanBufferLength; i++) - { - cntState = (_meanBuffer[i] >= (meanOfBuffer + deadzone)); - cntState -= (_meanBuffer[i] <= (meanOfBuffer - deadzone)); - if (cntStateOld == 0) - { - cntStateOld = -cntState; - } - if (((cntState + cntStateOld) == 0) && (cntState != 0)) - { - numZeros++; - cntStateOld = cntState; - } + // Count zero crossings. + cntStateOld = (mean_buffer_[0] >= (meanOfBuffer + deadzone)); + cntStateOld -= (mean_buffer_[0] <= (meanOfBuffer - deadzone)); + for (i = 1; i < mean_buffer_length_; i++) { + cntState = (mean_buffer_[i] >= (meanOfBuffer + deadzone)); + cntState -= (mean_buffer_[i] <= (meanOfBuffer - deadzone)); + if (cntStateOld == 0) { + cntStateOld = -cntState; } - /* END count zero crossings */ + if (((cntState + cntStateOld) == 0) && (cntState != 0)) { + numZeros++; + cntStateOld = cntState; + } + } + // END count zero crossings. - /* Frequency estimation according to: - * freqEst = numZeros * frameRate / 2 / _meanBufferLength; - * - * Resolution is set to Q4 - */ - freqEst = ((numZeros * 90000) << 3); - freqEst /= (_timestampBuffer[0] - _timestampBuffer[_meanBufferLength - 1]); + /* Frequency estimation according to: + * freqEst = numZeros * frame_rate / 2 / mean_buffer_length_; + * + * Resolution is set to Q4 + */ + freqEst = ((numZeros * 90000) << 3); + freqEst /= + (timestamp_buffer_[0] - timestamp_buffer_[mean_buffer_length_ - 1]); - /* Translate frequency estimate to regions close to 100 and 120 Hz */ - uint8_t freqState = 0; // Current translation state; - // (0) Not in interval, - // (1) Within valid interval, - // (2) Out of range - int32_t freqAlias = freqEst; - if (freqEst > kMinFrequencyToDetect) - { - uint8_t aliasState = 1; - while(freqState == 0) - { - /* Increase frequency */ - freqAlias += (aliasState * _frameRate); - freqAlias += ((freqEst << 1) * (1 - (aliasState << 1))); - /* Compute state */ - freqState = (abs(freqAlias - (100 << 4)) <= kFrequencyDeviation); - freqState += (abs(freqAlias - (120 << 4)) <= kFrequencyDeviation); - freqState += 2 * (freqAlias > ((120 << 4) + kFrequencyDeviation)); - /* Switch alias state */ - aliasState++; - aliasState &= 0x01; - } + /* Translate frequency estimate to regions close to 100 and 120 Hz */ + uint8_t freqState = 0; // Current translation state; + // (0) Not in interval, + // (1) Within valid interval, + // (2) Out of range + int32_t freqAlias = freqEst; + if (freqEst > kMinFrequencyToDetect) { + uint8_t aliasState = 1; + while(freqState == 0) { + /* Increase frequency */ + freqAlias += (aliasState * frame_rate_); + freqAlias += ((freqEst << 1) * (1 - (aliasState << 1))); + /* Compute state */ + freqState = (abs(freqAlias - (100 << 4)) <= kFrequencyDeviation); + freqState += (abs(freqAlias - (120 << 4)) <= kFrequencyDeviation); + freqState += 2 * (freqAlias > ((120 << 4) + kFrequencyDeviation)); + /* Switch alias state */ + aliasState++; + aliasState &= 0x01; } - /* Is frequency estimate within detection region? */ - if (freqState == 1) - { - retVal = 1; - }else if (freqState == 0) - { - retVal = 2; - }else - { - retVal = 0; - } - return retVal; + } + /* Is frequency estimate within detection region? */ + if (freqState == 1) { + ret_val = 1; + } else if (freqState == 0) { + ret_val = 2; + } else { + ret_val = 0; + } + return ret_val; } -} // namespace +} // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/deflickering.h b/webrtc/modules/video_processing/main/source/deflickering.h index d3f8139be..53ffebed5 100644 --- a/webrtc/modules/video_processing/main/source/deflickering.h +++ b/webrtc/modules/video_processing/main/source/deflickering.h @@ -8,12 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -/* - * deflickering.h - */ - -#ifndef VPM_DEFLICKERING_H -#define VPM_DEFLICKERING_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCEdeflickering__H +#define WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCEdeflickering__H #include // NULL @@ -22,44 +18,43 @@ namespace webrtc { -class VPMDeflickering -{ -public: - VPMDeflickering(); - ~VPMDeflickering(); +class VPMDeflickering { + public: + VPMDeflickering(); + ~VPMDeflickering(); - int32_t ChangeUniqueId(int32_t id); + int32_t ChangeUniqueId(int32_t id); - void Reset(); + void Reset(); + int32_t ProcessFrame(I420VideoFrame* frame, + VideoProcessingModule::FrameStats* stats); - int32_t ProcessFrame(I420VideoFrame* frame, - VideoProcessingModule::FrameStats* stats); -private: - int32_t PreDetection(uint32_t timestamp, - const VideoProcessingModule::FrameStats& stats); + private: + int32_t PreDetection(uint32_t timestamp, + const VideoProcessingModule::FrameStats& stats); - int32_t DetectFlicker(); + int32_t DetectFlicker(); - enum { kMeanBufferLength = 32 }; - enum { kFrameHistorySize = 15 }; - enum { kNumProbs = 12 }; - enum { kNumQuants = kNumProbs + 2 }; - enum { kMaxOnlyLength = 5 }; + enum { kMeanBufferLength = 32 }; + enum { kFrameHistory_size = 15 }; + enum { kNumProbs = 12 }; + enum { kNumQuants = kNumProbs + 2 }; + enum { kMaxOnlyLength = 5 }; - int32_t _id; + int32_t id_; - uint32_t _meanBufferLength; - uint8_t _detectionState; // 0: No flickering - // 1: Flickering detected - // 2: In flickering - int32_t _meanBuffer[kMeanBufferLength]; - uint32_t _timestampBuffer[kMeanBufferLength]; - uint32_t _frameRate; - static const uint16_t _probUW16[kNumProbs]; - static const uint16_t _weightUW16[kNumQuants - kMaxOnlyLength]; - uint8_t _quantHistUW8[kFrameHistorySize][kNumQuants]; + uint32_t mean_buffer_length_; + uint8_t detection_state_; // 0: No flickering + // 1: Flickering detected + // 2: In flickering + int32_t mean_buffer_[kMeanBufferLength]; + uint32_t timestamp_buffer_[kMeanBufferLength]; + uint32_t frame_rate_; + static const uint16_t prob_uw16_[kNumProbs]; + static const uint16_t weight_uw16_[kNumQuants - kMaxOnlyLength]; + uint8_t quant_hist_uw8_[kFrameHistory_size][kNumQuants]; }; -} // namespace +} // namespace webrtc -#endif // VPM_DEFLICKERING_H +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCEdeflickering__H diff --git a/webrtc/modules/video_processing/main/source/denoising.cc b/webrtc/modules/video_processing/main/source/denoising.cc index 45326fa54..79c4bcc3d 100644 --- a/webrtc/modules/video_processing/main/source/denoising.cc +++ b/webrtc/modules/video_processing/main/source/denoising.cc @@ -14,167 +14,146 @@ #include namespace webrtc { +// Down-sampling in time (unit: number of frames) +enum { kSubsamplingTime = 0 }; +// Sub-sampling in width (unit: power of 2. +enum { kSubsamplingWidth = 0 }; +// Sub-sampling in height (unit: power of 2) +enum { kSubsamplingHeight = 0 }; +// (Q8) De-noising filter parameter +enum { kDenoiseFiltParam = 179 }; +// (Q8) 1 - filter parameter +enum { kDenoiseFiltParamRec = 77 }; +// (Q8) De-noising threshold level +enum { kDenoiseThreshold = 19200 }; -enum { kSubsamplingTime = 0 }; // Down-sampling in time (unit: number of frames) -enum { kSubsamplingWidth = 0 }; // Sub-sampling in width (unit: power of 2) -enum { kSubsamplingHeight = 0 }; // Sub-sampling in height (unit: power of 2) -enum { kDenoiseFiltParam = 179 }; // (Q8) De-noising filter parameter -enum { kDenoiseFiltParamRec = 77 }; // (Q8) 1 - filter parameter -enum { kDenoiseThreshold = 19200 }; // (Q8) De-noising threshold level - -VPMDenoising::VPMDenoising() : - _id(0), - _moment1(NULL), - _moment2(NULL) -{ - Reset(); +VPMDenoising::VPMDenoising() + : id_(0), + moment1_(NULL), + moment2_(NULL) { + Reset(); } -VPMDenoising::~VPMDenoising() -{ - if (_moment1) - { - delete [] _moment1; - _moment1 = NULL; - } - - if (_moment2) - { - delete [] _moment2; - _moment2 = NULL; - } +VPMDenoising::~VPMDenoising() { + if (moment1_) { + delete [] moment1_; + moment1_ = NULL; } -int32_t -VPMDenoising::ChangeUniqueId(const int32_t id) -{ - _id = id; - return VPM_OK; + if (moment2_) { + delete [] moment2_; + moment2_ = NULL; + } } -void -VPMDenoising::Reset() -{ - _frameSize = 0; - _denoiseFrameCnt = 0; - - if (_moment1) - { - delete [] _moment1; - _moment1 = NULL; - } - - if (_moment2) - { - delete [] _moment2; - _moment2 = NULL; - } +int32_t VPMDenoising::ChangeUniqueId(const int32_t id) { + id_ = id; + return VPM_OK; } -int32_t -VPMDenoising::ProcessFrame(I420VideoFrame* frame) -{ - assert(frame); - int32_t thevar; - int k; - int jsub, ksub; - int32_t diff0; - uint32_t tmpMoment1; - uint32_t tmpMoment2; - uint32_t tmp; - int32_t numPixelsChanged = 0; +void VPMDenoising::Reset() { + frame_size_ = 0; + denoise_frame_cnt_ = 0; - if (frame->IsZeroSize()) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id, - "zero size frame"); - return VPM_GENERAL_ERROR; + if (moment1_) { + delete [] moment1_; + moment1_ = NULL; + } + + if (moment2_) { + delete [] moment2_; + moment2_ = NULL; + } +} + +int32_t VPMDenoising::ProcessFrame(I420VideoFrame* frame) { + assert(frame); + int32_t thevar; + int k; + int jsub, ksub; + int32_t diff0; + uint32_t tmp_moment1; + uint32_t tmp_moment2; + uint32_t tmp; + int32_t num_pixels_changed = 0; + + if (frame->IsZeroSize()) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, id_, + "zero size frame"); + return VPM_GENERAL_ERROR; + } + + int width = frame->width(); + int height = frame->height(); + + /* Size of luminance component */ + const uint32_t y_size = height * width; + + /* Initialization */ + if (y_size != frame_size_) { + delete [] moment1_; + moment1_ = NULL; + + delete [] moment2_; + moment2_ = NULL; + } + frame_size_ = y_size; + + if (!moment1_) { + moment1_ = new uint32_t[y_size]; + memset(moment1_, 0, sizeof(uint32_t)*y_size); + } + + if (!moment2_) { + moment2_ = new uint32_t[y_size]; + memset(moment2_, 0, sizeof(uint32_t)*y_size); + } + + /* Apply de-noising on each pixel, but update variance sub-sampled */ + uint8_t* buffer = frame->buffer(kYPlane); + for (int i = 0; i < height; i++) { // Collect over height + k = i * width; + ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width; + for (int j = 0; j < width; j++) { // Collect over width + jsub = ((j >> kSubsamplingWidth) << kSubsamplingWidth); + /* Update mean value for every pixel and every frame */ + tmp_moment1 = moment1_[k + j]; + tmp_moment1 *= kDenoiseFiltParam; // Q16 + tmp_moment1 += ((kDenoiseFiltParamRec * ((uint32_t)buffer[k + j])) << 8); + tmp_moment1 >>= 8; // Q8 + moment1_[k + j] = tmp_moment1; + + tmp_moment2 = moment2_[ksub + jsub]; + if ((ksub == k) && (jsub == j) && (denoise_frame_cnt_ == 0)) { + tmp = ((uint32_t)buffer[k + j] * + (uint32_t)buffer[k + j]); + tmp_moment2 *= kDenoiseFiltParam; // Q16 + tmp_moment2 += ((kDenoiseFiltParamRec * tmp) << 8); + tmp_moment2 >>= 8; // Q8 + } + moment2_[k + j] = tmp_moment2; + /* Current event = deviation from mean value */ + diff0 = ((int32_t)buffer[k + j] << 8) - moment1_[k + j]; + /* Recent events = variance (variations over time) */ + thevar = moment2_[k + j]; + thevar -= ((moment1_[k + j] * moment1_[k + j]) >> 8); + // De-noising criteria, i.e., when should we replace a pixel by its mean. + // 1) recent events are minor. + // 2) current events are minor. + if ((thevar < kDenoiseThreshold) + && ((diff0 * diff0 >> 8) < kDenoiseThreshold)) { + // Replace with mean. + buffer[k + j] = (uint8_t)(moment1_[k + j] >> 8); + num_pixels_changed++; + } } + } - int width = frame->width(); - int height = frame->height(); + denoise_frame_cnt_++; + if (denoise_frame_cnt_ > kSubsamplingTime) + denoise_frame_cnt_ = 0; - /* Size of luminance component */ - const uint32_t ysize = height * width; - - /* Initialization */ - if (ysize != _frameSize) - { - delete [] _moment1; - _moment1 = NULL; - - delete [] _moment2; - _moment2 = NULL; - } - _frameSize = ysize; - - if (!_moment1) - { - _moment1 = new uint32_t[ysize]; - memset(_moment1, 0, sizeof(uint32_t)*ysize); - } - - if (!_moment2) - { - _moment2 = new uint32_t[ysize]; - memset(_moment2, 0, sizeof(uint32_t)*ysize); - } - - /* Apply de-noising on each pixel, but update variance sub-sampled */ - uint8_t* buffer = frame->buffer(kYPlane); - for (int i = 0; i < height; i++) - { // Collect over height - k = i * width; - ksub = ((i >> kSubsamplingHeight) << kSubsamplingHeight) * width; - for (int j = 0; j < width; j++) - { // Collect over width - jsub = ((j >> kSubsamplingWidth) << kSubsamplingWidth); - /* Update mean value for every pixel and every frame */ - tmpMoment1 = _moment1[k + j]; - tmpMoment1 *= kDenoiseFiltParam; // Q16 - tmpMoment1 += ((kDenoiseFiltParamRec * - ((uint32_t)buffer[k + j])) << 8); - tmpMoment1 >>= 8; // Q8 - _moment1[k + j] = tmpMoment1; - - tmpMoment2 = _moment2[ksub + jsub]; - if ((ksub == k) && (jsub == j) && (_denoiseFrameCnt == 0)) - { - tmp = ((uint32_t)buffer[k + j] * - (uint32_t)buffer[k + j]); - tmpMoment2 *= kDenoiseFiltParam; // Q16 - tmpMoment2 += ((kDenoiseFiltParamRec * tmp)<<8); - tmpMoment2 >>= 8; // Q8 - } - _moment2[k + j] = tmpMoment2; - /* Current event = deviation from mean value */ - diff0 = ((int32_t)buffer[k + j] << 8) - _moment1[k + j]; - /* Recent events = variance (variations over time) */ - thevar = _moment2[k + j]; - thevar -= ((_moment1[k + j] * _moment1[k + j]) >> 8); - /*************************************************************************** - * De-noising criteria, i.e., when should we replace a pixel by its mean - * - * 1) recent events are minor - * 2) current events are minor - ***************************************************************************/ - if ((thevar < kDenoiseThreshold) - && ((diff0 * diff0 >> 8) < kDenoiseThreshold)) - { // Replace with mean - buffer[k + j] = (uint8_t)(_moment1[k + j] >> 8); - numPixelsChanged++; - } - } - } - - /* Update frame counter */ - _denoiseFrameCnt++; - if (_denoiseFrameCnt > kSubsamplingTime) - { - _denoiseFrameCnt = 0; - } - - return numPixelsChanged; + return num_pixels_changed; } } // namespace diff --git a/webrtc/modules/video_processing/main/source/denoising.h b/webrtc/modules/video_processing/main/source/denoising.h index b9d09c081..60645fbdb 100644 --- a/webrtc/modules/video_processing/main/source/denoising.h +++ b/webrtc/modules/video_processing/main/source/denoising.h @@ -8,39 +8,35 @@ * be found in the AUTHORS file in the root of the source tree. */ -/* - * denoising.h - */ -#ifndef VPM_DENOISING_H -#define VPM_DENOISING_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_DENOISING_H_ +#define WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_DENOISING_H_ #include "webrtc/modules/video_processing/main/interface/video_processing.h" #include "webrtc/typedefs.h" namespace webrtc { -class VPMDenoising -{ -public: - VPMDenoising(); - ~VPMDenoising(); +class VPMDenoising { + public: + VPMDenoising(); + ~VPMDenoising(); - int32_t ChangeUniqueId(int32_t id); + int32_t ChangeUniqueId(int32_t id); - void Reset(); + void Reset(); - int32_t ProcessFrame(I420VideoFrame* frame); + int32_t ProcessFrame(I420VideoFrame* frame); -private: - int32_t _id; + private: + int32_t id_; - uint32_t* _moment1; // (Q8) First order moment (mean) - uint32_t* _moment2; // (Q8) Second order moment - uint32_t _frameSize; // Size (# of pixels) of frame - int _denoiseFrameCnt; // Counter for subsampling in time + uint32_t* moment1_; // (Q8) First order moment (mean). + uint32_t* moment2_; // (Q8) Second order moment. + uint32_t frame_size_; // Size (# of pixels) of frame. + int denoise_frame_cnt_; // Counter for subsampling in time. }; -} // namespace +} // namespace webrtc + +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_DENOISING_H_ -#endif // VPM_DENOISING_H - diff --git a/webrtc/modules/video_processing/main/source/frame_preprocessor.cc b/webrtc/modules/video_processing/main/source/frame_preprocessor.cc index fc952c0b8..de4907029 100644 --- a/webrtc/modules/video_processing/main/source/frame_preprocessor.cc +++ b/webrtc/modules/video_processing/main/source/frame_preprocessor.cc @@ -13,177 +13,137 @@ namespace webrtc { -VPMFramePreprocessor::VPMFramePreprocessor(): -_id(0), -_contentMetrics(NULL), -_maxFrameRate(0), -_resampledFrame(), -_enableCA(false), -_frameCnt(0) -{ - _spatialResampler = new VPMSimpleSpatialResampler(); - _ca = new VPMContentAnalysis(true); - _vd = new VPMVideoDecimator(); +VPMFramePreprocessor::VPMFramePreprocessor() + : id_(0), + content_metrics_(NULL), + max_frame_rate_(0), + resampled_frame_(), + enable_ca_(false), + frame_cnt_(0) { + spatial_resampler_ = new VPMSimpleSpatialResampler(); + ca_ = new VPMContentAnalysis(true); + vd_ = new VPMVideoDecimator(); } -VPMFramePreprocessor::~VPMFramePreprocessor() -{ - Reset(); - delete _spatialResampler; - delete _ca; - delete _vd; +VPMFramePreprocessor::~VPMFramePreprocessor() { + Reset(); + delete spatial_resampler_; + delete ca_; + delete vd_; } -int32_t -VPMFramePreprocessor::ChangeUniqueId(const int32_t id) -{ - _id = id; - return VPM_OK; +int32_t VPMFramePreprocessor::ChangeUniqueId(const int32_t id) { + id_ = id; + return VPM_OK; } -void -VPMFramePreprocessor::Reset() -{ - _ca->Release(); - _vd->Reset(); - _contentMetrics = NULL; - _spatialResampler->Reset(); - _enableCA = false; - _frameCnt = 0; -} - - -void -VPMFramePreprocessor::EnableTemporalDecimation(bool enable) -{ - _vd->EnableTemporalDecimation(enable); -} -void -VPMFramePreprocessor::EnableContentAnalysis(bool enable) -{ - _enableCA = enable; +void VPMFramePreprocessor::Reset() { + ca_->Release(); + vd_->Reset(); + content_metrics_ = NULL; + spatial_resampler_->Reset(); + enable_ca_ = false; + frame_cnt_ = 0; } -void -VPMFramePreprocessor::SetInputFrameResampleMode(VideoFrameResampling resamplingMode) -{ - _spatialResampler->SetInputFrameResampleMode(resamplingMode); + +void VPMFramePreprocessor::EnableTemporalDecimation(bool enable) { + vd_->EnableTemporalDecimation(enable); } - -int32_t -VPMFramePreprocessor::SetMaxFrameRate(uint32_t maxFrameRate) -{ - if (maxFrameRate == 0) - { - return VPM_PARAMETER_ERROR; +void VPMFramePreprocessor::EnableContentAnalysis(bool enable) { + enable_ca_ = enable; +} + +void VPMFramePreprocessor::SetInputFrameResampleMode( + VideoFrameResampling resampling_mode) { + spatial_resampler_->SetInputFrameResampleMode(resampling_mode); +} + +int32_t VPMFramePreprocessor::SetMaxFramerate(uint32_t max_frame_rate) { + if (max_frame_rate == 0) return VPM_PARAMETER_ERROR; + + // Max allowed frame_rate. + max_frame_rate_ = max_frame_rate; + return vd_->SetMaxFramerate(max_frame_rate); +} + +int32_t VPMFramePreprocessor::SetTargetResolution( + uint32_t width, uint32_t height, uint32_t frame_rate) { + if ( (width == 0) || (height == 0) || (frame_rate == 0)) { + return VPM_PARAMETER_ERROR; + } + int32_t ret_val = 0; + ret_val = spatial_resampler_->SetTargetFrameSize(width, height); + + if (ret_val < 0) return ret_val; + + ret_val = vd_->SetTargetframe_rate(frame_rate); + if (ret_val < 0) return ret_val; + + return VPM_OK; +} + +void VPMFramePreprocessor::UpdateIncomingframe_rate() { + vd_->UpdateIncomingframe_rate(); +} + +uint32_t VPMFramePreprocessor::Decimatedframe_rate() { + return vd_->Decimatedframe_rate(); +} + + +uint32_t VPMFramePreprocessor::DecimatedWidth() const { + return spatial_resampler_->TargetWidth(); +} + + +uint32_t VPMFramePreprocessor::DecimatedHeight() const { + return spatial_resampler_->TargetHeight(); +} + + +int32_t VPMFramePreprocessor::PreprocessFrame(const I420VideoFrame& frame, + I420VideoFrame** processed_frame) { + if (frame.IsZeroSize()) { + return VPM_PARAMETER_ERROR; + } + + vd_->UpdateIncomingframe_rate(); + + if (vd_->DropFrame()) { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, id_, + "Drop frame due to frame rate"); + return 1; // drop 1 frame + } + + // Resizing incoming frame if needed. Otherwise, remains NULL. + // We are not allowed to resample the input frame (must make a copy of it). + *processed_frame = NULL; + if (spatial_resampler_->ApplyResample(frame.width(), frame.height())) { + int32_t ret = spatial_resampler_->ResampleFrame(frame, &resampled_frame_); + if (ret != VPM_OK) return ret; + *processed_frame = &resampled_frame_; + } + + // Perform content analysis on the frame to be encoded. + if (enable_ca_) { + // Compute new metrics every |kSkipFramesCA| frames, starting with + // the first frame. + if (frame_cnt_ % kSkipFrameCA == 0) { + if (*processed_frame == NULL) { + content_metrics_ = ca_->ComputeContentMetrics(frame); + } else { + content_metrics_ = ca_->ComputeContentMetrics(resampled_frame_); + } } - //Max allowed frame rate - _maxFrameRate = maxFrameRate; - - return _vd->SetMaxFrameRate(maxFrameRate); -} - - -int32_t -VPMFramePreprocessor::SetTargetResolution(uint32_t width, uint32_t height, uint32_t frameRate) -{ - if ( (width == 0) || (height == 0) || (frameRate == 0)) - { - return VPM_PARAMETER_ERROR; - } - int32_t retVal = 0; - retVal = _spatialResampler->SetTargetFrameSize(width, height); - if (retVal < 0) - { - return retVal; - } - retVal = _vd->SetTargetFrameRate(frameRate); - if (retVal < 0) - { - return retVal; - } - - return VPM_OK; + ++frame_cnt_; + } + return VPM_OK; } -void -VPMFramePreprocessor::UpdateIncomingFrameRate() -{ - _vd->UpdateIncomingFrameRate(); -} - -uint32_t -VPMFramePreprocessor::DecimatedFrameRate() -{ - return _vd->DecimatedFrameRate(); -} - - -uint32_t -VPMFramePreprocessor::DecimatedWidth() const -{ - return _spatialResampler->TargetWidth(); -} - - -uint32_t -VPMFramePreprocessor::DecimatedHeight() const -{ - return _spatialResampler->TargetHeight(); -} - - -int32_t -VPMFramePreprocessor::PreprocessFrame(const I420VideoFrame& frame, - I420VideoFrame** processedFrame) -{ - if (frame.IsZeroSize()) - { - return VPM_PARAMETER_ERROR; - } - - _vd->UpdateIncomingFrameRate(); - - if (_vd->DropFrame()) - { - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, _id, - "Drop frame due to frame rate"); - return 1; // drop 1 frame - } - - // Resizing incoming frame if needed. Otherwise, remains NULL. - // We are not allowed to resample the input frame (must make a copy of it). - *processedFrame = NULL; - if (_spatialResampler->ApplyResample(frame.width(), frame.height())) { - int32_t ret = _spatialResampler->ResampleFrame(frame, &_resampledFrame); - if (ret != VPM_OK) - return ret; - *processedFrame = &_resampledFrame; - } - - // Perform content analysis on the frame to be encoded. - if (_enableCA) - { - // Compute new metrics every |kSkipFramesCA| frames, starting with - // the first frame. - if (_frameCnt % kSkipFrameCA == 0) { - if (*processedFrame == NULL) { - _contentMetrics = _ca->ComputeContentMetrics(frame); - } else { - _contentMetrics = _ca->ComputeContentMetrics(_resampledFrame); - } - } - ++_frameCnt; - } - return VPM_OK; -} - - -VideoContentMetrics* -VPMFramePreprocessor::ContentMetrics() const -{ - return _contentMetrics; +VideoContentMetrics* VPMFramePreprocessor::ContentMetrics() const { + return content_metrics_; } } // namespace diff --git a/webrtc/modules/video_processing/main/source/frame_preprocessor.h b/webrtc/modules/video_processing/main/source/frame_preprocessor.h index f2d94a239..ca62d38fc 100644 --- a/webrtc/modules/video_processing/main/source/frame_preprocessor.h +++ b/webrtc/modules/video_processing/main/source/frame_preprocessor.h @@ -11,8 +11,8 @@ /* * frame_preprocessor.h */ -#ifndef VPM_FRAME_PREPROCESSOR_H -#define VPM_FRAME_PREPROCESSOR_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_FRAME_PREPROCESSOR_H +#define WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_FRAME_PREPROCESSOR_H #include "webrtc/modules/video_processing/main/interface/video_processing.h" #include "webrtc/modules/video_processing/main/source/content_analysis.h" @@ -22,65 +22,62 @@ namespace webrtc { +class VPMFramePreprocessor { + public: + VPMFramePreprocessor(); + ~VPMFramePreprocessor(); -class VPMFramePreprocessor -{ -public: + int32_t ChangeUniqueId(const int32_t id); - VPMFramePreprocessor(); - ~VPMFramePreprocessor(); + void Reset(); - int32_t ChangeUniqueId(const int32_t id); + // Enable temporal decimation. + void EnableTemporalDecimation(bool enable); - void Reset(); + void SetInputFrameResampleMode(VideoFrameResampling resampling_mode); - // Enable temporal decimation - void EnableTemporalDecimation(bool enable); + // Enable content analysis. + void EnableContentAnalysis(bool enable); - void SetInputFrameResampleMode(VideoFrameResampling resamplingMode); + // Set max frame rate. + int32_t SetMaxFramerate(uint32_t max_frame_rate); - //Enable content analysis - void EnableContentAnalysis(bool enable); + // Set target resolution: frame rate and dimension. + int32_t SetTargetResolution(uint32_t width, uint32_t height, + uint32_t frame_rate); - //Set max frame rate - int32_t SetMaxFrameRate(uint32_t maxFrameRate); + // Update incoming frame rate/dimension. + void UpdateIncomingframe_rate(); - //Set target resolution: frame rate and dimension - int32_t SetTargetResolution(uint32_t width, uint32_t height, - uint32_t frameRate); + int32_t updateIncomingFrameSize(uint32_t width, uint32_t height); - //Update incoming frame rate/dimension - void UpdateIncomingFrameRate(); + // Set decimated values: frame rate/dimension. + uint32_t Decimatedframe_rate(); + uint32_t DecimatedWidth() const; + uint32_t DecimatedHeight() const; - int32_t updateIncomingFrameSize(uint32_t width, uint32_t height); + // Preprocess output: + int32_t PreprocessFrame(const I420VideoFrame& frame, + I420VideoFrame** processed_frame); + VideoContentMetrics* ContentMetrics() const; - //Set decimated values: frame rate/dimension - uint32_t DecimatedFrameRate(); - uint32_t DecimatedWidth() const; - uint32_t DecimatedHeight() 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 }; - //Preprocess output: - int32_t PreprocessFrame(const I420VideoFrame& frame, - I420VideoFrame** processedFrame); - VideoContentMetrics* ContentMetrics() const; + int32_t id_; + VideoContentMetrics* content_metrics_; + uint32_t max_frame_rate_; + I420VideoFrame resampled_frame_; + VPMSpatialResampler* spatial_resampler_; + VPMContentAnalysis* ca_; + VPMVideoDecimator* vd_; + bool enable_ca_; + int frame_cnt_; -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 }; +}; - int32_t _id; - VideoContentMetrics* _contentMetrics; - uint32_t _maxFrameRate; - I420VideoFrame _resampledFrame; - VPMSpatialResampler* _spatialResampler; - VPMContentAnalysis* _ca; - VPMVideoDecimator* _vd; - bool _enableCA; - int _frameCnt; - -}; // end of VPMFramePreprocessor class definition +} // namespace webrtc -} // namespace - -#endif // VPM_FRAME_PREPROCESS_H +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_FRAME_PREPROCESSOR_H diff --git a/webrtc/modules/video_processing/main/source/spatial_resampler.cc b/webrtc/modules/video_processing/main/source/spatial_resampler.cc index f66153da8..fd90c8f76 100644 --- a/webrtc/modules/video_processing/main/source/spatial_resampler.cc +++ b/webrtc/modules/video_processing/main/source/spatial_resampler.cc @@ -14,109 +14,85 @@ namespace webrtc { VPMSimpleSpatialResampler::VPMSimpleSpatialResampler() -: -_resamplingMode(kFastRescaling), -_targetWidth(0), -_targetHeight(0), -_scaler() -{ -} + : resampling_mode_(kFastRescaling), + target_width_(0), + target_height_(0), + scaler_() {} -VPMSimpleSpatialResampler::~VPMSimpleSpatialResampler() -{ - // -} +VPMSimpleSpatialResampler::~VPMSimpleSpatialResampler() {} -int32_t -VPMSimpleSpatialResampler::SetTargetFrameSize(int32_t width, - int32_t height) -{ - if (_resamplingMode == kNoRescaling) { - return VPM_OK; - } +int32_t VPMSimpleSpatialResampler::SetTargetFrameSize(int32_t width, + int32_t height) { + if (resampling_mode_ == kNoRescaling) return VPM_OK; - if (width < 1 || height < 1) { - return VPM_PARAMETER_ERROR; - } + if (width < 1 || height < 1) return VPM_PARAMETER_ERROR; - _targetWidth = width; - _targetHeight = height; + target_width_ = width; + target_height_ = height; return VPM_OK; } -void -VPMSimpleSpatialResampler::SetInputFrameResampleMode(VideoFrameResampling - resamplingMode) -{ - _resamplingMode = resamplingMode; +void VPMSimpleSpatialResampler::SetInputFrameResampleMode( + VideoFrameResampling resampling_mode) { + resampling_mode_ = resampling_mode; } -void -VPMSimpleSpatialResampler::Reset() -{ - _resamplingMode = kFastRescaling; - _targetWidth = 0; - _targetHeight = 0; +void VPMSimpleSpatialResampler::Reset() { + resampling_mode_ = kFastRescaling; + target_width_ = 0; + target_height_ = 0; } -int32_t -VPMSimpleSpatialResampler::ResampleFrame(const I420VideoFrame& inFrame, - I420VideoFrame* outFrame) -{ +int32_t VPMSimpleSpatialResampler::ResampleFrame(const I420VideoFrame& inFrame, + I420VideoFrame* outFrame) { // Don't copy if frame remains as is. - if (_resamplingMode == kNoRescaling) + if (resampling_mode_ == kNoRescaling) return VPM_OK; // Check if re-sampling is needed - else if ((inFrame.width() == _targetWidth) && - (inFrame.height() == _targetHeight)) { + else if ((inFrame.width() == target_width_) && + (inFrame.height() == target_height_)) { return VPM_OK; } // Setting scaler // TODO(mikhal/marpan): Should we allow for setting the filter mode in - // _scale.Set() with |_resamplingMode|? - int retVal = 0; - retVal = _scaler.Set(inFrame.width(), inFrame.height(), - _targetWidth, _targetHeight, kI420, kI420, kScaleBox); - if (retVal < 0) - return retVal; + // _scale.Set() with |resampling_mode_|? + int ret_val = 0; + ret_val = scaler_.Set(inFrame.width(), inFrame.height(), + target_width_, target_height_, kI420, kI420, kScaleBox); + if (ret_val < 0) + return ret_val; - retVal = _scaler.Scale(inFrame, outFrame); + ret_val = scaler_.Scale(inFrame, outFrame); // Setting time parameters to the output frame. // Timestamp will be reset in Scale call above, so we should set it after. outFrame->set_timestamp(inFrame.timestamp()); outFrame->set_render_time_ms(inFrame.render_time_ms()); - if (retVal == 0) + if (ret_val == 0) return VPM_OK; else return VPM_SCALE_ERROR; } -int32_t -VPMSimpleSpatialResampler::TargetHeight() -{ - return _targetHeight; +int32_t VPMSimpleSpatialResampler::TargetHeight() { + return target_height_; } -int32_t -VPMSimpleSpatialResampler::TargetWidth() -{ - return _targetWidth; +int32_t VPMSimpleSpatialResampler::TargetWidth() { + return target_width_; } -bool -VPMSimpleSpatialResampler::ApplyResample(int32_t width, - int32_t height) -{ - if ((width == _targetWidth && height == _targetHeight) || - _resamplingMode == kNoRescaling) +bool VPMSimpleSpatialResampler::ApplyResample(int32_t width, + int32_t height) { + if ((width == target_width_ && height == target_height_) || + resampling_mode_ == kNoRescaling) return false; else return true; } -} // namespace +} // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/spatial_resampler.h b/webrtc/modules/video_processing/main/source/spatial_resampler.h index 69d5cf886..05247341d 100644 --- a/webrtc/modules/video_processing/main/source/spatial_resampler.h +++ b/webrtc/modules/video_processing/main/source/spatial_resampler.h @@ -8,12 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -/* - * spatial_resampler.h - */ - -#ifndef VPM_SPATIAL_RESAMPLER_H -#define VPM_SPATIAL_RESAMPLER_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_SPATIAL_RESAMPLER_H +#define WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_SPATIAL_RESAMPLER_H #include "webrtc/typedefs.h" @@ -25,13 +21,12 @@ namespace webrtc { -class VPMSpatialResampler -{ -public: +class VPMSpatialResampler { + public: virtual ~VPMSpatialResampler() {}; virtual int32_t SetTargetFrameSize(int32_t width, int32_t height) = 0; virtual void SetInputFrameResampleMode(VideoFrameResampling - resamplingMode) = 0; + resampling_mode) = 0; virtual void Reset() = 0; virtual int32_t ResampleFrame(const I420VideoFrame& inFrame, I420VideoFrame* outFrame) = 0; @@ -40,13 +35,12 @@ public: virtual bool ApplyResample(int32_t width, int32_t height) = 0; }; -class VPMSimpleSpatialResampler : public VPMSpatialResampler -{ -public: +class VPMSimpleSpatialResampler : public VPMSpatialResampler { + public: VPMSimpleSpatialResampler(); ~VPMSimpleSpatialResampler(); virtual int32_t SetTargetFrameSize(int32_t width, int32_t height); - virtual void SetInputFrameResampleMode(VideoFrameResampling resamplingMode); + virtual void SetInputFrameResampleMode(VideoFrameResampling resampling_mode); virtual void Reset(); virtual int32_t ResampleFrame(const I420VideoFrame& inFrame, I420VideoFrame* outFrame); @@ -54,14 +48,14 @@ public: virtual int32_t TargetHeight(); virtual bool ApplyResample(int32_t width, int32_t height); -private: + private: - VideoFrameResampling _resamplingMode; - int32_t _targetWidth; - int32_t _targetHeight; - Scaler _scaler; + VideoFrameResampling resampling_mode_; + int32_t target_width_; + int32_t target_height_; + Scaler scaler_; }; -} // namespace +} // namespace webrtc -#endif +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_SPATIAL_RESAMPLER_H diff --git a/webrtc/modules/video_processing/main/source/video_decimator.cc b/webrtc/modules/video_processing/main/source/video_decimator.cc index 84a6cad15..8fd3d0369 100644 --- a/webrtc/modules/video_processing/main/source/video_decimator.cc +++ b/webrtc/modules/video_processing/main/source/video_decimator.cc @@ -17,219 +17,156 @@ namespace webrtc { VPMVideoDecimator::VPMVideoDecimator() -: -_overShootModifier(0), -_dropCount(0), -_keepCount(0), -_targetFrameRate(30), -_incomingFrameRate(0.0f), -_maxFrameRate(30), -_incomingFrameTimes(), -_enableTemporalDecimation(true) -{ - Reset(); + : overshoot_modifier_(0), + drop_count_(0), + keep_count_(0), + target_frame_rate_(30), + incoming_frame_rate_(0.0f), + max_frame_rate_(30), + incoming_frame_times_(), + enable_temporal_decimation_(true) { + Reset(); } -VPMVideoDecimator::~VPMVideoDecimator() -{ - // +VPMVideoDecimator::~VPMVideoDecimator() {} + +void VPMVideoDecimator::Reset() { + overshoot_modifier_ = 0; + drop_count_ = 0; + keep_count_ = 0; + target_frame_rate_ = 30; + incoming_frame_rate_ = 0.0f; + max_frame_rate_ = 30; + memset(incoming_frame_times_, 0, sizeof(incoming_frame_times_)); + enable_temporal_decimation_ = true; } -void -VPMVideoDecimator::Reset() -{ - _overShootModifier = 0; - _dropCount = 0; - _keepCount = 0; - _targetFrameRate = 30; - _incomingFrameRate = 0.0f; - _maxFrameRate = 30; - memset(_incomingFrameTimes, 0, sizeof(_incomingFrameTimes)); - _enableTemporalDecimation = true; +void VPMVideoDecimator::EnableTemporalDecimation(bool enable) { + enable_temporal_decimation_ = enable; } -void -VPMVideoDecimator::EnableTemporalDecimation(bool enable) -{ - _enableTemporalDecimation = enable; -} -int32_t -VPMVideoDecimator::SetMaxFrameRate(uint32_t maxFrameRate) -{ - if (maxFrameRate == 0) - { - return VPM_PARAMETER_ERROR; - } +int32_t VPMVideoDecimator::SetMaxFramerate(uint32_t max_frame_rate) { + if (max_frame_rate == 0) return VPM_PARAMETER_ERROR; - _maxFrameRate = maxFrameRate; - - if (_targetFrameRate > _maxFrameRate) - { - _targetFrameRate = _maxFrameRate; + max_frame_rate_ = max_frame_rate; - } - return VPM_OK; + if (target_frame_rate_ > max_frame_rate_) + target_frame_rate_ = max_frame_rate_; + + return VPM_OK; } -int32_t -VPMVideoDecimator::SetTargetFrameRate(uint32_t frameRate) -{ - if (frameRate == 0) - { - return VPM_PARAMETER_ERROR; - } - if (frameRate > _maxFrameRate) - { - //override - _targetFrameRate = _maxFrameRate; - } - else - { - _targetFrameRate = frameRate; - } - return VPM_OK; +int32_t VPMVideoDecimator::SetTargetframe_rate(uint32_t frame_rate) { + if (frame_rate == 0) return VPM_PARAMETER_ERROR; + + if (frame_rate > max_frame_rate_) { + // Override. + target_frame_rate_ = max_frame_rate_; + } else { + target_frame_rate_ = frame_rate; + } + return VPM_OK; } -bool -VPMVideoDecimator::DropFrame() -{ - if (!_enableTemporalDecimation) - { - return false; +bool VPMVideoDecimator::DropFrame() { + if (!enable_temporal_decimation_) return false; + + if (incoming_frame_rate_ <= 0) return false; + + const uint32_t incomingframe_rate = + static_cast(incoming_frame_rate_ + 0.5f); + + if (target_frame_rate_ == 0) return true; + + bool drop = false; + if (incomingframe_rate > target_frame_rate_) { + int32_t overshoot = + overshoot_modifier_ + (incomingframe_rate - target_frame_rate_); + if (overshoot < 0) { + overshoot = 0; + overshoot_modifier_ = 0; } - if (_incomingFrameRate <= 0) - { - return false; + if (overshoot && 2 * overshoot < (int32_t) incomingframe_rate) { + if (drop_count_) { // Just got here so drop to be sure. + drop_count_ = 0; + return true; + } + const uint32_t dropVar = incomingframe_rate / overshoot; + + if (keep_count_ >= dropVar) { + drop = true; + overshoot_modifier_ = -((int32_t) incomingframe_rate % overshoot) / 3; + keep_count_ = 1; + } else { + keep_count_++; + } + } else { + keep_count_ = 0; + const uint32_t dropVar = overshoot / target_frame_rate_; + if (drop_count_ < dropVar) { + drop = true; + drop_count_++; + } else { + overshoot_modifier_ = overshoot % target_frame_rate_; + drop = false; + drop_count_ = 0; + } } - - const uint32_t incomingFrameRate = static_cast(_incomingFrameRate + 0.5f); - - if (_targetFrameRate == 0) - { - return true; - } - - bool drop = false; - if (incomingFrameRate > _targetFrameRate) - { - int32_t overshoot = _overShootModifier + (incomingFrameRate - _targetFrameRate); - if(overshoot < 0) - { - overshoot = 0; - _overShootModifier = 0; - } - - if (overshoot && 2 * overshoot < (int32_t) incomingFrameRate) - { - - if (_dropCount) // Just got here so drop to be sure. - { - _dropCount = 0; - return true; - } - const uint32_t dropVar = incomingFrameRate / overshoot; - - if (_keepCount >= dropVar) - { - drop = true; - _overShootModifier = -((int32_t) incomingFrameRate % overshoot) / 3; - _keepCount = 1; - } - else - { - - _keepCount++; - } - } - else - { - _keepCount = 0; - const uint32_t dropVar = overshoot / _targetFrameRate; - if (_dropCount < dropVar) - { - drop = true; - _dropCount++; - } - else - { - _overShootModifier = overshoot % _targetFrameRate; - drop = false; - _dropCount = 0; - } - } - } - - return drop; + } + return drop; } -uint32_t -VPMVideoDecimator::DecimatedFrameRate() -{ - ProcessIncomingFrameRate(TickTime::MillisecondTimestamp()); - if (!_enableTemporalDecimation) - { - return static_cast(_incomingFrameRate + 0.5f); - } - return VD_MIN(_targetFrameRate, static_cast(_incomingFrameRate + 0.5f)); +uint32_t VPMVideoDecimator::Decimatedframe_rate() { +ProcessIncomingframe_rate(TickTime::MillisecondTimestamp()); + if (!enable_temporal_decimation_) { + return static_cast(incoming_frame_rate_ + 0.5f); + } + return VD_MIN(target_frame_rate_, + static_cast(incoming_frame_rate_ + 0.5f)); } -uint32_t -VPMVideoDecimator::InputFrameRate() -{ - ProcessIncomingFrameRate(TickTime::MillisecondTimestamp()); - return static_cast(_incomingFrameRate + 0.5f); +uint32_t VPMVideoDecimator::Inputframe_rate() { + ProcessIncomingframe_rate(TickTime::MillisecondTimestamp()); + return static_cast(incoming_frame_rate_ + 0.5f); } -void -VPMVideoDecimator::UpdateIncomingFrameRate() -{ - int64_t now = TickTime::MillisecondTimestamp(); - if(_incomingFrameTimes[0] == 0) - { - // first no shift - } else - { - // shift - for(int i = (kFrameCountHistorySize - 2); i >= 0 ; i--) - { - _incomingFrameTimes[i+1] = _incomingFrameTimes[i]; - } +void VPMVideoDecimator::UpdateIncomingframe_rate() { + int64_t now = TickTime::MillisecondTimestamp(); + if (incoming_frame_times_[0] == 0) { + // First no shift. + } else { + // Shift. + for (int i = kFrameCountHistory_size - 2; i >= 0; i--) { + incoming_frame_times_[i+1] = incoming_frame_times_[i]; } - _incomingFrameTimes[0] = now; - ProcessIncomingFrameRate(now); + } + incoming_frame_times_[0] = now; + ProcessIncomingframe_rate(now); } -void -VPMVideoDecimator::ProcessIncomingFrameRate(int64_t now) -{ - int32_t num = 0; - int32_t nrOfFrames = 0; - for(num = 1; num < (kFrameCountHistorySize - 1); num++) - { - if (_incomingFrameTimes[num] <= 0 || - now - _incomingFrameTimes[num] > kFrameHistoryWindowMs) // don't use data older than 2sec - { - break; - } else - { - nrOfFrames++; - } +void VPMVideoDecimator::ProcessIncomingframe_rate(int64_t now) { + int32_t num = 0; + int32_t nrOfFrames = 0; + for (num = 1; num < (kFrameCountHistory_size - 1); num++) { + // Don't use data older than 2sec. + if (incoming_frame_times_[num] <= 0 || + now - incoming_frame_times_[num] > kFrameHistoryWindowMs) { + break; + } else { + nrOfFrames++; } - if (num > 1) - { - int64_t diff = now - _incomingFrameTimes[num-1]; - _incomingFrameRate = 1.0; - if(diff >0) - { - _incomingFrameRate = nrOfFrames * 1000.0f / static_cast(diff); - } - } - else - { - _incomingFrameRate = static_cast(nrOfFrames); + } + if (num > 1) { + int64_t diff = now - incoming_frame_times_[num-1]; + incoming_frame_rate_ = 1.0; + if (diff > 0) { + incoming_frame_rate_ = nrOfFrames * 1000.0f / static_cast(diff); } + } else { + incoming_frame_rate_ = static_cast(nrOfFrames); + } } -} // namespace +} // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/video_decimator.h b/webrtc/modules/video_processing/main/source/video_decimator.h index 0a6a14085..d17da6188 100644 --- a/webrtc/modules/video_processing/main/source/video_decimator.h +++ b/webrtc/modules/video_processing/main/source/video_decimator.h @@ -8,58 +8,53 @@ * be found in the AUTHORS file in the root of the source tree. */ -/* - * video_decimator.h - */ -#ifndef VPM_VIDEO_DECIMATOR_H -#define VPM_VIDEO_DECIMATOR_H +#ifndef WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_VIDEO_DECIMATOR_H +#define WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_VIDEO_DECIMATOR_H #include "webrtc/modules/interface/module_common_types.h" #include "webrtc/typedefs.h" namespace webrtc { -class VPMVideoDecimator -{ -public: - VPMVideoDecimator(); - ~VPMVideoDecimator(); - - void Reset(); - - void EnableTemporalDecimation(bool enable); - - int32_t SetMaxFrameRate(uint32_t maxFrameRate); - int32_t SetTargetFrameRate(uint32_t frameRate); +class VPMVideoDecimator { + public: + VPMVideoDecimator(); + ~VPMVideoDecimator(); - bool DropFrame(); - - void UpdateIncomingFrameRate(); + void Reset(); - // Get Decimated Frame Rate/Dimensions - uint32_t DecimatedFrameRate(); + void EnableTemporalDecimation(bool enable); - //Get input frame rate - uint32_t InputFrameRate(); + int32_t SetMaxFramerate(uint32_t max_frame_rate); + int32_t SetTargetframe_rate(uint32_t frame_rate); -private: - void ProcessIncomingFrameRate(int64_t now); + bool DropFrame(); - enum { kFrameCountHistorySize = 90}; - enum { kFrameHistoryWindowMs = 2000}; + void UpdateIncomingframe_rate(); - // Temporal decimation - int32_t _overShootModifier; - uint32_t _dropCount; - uint32_t _keepCount; - uint32_t _targetFrameRate; - float _incomingFrameRate; - uint32_t _maxFrameRate; - int64_t _incomingFrameTimes[kFrameCountHistorySize]; - bool _enableTemporalDecimation; + // Get Decimated Frame Rate/Dimensions. + uint32_t Decimatedframe_rate(); + // Get input frame rate. + uint32_t Inputframe_rate(); + + private: + void ProcessIncomingframe_rate(int64_t now); + + enum { kFrameCountHistory_size = 90}; + enum { kFrameHistoryWindowMs = 2000}; + + // Temporal decimation. + int32_t overshoot_modifier_; + uint32_t drop_count_; + uint32_t keep_count_; + uint32_t target_frame_rate_; + float incoming_frame_rate_; + uint32_t max_frame_rate_; + int64_t incoming_frame_times_[kFrameCountHistory_size]; + bool enable_temporal_decimation_; }; -} // namespace +} // namespace webrtc -#endif +#endif // WEBRTC_MODULES_VIDEO_PROCESSING_MAIN_SOURCE_VIDEO_DECIMATOR_H diff --git a/webrtc/modules/video_processing/main/source/video_processing_impl.cc b/webrtc/modules/video_processing/main/source/video_processing_impl.cc index 8152cd173..af1bfe1a4 100644 --- a/webrtc/modules/video_processing/main/source/video_processing_impl.cc +++ b/webrtc/modules/video_processing/main/source/video_processing_impl.cc @@ -17,277 +17,204 @@ namespace webrtc { -namespace -{ - void - SetSubSampling(VideoProcessingModule::FrameStats* stats, - const int32_t width, - const int32_t height) - { - if (width * height >= 640 * 480) - { - stats->subSamplWidth = 3; - stats->subSamplHeight = 3; - } - else if (width * height >= 352 * 288) - { - stats->subSamplWidth = 2; - stats->subSamplHeight = 2; - } - else if (width * height >= 176 * 144) - { - stats->subSamplWidth = 1; - stats->subSamplHeight = 1; - } - else - { - stats->subSamplWidth = 0; - stats->subSamplHeight = 0; - } - } -} - -VideoProcessingModule* -VideoProcessingModule::Create(const int32_t id) -{ - - return new VideoProcessingModuleImpl(id); -} - -void -VideoProcessingModule::Destroy(VideoProcessingModule* module) -{ - if (module) - { - delete static_cast(module); - } -} - -int32_t -VideoProcessingModuleImpl::ChangeUniqueId(const int32_t id) -{ - CriticalSectionScoped mutex(&_mutex); - _id = id; - _brightnessDetection.ChangeUniqueId(id); - _deflickering.ChangeUniqueId(id); - _denoising.ChangeUniqueId(id); - _framePreProcessor.ChangeUniqueId(id); - return VPM_OK; -} - -int32_t -VideoProcessingModuleImpl::Id() const -{ - CriticalSectionScoped mutex(&_mutex); - return _id; -} - -VideoProcessingModuleImpl::VideoProcessingModuleImpl(const int32_t id) : - _id(id), - _mutex(*CriticalSectionWrapper::CreateCriticalSection()) -{ - _brightnessDetection.ChangeUniqueId(id); - _deflickering.ChangeUniqueId(id); - _denoising.ChangeUniqueId(id); - _framePreProcessor.ChangeUniqueId(id); - WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoPreocessing, _id, - "Created"); -} - - -VideoProcessingModuleImpl::~VideoProcessingModuleImpl() -{ - WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoPreocessing, _id, - "Destroyed"); - - delete &_mutex; -} - -void -VideoProcessingModuleImpl::Reset() -{ - CriticalSectionScoped mutex(&_mutex); - _deflickering.Reset(); - _denoising.Reset(); - _brightnessDetection.Reset(); - _framePreProcessor.Reset(); - -} - -int32_t -VideoProcessingModule::GetFrameStats(FrameStats* stats, - const I420VideoFrame& frame) -{ - if (frame.IsZeroSize()) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, -1, - "zero size frame"); - return VPM_PARAMETER_ERROR; - } - - int width = frame.width(); - int height = frame.height(); - - ClearFrameStats(stats); // The histogram needs to be zeroed out. - SetSubSampling(stats, 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)) - { - int k = i * width; - for (int j = 0; j < width; j += (1 << stats->subSamplWidth)) - { - stats->hist[buffer[k + j]]++; - stats->sum += buffer[k + j]; - } - } - - stats->numPixels = (width * height) / ((1 << stats->subSamplWidth) * - (1 << stats->subSamplHeight)); - assert(stats->numPixels > 0); - - // Compute mean value of frame - stats->mean = stats->sum / stats->numPixels; - - return VPM_OK; -} - -bool -VideoProcessingModule::ValidFrameStats(const FrameStats& stats) -{ - if (stats.numPixels == 0) - { - return false; - } - - return true; -} - -void -VideoProcessingModule::ClearFrameStats(FrameStats* stats) -{ - stats->mean = 0; - stats->sum = 0; - stats->numPixels = 0; +namespace { +void SetSubSampling(VideoProcessingModule::FrameStats* stats, + const int32_t width, + const int32_t height) { + if (width * height >= 640 * 480) { + stats->subSamplWidth = 3; + stats->subSamplHeight = 3; + } else if (width * height >= 352 * 288) { + stats->subSamplWidth = 2; + stats->subSamplHeight = 2; + } else if (width * height >= 176 * 144) { + stats->subSamplWidth = 1; + stats->subSamplHeight = 1; + } else { stats->subSamplWidth = 0; stats->subSamplHeight = 0; - memset(stats->hist, 0, sizeof(stats->hist)); + } } - -int32_t -VideoProcessingModule::ColorEnhancement(I420VideoFrame* frame) -{ - return VideoProcessing::ColorEnhancement(frame); -} - -int32_t -VideoProcessingModule::Brighten(I420VideoFrame* frame, int delta) -{ - return VideoProcessing::Brighten(frame, delta); -} - -int32_t -VideoProcessingModuleImpl::Deflickering(I420VideoFrame* frame, - FrameStats* stats) -{ - CriticalSectionScoped mutex(&_mutex); - return _deflickering.ProcessFrame(frame, stats); -} - -int32_t -VideoProcessingModuleImpl::Denoising(I420VideoFrame* frame) -{ - CriticalSectionScoped mutex(&_mutex); - return _denoising.ProcessFrame(frame); -} - -int32_t -VideoProcessingModuleImpl::BrightnessDetection(const I420VideoFrame& frame, - const FrameStats& stats) -{ - CriticalSectionScoped mutex(&_mutex); - return _brightnessDetection.ProcessFrame(frame, stats); -} - - -void -VideoProcessingModuleImpl::EnableTemporalDecimation(bool enable) -{ - CriticalSectionScoped mutex(&_mutex); - _framePreProcessor.EnableTemporalDecimation(enable); -} - - -void -VideoProcessingModuleImpl::SetInputFrameResampleMode(VideoFrameResampling - resamplingMode) -{ - CriticalSectionScoped cs(&_mutex); - _framePreProcessor.SetInputFrameResampleMode(resamplingMode); -} - -int32_t -VideoProcessingModuleImpl::SetMaxFrameRate(uint32_t maxFrameRate) -{ - CriticalSectionScoped cs(&_mutex); - return _framePreProcessor.SetMaxFrameRate(maxFrameRate); - -} - -int32_t -VideoProcessingModuleImpl::SetTargetResolution(uint32_t width, - uint32_t height, - uint32_t frameRate) -{ - CriticalSectionScoped cs(&_mutex); - return _framePreProcessor.SetTargetResolution(width, height, frameRate); -} - - -uint32_t -VideoProcessingModuleImpl::DecimatedFrameRate() -{ - CriticalSectionScoped cs(&_mutex); - return _framePreProcessor.DecimatedFrameRate(); -} - - -uint32_t -VideoProcessingModuleImpl::DecimatedWidth() const -{ - CriticalSectionScoped cs(&_mutex); - return _framePreProcessor.DecimatedWidth(); -} - -uint32_t -VideoProcessingModuleImpl::DecimatedHeight() const -{ - CriticalSectionScoped cs(&_mutex); - return _framePreProcessor.DecimatedHeight(); -} - -int32_t -VideoProcessingModuleImpl::PreprocessFrame(const I420VideoFrame& frame, - I420VideoFrame **processedFrame) -{ - CriticalSectionScoped mutex(&_mutex); - return _framePreProcessor.PreprocessFrame(frame, processedFrame); -} - -VideoContentMetrics* -VideoProcessingModuleImpl::ContentMetrics() const -{ - CriticalSectionScoped mutex(&_mutex); - return _framePreProcessor.ContentMetrics(); -} - - -void -VideoProcessingModuleImpl::EnableContentAnalysis(bool enable) -{ - CriticalSectionScoped mutex(&_mutex); - _framePreProcessor.EnableContentAnalysis(enable); -} - } // namespace + +VideoProcessingModule* VideoProcessingModule::Create(const int32_t id) { + return new VideoProcessingModuleImpl(id); +} + +void VideoProcessingModule::Destroy(VideoProcessingModule* module) { + if (module) + delete static_cast(module); +} + +int32_t VideoProcessingModuleImpl::ChangeUniqueId(const int32_t id) { + CriticalSectionScoped mutex(&mutex_); + id_ = id; + brightness_detection_.ChangeUniqueId(id); + deflickering_.ChangeUniqueId(id); + denoising_.ChangeUniqueId(id); + frame_pre_processor_.ChangeUniqueId(id); + return VPM_OK; +} + +int32_t VideoProcessingModuleImpl::Id() const { + CriticalSectionScoped mutex(&mutex_); + return id_; +} + +VideoProcessingModuleImpl::VideoProcessingModuleImpl(const int32_t id) + : id_(id), + mutex_(*CriticalSectionWrapper::CreateCriticalSection()) { + brightness_detection_.ChangeUniqueId(id); + deflickering_.ChangeUniqueId(id); + denoising_.ChangeUniqueId(id); + frame_pre_processor_.ChangeUniqueId(id); + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoPreocessing, id_, + "Created"); +} + +VideoProcessingModuleImpl::~VideoProcessingModuleImpl() { + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoPreocessing, id_, + "Destroyed"); + delete &mutex_; +} + +void VideoProcessingModuleImpl::Reset() { + CriticalSectionScoped mutex(&mutex_); + deflickering_.Reset(); + denoising_.Reset(); + brightness_detection_.Reset(); + frame_pre_processor_.Reset(); +} + +int32_t VideoProcessingModule::GetFrameStats(FrameStats* stats, + const I420VideoFrame& frame) { + if (frame.IsZeroSize()) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, -1, + "zero size frame"); + return VPM_PARAMETER_ERROR; + } + + int width = frame.width(); + int height = frame.height(); + + ClearFrameStats(stats); // The histogram needs to be zeroed out. + SetSubSampling(stats, 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)) { + int k = i * width; + for (int j = 0; j < width; j += (1 << stats->subSamplWidth)) { + stats->hist[buffer[k + j]]++; + stats->sum += buffer[k + j]; + } + } + + stats->num_pixels = (width * height) / ((1 << stats->subSamplWidth) * + (1 << stats->subSamplHeight)); + 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) { + if (stats.num_pixels == 0) return false; + return true; +} + +void VideoProcessingModule::ClearFrameStats(FrameStats* stats) { + stats->mean = 0; + stats->sum = 0; + stats->num_pixels = 0; + stats->subSamplWidth = 0; + stats->subSamplHeight = 0; + memset(stats->hist, 0, sizeof(stats->hist)); +} + +int32_t VideoProcessingModule::ColorEnhancement(I420VideoFrame* frame) { + return VideoProcessing::ColorEnhancement(frame); +} + +int32_t VideoProcessingModule::Brighten(I420VideoFrame* frame, int delta) { + return VideoProcessing::Brighten(frame, delta); +} + +int32_t VideoProcessingModuleImpl::Deflickering(I420VideoFrame* frame, + FrameStats* stats) { + CriticalSectionScoped mutex(&mutex_); + return deflickering_.ProcessFrame(frame, stats); +} + +int32_t VideoProcessingModuleImpl::Denoising(I420VideoFrame* frame) { + CriticalSectionScoped mutex(&mutex_); + return denoising_.ProcessFrame(frame); +} + +int32_t VideoProcessingModuleImpl::BrightnessDetection( + const I420VideoFrame& frame, + const FrameStats& stats) { + CriticalSectionScoped mutex(&mutex_); + return brightness_detection_.ProcessFrame(frame, stats); +} + + +void VideoProcessingModuleImpl::EnableTemporalDecimation(bool enable) { + CriticalSectionScoped mutex(&mutex_); + frame_pre_processor_.EnableTemporalDecimation(enable); +} + + +void VideoProcessingModuleImpl::SetInputFrameResampleMode(VideoFrameResampling + resampling_mode) { + CriticalSectionScoped cs(&mutex_); + frame_pre_processor_.SetInputFrameResampleMode(resampling_mode); +} + +int32_t VideoProcessingModuleImpl::SetMaxFramerate(uint32_t max_frame_rate) { + CriticalSectionScoped cs(&mutex_); + return frame_pre_processor_.SetMaxFramerate(max_frame_rate); +} + +int32_t VideoProcessingModuleImpl::SetTargetResolution(uint32_t width, + uint32_t height, + uint32_t frame_rate) { + CriticalSectionScoped cs(&mutex_); + return frame_pre_processor_.SetTargetResolution(width, height, frame_rate); +} + +uint32_t VideoProcessingModuleImpl::Decimatedframe_rate() { + CriticalSectionScoped cs(&mutex_); + return frame_pre_processor_.Decimatedframe_rate(); +} + +uint32_t VideoProcessingModuleImpl::DecimatedWidth() const { + CriticalSectionScoped cs(&mutex_); + return frame_pre_processor_.DecimatedWidth(); +} + +uint32_t VideoProcessingModuleImpl::DecimatedHeight() const { + CriticalSectionScoped cs(&mutex_); + return frame_pre_processor_.DecimatedHeight(); +} + +int32_t VideoProcessingModuleImpl::PreprocessFrame( + const I420VideoFrame& frame, + I420VideoFrame **processed_frame) { + CriticalSectionScoped mutex(&mutex_); + return frame_pre_processor_.PreprocessFrame(frame, processed_frame); +} + +VideoContentMetrics* VideoProcessingModuleImpl::ContentMetrics() const { + CriticalSectionScoped mutex(&mutex_); + return frame_pre_processor_.ContentMetrics(); +} + +void VideoProcessingModuleImpl::EnableContentAnalysis(bool enable) { + CriticalSectionScoped mutex(&mutex_); + frame_pre_processor_.EnableContentAnalysis(enable); +} + +} // namespace webrtc diff --git a/webrtc/modules/video_processing/main/source/video_processing_impl.h b/webrtc/modules/video_processing/main/source/video_processing_impl.h index 278aa7b14..913bb6483 100644 --- a/webrtc/modules/video_processing/main/source/video_processing_impl.h +++ b/webrtc/modules/video_processing/main/source/video_processing_impl.h @@ -22,67 +22,64 @@ namespace webrtc { class CriticalSectionWrapper; -class VideoProcessingModuleImpl : public VideoProcessingModule -{ -public: +class VideoProcessingModuleImpl : public VideoProcessingModule { + public: + VideoProcessingModuleImpl(int32_t id); - VideoProcessingModuleImpl(int32_t id); + virtual ~VideoProcessingModuleImpl(); - virtual ~VideoProcessingModuleImpl(); + int32_t Id() const; - int32_t Id() const; + virtual int32_t ChangeUniqueId(const int32_t id); - virtual int32_t ChangeUniqueId(const int32_t id); + virtual void Reset(); - virtual void Reset(); + virtual int32_t Deflickering(I420VideoFrame* frame, FrameStats* stats); - virtual int32_t Deflickering(I420VideoFrame* frame, FrameStats* stats); + virtual int32_t Denoising(I420VideoFrame* frame); - virtual int32_t Denoising(I420VideoFrame* frame); + virtual int32_t BrightnessDetection(const I420VideoFrame& frame, + const FrameStats& stats); - virtual int32_t BrightnessDetection(const I420VideoFrame& frame, - const FrameStats& stats); + // Frame pre-processor functions - //Frame pre-processor functions + // Enable temporal decimation + virtual void EnableTemporalDecimation(bool enable); - //Enable temporal decimation - virtual void EnableTemporalDecimation(bool enable); + virtual void SetInputFrameResampleMode(VideoFrameResampling resampling_mode); - virtual void SetInputFrameResampleMode(VideoFrameResampling resamplingMode); + // Enable content analysis + virtual void EnableContentAnalysis(bool enable); - //Enable content analysis - virtual void EnableContentAnalysis(bool enable); + // Set max frame rate + virtual int32_t SetMaxFramerate(uint32_t max_frame_rate); - //Set max frame rate - virtual int32_t SetMaxFrameRate(uint32_t maxFrameRate); - - // Set Target Resolution: frame rate and dimension - virtual int32_t SetTargetResolution(uint32_t width, - uint32_t height, - uint32_t frameRate); + // Set Target Resolution: frame rate and dimension + virtual int32_t SetTargetResolution(uint32_t width, + uint32_t height, + uint32_t frame_rate); - // Get decimated values: frame rate/dimension - virtual uint32_t DecimatedFrameRate(); - virtual uint32_t DecimatedWidth() const; - virtual uint32_t DecimatedHeight() const; + // Get decimated values: frame rate/dimension + virtual uint32_t Decimatedframe_rate(); + virtual uint32_t DecimatedWidth() const; + virtual uint32_t DecimatedHeight() const; - // Preprocess: - // Pre-process incoming frame: Sample when needed and compute content - // metrics when enabled. - // If no resampling takes place - processedFrame is set to NULL. - virtual int32_t PreprocessFrame(const I420VideoFrame& frame, - I420VideoFrame** processedFrame); - virtual VideoContentMetrics* ContentMetrics() const; + // 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. + virtual int32_t PreprocessFrame(const I420VideoFrame& frame, + I420VideoFrame** processed_frame); + virtual VideoContentMetrics* ContentMetrics() const; -private: - int32_t _id; - CriticalSectionWrapper& _mutex; - - VPMDeflickering _deflickering; - VPMDenoising _denoising; - VPMBrightnessDetection _brightnessDetection; - VPMFramePreprocessor _framePreProcessor; + private: + int32_t id_; + CriticalSectionWrapper& mutex_; + VPMDeflickering deflickering_; + VPMDenoising denoising_; + VPMBrightnessDetection brightness_detection_; + VPMFramePreprocessor frame_pre_processor_; }; } // namespace diff --git a/webrtc/modules/video_processing/main/test/unit_test/brightness_detection_test.cc b/webrtc/modules/video_processing/main/test/unit_test/brightness_detection_test.cc index d17ade969..d7ac72908 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/brightness_detection_test.cc +++ b/webrtc/modules/video_processing/main/test/unit_test/brightness_detection_test.cc @@ -19,24 +19,24 @@ TEST_F(VideoProcessingModuleTest, BrightnessDetection) uint32_t frameNum = 0; int32_t brightnessWarning = 0; uint32_t warningCount = 0; - scoped_array video_buffer(new uint8_t[_frame_length]); - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) == - _frame_length) + scoped_array video_buffer(new uint8_t[frame_length_]); + while (fread(video_buffer.get(), 1, frame_length_, source_file_) == + frame_length_) { EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); frameNum++; VideoProcessingModule::FrameStats stats; - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - ASSERT_GE(brightnessWarning = _vpm->BrightnessDetection(_videoFrame, + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + ASSERT_GE(brightnessWarning = vpm_->BrightnessDetection(video_frame_, stats), 0); if (brightnessWarning != VideoProcessingModule::kNoWarning) { warningCount++; } } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; // Expect few warnings float warningProportion = static_cast(warningCount) / frameNum * 100; @@ -44,21 +44,21 @@ TEST_F(VideoProcessingModuleTest, BrightnessDetection) printf("Stock foreman: %.1f %%\n", warningProportion); EXPECT_LT(warningProportion, 10); - rewind(_sourceFile); + rewind(source_file_); frameNum = 0; warningCount = 0; - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) == - _frame_length && + while (fread(video_buffer.get(), 1, frame_length_, source_file_) == + frame_length_ && frameNum < 300) { EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); frameNum++; - uint8_t* frame = _videoFrame.buffer(kYPlane); + 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) @@ -69,8 +69,8 @@ TEST_F(VideoProcessingModuleTest, BrightnessDetection) } VideoProcessingModule::FrameStats stats; - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - ASSERT_GE(brightnessWarning = _vpm->BrightnessDetection(_videoFrame, + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + ASSERT_GE(brightnessWarning = vpm_->BrightnessDetection(video_frame_, stats), 0); EXPECT_NE(VideoProcessingModule::kDarkWarning, brightnessWarning); if (brightnessWarning == VideoProcessingModule::kBrightWarning) @@ -78,35 +78,35 @@ TEST_F(VideoProcessingModuleTest, BrightnessDetection) warningCount++; } } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; // Expect many brightness warnings warningProportion = static_cast(warningCount) / frameNum * 100; printf("Bright foreman: %.1f %%\n", warningProportion); EXPECT_GT(warningProportion, 95); - rewind(_sourceFile); + rewind(source_file_); frameNum = 0; warningCount = 0; - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) == - _frame_length && frameNum < 300) + while (fread(video_buffer.get(), 1, frame_length_, source_file_) == + frame_length_ && frameNum < 300) { EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); frameNum++; - uint8_t* y_plane = _videoFrame.buffer(kYPlane); + 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(yTmp); } VideoProcessingModule::FrameStats stats; - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - ASSERT_GE(brightnessWarning = _vpm->BrightnessDetection(_videoFrame, + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + ASSERT_GE(brightnessWarning = vpm_->BrightnessDetection(video_frame_, stats), 0); EXPECT_NE(VideoProcessingModule::kBrightWarning, brightnessWarning); if (brightnessWarning == VideoProcessingModule::kDarkWarning) @@ -114,7 +114,7 @@ TEST_F(VideoProcessingModuleTest, BrightnessDetection) warningCount++; } } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; // Expect many darkness warnings warningProportion = static_cast(warningCount) / frameNum * 100; diff --git a/webrtc/modules/video_processing/main/test/unit_test/color_enhancement_test.cc b/webrtc/modules/video_processing/main/test/unit_test/color_enhancement_test.cc index c048003fb..fc560bef1 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/color_enhancement_test.cc +++ b/webrtc/modules/video_processing/main/test/unit_test/color_enhancement_test.cc @@ -23,14 +23,14 @@ TEST_F(VideoProcessingModuleTest, ColorEnhancement) { TickTime t0; TickTime t1; - TickInterval accTicks; + TickInterval acc_ticks; // Use a shorter version of the Foreman clip for this test. - fclose(_sourceFile); + fclose(source_file_); const std::string video_file = webrtc::test::ResourcePath("foreman_cif_short", "yuv"); - _sourceFile = fopen(video_file.c_str(), "rb"); - ASSERT_TRUE(_sourceFile != NULL) << + source_file_ = fopen(video_file.c_str(), "rb"); + ASSERT_TRUE(source_file_ != NULL) << "Cannot read source file: " + video_file + "\n"; std::string output_file = webrtc::test::OutputPath() + @@ -39,27 +39,27 @@ TEST_F(VideoProcessingModuleTest, ColorEnhancement) ASSERT_TRUE(modFile != NULL) << "Could not open output file.\n"; uint32_t frameNum = 0; - scoped_array video_buffer(new uint8_t[_frame_length]); - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) == - _frame_length) + scoped_array 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, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); frameNum++; t0 = TickTime::Now(); - ASSERT_EQ(0, VideoProcessingModule::ColorEnhancement(&_videoFrame)); + ASSERT_EQ(0, VideoProcessingModule::ColorEnhancement(&video_frame_)); t1 = TickTime::Now(); - accTicks += t1 - t0; - if (PrintI420VideoFrame(_videoFrame, modFile) < 0) { + acc_ticks += t1 - t0; + if (PrintI420VideoFrame(video_frame_, modFile) < 0) { return; } } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; printf("\nTime per frame: %d us \n", - static_cast(accTicks.Microseconds() / frameNum)); + static_cast(acc_ticks.Microseconds() / frameNum)); rewind(modFile); printf("Comparing files...\n\n"); @@ -82,62 +82,62 @@ TEST_F(VideoProcessingModuleTest, ColorEnhancement) ASSERT_EQ(refLen, testLen) << "File lengths differ."; I420VideoFrame refVideoFrame; - refVideoFrame.CreateEmptyFrame(_width, _height, - _width, _half_width, _half_width); + refVideoFrame.CreateEmptyFrame(width_, height_, + width_, half_width_, half_width_); // Compare frame-by-frame. - scoped_array ref_buffer(new uint8_t[_frame_length]); - while (fread(video_buffer.get(), 1, _frame_length, modFile) == - _frame_length) + scoped_array ref_buffer(new uint8_t[frame_length_]); + while (fread(video_buffer.get(), 1, frame_length_, modFile) == + frame_length_) { // Using ConvertToI420 to add stride to the image. EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); - ASSERT_EQ(_frame_length, fread(ref_buffer.get(), 1, _frame_length, + width_, height_, + 0, kRotateNone, &video_frame_)); + ASSERT_EQ(frame_length_, fread(ref_buffer.get(), 1, frame_length_, refFile)); EXPECT_EQ(0, ConvertToI420(kI420, ref_buffer.get(), 0, 0, - _width, _height, + width_, height_, 0, kRotateNone, &refVideoFrame)); - EXPECT_EQ(0, memcmp(_videoFrame.buffer(kYPlane), + EXPECT_EQ(0, memcmp(video_frame_.buffer(kYPlane), refVideoFrame.buffer(kYPlane), - _size_y)); - EXPECT_EQ(0, memcmp(_videoFrame.buffer(kUPlane), + size_y_)); + EXPECT_EQ(0, memcmp(video_frame_.buffer(kUPlane), refVideoFrame.buffer(kUPlane), - _size_uv)); - EXPECT_EQ(0, memcmp(_videoFrame.buffer(kVPlane), + size_uv_)); + EXPECT_EQ(0, memcmp(video_frame_.buffer(kVPlane), refVideoFrame.buffer(kVPlane), - _size_uv)); + size_uv_)); } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; // Verify that all color pixels are enhanced, and no luminance values are // altered. - scoped_array testFrame(new uint8_t[_frame_length]); + scoped_array testFrame(new uint8_t[frame_length_]); // Use value 128 as probe value, since we know that this will be changed // in the enhancement. - memset(testFrame.get(), 128, _frame_length); + memset(testFrame.get(), 128, frame_length_); I420VideoFrame testVideoFrame; - testVideoFrame.CreateEmptyFrame(_width, _height, - _width, _half_width, _half_width); + testVideoFrame.CreateEmptyFrame(width_, height_, + width_, half_width_, half_width_); EXPECT_EQ(0, ConvertToI420(kI420, testFrame.get(), 0, 0, - _width, _height, 0, kRotateNone, + width_, height_, 0, kRotateNone, &testVideoFrame)); ASSERT_EQ(0, VideoProcessingModule::ColorEnhancement(&testVideoFrame)); EXPECT_EQ(0, memcmp(testVideoFrame.buffer(kYPlane), testFrame.get(), - _size_y)) + size_y_)) << "Function is modifying the luminance."; EXPECT_NE(0, memcmp(testVideoFrame.buffer(kUPlane), - testFrame.get() + _size_y, _size_uv)) << + testFrame.get() + size_y_, size_uv_)) << "Function is not modifying all chrominance pixels"; EXPECT_NE(0, memcmp(testVideoFrame.buffer(kVPlane), - testFrame.get() + _size_y + _size_uv, _size_uv)) << + testFrame.get() + size_y_ + size_uv_, size_uv_)) << "Function is not modifying all chrominance pixels"; ASSERT_EQ(0, fclose(refFile)); diff --git a/webrtc/modules/video_processing/main/test/unit_test/content_metrics_test.cc b/webrtc/modules/video_processing/main/test/unit_test/content_metrics_test.cc index 26080da78..36a1ad762 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/content_metrics_test.cc +++ b/webrtc/modules/video_processing/main/test/unit_test/content_metrics_test.cc @@ -15,32 +15,30 @@ namespace webrtc { -TEST_F(VideoProcessingModuleTest, ContentAnalysis) -{ - VPMContentAnalysis _ca_c(false); - VPMContentAnalysis _ca_sse(true); - VideoContentMetrics *_cM_c, *_cM_SSE; +TEST_F(VideoProcessingModuleTest, ContentAnalysis) { + VPMContentAnalysis ca__c(false); + VPMContentAnalysis ca__sse(true); + VideoContentMetrics *_cM_c, *_cM_SSE; - _ca_c.Initialize(_width,_height); - _ca_sse.Initialize(_width,_height); + ca__c.Initialize(width_,height_); + ca__sse.Initialize(width_,height_); - scoped_array video_buffer(new uint8_t[_frame_length]); - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) - == _frame_length) - { - // Using ConvertToI420 to add stride to the image. - EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); - _cM_c = _ca_c.ComputeContentMetrics(_videoFrame); - _cM_SSE = _ca_sse.ComputeContentMetrics(_videoFrame); + scoped_array 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, kRotateNone, &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(_sourceFile)) << "Error reading source file"; + 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 diff --git a/webrtc/modules/video_processing/main/test/unit_test/deflickering_test.cc b/webrtc/modules/video_processing/main/test/unit_test/deflickering_test.cc index 85f4fd6eb..0fa3f48b4 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/deflickering_test.cc +++ b/webrtc/modules/video_processing/main/test/unit_test/deflickering_test.cc @@ -23,17 +23,17 @@ TEST_F(VideoProcessingModuleTest, Deflickering) { enum { NumRuns = 30 }; uint32_t frameNum = 0; - const uint32_t frameRate = 15; + const uint32_t frame_rate = 15; - int64_t minRuntime = 0; - int64_t avgRuntime = 0; + int64_t min_runtime = 0; + int64_t avg_runtime = 0; // Close automatically opened Foreman. - fclose(_sourceFile); + fclose(source_file_); const std::string input_file = webrtc::test::ResourcePath("deflicker_before_cif_short", "yuv"); - _sourceFile = fopen(input_file.c_str(), "rb"); - ASSERT_TRUE(_sourceFile != NULL) << + source_file_ = fopen(input_file.c_str(), "rb"); + ASSERT_TRUE(source_file_ != NULL) << "Cannot read input file: " << input_file << "\n"; const std::string output_file = @@ -43,57 +43,57 @@ TEST_F(VideoProcessingModuleTest, Deflickering) "Could not open output file: " << output_file << "\n"; printf("\nRun time [us / frame]:\n"); - scoped_array video_buffer(new uint8_t[_frame_length]); - for (uint32_t runIdx = 0; runIdx < NumRuns; runIdx++) + scoped_array video_buffer(new uint8_t[frame_length_]); + for (uint32_t run_idx = 0; run_idx < NumRuns; run_idx++) { TickTime t0; TickTime t1; - TickInterval accTicks; + TickInterval acc_ticks; uint32_t timeStamp = 1; frameNum = 0; - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) == - _frame_length) + while (fread(video_buffer.get(), 1, frame_length_, source_file_) == + frame_length_) { frameNum++; EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); - _videoFrame.set_timestamp(timeStamp); + width_, height_, + 0, kRotateNone, &video_frame_)); + video_frame_.set_timestamp(timeStamp); t0 = TickTime::Now(); VideoProcessingModule::FrameStats stats; - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - ASSERT_EQ(0, _vpm->Deflickering(&_videoFrame, &stats)); + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + ASSERT_EQ(0, vpm_->Deflickering(&video_frame_, &stats)); t1 = TickTime::Now(); - accTicks += (t1 - t0); + acc_ticks += (t1 - t0); - if (runIdx == 0) + if (run_idx == 0) { - if (PrintI420VideoFrame(_videoFrame, deflickerFile) < 0) { + if (PrintI420VideoFrame(video_frame_, deflickerFile) < 0) { return; } } - timeStamp += (90000 / frameRate); + timeStamp += (90000 / frame_rate); } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; - printf("%u\n", static_cast(accTicks.Microseconds() / frameNum)); - if (accTicks.Microseconds() < minRuntime || runIdx == 0) + printf("%u\n", static_cast(acc_ticks.Microseconds() / frameNum)); + if (acc_ticks.Microseconds() < min_runtime || run_idx == 0) { - minRuntime = accTicks.Microseconds(); + min_runtime = acc_ticks.Microseconds(); } - avgRuntime += accTicks.Microseconds(); + avg_runtime += acc_ticks.Microseconds(); - rewind(_sourceFile); + rewind(source_file_); } ASSERT_EQ(0, fclose(deflickerFile)); // TODO(kjellander): Add verification of deflicker output file. printf("\nAverage run time = %d us / frame\n", - static_cast(avgRuntime / frameNum / NumRuns)); + static_cast(avg_runtime / frameNum / NumRuns)); printf("Min run time = %d us / frame\n\n", - static_cast(minRuntime / frameNum)); + static_cast(min_runtime / frameNum)); } } // namespace webrtc diff --git a/webrtc/modules/video_processing/main/test/unit_test/denoising_test.cc b/webrtc/modules/video_processing/main/test/unit_test/denoising_test.cc index 8a3439318..3023a2d7a 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/denoising_test.cc +++ b/webrtc/modules/video_processing/main/test/unit_test/denoising_test.cc @@ -25,8 +25,8 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_ANDROID(Denoising)) enum { NumRuns = 10 }; uint32_t frameNum = 0; - int64_t minRuntime = 0; - int64_t avgRuntime = 0; + int64_t min_runtime = 0; + int64_t avg_runtime = 0; const std::string denoise_filename = webrtc::test::OutputPath() + "denoise_testfile.yuv"; @@ -41,50 +41,50 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_ANDROID(Denoising)) "Could not open noisy file: " << noise_filename << "\n"; printf("\nRun time [us / frame]:\n"); - for (uint32_t runIdx = 0; runIdx < NumRuns; runIdx++) + for (uint32_t run_idx = 0; run_idx < NumRuns; run_idx++) { TickTime t0; TickTime t1; - TickInterval accTicks; + TickInterval acc_ticks; int32_t modifiedPixels = 0; frameNum = 0; - scoped_array video_buffer(new uint8_t[_frame_length]); - while (fread(video_buffer.get(), 1, _frame_length, _sourceFile) == - _frame_length) + scoped_array video_buffer(new uint8_t[frame_length_]); + while (fread(video_buffer.get(), 1, frame_length_, source_file_) == + frame_length_) { EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); frameNum++; - uint8_t* sourceBuffer = _videoFrame.buffer(kYPlane); + uint8_t* sourceBuffer = video_frame_.buffer(kYPlane); // Add noise to a part in video stream // Random noise // TODO: investigate the effectiveness of this test. - for (int ir = 0; ir < _height; ir++) + for (int ir = 0; ir < height_; ir++) { - uint32_t ik = ir * _width; - for (int ic = 0; ic < _width; ic++) + uint32_t ik = ir * width_; + for (int ic = 0; ic < width_; ic++) { uint8_t r = rand() % 16; r -= 8; - if (ir < _height / 4) + if (ir < height_ / 4) r = 0; - if (ir >= 3 * _height / 4) + if (ir >= 3 * height_ / 4) r = 0; - if (ic < _width / 4) + if (ic < width_ / 4) r = 0; - if (ic >= 3 * _width / 4) + if (ic >= 3 * width_ / 4) r = 0; /*uint8_t pixelValue = 0; - if (ir >= _height / 2) + if (ir >= height_ / 2) { // Region 3 or 4 pixelValue = 170; } - if (ic >= _width / 2) + if (ic >= width_ / 2) { // Region 2 or 4 pixelValue += 85; } @@ -95,42 +95,42 @@ TEST_F(VideoProcessingModuleTest, DISABLED_ON_ANDROID(Denoising)) } } - if (runIdx == 0) + if (run_idx == 0) { - if (PrintI420VideoFrame(_videoFrame, noiseFile) < 0) { + if (PrintI420VideoFrame(video_frame_, noiseFile) < 0) { return; } } t0 = TickTime::Now(); - ASSERT_GE(modifiedPixels = _vpm->Denoising(&_videoFrame), 0); + ASSERT_GE(modifiedPixels = vpm_->Denoising(&video_frame_), 0); t1 = TickTime::Now(); - accTicks += (t1 - t0); + acc_ticks += (t1 - t0); - if (runIdx == 0) + if (run_idx == 0) { - if (PrintI420VideoFrame(_videoFrame, noiseFile) < 0) { + if (PrintI420VideoFrame(video_frame_, noiseFile) < 0) { return; } } } - ASSERT_NE(0, feof(_sourceFile)) << "Error reading source file"; + ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; - printf("%u\n", static_cast(accTicks.Microseconds() / frameNum)); - if (accTicks.Microseconds() < minRuntime || runIdx == 0) + printf("%u\n", static_cast(acc_ticks.Microseconds() / frameNum)); + if (acc_ticks.Microseconds() < min_runtime || run_idx == 0) { - minRuntime = accTicks.Microseconds(); + min_runtime = acc_ticks.Microseconds(); } - avgRuntime += accTicks.Microseconds(); + avg_runtime += acc_ticks.Microseconds(); - rewind(_sourceFile); + rewind(source_file_); } ASSERT_EQ(0, fclose(denoiseFile)); ASSERT_EQ(0, fclose(noiseFile)); printf("\nAverage run time = %d us / frame\n", - static_cast(avgRuntime / frameNum / NumRuns)); + static_cast(avg_runtime / frameNum / NumRuns)); printf("Min run time = %d us / frame\n\n", - static_cast(minRuntime / frameNum)); + static_cast(min_runtime / frameNum)); } } // namespace webrtc diff --git a/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.cc b/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.cc index 66452603c..89c59ec8b 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.cc +++ b/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.cc @@ -18,297 +18,285 @@ namespace webrtc { -// The |sourceFrame| is scaled to |target_width|,|target_height|, using the +// The |sourceFrame| is scaled to |targetwidth_|,|targetheight_|, using the // filter mode set to |mode|. The |expected_psnr| is used to verify basic // quality when the resampled frame is scaled back up/down to the // original/source size. |expected_psnr| is set to be ~0.1/0.05dB lower than // actual PSNR verified under the same conditions. -void TestSize(const I420VideoFrame& sourceFrame, int target_width, - int target_height, int mode, double expected_psnr, +void TestSize(const I420VideoFrame& sourceFrame, int targetwidth_, + int targetheight_, int mode, double expected_psnr, VideoProcessingModule* vpm); bool CompareFrames(const webrtc::I420VideoFrame& frame1, const webrtc::I420VideoFrame& frame2); -VideoProcessingModuleTest::VideoProcessingModuleTest() : - _vpm(NULL), - _sourceFile(NULL), - _width(352), - _half_width((_width + 1) / 2), - _height(288), - _size_y(_width * _height), - _size_uv(_half_width * ((_height + 1) / 2)), - _frame_length(CalcBufferSize(kI420, _width, _height)) -{ -} +VideoProcessingModuleTest::VideoProcessingModuleTest() + : vpm_(NULL), + source_file_(NULL), + width_(352), + half_width_((width_ + 1) / 2), + height_(288), + size_y_(width_ * height_), + size_uv_(half_width_ * ((height_ + 1) / 2)), + frame_length_(CalcBufferSize(kI420, width_, height_)) {} -void VideoProcessingModuleTest::SetUp() -{ - _vpm = VideoProcessingModule::Create(0); - ASSERT_TRUE(_vpm != NULL); +void VideoProcessingModuleTest::SetUp() { + vpm_ = VideoProcessingModule::Create(0); + ASSERT_TRUE(vpm_ != NULL); - ASSERT_EQ(0, _videoFrame.CreateEmptyFrame(_width, _height, _width, - _half_width, _half_width)); + ASSERT_EQ(0, video_frame_.CreateEmptyFrame(width_, height_, width_, + half_width_, half_width_)); const std::string video_file = webrtc::test::ResourcePath("foreman_cif", "yuv"); - _sourceFile = fopen(video_file.c_str(),"rb"); - ASSERT_TRUE(_sourceFile != NULL) << + source_file_ = fopen(video_file.c_str(),"rb"); + ASSERT_TRUE(source_file_ != NULL) << "Cannot read source file: " + video_file + "\n"; } -void VideoProcessingModuleTest::TearDown() -{ - if (_sourceFile != NULL) { - ASSERT_EQ(0, fclose(_sourceFile)); +void VideoProcessingModuleTest::TearDown() { + if (source_file_ != NULL) { + ASSERT_EQ(0, fclose(source_file_)); } - _sourceFile = NULL; + source_file_ = NULL; - if (_vpm != NULL) { - VideoProcessingModule::Destroy(_vpm); + if (vpm_ != NULL) { + VideoProcessingModule::Destroy(vpm_); } - _vpm = NULL; + vpm_ = NULL; } -TEST_F(VideoProcessingModuleTest, HandleNullBuffer) -{ +TEST_F(VideoProcessingModuleTest, HandleNullBuffer) { // TODO(mikhal/stefan): Do we need this one? VideoProcessingModule::FrameStats stats; // Video frame with unallocated buffer. I420VideoFrame videoFrame; - videoFrame.set_width(_width); - videoFrame.set_height(_height); + videoFrame.set_width(width_); + videoFrame.set_height(height_); - EXPECT_EQ(-3, _vpm->GetFrameStats(&stats, videoFrame)); + EXPECT_EQ(-3, vpm_->GetFrameStats(&stats, videoFrame)); - EXPECT_EQ(-1, _vpm->ColorEnhancement(&videoFrame)); + EXPECT_EQ(-1, vpm_->ColorEnhancement(&videoFrame)); - EXPECT_EQ(-1, _vpm->Deflickering(&videoFrame, &stats)); + EXPECT_EQ(-1, vpm_->Deflickering(&videoFrame, &stats)); - EXPECT_EQ(-1, _vpm->Denoising(&videoFrame)); + EXPECT_EQ(-1, vpm_->Denoising(&videoFrame)); - EXPECT_EQ(-3, _vpm->BrightnessDetection(videoFrame, stats)); + EXPECT_EQ(-3, vpm_->BrightnessDetection(videoFrame, stats)); } -TEST_F(VideoProcessingModuleTest, HandleBadStats) -{ +TEST_F(VideoProcessingModuleTest, HandleBadStats) { VideoProcessingModule::FrameStats stats; - scoped_array video_buffer(new uint8_t[_frame_length]); - ASSERT_EQ(_frame_length, fread(video_buffer.get(), 1, _frame_length, - _sourceFile)); + scoped_array 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, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); - EXPECT_EQ(-1, _vpm->Deflickering(&_videoFrame, &stats)); + EXPECT_EQ(-1, vpm_->Deflickering(&video_frame_, &stats)); - EXPECT_EQ(-3, _vpm->BrightnessDetection(_videoFrame, stats)); + EXPECT_EQ(-3, vpm_->BrightnessDetection(video_frame_, stats)); } -TEST_F(VideoProcessingModuleTest, HandleBadSize) -{ +TEST_F(VideoProcessingModuleTest, HandleBadSize) { VideoProcessingModule::FrameStats stats; - _videoFrame.ResetSize(); - _videoFrame.set_width(_width); - _videoFrame.set_height(0); - EXPECT_EQ(-3, _vpm->GetFrameStats(&stats, _videoFrame)); + video_frame_.ResetSize(); + video_frame_.set_width(width_); + video_frame_.set_height(0); + EXPECT_EQ(-3, vpm_->GetFrameStats(&stats, video_frame_)); - EXPECT_EQ(-1, _vpm->ColorEnhancement(&_videoFrame)); + EXPECT_EQ(-1, vpm_->ColorEnhancement(&video_frame_)); - EXPECT_EQ(-1, _vpm->Deflickering(&_videoFrame, &stats)); + EXPECT_EQ(-1, vpm_->Deflickering(&video_frame_, &stats)); - EXPECT_EQ(-1, _vpm->Denoising(&_videoFrame)); + EXPECT_EQ(-1, vpm_->Denoising(&video_frame_)); - EXPECT_EQ(-3, _vpm->BrightnessDetection(_videoFrame, stats)); + EXPECT_EQ(-3, vpm_->BrightnessDetection(video_frame_, stats)); - EXPECT_EQ(VPM_PARAMETER_ERROR, _vpm->SetTargetResolution(0,0,0)); - EXPECT_EQ(VPM_PARAMETER_ERROR, _vpm->SetMaxFrameRate(0)); + EXPECT_EQ(VPM_PARAMETER_ERROR, vpm_->SetTargetResolution(0,0,0)); + EXPECT_EQ(VPM_PARAMETER_ERROR, vpm_->SetMaxFramerate(0)); - I420VideoFrame *outFrame = NULL; - EXPECT_EQ(VPM_PARAMETER_ERROR, _vpm->PreprocessFrame(_videoFrame, - &outFrame)); + I420VideoFrame *out_frame = NULL; + EXPECT_EQ(VPM_PARAMETER_ERROR, vpm_->PreprocessFrame(video_frame_, + &out_frame)); } -TEST_F(VideoProcessingModuleTest, IdenticalResultsAfterReset) -{ - I420VideoFrame videoFrame2; +TEST_F(VideoProcessingModuleTest, IdenticalResultsAfterReset) { + I420VideoFrame video_frame2; VideoProcessingModule::FrameStats stats; // Only testing non-static functions here. - scoped_array video_buffer(new uint8_t[_frame_length]); - ASSERT_EQ(_frame_length, fread(video_buffer.get(), 1, _frame_length, - _sourceFile)); + scoped_array 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, kRotateNone, &_videoFrame)); - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - ASSERT_EQ(0, videoFrame2.CopyFrame(_videoFrame)); - ASSERT_EQ(0, _vpm->Deflickering(&_videoFrame, &stats)); - _vpm->Reset(); + width_, height_, + 0, kRotateNone, &video_frame_)); + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + ASSERT_EQ(0, video_frame2.CopyFrame(video_frame_)); + ASSERT_EQ(0, vpm_->Deflickering(&video_frame_, &stats)); + vpm_->Reset(); // Retrieve frame stats again in case Deflickering() has zeroed them. - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, videoFrame2)); - ASSERT_EQ(0, _vpm->Deflickering(&videoFrame2, &stats)); - EXPECT_TRUE(CompareFrames(_videoFrame, videoFrame2)); + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame2)); + ASSERT_EQ(0, vpm_->Deflickering(&video_frame2, &stats)); + EXPECT_TRUE(CompareFrames(video_frame_, video_frame2)); - ASSERT_EQ(_frame_length, fread(video_buffer.get(), 1, _frame_length, - _sourceFile)); + ASSERT_EQ(frame_length_, fread(video_buffer.get(), 1, frame_length_, + source_file_)); // Using ConvertToI420 to add stride to the image. EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); - videoFrame2.CopyFrame(_videoFrame); - EXPECT_TRUE(CompareFrames(_videoFrame, videoFrame2)); - ASSERT_GE(_vpm->Denoising(&_videoFrame), 0); - _vpm->Reset(); - ASSERT_GE(_vpm->Denoising(&videoFrame2), 0); - EXPECT_TRUE(CompareFrames(_videoFrame, videoFrame2)); + width_, height_, + 0, kRotateNone, &video_frame_)); + video_frame2.CopyFrame(video_frame_); + EXPECT_TRUE(CompareFrames(video_frame_, video_frame2)); + ASSERT_GE(vpm_->Denoising(&video_frame_), 0); + vpm_->Reset(); + ASSERT_GE(vpm_->Denoising(&video_frame2), 0); + EXPECT_TRUE(CompareFrames(video_frame_, video_frame2)); - ASSERT_EQ(_frame_length, fread(video_buffer.get(), 1, _frame_length, - _sourceFile)); + 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, kRotateNone, &_videoFrame)); - ASSERT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - videoFrame2.CopyFrame(_videoFrame); - ASSERT_EQ(0, _vpm->BrightnessDetection(_videoFrame, stats)); - _vpm->Reset(); - ASSERT_EQ(0, _vpm->BrightnessDetection(videoFrame2, stats)); - EXPECT_TRUE(CompareFrames(_videoFrame, videoFrame2)); + width_, height_, + 0, kRotateNone, &video_frame_)); + ASSERT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + video_frame2.CopyFrame(video_frame_); + ASSERT_EQ(0, vpm_->BrightnessDetection(video_frame_, stats)); + vpm_->Reset(); + ASSERT_EQ(0, vpm_->BrightnessDetection(video_frame2, stats)); + EXPECT_TRUE(CompareFrames(video_frame_, video_frame2)); } -TEST_F(VideoProcessingModuleTest, FrameStats) -{ +TEST_F(VideoProcessingModuleTest, FrameStats) { VideoProcessingModule::FrameStats stats; - scoped_array video_buffer(new uint8_t[_frame_length]); - ASSERT_EQ(_frame_length, fread(video_buffer.get(), 1, _frame_length, - _sourceFile)); + scoped_array 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, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); - EXPECT_FALSE(_vpm->ValidFrameStats(stats)); - EXPECT_EQ(0, _vpm->GetFrameStats(&stats, _videoFrame)); - EXPECT_TRUE(_vpm->ValidFrameStats(stats)); + EXPECT_FALSE(vpm_->ValidFrameStats(stats)); + EXPECT_EQ(0, vpm_->GetFrameStats(&stats, video_frame_)); + EXPECT_TRUE(vpm_->ValidFrameStats(stats)); printf("\nFrameStats\n"); - printf("mean: %u\nnumPixels: %u\nsubSamplWidth: " + printf("mean: %u\nnum_pixels: %u\nsubSamplWidth: " "%u\nsumSamplHeight: %u\nsum: %u\n\n", static_cast(stats.mean), - static_cast(stats.numPixels), + static_cast(stats.num_pixels), static_cast(stats.subSamplHeight), static_cast(stats.subSamplWidth), static_cast(stats.sum)); - _vpm->ClearFrameStats(&stats); - EXPECT_FALSE(_vpm->ValidFrameStats(stats)); + vpm_->ClearFrameStats(&stats); + EXPECT_FALSE(vpm_->ValidFrameStats(stats)); } -TEST_F(VideoProcessingModuleTest, PreprocessorLogic) -{ +TEST_F(VideoProcessingModuleTest, PreprocessorLogic) { // Disable temporal sampling (frame dropping). - _vpm->EnableTemporalDecimation(false); + vpm_->EnableTemporalDecimation(false); int resolution = 100; - EXPECT_EQ(VPM_OK, _vpm->SetMaxFrameRate(30)); - EXPECT_EQ(VPM_OK, _vpm->SetTargetResolution(resolution, resolution, 15)); - EXPECT_EQ(VPM_OK, _vpm->SetTargetResolution(resolution, resolution, 30)); + EXPECT_EQ(VPM_OK, vpm_->SetMaxFramerate(30)); + EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 15)); + EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 30)); // Disable spatial sampling. - _vpm->SetInputFrameResampleMode(kNoRescaling); - EXPECT_EQ(VPM_OK, _vpm->SetTargetResolution(resolution, resolution, 30)); - I420VideoFrame* outFrame = NULL; + vpm_->SetInputFrameResampleMode(kNoRescaling); + EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 30)); + I420VideoFrame* out_frame = NULL; // Set rescaling => output frame != NULL. - _vpm->SetInputFrameResampleMode(kFastRescaling); - EXPECT_EQ(VPM_OK, _vpm->SetTargetResolution(resolution, resolution, 30)); - EXPECT_EQ(VPM_OK, _vpm->PreprocessFrame(_videoFrame, &outFrame)); - EXPECT_FALSE(outFrame == NULL); - if (outFrame) { - EXPECT_EQ(resolution, outFrame->width()); - EXPECT_EQ(resolution, outFrame->height()); + vpm_->SetInputFrameResampleMode(kFastRescaling); + EXPECT_EQ(VPM_OK, vpm_->SetTargetResolution(resolution, resolution, 30)); + EXPECT_EQ(VPM_OK, vpm_->PreprocessFrame(video_frame_, &out_frame)); + EXPECT_FALSE(out_frame == NULL); + if (out_frame) { + EXPECT_EQ(resolution, out_frame->width()); + EXPECT_EQ(resolution, out_frame->height()); } // No rescaling=> output frame = NULL. - _vpm->SetInputFrameResampleMode(kNoRescaling); - EXPECT_EQ(VPM_OK, _vpm->PreprocessFrame(_videoFrame, &outFrame)); - EXPECT_TRUE(outFrame == NULL); + vpm_->SetInputFrameResampleMode(kNoRescaling); + EXPECT_EQ(VPM_OK, vpm_->PreprocessFrame(video_frame_, &out_frame)); + EXPECT_TRUE(out_frame == NULL); } -TEST_F(VideoProcessingModuleTest, Resampler) -{ +TEST_F(VideoProcessingModuleTest, Resampler) { enum { NumRuns = 1 }; - int64_t minRuntime = 0; - int64_t avgRuntime = 0; + int64_t min_runtime = 0; + int64_t avg_runtime = 0; TickTime t0; TickTime t1; - TickInterval accTicks; + TickInterval acc_ticks; - rewind(_sourceFile); - ASSERT_TRUE(_sourceFile != NULL) << + rewind(source_file_); + ASSERT_TRUE(source_file_ != NULL) << "Cannot read input file \n"; // CA not needed here - _vpm->EnableContentAnalysis(false); + vpm_->EnableContentAnalysis(false); // no temporal decimation - _vpm->EnableTemporalDecimation(false); + vpm_->EnableTemporalDecimation(false); // Reading test frame - scoped_array video_buffer(new uint8_t[_frame_length]); - ASSERT_EQ(_frame_length, fread(video_buffer.get(), 1, _frame_length, - _sourceFile)); + scoped_array video_buffer(new uint8_t[frame_length_]); + ASSERT_EQ(frame_length_, fread(video_buffer.get(), 1, frame_length_, + source_file_)); // Using ConvertToI420 to add stride to the image. EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, - _width, _height, - 0, kRotateNone, &_videoFrame)); + width_, height_, + 0, kRotateNone, &video_frame_)); - for (uint32_t runIdx = 0; runIdx < NumRuns; runIdx++) - { - // initiate test timer + for (uint32_t run_idx = 0; run_idx < NumRuns; run_idx++) { + // Initiate test timer. t0 = TickTime::Now(); // Init the sourceFrame with a timestamp. - _videoFrame.set_render_time_ms(t0.MillisecondTimestamp()); - _videoFrame.set_timestamp(t0.MillisecondTimestamp() * 90); + video_frame_.set_render_time_ms(t0.MillisecondTimestamp()); + video_frame_.set_timestamp(t0.MillisecondTimestamp() * 90); // Test scaling to different sizes: source is of |width|/|height| = 352/288. // Scaling mode in VPM is currently fixed to kScaleBox (mode = 3). - TestSize(_videoFrame, 100, 50, 3, 24.0, _vpm); - TestSize(_videoFrame, 352/4, 288/4, 3, 25.2, _vpm); - TestSize(_videoFrame, 352/2, 288/2, 3, 28.1, _vpm); - TestSize(_videoFrame, 352, 288, 3, -1, _vpm); // no resampling. - TestSize(_videoFrame, 2*352, 2*288, 3, 32.2, _vpm); - TestSize(_videoFrame, 400, 256, 3, 31.3, _vpm); - TestSize(_videoFrame, 480, 640, 3, 32.15, _vpm); - TestSize(_videoFrame, 960, 720, 3, 32.2, _vpm); - TestSize(_videoFrame, 1280, 720, 3, 32.15, _vpm); + TestSize(video_frame_, 100, 50, 3, 24.0, vpm_); + TestSize(video_frame_, 352/4, 288/4, 3, 25.2, vpm_); + TestSize(video_frame_, 352/2, 288/2, 3, 28.1, vpm_); + TestSize(video_frame_, 352, 288, 3, -1, vpm_); // no resampling. + TestSize(video_frame_, 2*352, 2*288, 3, 32.2, vpm_); + TestSize(video_frame_, 400, 256, 3, 31.3, vpm_); + TestSize(video_frame_, 480, 640, 3, 32.15, vpm_); + TestSize(video_frame_, 960, 720, 3, 32.2, vpm_); + TestSize(video_frame_, 1280, 720, 3, 32.15, vpm_); // Upsampling to odd size. - TestSize(_videoFrame, 501, 333, 3, 32.05, _vpm); + TestSize(video_frame_, 501, 333, 3, 32.05, vpm_); // Downsample to odd size. - TestSize(_videoFrame, 281, 175, 3, 29.3, _vpm); + TestSize(video_frame_, 281, 175, 3, 29.3, vpm_); // stop timer t1 = TickTime::Now(); - accTicks += (t1 - t0); + acc_ticks += (t1 - t0); - if (accTicks.Microseconds() < minRuntime || runIdx == 0) { - minRuntime = accTicks.Microseconds(); + if (acc_ticks.Microseconds() < min_runtime || run_idx == 0) { + min_runtime = acc_ticks.Microseconds(); } - avgRuntime += accTicks.Microseconds(); + avg_runtime += acc_ticks.Microseconds(); } printf("\nAverage run time = %d us / frame\n", - //static_cast(avgRuntime / frameNum / NumRuns)); - static_cast(avgRuntime)); + //static_cast(avg_runtime / frameNum / NumRuns)); + static_cast(avg_runtime)); printf("Min run time = %d us / frame\n\n", - //static_cast(minRuntime / frameNum)); - static_cast(minRuntime)); + //static_cast(min_runtime / frameNum)); + static_cast(min_runtime)); } -void TestSize(const I420VideoFrame& source_frame, int target_width, - int target_height, int mode, double expected_psnr, +void TestSize(const I420VideoFrame& source_frame, int targetwidth_, + int targetheight_, int mode, double expected_psnr, VideoProcessingModule* vpm) { - int source_width = source_frame.width(); - int source_height = source_frame.height(); + int sourcewidth_ = source_frame.width(); + int sourceheight_ = source_frame.height(); I420VideoFrame* out_frame = NULL; - ASSERT_EQ(VPM_OK, vpm->SetTargetResolution(target_width, target_height, 30)); + ASSERT_EQ(VPM_OK, vpm->SetTargetResolution(targetwidth_, targetheight_, 30)); ASSERT_EQ(VPM_OK, vpm->PreprocessFrame(source_frame, &out_frame)); if (out_frame) { @@ -321,19 +309,19 @@ void TestSize(const I420VideoFrame& source_frame, int target_width, // (2) scale the resampled frame (|out_frame|) back to the original size and // compute PSNR relative to |source_frame| (for automatic verification). // (3) write out the processed frame for viewing. - if (target_width != static_cast(source_width) || - target_height != static_cast(source_height)) { + if (targetwidth_ != static_cast(sourcewidth_) || + targetheight_ != static_cast(sourceheight_)) { // Write the processed frame to file for visual inspection. std::ostringstream filename; filename << webrtc::test::OutputPath() << "Resampler_"<< mode << "_" << - "from_" << source_width << "x" << source_height << "_to_" << - target_width << "x" << target_height << "_30Hz_P420.yuv"; + "from_" << sourcewidth_ << "x" << sourceheight_ << "_to_" << + targetwidth_ << "x" << targetheight_ << "_30Hz_P420.yuv"; std::cout << "Watch " << filename.str() << " and verify that it is okay." << std::endl; FILE* stand_alone_file = fopen(filename.str().c_str(), "wb"); if (PrintI420VideoFrame(*out_frame, stand_alone_file) < 0) { fprintf(stderr, "Failed to write frame for scaling to width/height: " - " %d %d \n", target_width, target_height); + " %d %d \n", targetwidth_, targetheight_); return; } fclose(stand_alone_file); @@ -342,8 +330,8 @@ void TestSize(const I420VideoFrame& source_frame, int target_width, resampled_source_frame.CopyFrame(*out_frame); // Scale |resampled_source_frame| back to original/source size. - ASSERT_EQ(VPM_OK, vpm->SetTargetResolution(source_width, - source_height, + ASSERT_EQ(VPM_OK, vpm->SetTargetResolution(sourcewidth_, + sourceheight_, 30)); ASSERT_EQ(VPM_OK, vpm->PreprocessFrame(resampled_source_frame, &out_frame)); @@ -351,14 +339,14 @@ void TestSize(const I420VideoFrame& source_frame, int target_width, // Write the processed frame to file for visual inspection. std::ostringstream filename2; filename2 << webrtc::test::OutputPath() << "Resampler_"<< mode << "_" << - "from_" << target_width << "x" << target_height << "_to_" << - source_width << "x" << source_height << "_30Hz_P420.yuv"; + "from_" << targetwidth_ << "x" << targetheight_ << "_to_" << + sourcewidth_ << "x" << sourceheight_ << "_30Hz_P420.yuv"; std::cout << "Watch " << filename2.str() << " and verify that it is okay." << std::endl; stand_alone_file = fopen(filename2.str().c_str(), "wb"); if (PrintI420VideoFrame(*out_frame, stand_alone_file) < 0) { fprintf(stderr, "Failed to write frame for scaling to width/height " - "%d %d \n", source_width, source_height); + "%d %d \n", sourcewidth_, sourceheight_); return; } fclose(stand_alone_file); @@ -368,7 +356,7 @@ void TestSize(const I420VideoFrame& source_frame, int target_width, EXPECT_GT(psnr, expected_psnr); printf("PSNR: %f. PSNR is between source of size %d %d, and a modified " "source which is scaled down/up to: %d %d, and back to source size \n", - psnr, source_width, source_height, target_width, target_height); + psnr, sourcewidth_, sourceheight_, targetwidth_, targetheight_); } } diff --git a/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.h b/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.h index db8841b5d..6daf9c2fd 100644 --- a/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.h +++ b/webrtc/modules/video_processing/main/test/unit_test/video_processing_unittest.h @@ -18,31 +18,28 @@ namespace webrtc { -class VideoProcessingModuleTest : public ::testing::Test -{ -protected: - VideoProcessingModuleTest(); - virtual void SetUp(); - virtual void TearDown(); - static void SetUpTestCase() - { - Trace::CreateTrace(); - std::string trace_file = webrtc::test::OutputPath() + "VPMTrace.txt"; - ASSERT_EQ(0, Trace::SetTraceFile(trace_file.c_str())); - } - static void TearDownTestCase() - { - Trace::ReturnTrace(); - } - VideoProcessingModule* _vpm; - FILE* _sourceFile; - I420VideoFrame _videoFrame; - const int _width; - const int _half_width; - const int _height; - const int _size_y; - const int _size_uv; - const unsigned int _frame_length; +class VideoProcessingModuleTest : public ::testing::Test { + protected: + VideoProcessingModuleTest(); + virtual void SetUp(); + virtual void TearDown(); + static void SetUpTestCase() { + Trace::CreateTrace(); + std::string trace_file = webrtc::test::OutputPath() + "VPMTrace.txt"; + ASSERT_EQ(0, Trace::SetTraceFile(trace_file.c_str())); + } + static void TearDownTestCase() { + Trace::ReturnTrace(); + } + VideoProcessingModule* vpm_; + FILE* source_file_; + I420VideoFrame video_frame_; + const int width_; + const int half_width_; + const int height_; + const int size_y_; + const int size_uv_; + const unsigned int frame_length_; }; } // namespace webrtc