Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: webrtc/modules/video_processing/video_denoiser.cc

Issue 1871853003: External VNR speed improvement and more. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: More clean-up. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/modules/video_processing/video_denoiser.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10
10 #include "webrtc/common_video/libyuv/include/scaler.h" 11 #include "webrtc/common_video/libyuv/include/scaler.h"
11 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" 12 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
12 #include "webrtc/modules/video_processing/video_denoiser.h" 13 #include "webrtc/modules/video_processing/video_denoiser.h"
13 14
15 #if DISPLAY // Rectangle diagnostics
16 static void CopyMem8x8(const uint8_t* src,
17 int src_stride,
18 uint8_t* dst,
19 int dst_stride) {
20 for (int i = 0; i < 8; i++) {
21 memcpy(dst, src, 8);
22 src += src_stride;
23 dst += dst_stride;
24 }
25 }
26
27 static void ShowRect(const std::unique_ptr<DenoiserFilter>& filter,
28 const std::unique_ptr<uint8_t[]>& d_status,
29 const std::unique_ptr<uint8_t[]>& moving_edge_red,
30 const std::unique_ptr<uint8_t[]>& x_density,
31 const std::unique_ptr<uint8_t[]>& y_density,
32 const uint8_t* u_src,
33 const uint8_t* v_src,
34 uint8_t* u_dst,
35 uint8_t* v_dst,
36 int mb_rows_,
37 int mb_cols_,
38 int stride_u_,
39 int stride_v_) {
40 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) {
41 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) {
42 int mb_index = mb_row * mb_cols_ + mb_col;
43 const uint8_t* mb_src_u =
44 u_src + (mb_row << 3) * stride_u_ + (mb_col << 3);
45 const uint8_t* mb_src_v =
46 v_src + (mb_row << 3) * stride_v_ + (mb_col << 3);
47 uint8_t* mb_dst_u = u_dst + (mb_row << 3) * stride_u_ + (mb_col << 3);
48 uint8_t* mb_dst_v = v_dst + (mb_row << 3) * stride_v_ + (mb_col << 3);
49 uint8_t uv_tmp[8 * 8];
50 memset(uv_tmp, 200, 8 * 8);
51 if (d_status[mb_index] == 1) {
52 // Paint to red.
53 CopyMem8x8(mb_src_u, stride_u_, mb_dst_u, stride_u_);
54 CopyMem8x8(uv_tmp, 8, mb_dst_v, stride_v_);
55 } else if (moving_edge_red[mb_row * mb_cols_ + mb_col] &&
56 x_density[mb_col] * y_density[mb_row]) {
57 // Paint to blue.
58 CopyMem8x8(uv_tmp, 8, mb_dst_u, stride_u_);
59 CopyMem8x8(mb_src_v, stride_v_, mb_dst_v, stride_v_);
60 } else {
61 CopyMem8x8(mb_src_u, stride_u_, mb_dst_u, stride_u_);
62 CopyMem8x8(mb_src_v, stride_v_, mb_dst_v, stride_v_);
63 }
64 }
65 }
66 }
67 #endif
68
14 namespace webrtc { 69 namespace webrtc {
15 70
16 VideoDenoiser::VideoDenoiser(bool runtime_cpu_detection) 71 VideoDenoiser::VideoDenoiser(bool runtime_cpu_detection)
17 : width_(0), 72 : width_(0),
18 height_(0), 73 height_(0),
19 filter_(DenoiserFilter::Create(runtime_cpu_detection, &cpu_type_)), 74 filter_(DenoiserFilter::Create(runtime_cpu_detection, &cpu_type_)),
20 ne_(new NoiseEstimation()) {} 75 ne_(new NoiseEstimation()) {}
21 76
22 #if EXPERIMENTAL 77 void VideoDenoiser::DenoiserReset(const VideoFrame& frame,
23 // Check the mb position(1: close to the center, 3: close to the border). 78 VideoFrame* denoised_frame,
24 static int PositionCheck(int mb_row, int mb_col, int mb_rows, int mb_cols) { 79 VideoFrame* denoised_frame_prev) {
25 if ((mb_row >= (mb_rows >> 3)) && (mb_row <= (7 * mb_rows >> 3)) && 80 width_ = frame.width();
26 (mb_col >= (mb_cols >> 3)) && (mb_col <= (7 * mb_cols >> 3))) 81 height_ = frame.height();
82 mb_cols_ = width_ >> 4;
83 mb_rows_ = height_ >> 4;
84 stride_y_ = frame.stride(kYPlane);
85 stride_u_ = frame.stride(kUPlane);
86 stride_v_ = frame.stride(kVPlane);
87
88 // Allocate an empty buffer for denoised_frame_prev.
89 denoised_frame_prev->CreateEmptyFrame(width_, height_, stride_y_, stride_u_,
90 stride_v_);
91 // Allocate and initialize denoised_frame with key frame.
92 denoised_frame->CreateFrame(frame.buffer(kYPlane), frame.buffer(kUPlane),
93 frame.buffer(kVPlane), width_, height_, stride_y_,
94 stride_u_, stride_v_, kVideoRotation_0);
95 // Set time parameters to the output frame.
96 denoised_frame->set_timestamp(frame.timestamp());
97 denoised_frame->set_render_time_ms(frame.render_time_ms());
98
99 // Init noise estimator and allocate buffers.
100 ne_->Init(width_, height_, cpu_type_);
101 moving_edge_.reset(new uint8_t[mb_cols_ * mb_rows_]);
102 mb_filter_decision_.reset(new DenoiserDecision[mb_cols_ * mb_rows_]);
103 x_density_.reset(new uint8_t[mb_cols_]);
104 y_density_.reset(new uint8_t[mb_rows_]);
105 moving_object_.reset(new uint8_t[mb_cols_ * mb_rows_]);
106 }
107
108 int VideoDenoiser::PositionCheck(int mb_row, int mb_col, int noise_level) {
109 if (noise_level == 0)
27 return 1; 110 return 1;
28 else if ((mb_row >= (mb_rows >> 4)) && (mb_row <= (15 * mb_rows >> 4)) && 111 if ((mb_row <= (mb_rows_ >> 4)) || (mb_col <= (mb_cols_ >> 4)) ||
29 (mb_col >= (mb_cols >> 4)) && (mb_col <= (15 * mb_cols >> 4))) 112 (mb_col >= (15 * mb_cols_ >> 4)))
113 return 3;
114 else if ((mb_row <= (mb_rows_ >> 3)) || (mb_col <= (mb_cols_ >> 3)) ||
115 (mb_col >= (7 * mb_cols_ >> 3)))
30 return 2; 116 return 2;
31 else 117 else
32 return 3; 118 return 1;
33 } 119 }
34 120
35 static void ReduceFalseDetection(const std::unique_ptr<uint8_t[]>& d_status, 121 void VideoDenoiser::ReduceFalseDetection(
36 std::unique_ptr<uint8_t[]>* d_status_tmp1, 122 const std::unique_ptr<uint8_t[]>& d_status,
37 std::unique_ptr<uint8_t[]>* d_status_tmp2, 123 std::unique_ptr<uint8_t[]>* moving_edge_red,
38 int noise_level, 124 int noise_level) {
39 int mb_rows, 125 // From up left corner.
40 int mb_cols) { 126 int mb_col_stop = mb_cols_ - 1;
41 // Draft. This can be optimized. This code block is to reduce false detection 127 for (int mb_row = 0; mb_row <= mb_rows_ - 1; ++mb_row) {
42 // in moving object detection. 128 for (int mb_col = 0; mb_col <= mb_col_stop; ++mb_col) {
43 int mb_row_min = noise_level ? mb_rows >> 3 : 1; 129 if (d_status[mb_row * mb_cols_ + mb_col]) {
44 int mb_col_min = noise_level ? mb_cols >> 3 : 1; 130 mb_col_stop = mb_col - 1;
45 int mb_row_max = noise_level ? (7 * mb_rows >> 3) : mb_rows - 2; 131 break;
46 int mb_col_max = noise_level ? (7 * mb_cols >> 3) : mb_cols - 2; 132 }
47 memcpy((*d_status_tmp1).get(), d_status.get(), mb_rows * mb_cols); 133 (*moving_edge_red)[mb_row * mb_cols_ + mb_col] = 0;
48 // Up left. 134 }
49 for (int mb_row = mb_row_min; mb_row <= mb_row_max; ++mb_row) { 135 }
50 for (int mb_col = mb_col_min; mb_col <= mb_col_max; ++mb_col) { 136 // From bottom left corner.
51 (*d_status_tmp1)[mb_row * mb_cols + mb_col] |= 137 mb_col_stop = mb_cols_ - 1;
52 ((*d_status_tmp1)[(mb_row - 1) * mb_cols + mb_col] | 138 for (int mb_row = mb_rows_ - 1; mb_row >= 0; --mb_row) {
53 (*d_status_tmp1)[mb_row * mb_cols + mb_col - 1]); 139 for (int mb_col = 0; mb_col <= mb_col_stop; ++mb_col) {
54 } 140 if (d_status[mb_row * mb_cols_ + mb_col]) {
55 } 141 mb_col_stop = mb_col - 1;
56 memcpy((*d_status_tmp2).get(), (*d_status_tmp1).get(), mb_rows * mb_cols); 142 break;
57 memcpy((*d_status_tmp1).get(), d_status.get(), mb_rows * mb_cols); 143 }
58 // Bottom left. 144 (*moving_edge_red)[mb_row * mb_cols_ + mb_col] = 0;
59 for (int mb_row = mb_row_max; mb_row >= mb_row_min; --mb_row) { 145 }
60 for (int mb_col = mb_col_min; mb_col <= mb_col_max; ++mb_col) { 146 }
61 (*d_status_tmp1)[mb_row * mb_cols + mb_col] |= 147 // From up right corner.
62 ((*d_status_tmp1)[(mb_row + 1) * mb_cols + mb_col] | 148 mb_col_stop = 0;
63 (*d_status_tmp1)[mb_row * mb_cols + mb_col - 1]); 149 for (int mb_row = 0; mb_row <= mb_rows_ - 1; ++mb_row) {
64 (*d_status_tmp2)[mb_row * mb_cols + mb_col] &= 150 for (int mb_col = mb_cols_ - 1; mb_col >= mb_col_stop; --mb_col) {
65 (*d_status_tmp1)[mb_row * mb_cols + mb_col]; 151 if (d_status[mb_row * mb_cols_ + mb_col]) {
66 } 152 mb_col_stop = mb_col + 1;
67 } 153 break;
68 memcpy((*d_status_tmp1).get(), d_status.get(), mb_rows * mb_cols); 154 }
69 // Up right. 155 (*moving_edge_red)[mb_row * mb_cols_ + mb_col] = 0;
70 for (int mb_row = mb_row_min; mb_row <= mb_row_max; ++mb_row) { 156 }
71 for (int mb_col = mb_col_max; mb_col >= mb_col_min; --mb_col) { 157 }
72 (*d_status_tmp1)[mb_row * mb_cols + mb_col] |= 158 // From bottom right corner.
73 ((*d_status_tmp1)[(mb_row - 1) * mb_cols + mb_col] | 159 mb_col_stop = 0;
74 (*d_status_tmp1)[mb_row * mb_cols + mb_col + 1]); 160 for (int mb_row = mb_rows_ - 1; mb_row >= 0; --mb_row) {
75 (*d_status_tmp2)[mb_row * mb_cols + mb_col] &= 161 for (int mb_col = mb_cols_ - 1; mb_col >= mb_col_stop; --mb_col) {
76 (*d_status_tmp1)[mb_row * mb_cols + mb_col]; 162 if (d_status[mb_row * mb_cols_ + mb_col]) {
77 } 163 mb_col_stop = mb_col + 1;
78 } 164 break;
79 memcpy((*d_status_tmp1).get(), d_status.get(), mb_rows * mb_cols); 165 }
80 // Bottom right. 166 (*moving_edge_red)[mb_row * mb_cols_ + mb_col] = 0;
81 for (int mb_row = mb_row_max; mb_row >= mb_row_min; --mb_row) { 167 }
82 for (int mb_col = mb_col_max; mb_col >= mb_col_min; --mb_col) { 168 }
83 (*d_status_tmp1)[mb_row * mb_cols + mb_col] |= 169 }
84 ((*d_status_tmp1)[(mb_row + 1) * mb_cols + mb_col] | 170
85 (*d_status_tmp1)[mb_row * mb_cols + mb_col + 1]); 171 bool VideoDenoiser::IsTrailingBlock(const std::unique_ptr<uint8_t[]>& d_status,
86 (*d_status_tmp2)[mb_row * mb_cols + mb_col] &= 172 int mb_row,
87 (*d_status_tmp1)[mb_row * mb_cols + mb_col]; 173 int mb_col) {
88 } 174 bool ret = false;
89 } 175 int mb_index = mb_row * mb_cols_ + mb_col;
90 } 176 if (!mb_row || !mb_col || mb_row == mb_rows_ - 1 || mb_col == mb_cols_ - 1)
91 177 ret = false;
92 static bool TrailingBlock(const std::unique_ptr<uint8_t[]>& d_status, 178 else
93 int mb_row, 179 ret = d_status[mb_index + 1] || d_status[mb_index - 1] ||
94 int mb_col, 180 d_status[mb_index + mb_cols_] || d_status[mb_index - mb_cols_];
95 int mb_rows, 181 return ret;
96 int mb_cols) { 182 }
97 int mb_index = mb_row * mb_cols + mb_col; 183
98 if (!mb_row || !mb_col || mb_row == mb_rows - 1 || mb_col == mb_cols - 1) 184 void VideoDenoiser::CopySrcOnMOB(const uint8_t* y_src, uint8_t* y_dst) {
99 return false; 185 // Loop over to copy src block if the block is marked as moving object block
100 return d_status[mb_index + 1] || d_status[mb_index - 1] || 186 // or if the block may cause trailing artifacts.
101 d_status[mb_index + mb_cols] || d_status[mb_index - mb_cols]; 187 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) {
102 } 188 const int mb_index_base = mb_row * mb_cols_;
103 #endif 189 const int offset_base = (mb_row << 4) * stride_y_;
104 190 const uint8_t* mb_src_base = y_src + offset_base;
105 #if DISPLAY 191 uint8_t* mb_dst_base = y_dst + offset_base;
106 void ShowRect(const std::unique_ptr<DenoiserFilter>& filter, 192 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) {
107 const std::unique_ptr<uint8_t[]>& d_status, 193 const int mb_index = mb_index_base + mb_col;
108 const std::unique_ptr<uint8_t[]>& d_status_tmp2, 194 const uint32_t offset_col = mb_col << 4;
109 const std::unique_ptr<uint8_t[]>& x_density, 195 const uint8_t* mb_src = mb_src_base + offset_col;
110 const std::unique_ptr<uint8_t[]>& y_density, 196 uint8_t* mb_dst = mb_dst_base + offset_col;
111 const uint8_t* u_src, 197 // Check if the block is a moving object block or may cause a trailing
112 const uint8_t* v_src, 198 // artifacts.
113 uint8_t* u_dst, 199 if (mb_filter_decision_[mb_index] != FILTER_BLOCK ||
114 uint8_t* v_dst, 200 IsTrailingBlock(moving_edge_, mb_row, mb_col) ||
115 int mb_rows, 201 (x_density_[mb_col] * y_density_[mb_row] &&
116 int mb_cols, 202 moving_object_[mb_row * mb_cols_ + mb_col])) {
117 int stride_u, 203 // Copy y source.
118 int stride_v) { 204 filter_->CopyMem16x16(mb_src, stride_y_, mb_dst, stride_y_);
119 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) { 205 }
120 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) { 206 }
121 int mb_index = mb_row * mb_cols + mb_col; 207 }
122 const uint8_t* mb_src_u = 208 }
123 u_src + (mb_row << 3) * stride_u + (mb_col << 3);
124 const uint8_t* mb_src_v =
125 v_src + (mb_row << 3) * stride_v + (mb_col << 3);
126 uint8_t* mb_dst_u = u_dst + (mb_row << 3) * stride_u + (mb_col << 3);
127 uint8_t* mb_dst_v = v_dst + (mb_row << 3) * stride_v + (mb_col << 3);
128 uint8_t y_tmp_255[8 * 8];
129 memset(y_tmp_255, 200, 8 * 8);
130 // x_density_[mb_col] * y_density_[mb_row]
131 if (d_status[mb_index] == 1) {
132 // Paint to red.
133 filter->CopyMem8x8(mb_src_u, stride_u, mb_dst_u, stride_u);
134 filter->CopyMem8x8(y_tmp_255, 8, mb_dst_v, stride_v);
135 #if EXPERIMENTAL
136 } else if (d_status_tmp2[mb_row * mb_cols + mb_col] &&
137 x_density[mb_col] * y_density[mb_row]) {
138 #else
139 } else if (x_density[mb_col] * y_density[mb_row]) {
140 #endif
141 // Paint to blue.
142 filter->CopyMem8x8(y_tmp_255, 8, mb_dst_u, stride_u);
143 filter->CopyMem8x8(mb_src_v, stride_v, mb_dst_v, stride_v);
144 } else {
145 filter->CopyMem8x8(mb_src_u, stride_u, mb_dst_u, stride_u);
146 filter->CopyMem8x8(mb_src_v, stride_v, mb_dst_v, stride_v);
147 }
148 }
149 }
150 }
151 #endif
152 209
153 void VideoDenoiser::DenoiseFrame(const VideoFrame& frame, 210 void VideoDenoiser::DenoiseFrame(const VideoFrame& frame,
154 VideoFrame* denoised_frame, 211 VideoFrame* denoised_frame,
155 VideoFrame* denoised_frame_prev, 212 VideoFrame* denoised_frame_prev,
156 int noise_level_prev) { 213 bool noise_estimation_enabled) {
157 int stride_y = frame.stride(kYPlane); 214 // If previous width and height are different from current frame's, need to
158 int stride_u = frame.stride(kUPlane); 215 // reallocate the buffers and no denoising for the current frame.
159 int stride_v = frame.stride(kVPlane);
160 // If previous width and height are different from current frame's, then no
161 // denoising for the current frame.
162 if (width_ != frame.width() || height_ != frame.height()) { 216 if (width_ != frame.width() || height_ != frame.height()) {
163 width_ = frame.width(); 217 DenoiserReset(frame, denoised_frame, denoised_frame_prev);
164 height_ = frame.height();
165 denoised_frame->CreateFrame(frame.buffer(kYPlane), frame.buffer(kUPlane),
166 frame.buffer(kVPlane), width_, height_,
167 stride_y, stride_u, stride_v, kVideoRotation_0);
168 denoised_frame_prev->CreateFrame(
169 frame.buffer(kYPlane), frame.buffer(kUPlane), frame.buffer(kVPlane),
170 width_, height_, stride_y, stride_u, stride_v, kVideoRotation_0);
171 // Setting time parameters to the output frame.
172 denoised_frame->set_timestamp(frame.timestamp());
173 denoised_frame->set_render_time_ms(frame.render_time_ms());
174 ne_->Init(width_, height_, cpu_type_);
175 return; 218 return;
176 } 219 }
177 // For 16x16 block. 220
178 int mb_cols = width_ >> 4; 221 // Set buffer pointers.
179 int mb_rows = height_ >> 4; 222 const uint8_t* y_src = frame.buffer(kYPlane);
180 if (metrics_.get() == nullptr) 223 const uint8_t* u_src = frame.buffer(kUPlane);
181 metrics_.reset(new DenoiseMetrics[mb_cols * mb_rows]()); 224 const uint8_t* v_src = frame.buffer(kVPlane);
182 if (d_status_.get() == nullptr) {
183 d_status_.reset(new uint8_t[mb_cols * mb_rows]());
184 #if EXPERIMENTAL
185 d_status_tmp1_.reset(new uint8_t[mb_cols * mb_rows]());
186 d_status_tmp2_.reset(new uint8_t[mb_cols * mb_rows]());
187 #endif
188 x_density_.reset(new uint8_t[mb_cols]());
189 y_density_.reset(new uint8_t[mb_rows]());
190 }
191
192 // Denoise on Y plane.
193 uint8_t* y_dst = denoised_frame->buffer(kYPlane); 225 uint8_t* y_dst = denoised_frame->buffer(kYPlane);
194 uint8_t* u_dst = denoised_frame->buffer(kUPlane); 226 uint8_t* u_dst = denoised_frame->buffer(kUPlane);
195 uint8_t* v_dst = denoised_frame->buffer(kVPlane); 227 uint8_t* v_dst = denoised_frame->buffer(kVPlane);
196 uint8_t* y_dst_prev = denoised_frame_prev->buffer(kYPlane); 228 uint8_t* y_dst_prev = denoised_frame_prev->buffer(kYPlane);
197 const uint8_t* y_src = frame.buffer(kYPlane); 229 memset(x_density_.get(), 0, mb_cols_);
198 const uint8_t* u_src = frame.buffer(kUPlane); 230 memset(y_density_.get(), 0, mb_rows_);
199 const uint8_t* v_src = frame.buffer(kVPlane); 231 memset(moving_object_.get(), 1, mb_cols_ * mb_rows_);
200 uint8_t noise_level = noise_level_prev == -1 ? 0 : ne_->GetNoiseLevel(); 232
201 // Temporary buffer to store denoising result. 233 uint8_t noise_level = noise_estimation_enabled ? ne_->GetNoiseLevel() : 0;
202 uint8_t y_tmp[16 * 16] = {0}; 234 int thr_var_base = 16 * 16 * 5;
203 memset(x_density_.get(), 0, mb_cols);
204 memset(y_density_.get(), 0, mb_rows);
205
206 // Loop over blocks to accumulate/extract noise level and update x/y_density 235 // Loop over blocks to accumulate/extract noise level and update x/y_density
207 // factors for moving object detection. 236 // factors for moving object detection.
208 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) { 237 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) {
209 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) { 238 const int mb_index_base = mb_row * mb_cols_;
210 const uint8_t* mb_src = y_src + (mb_row << 4) * stride_y + (mb_col << 4); 239 const int offset_base = (mb_row << 4) * stride_y_;
211 uint8_t* mb_dst_prev = 240 const uint8_t* mb_src_base = y_src + offset_base;
212 y_dst_prev + (mb_row << 4) * stride_y + (mb_col << 4); 241 uint8_t* mb_dst_base = y_dst + offset_base;
213 int mb_index = mb_row * mb_cols + mb_col; 242 uint8_t* mb_dst_prev_base = y_dst_prev + offset_base;
214 #if EXPERIMENTAL 243 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) {
215 int pos_factor = PositionCheck(mb_row, mb_col, mb_rows, mb_cols); 244 const int mb_index = mb_index_base + mb_col;
216 uint32_t thr_var_adp = 16 * 16 * 5 * (noise_level ? pos_factor : 1); 245 const bool ne_enable = (mb_index % NOISE_SUBSAMPLE_INTERVAL == 0);
217 #else 246 const int pos_factor = PositionCheck(mb_row, mb_col, noise_level);
218 uint32_t thr_var_adp = 16 * 16 * 5; 247 const uint32_t thr_var_adp = thr_var_base * pos_factor;
219 #endif 248 const uint32_t offset_col = mb_col << 4;
220 int brightness = 0; 249 const uint8_t* mb_src = mb_src_base + offset_col;
221 for (int i = 0; i < 16; ++i) { 250 uint8_t* mb_dst = mb_dst_base + offset_col;
222 for (int j = 0; j < 16; ++j) { 251 uint8_t* mb_dst_prev = mb_dst_prev_base + offset_col;
223 brightness += mb_src[i * stride_y + j]; 252
253 // TODO(jackychen): Need SSE2/NEON opt.
254 int luma = 0;
255 if (ne_enable) {
256 for (int i = 4; i < 12; ++i) {
257 for (int j = 4; j < 12; ++j) {
258 luma += mb_src[i * stride_y_ + j];
259 }
224 } 260 }
225 } 261 }
226 262
227 // Get the denoised block. 263 // Get the filtered block and filter_decision.
228 filter_->MbDenoise(mb_dst_prev, stride_y, y_tmp, 16, mb_src, stride_y, 0, 264 mb_filter_decision_[mb_index] =
229 1, true); 265 filter_->MbDenoise(mb_dst_prev, stride_y_, mb_dst, stride_y_, mb_src,
230 // The variance is based on the denoised blocks in time T and T-1. 266 stride_y_, 0, noise_level);
231 metrics_[mb_index].var = filter_->Variance16x8( 267
232 mb_dst_prev, stride_y, y_tmp, 16, &metrics_[mb_index].sad); 268 // If filter decision is FILTER_BLOCK, no need to check moving edge.
233 269 // It is unlikely for a moving edge block to be filtered in current
234 if (metrics_[mb_index].var > thr_var_adp) { 270 // setting.
235 ne_->ResetConsecLowVar(mb_index); 271 if (mb_filter_decision_[mb_index] == FILTER_BLOCK) {
236 d_status_[mb_index] = 1; 272 uint32_t sse_t = 0;
237 #if EXPERIMENTAL 273 if (ne_enable) {
238 if (noise_level == 0 || pos_factor < 3) { 274 // The variance used in noise estimation is based on the src block in
239 x_density_[mb_col] += 1; 275 // time t (mb_src) and filtered block in time t-1 (mb_dist_prev).
240 y_density_[mb_row] += 1; 276 uint32_t noise_var = filter_->Variance16x8(mb_dst_prev, stride_y_,
277 mb_src, stride_y_, &sse_t);
278 ne_->GetNoise(mb_index, noise_var, luma);
241 } 279 }
242 #else 280 moving_edge_[mb_index] = 0; // Not a moving edge block.
243 x_density_[mb_col] += 1;
244 y_density_[mb_row] += 1;
245 #endif
246 } else { 281 } else {
247 uint32_t sse_t = 0; 282 uint32_t sse_t = 0;
248 // The variance is based on the src blocks in time T and denoised block 283 // The variance used in MOD is based on the filtered blocks in time
249 // in time T-1. 284 // T (mb_dst) and T-1 (mb_dst_prev).
250 uint32_t noise_var = filter_->Variance16x8(mb_dst_prev, stride_y, 285 uint32_t noise_var = filter_->Variance16x8(mb_dst_prev, stride_y_,
251 mb_src, stride_y, &sse_t); 286 mb_dst, stride_y_, &sse_t);
252 ne_->GetNoise(mb_index, noise_var, brightness); 287 if (noise_var > thr_var_adp) { // Moving edge checking.
253 d_status_[mb_index] = 0; 288 if (ne_enable) {
254 } 289 ne_->ResetConsecLowVar(mb_index);
255 // Track denoised frame. 290 }
256 filter_->CopyMem16x16(y_tmp, 16, mb_dst_prev, stride_y); 291 moving_edge_[mb_index] = 1; // Mark as moving edge block.
257 } 292 x_density_[mb_col] += (pos_factor < 3);
258 } 293 y_density_[mb_row] += (pos_factor < 3);
259
260 #if EXPERIMENTAL
261 ReduceFalseDetection(d_status_, &d_status_tmp1_, &d_status_tmp2_, noise_level,
262 mb_rows, mb_cols);
263 #endif
264
265 // Denoise each MB based on the results of moving objects detection.
266 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) {
267 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) {
268 const uint8_t* mb_src = y_src + (mb_row << 4) * stride_y + (mb_col << 4);
269 uint8_t* mb_dst = y_dst + (mb_row << 4) * stride_y + (mb_col << 4);
270 const uint8_t* mb_src_u =
271 u_src + (mb_row << 3) * stride_u + (mb_col << 3);
272 const uint8_t* mb_src_v =
273 v_src + (mb_row << 3) * stride_v + (mb_col << 3);
274 uint8_t* mb_dst_u = u_dst + (mb_row << 3) * stride_u + (mb_col << 3);
275 uint8_t* mb_dst_v = v_dst + (mb_row << 3) * stride_v + (mb_col << 3);
276 #if EXPERIMENTAL
277 if ((!d_status_tmp2_[mb_row * mb_cols + mb_col] ||
278 x_density_[mb_col] * y_density_[mb_row] == 0) &&
279 !TrailingBlock(d_status_, mb_row, mb_col, mb_rows, mb_cols)) {
280 #else
281 if (x_density_[mb_col] * y_density_[mb_row] == 0) {
282 #endif
283 if (filter_->MbDenoise(mb_dst, stride_y, y_tmp, 16, mb_src, stride_y, 0,
284 noise_level, false) == FILTER_BLOCK) {
285 filter_->CopyMem16x16(y_tmp, 16, mb_dst, stride_y);
286 } else { 294 } else {
287 // Copy y source. 295 moving_edge_[mb_index] = 0;
288 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); 296 if (ne_enable) {
297 // The variance used in noise estimation is based on the src block
298 // in time t (mb_src) and filtered block in time t-1 (mb_dist_prev).
299 uint32_t noise_var = filter_->Variance16x8(
300 mb_dst_prev, stride_y_, mb_src, stride_y_, &sse_t);
301 ne_->GetNoise(mb_index, noise_var, luma);
302 }
289 } 303 }
290 } else { 304 }
291 // Copy y source. 305 } // End of for loop
292 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); 306 } // End of for loop
293 } 307
294 filter_->CopyMem8x8(mb_src_u, stride_u, mb_dst_u, stride_u); 308 ReduceFalseDetection(moving_edge_, &moving_object_, noise_level);
295 filter_->CopyMem8x8(mb_src_v, stride_v, mb_dst_v, stride_v); 309
296 } 310 CopySrcOnMOB(y_src, y_dst);
297 } 311
312 // TODO(jackychen): Need SSE2/NEON opt.
313 // Copy u/v planes.
314 memcpy(u_dst, u_src, (height_ >> 1) * stride_u_);
315 memcpy(v_dst, v_src, (height_ >> 1) * stride_v_);
316
317 // Set time parameters to the output frame.
318 denoised_frame->set_timestamp(frame.timestamp());
319 denoised_frame->set_render_time_ms(frame.render_time_ms());
298 320
299 #if DISPLAY // Rectangle diagnostics 321 #if DISPLAY // Rectangle diagnostics
300 // Show rectangular region 322 // Show rectangular region
301 ShowRect(filter_, d_status_, d_status_tmp2_, x_density_, y_density_, u_src, 323 ShowRect(filter_, moving_edge_, moving_object_, x_density_, y_density_, u_src,
302 v_src, u_dst, v_dst, mb_rows, mb_cols, stride_u, stride_v); 324 v_src, u_dst, v_dst, mb_rows_, mb_cols_, stride_u_, stride_v_);
303 #endif 325 #endif
304
305 // Setting time parameters to the output frame.
306 denoised_frame->set_timestamp(frame.timestamp());
307 denoised_frame->set_render_time_ms(frame.render_time_ms());
308 return;
309 } 326 }
310 327
311 } // namespace webrtc 328 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/video_processing/video_denoiser.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698