blob: 77ec965810ffc78535ea5a6340f62439fba98fc0 [file] [log] [blame]
jackychenfa0befe2016-04-01 07:46:58 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/video_processing/util/noise_estimation.h"
jackychene42c0ae2016-04-16 10:44:16 -070012#if DISPLAY
13#include <android/log.h>
14#endif
jackychenfa0befe2016-04-01 07:46:58 -070015
16namespace webrtc {
17
18void NoiseEstimation::Init(int width, int height, CpuType cpu_type) {
19 int mb_cols = width >> 4;
20 int mb_rows = height >> 4;
21 consec_low_var_.reset(new uint32_t[mb_cols * mb_rows]());
22 width_ = width;
23 height_ = height;
24 mb_cols_ = width_ >> 4;
25 mb_rows_ = height_ >> 4;
26 cpu_type_ = cpu_type;
27}
28
29void NoiseEstimation::GetNoise(int mb_index, uint32_t var, uint32_t luma) {
30 consec_low_var_[mb_index]++;
31 num_static_block_++;
32 if (consec_low_var_[mb_index] >= kConsecLowVarFrame &&
jackychenafaae0d2016-04-12 23:02:55 -070033 (luma >> 6) < kAverageLumaMax && (luma >> 6) > kAverageLumaMin) {
jackychenfa0befe2016-04-01 07:46:58 -070034 // Normalized var by the average luma value, this gives more weight to
35 // darker blocks.
jackychenafaae0d2016-04-12 23:02:55 -070036 int nor_var = var / (luma >> 10);
jackychenfa0befe2016-04-01 07:46:58 -070037 noise_var_ +=
38 nor_var > kBlockSelectionVarMax ? kBlockSelectionVarMax : nor_var;
39 num_noisy_block_++;
40 }
41}
42
43void NoiseEstimation::ResetConsecLowVar(int mb_index) {
44 consec_low_var_[mb_index] = 0;
45}
46
47void NoiseEstimation::UpdateNoiseLevel() {
48 // TODO(jackychen): Tune a threshold for numb_noisy_block > T to make the
49 // condition more reasonable.
50 // No enough samples implies the motion of the camera or too many moving
51 // objects in the frame.
jackychenafaae0d2016-04-12 23:02:55 -070052 if (num_static_block_ <
53 (0.65 * mb_cols_ * mb_rows_ / NOISE_SUBSAMPLE_INTERVAL) ||
54 !num_noisy_block_) {
55#if DISPLAY
jackychene42c0ae2016-04-16 10:44:16 -070056 if (cpu_type_) {
57 printf("Not enough samples. %d \n", num_static_block_);
58 } else {
59 __android_log_print(ANDROID_LOG_DEBUG, "DISPLAY",
60 "Not enough samples. %d \n", num_static_block_);
61 }
jackychenafaae0d2016-04-12 23:02:55 -070062#endif
jackychenfa0befe2016-04-01 07:46:58 -070063 noise_var_ = 0;
64 noise_var_accum_ = 0;
jackychenfa0befe2016-04-01 07:46:58 -070065 num_noisy_block_ = 0;
jackychenafaae0d2016-04-12 23:02:55 -070066 num_static_block_ = 0;
jackychenfa0befe2016-04-01 07:46:58 -070067 return;
68 } else {
jackychenafaae0d2016-04-12 23:02:55 -070069#if DISPLAY
jackychene42c0ae2016-04-16 10:44:16 -070070 if (cpu_type_) {
71 printf("%d %d fraction = %.3f\n", num_static_block_,
72 mb_cols_ * mb_rows_ / NOISE_SUBSAMPLE_INTERVAL,
73 percent_static_block_);
74 } else {
75 __android_log_print(ANDROID_LOG_DEBUG, "DISPLAY",
76 "%d %d fraction = %.3f\n", num_static_block_,
77 mb_cols_ * mb_rows_ / NOISE_SUBSAMPLE_INTERVAL,
78 percent_static_block_);
79 }
jackychenafaae0d2016-04-12 23:02:55 -070080#endif
jackychenfa0befe2016-04-01 07:46:58 -070081 // Normalized by the number of noisy blocks.
82 noise_var_ /= num_noisy_block_;
83 // Get the percentage of static blocks.
jackychenafaae0d2016-04-12 23:02:55 -070084 percent_static_block_ = static_cast<double>(num_static_block_) /
85 (mb_cols_ * mb_rows_ / NOISE_SUBSAMPLE_INTERVAL);
jackychenfa0befe2016-04-01 07:46:58 -070086 num_noisy_block_ = 0;
87 num_static_block_ = 0;
88 }
89 // For the first frame just update the value with current noise_var_,
90 // otherwise, use the averaging window.
91 if (noise_var_accum_ == 0) {
92 noise_var_accum_ = noise_var_;
93 } else {
94 noise_var_accum_ = (noise_var_accum_ * 15 + noise_var_) / 16;
95 }
jackychenfa0befe2016-04-01 07:46:58 -070096#if DISPLAY
jackychene42c0ae2016-04-16 10:44:16 -070097 if (cpu_type_) {
98 printf("noise_var_accum_ = %.1f, noise_var_ = %d.\n", noise_var_accum_,
99 noise_var_);
100 } else {
101 __android_log_print(ANDROID_LOG_DEBUG, "DISPLAY",
102 "noise_var_accum_ = %.1f, noise_var_ = %d.\n",
103 noise_var_accum_, noise_var_);
104 }
jackychenfa0befe2016-04-01 07:46:58 -0700105#endif
jackychenafaae0d2016-04-12 23:02:55 -0700106 // Reset noise_var_ for the next frame.
107 noise_var_ = 0;
jackychenfa0befe2016-04-01 07:46:58 -0700108}
109
110uint8_t NoiseEstimation::GetNoiseLevel() {
111 int noise_thr = cpu_type_ ? kNoiseThreshold : kNoiseThresholdNeon;
112 UpdateNoiseLevel();
113 if (noise_var_accum_ > noise_thr) {
114 return 1;
115 }
116 return 0;
117}
118
119} // namespace webrtc