OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebM 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 |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 } | 129 } |
130 | 130 |
131 /* Update pointers for next iteration. */ | 131 /* Update pointers for next iteration. */ |
132 sig += sig_stride; | 132 sig += sig_stride; |
133 mc_running_avg_y += mc_avg_y_stride; | 133 mc_running_avg_y += mc_avg_y_stride; |
134 running_avg_y += avg_y_stride; | 134 running_avg_y += avg_y_stride; |
135 } | 135 } |
136 | 136 |
137 sum_diff_thresh= SUM_DIFF_THRESHOLD; | 137 sum_diff_thresh= SUM_DIFF_THRESHOLD; |
138 if (increase_denoising) sum_diff_thresh = SUM_DIFF_THRESHOLD_HIGH; | 138 if (increase_denoising) sum_diff_thresh = SUM_DIFF_THRESHOLD_HIGH; |
139 if (abs(sum_diff) > sum_diff_thresh) | 139 if (abs(sum_diff) > sum_diff_thresh) { |
| 140 // Before returning to copy the block (i.e., apply no denoising), check |
| 141 // if we can still apply some (weaker) temporal filtering to this block, |
| 142 // that would otherwise not be denoised at all. Simplest is to apply |
| 143 // an additional adjustment to running_avg_y to bring it closer to sig. |
| 144 // The adjustment is capped by a maximum delta, and chosen such that |
| 145 // in most cases the resulting sum_diff will be within the |
| 146 // accceptable range given by sum_diff_thresh. |
| 147 |
| 148 // The delta is set by the excess of absolute pixel diff over threshold. |
| 149 int delta = ((abs(sum_diff) - sum_diff_thresh) >> 8) + 1; |
| 150 // Only apply the adjustment for max delta up to 3. |
| 151 if (delta < 4) { |
| 152 sig -= sig_stride * 16; |
| 153 mc_running_avg_y -= mc_avg_y_stride * 16; |
| 154 running_avg_y -= avg_y_stride * 16; |
| 155 for (r = 0; r < 16; ++r) { |
| 156 for (c = 0; c < 16; ++c) { |
| 157 int diff = mc_running_avg_y[c] - sig[c]; |
| 158 int adjustment = abs(diff); |
| 159 if (adjustment > delta) |
| 160 adjustment = delta; |
| 161 if (diff > 0) { |
| 162 // Bring denoised signal down. |
| 163 if (running_avg_y[c] - adjustment < 0) |
| 164 running_avg_y[c] = 0; |
| 165 else |
| 166 running_avg_y[c] = running_avg_y[c] - adjustment; |
| 167 sum_diff -= adjustment; |
| 168 } else if (diff < 0) { |
| 169 // Bring denoised signal up. |
| 170 if (running_avg_y[c] + adjustment > 255) |
| 171 running_avg_y[c] = 255; |
| 172 else |
| 173 running_avg_y[c] = running_avg_y[c] + adjustment; |
| 174 sum_diff += adjustment; |
| 175 } |
| 176 } |
| 177 // TODO(marpan): Check here if abs(sum_diff) has gone below the |
| 178 // threshold sum_diff_thresh, and if so, we can exit the row loop. |
| 179 sig += sig_stride; |
| 180 mc_running_avg_y += mc_avg_y_stride; |
| 181 running_avg_y += avg_y_stride; |
| 182 } |
| 183 if (abs(sum_diff) > sum_diff_thresh) |
| 184 return COPY_BLOCK; |
| 185 } else { |
140 return COPY_BLOCK; | 186 return COPY_BLOCK; |
| 187 } |
| 188 } |
141 | 189 |
142 vp8_copy_mem16x16(running_avg_y_start, avg_y_stride, sig_start, sig_stride); | 190 vp8_copy_mem16x16(running_avg_y_start, avg_y_stride, sig_start, sig_stride); |
143 return FILTER_BLOCK; | 191 return FILTER_BLOCK; |
144 } | 192 } |
145 | 193 |
146 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height) | 194 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height, |
| 195 int num_mb_rows, int num_mb_cols) |
147 { | 196 { |
148 int i; | 197 int i; |
149 assert(denoiser); | 198 assert(denoiser); |
| 199 denoiser->num_mb_cols = num_mb_cols; |
150 | 200 |
151 for (i = 0; i < MAX_REF_FRAMES; i++) | 201 for (i = 0; i < MAX_REF_FRAMES; i++) |
152 { | 202 { |
153 denoiser->yv12_running_avg[i].flags = 0; | 203 denoiser->yv12_running_avg[i].flags = 0; |
154 | 204 |
155 if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width, | 205 if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width, |
156 height, VP8BORDERINPIXELS) | 206 height, VP8BORDERINPIXELS) |
157 < 0) | 207 < 0) |
158 { | 208 { |
159 vp8_denoiser_free(denoiser); | 209 vp8_denoiser_free(denoiser); |
160 return 1; | 210 return 1; |
161 } | 211 } |
162 vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0, | 212 vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0, |
163 denoiser->yv12_running_avg[i].frame_size); | 213 denoiser->yv12_running_avg[i].frame_size); |
164 | 214 |
165 } | 215 } |
166 denoiser->yv12_mc_running_avg.flags = 0; | 216 denoiser->yv12_mc_running_avg.flags = 0; |
167 | 217 |
168 if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width, | 218 if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width, |
169 height, VP8BORDERINPIXELS) < 0) | 219 height, VP8BORDERINPIXELS) < 0) |
170 { | 220 { |
171 vp8_denoiser_free(denoiser); | 221 vp8_denoiser_free(denoiser); |
172 return 1; | 222 return 1; |
173 } | 223 } |
174 | 224 |
175 vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0, | 225 vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0, |
176 denoiser->yv12_mc_running_avg.frame_size); | 226 denoiser->yv12_mc_running_avg.frame_size); |
| 227 |
| 228 denoiser->denoise_state = vpx_calloc((num_mb_rows * num_mb_cols), 1); |
| 229 vpx_memset(denoiser->denoise_state, 0, (num_mb_rows * num_mb_cols)); |
| 230 |
177 return 0; | 231 return 0; |
178 } | 232 } |
179 | 233 |
180 void vp8_denoiser_free(VP8_DENOISER *denoiser) | 234 void vp8_denoiser_free(VP8_DENOISER *denoiser) |
181 { | 235 { |
182 int i; | 236 int i; |
183 assert(denoiser); | 237 assert(denoiser); |
184 | 238 |
185 for (i = 0; i < MAX_REF_FRAMES ; i++) | 239 for (i = 0; i < MAX_REF_FRAMES ; i++) |
186 { | 240 { |
187 vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]); | 241 vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]); |
188 } | 242 } |
189 vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg); | 243 vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg); |
190 } | 244 } |
191 | 245 |
192 | 246 |
193 void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, | 247 void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, |
194 MACROBLOCK *x, | 248 MACROBLOCK *x, |
195 unsigned int best_sse, | 249 unsigned int best_sse, |
196 unsigned int zero_mv_sse, | 250 unsigned int zero_mv_sse, |
197 int recon_yoffset, | 251 int recon_yoffset, |
198 int recon_uvoffset) | 252 int recon_uvoffset, |
| 253 loop_filter_info_n *lfi_n, |
| 254 int mb_row, |
| 255 int mb_col, |
| 256 int block_index) |
199 { | 257 { |
200 int mv_row; | 258 int mv_row; |
201 int mv_col; | 259 int mv_col; |
202 unsigned int motion_magnitude2; | 260 unsigned int motion_magnitude2; |
203 unsigned int sse_thresh; | 261 unsigned int sse_thresh; |
| 262 int sse_diff_thresh = 0; |
| 263 // Spatial loop filter: only applied selectively based on |
| 264 // temporal filter state of block relative to top/left neighbors. |
| 265 int apply_spatial_loop_filter = 1; |
204 MV_REFERENCE_FRAME frame = x->best_reference_frame; | 266 MV_REFERENCE_FRAME frame = x->best_reference_frame; |
205 MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame; | 267 MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame; |
206 | 268 |
207 enum vp8_denoiser_decision decision = FILTER_BLOCK; | 269 enum vp8_denoiser_decision decision = FILTER_BLOCK; |
208 | 270 |
209 if (zero_frame) | 271 if (zero_frame) |
210 { | 272 { |
211 YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame]; | 273 YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame]; |
212 YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg; | 274 YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg; |
213 YV12_BUFFER_CONFIG saved_pre,saved_dst; | 275 YV12_BUFFER_CONFIG saved_pre,saved_dst; |
214 MB_MODE_INFO saved_mbmi; | 276 MB_MODE_INFO saved_mbmi; |
215 MACROBLOCKD *filter_xd = &x->e_mbd; | 277 MACROBLOCKD *filter_xd = &x->e_mbd; |
216 MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi; | 278 MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi; |
217 int sse_diff = zero_mv_sse - best_sse; | 279 int sse_diff = 0; |
| 280 // Bias on zero motion vector sse. |
| 281 int zero_bias = 95; |
| 282 zero_mv_sse = (unsigned int)((int64_t)zero_mv_sse * zero_bias / 100); |
| 283 sse_diff = zero_mv_sse - best_sse; |
218 | 284 |
219 saved_mbmi = *mbmi; | 285 saved_mbmi = *mbmi; |
220 | 286 |
221 /* Use the best MV for the compensation. */ | 287 /* Use the best MV for the compensation. */ |
222 mbmi->ref_frame = x->best_reference_frame; | 288 mbmi->ref_frame = x->best_reference_frame; |
223 mbmi->mode = x->best_sse_inter_mode; | 289 mbmi->mode = x->best_sse_inter_mode; |
224 mbmi->mv = x->best_sse_mv; | 290 mbmi->mv = x->best_sse_mv; |
225 mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs; | 291 mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs; |
226 mv_col = x->best_sse_mv.as_mv.col; | 292 mv_col = x->best_sse_mv.as_mv.col; |
227 mv_row = x->best_sse_mv.as_mv.row; | 293 mv_row = x->best_sse_mv.as_mv.row; |
| 294 // Bias to zero_mv if small amount of motion. |
| 295 // Note sse_diff_thresh is intialized to zero, so this ensures |
| 296 // we will always choose zero_mv for denoising if |
| 297 // zero_mv_see <= best_sse (i.e., sse_diff <= 0). |
| 298 if ((unsigned int)(mv_row * mv_row + mv_col * mv_col) |
| 299 <= NOISE_MOTION_THRESHOLD) |
| 300 sse_diff_thresh = (int)SSE_DIFF_THRESHOLD; |
228 | 301 |
229 if (frame == INTRA_FRAME || | 302 if (frame == INTRA_FRAME || |
230 ((unsigned int)(mv_row *mv_row + mv_col *mv_col) | 303 sse_diff <= sse_diff_thresh) |
231 <= NOISE_MOTION_THRESHOLD && | |
232 sse_diff < (int)SSE_DIFF_THRESHOLD)) | |
233 { | 304 { |
234 /* | 305 /* |
235 * Handle intra blocks as referring to last frame with zero motion | 306 * Handle intra blocks as referring to last frame with zero motion |
236 * and let the absolute pixel difference affect the filter factor. | 307 * and let the absolute pixel difference affect the filter factor. |
237 * Also consider small amount of motion as being random walk due | 308 * Also consider small amount of motion as being random walk due |
238 * to noise, if it doesn't mean that we get a much bigger error. | 309 * to noise, if it doesn't mean that we get a much bigger error. |
239 * Note that any changes to the mode info only affects the | 310 * Note that any changes to the mode info only affects the |
240 * denoising. | 311 * denoising. |
241 */ | 312 */ |
242 mbmi->ref_frame = | 313 mbmi->ref_frame = |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 int mc_avg_y_stride = denoiser->yv12_mc_running_avg.y_stride; | 372 int mc_avg_y_stride = denoiser->yv12_mc_running_avg.y_stride; |
302 unsigned char *running_avg_y = | 373 unsigned char *running_avg_y = |
303 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset; | 374 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset; |
304 int avg_y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride; | 375 int avg_y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride; |
305 | 376 |
306 /* Filter. */ | 377 /* Filter. */ |
307 decision = vp8_denoiser_filter(mc_running_avg_y, mc_avg_y_stride, | 378 decision = vp8_denoiser_filter(mc_running_avg_y, mc_avg_y_stride, |
308 running_avg_y, avg_y_stride, | 379 running_avg_y, avg_y_stride, |
309 x->thismb, 16, motion_magnitude2, | 380 x->thismb, 16, motion_magnitude2, |
310 x->increase_denoising); | 381 x->increase_denoising); |
| 382 denoiser->denoise_state[block_index] = motion_magnitude2 > 0 ? |
| 383 kFilterNonZeroMV : kFilterZeroMV; |
311 } | 384 } |
312 if (decision == COPY_BLOCK) | 385 if (decision == COPY_BLOCK) |
313 { | 386 { |
314 /* No filtering of this block; it differs too much from the predictor, | 387 /* No filtering of this block; it differs too much from the predictor, |
315 * or the motion vector magnitude is considered too big. | 388 * or the motion vector magnitude is considered too big. |
316 */ | 389 */ |
317 vp8_copy_mem16x16( | 390 vp8_copy_mem16x16( |
318 x->thismb, 16, | 391 x->thismb, 16, |
319 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset
, | 392 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset
, |
320 denoiser->yv12_running_avg[INTRA_FRAME].y_stride); | 393 denoiser->yv12_running_avg[INTRA_FRAME].y_stride); |
| 394 denoiser->denoise_state[block_index] = kNoFilter; |
| 395 } |
| 396 // Option to selectively deblock the denoised signal. |
| 397 if (apply_spatial_loop_filter) { |
| 398 loop_filter_info lfi; |
| 399 int apply_filter_col = 0; |
| 400 int apply_filter_row = 0; |
| 401 int apply_filter = 0; |
| 402 int y_stride = denoiser->yv12_running_avg[INTRA_FRAME].y_stride; |
| 403 int uv_stride =denoiser->yv12_running_avg[INTRA_FRAME].uv_stride; |
| 404 |
| 405 // Fix filter level to some nominal value for now. |
| 406 int filter_level = 32; |
| 407 |
| 408 int hev_index = lfi_n->hev_thr_lut[INTER_FRAME][filter_level]; |
| 409 lfi.mblim = lfi_n->mblim[filter_level]; |
| 410 lfi.blim = lfi_n->blim[filter_level]; |
| 411 lfi.lim = lfi_n->lim[filter_level]; |
| 412 lfi.hev_thr = lfi_n->hev_thr[hev_index]; |
| 413 |
| 414 // Apply filter if there is a difference in the denoiser filter state |
| 415 // between the current and left/top block, or if non-zero motion vector |
| 416 // is used for the motion-compensated filtering. |
| 417 if (mb_col > 0) { |
| 418 apply_filter_col = !((denoiser->denoise_state[block_index] == |
| 419 denoiser->denoise_state[block_index - 1]) && |
| 420 denoiser->denoise_state[block_index] != kFilterNonZeroMV); |
| 421 if (apply_filter_col) { |
| 422 // Filter left vertical edge. |
| 423 apply_filter = 1; |
| 424 vp8_loop_filter_mbv( |
| 425 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset, |
| 426 NULL, NULL, y_stride, uv_stride, &lfi); |
| 427 } |
| 428 } |
| 429 if (mb_row > 0) { |
| 430 apply_filter_row = !((denoiser->denoise_state[block_index] == |
| 431 denoiser->denoise_state[block_index - denoiser->num_mb_cols]) && |
| 432 denoiser->denoise_state[block_index] != kFilterNonZeroMV); |
| 433 if (apply_filter_row) { |
| 434 // Filter top horizontal edge. |
| 435 apply_filter = 1; |
| 436 vp8_loop_filter_mbh( |
| 437 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset, |
| 438 NULL, NULL, y_stride, uv_stride, &lfi); |
| 439 } |
| 440 } |
| 441 if (apply_filter) { |
| 442 // Update the signal block |x|. Pixel changes are only to top and/or |
| 443 // left boundary pixels: can we avoid full block copy here. |
| 444 vp8_copy_mem16x16( |
| 445 denoiser->yv12_running_avg[INTRA_FRAME].y_buffer + recon_yoffset, |
| 446 y_stride, x->thismb, 16); |
| 447 } |
321 } | 448 } |
322 } | 449 } |
OLD | NEW |