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 |
11 #include <assert.h> | 11 #include <assert.h> |
| 12 #include <limits.h> |
12 #include "vpx_scale/yv12config.h" | 13 #include "vpx_scale/yv12config.h" |
13 #include "vpx/vpx_integer.h" | 14 #include "vpx/vpx_integer.h" |
| 15 #include "vp9/common/vp9_reconinter.h" |
14 #include "vp9/encoder/vp9_denoiser.h" | 16 #include "vp9/encoder/vp9_denoiser.h" |
15 | 17 |
| 18 /* The VP9 denoiser is a work-in-progress. It currently is only designed to work |
| 19 * with speed 6, though it (inexplicably) seems to also work with speed 5 (one |
| 20 * would need to modify the source code in vp9_pickmode.c and vp9_encoder.c to |
| 21 * make the calls to the vp9_denoiser_* functions when in speed 5). |
| 22 * |
| 23 * The implementation is very similar to that of the VP8 denoiser. While |
| 24 * choosing the motion vectors / reference frames, the denoiser is run, and if |
| 25 * it did not modify the signal to much, the denoised block is copied to the |
| 26 * signal. |
| 27 */ |
| 28 |
| 29 #ifdef OUTPUT_YUV_DENOISED |
| 30 static void make_grayscale(YV12_BUFFER_CONFIG *yuv); |
| 31 #endif |
| 32 |
16 static const int widths[] = {4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64}; | 33 static const int widths[] = {4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64}; |
17 static const int heights[] = {4, 8, 4, 8, 16, 8, 16, 32, 16, 32, 64, 32, 64}; | 34 static const int heights[] = {4, 8, 4, 8, 16, 8, 16, 32, 16, 32, 64, 32, 64}; |
18 | 35 |
19 int vp9_denoiser_filter() { | 36 static int absdiff_thresh(BLOCK_SIZE bs, int increase_denoising) { |
20 return 0; | 37 (void)bs; |
| 38 return 3 + (increase_denoising ? 1 : 0); |
21 } | 39 } |
22 | 40 |
23 static int update_running_avg(const uint8_t *mc_avg, int mc_avg_stride, | 41 static int delta_thresh(BLOCK_SIZE bs, int increase_denoising) { |
24 uint8_t *avg, int avg_stride, | 42 (void)bs; |
25 const uint8_t *sig, int sig_stride, | 43 (void)increase_denoising; |
26 int increase_denoising, BLOCK_SIZE bs) { | 44 return 4; |
| 45 } |
| 46 |
| 47 static int noise_motion_thresh(BLOCK_SIZE bs, int increase_denoising) { |
| 48 (void)bs; |
| 49 (void)increase_denoising; |
| 50 return 25 * 25; |
| 51 } |
| 52 |
| 53 static unsigned int sse_thresh(BLOCK_SIZE bs, int increase_denoising) { |
| 54 return widths[bs] * heights[bs] * (increase_denoising ? 60 : 40); |
| 55 } |
| 56 |
| 57 static int sse_diff_thresh(BLOCK_SIZE bs, int increase_denoising, |
| 58 int mv_row, int mv_col) { |
| 59 if (mv_row * mv_row + mv_col * mv_col > |
| 60 noise_motion_thresh(bs, increase_denoising)) { |
| 61 return 0; |
| 62 } else { |
| 63 return widths[bs] * heights[bs] * 20; |
| 64 } |
| 65 } |
| 66 |
| 67 static int total_adj_strong_thresh(BLOCK_SIZE bs, int increase_denoising) { |
| 68 return widths[bs] * heights[bs] * (increase_denoising ? 3 : 2); |
| 69 } |
| 70 |
| 71 static int total_adj_weak_thresh(BLOCK_SIZE bs, int increase_denoising) { |
| 72 return widths[bs] * heights[bs] * (increase_denoising ? 3 : 2); |
| 73 } |
| 74 |
| 75 static VP9_DENOISER_DECISION denoiser_filter(const uint8_t *sig, int sig_stride, |
| 76 const uint8_t *mc_avg, |
| 77 int mc_avg_stride, |
| 78 uint8_t *avg, int avg_stride, |
| 79 int increase_denoising, |
| 80 BLOCK_SIZE bs) { |
27 int r, c; | 81 int r, c; |
28 int diff, adj, absdiff; | 82 const uint8_t *sig_start = sig; |
29 int shift_inc1 = 0, shift_inc2 = 1; | 83 const uint8_t *mc_avg_start = mc_avg; |
| 84 uint8_t *avg_start = avg; |
| 85 int diff, adj, absdiff, delta; |
30 int adj_val[] = {3, 4, 6}; | 86 int adj_val[] = {3, 4, 6}; |
31 int total_adj = 0; | 87 int total_adj = 0; |
32 | 88 |
33 if (increase_denoising) { | 89 // First attempt to apply a strong temporal denoising filter. |
34 shift_inc1 = 1; | |
35 shift_inc2 = 2; | |
36 } | |
37 | |
38 for (r = 0; r < heights[bs]; ++r) { | 90 for (r = 0; r < heights[bs]; ++r) { |
39 for (c = 0; c < widths[bs]; ++c) { | 91 for (c = 0; c < widths[bs]; ++c) { |
40 diff = mc_avg[c] - sig[c]; | 92 diff = mc_avg[c] - sig[c]; |
41 absdiff = abs(diff); | 93 absdiff = abs(diff); |
42 | 94 |
43 if (absdiff <= 3 + shift_inc1) { | 95 if (absdiff <= absdiff_thresh(bs, increase_denoising)) { |
44 avg[c] = mc_avg[c]; | 96 avg[c] = mc_avg[c]; |
45 total_adj += diff; | 97 total_adj += diff; |
46 } else { | 98 } else { |
47 switch (absdiff) { | 99 switch (absdiff) { |
48 case 4: case 5: case 6: case 7: | 100 case 4: case 5: case 6: case 7: |
49 adj = adj_val[0]; | 101 adj = adj_val[0]; |
50 break; | 102 break; |
51 case 8: case 9: case 10: case 11: | 103 case 8: case 9: case 10: case 11: |
52 case 12: case 13: case 14: case 15: | 104 case 12: case 13: case 14: case 15: |
53 adj = adj_val[1]; | 105 adj = adj_val[1]; |
54 break; | 106 break; |
55 default: | 107 default: |
56 adj = adj_val[2]; | 108 adj = adj_val[2]; |
57 } | 109 } |
58 if (diff > 0) { | 110 if (diff > 0) { |
59 avg[c] = MIN(UINT8_MAX, sig[c] + adj); | 111 avg[c] = MIN(UINT8_MAX, sig[c] + adj); |
60 total_adj += adj; | 112 total_adj += adj; |
61 } else { | 113 } else { |
62 avg[c] = MAX(0, sig[c] - adj); | 114 avg[c] = MAX(0, sig[c] - adj); |
63 total_adj -= adj; | 115 total_adj -= adj; |
64 } | 116 } |
65 } | 117 } |
66 } | 118 } |
67 sig += sig_stride; | 119 sig += sig_stride; |
68 avg += avg_stride; | 120 avg += avg_stride; |
69 mc_avg += mc_avg_stride; | 121 mc_avg += mc_avg_stride; |
70 } | 122 } |
71 return total_adj; | 123 |
| 124 // If the strong filter did not modify the signal too much, we're all set. |
| 125 if (abs(total_adj) <= total_adj_strong_thresh(bs, increase_denoising)) { |
| 126 return FILTER_BLOCK; |
| 127 } |
| 128 |
| 129 // Otherwise, we try to dampen the filter if the delta is not too high. |
| 130 delta = ((abs(total_adj) - total_adj_strong_thresh(bs, increase_denoising)) |
| 131 >> 8) + 1; |
| 132 if (delta > delta_thresh(bs, increase_denoising)) { |
| 133 return COPY_BLOCK; |
| 134 } |
| 135 |
| 136 mc_avg = mc_avg_start; |
| 137 avg = avg_start; |
| 138 sig = sig_start; |
| 139 for (r = 0; r < heights[bs]; ++r) { |
| 140 for (c = 0; c < widths[bs]; ++c) { |
| 141 diff = mc_avg[c] - sig[c]; |
| 142 adj = abs(diff); |
| 143 if (adj > delta) { |
| 144 adj = delta; |
| 145 } |
| 146 if (diff > 0) { |
| 147 avg[c] = MAX(0, avg[c] - adj); |
| 148 total_adj += adj; |
| 149 } else { |
| 150 avg[c] = MIN(UINT8_MAX, avg[c] + adj); |
| 151 total_adj -= adj; |
| 152 } |
| 153 } |
| 154 sig += sig_stride; |
| 155 avg += avg_stride; |
| 156 mc_avg += mc_avg_stride; |
| 157 } |
| 158 |
| 159 // We can use the filter if it has been sufficiently dampened |
| 160 if (abs(total_adj) <= total_adj_weak_thresh(bs, increase_denoising)) { |
| 161 return FILTER_BLOCK; |
| 162 } |
| 163 return COPY_BLOCK; |
72 } | 164 } |
73 | 165 |
74 static uint8_t *block_start(uint8_t *framebuf, int stride, | 166 static uint8_t *block_start(uint8_t *framebuf, int stride, |
75 int mi_row, int mi_col) { | 167 int mi_row, int mi_col) { |
76 return framebuf + (stride * mi_row * 8) + (mi_col * 8); | 168 return framebuf + (stride * mi_row * 8) + (mi_col * 8); |
77 } | 169 } |
78 | 170 |
79 void copy_block(uint8_t *dest, int dest_stride, | 171 static void copy_block(uint8_t *dest, int dest_stride, |
80 uint8_t *src, int src_stride, BLOCK_SIZE bs) { | 172 const uint8_t *src, int src_stride, BLOCK_SIZE bs) { |
81 int r, c; | 173 int r; |
82 for (r = 0; r < heights[bs]; ++r) { | 174 for (r = 0; r < heights[bs]; ++r) { |
83 for (c = 0; c < widths[bs]; ++c) { | 175 vpx_memcpy(dest, src, widths[bs]); |
84 dest[c] = src[c]; | |
85 } | |
86 dest += dest_stride; | 176 dest += dest_stride; |
87 src += src_stride; | 177 src += src_stride; |
88 } | 178 } |
89 } | 179 } |
90 | 180 |
| 181 static VP9_DENOISER_DECISION perform_motion_compensation(VP9_DENOISER *denoiser, |
| 182 MACROBLOCK *mb, |
| 183 BLOCK_SIZE bs, |
| 184 int increase_denoising, |
| 185 int mi_row, |
| 186 int mi_col) { |
| 187 int mv_col, mv_row; |
| 188 int sse_diff = denoiser->zero_mv_sse - denoiser->best_sse; |
| 189 MV_REFERENCE_FRAME frame; |
| 190 MACROBLOCKD *filter_mbd = &mb->e_mbd; |
| 191 MB_MODE_INFO *mbmi = &filter_mbd->mi[0]->mbmi; |
| 192 |
| 193 // We will restore these after motion compensation. |
| 194 MB_MODE_INFO saved_mbmi = *mbmi; |
| 195 struct buf_2d saved_dst = filter_mbd->plane[0].dst; |
| 196 struct buf_2d saved_pre[2]; |
| 197 saved_pre[0] = filter_mbd->plane[0].pre[0]; |
| 198 saved_pre[1] = filter_mbd->plane[0].pre[1]; |
| 199 |
| 200 mv_col = denoiser->best_sse_mv.as_mv.col; |
| 201 mv_row = denoiser->best_sse_mv.as_mv.row; |
| 202 |
| 203 frame = denoiser->best_reference_frame; |
| 204 |
| 205 // If the best reference frame uses inter-prediction and there is enough of a |
| 206 // difference in sum-squared-error, use it. |
| 207 if (frame != INTRA_FRAME && |
| 208 sse_diff > sse_diff_thresh(bs, increase_denoising, mv_row, mv_col)) { |
| 209 mbmi->ref_frame[0] = denoiser->best_reference_frame; |
| 210 mbmi->mode = denoiser->best_sse_inter_mode; |
| 211 mbmi->mv[0] = denoiser->best_sse_mv; |
| 212 } else { |
| 213 // Otherwise, use the zero reference frame. |
| 214 frame = denoiser->best_zeromv_reference_frame; |
| 215 |
| 216 mbmi->ref_frame[0] = denoiser->best_zeromv_reference_frame; |
| 217 mbmi->mode = ZEROMV; |
| 218 mbmi->mv[0].as_int = 0; |
| 219 |
| 220 denoiser->best_sse_inter_mode = ZEROMV; |
| 221 denoiser->best_sse_mv.as_int = 0; |
| 222 denoiser->best_sse = denoiser->zero_mv_sse; |
| 223 } |
| 224 |
| 225 // Set the pointers in the MACROBLOCKD to point to the buffers in the denoiser |
| 226 // struct. |
| 227 filter_mbd->plane[0].pre[0].buf = |
| 228 block_start(denoiser->running_avg_y[frame].y_buffer, |
| 229 denoiser->running_avg_y[frame].y_stride, |
| 230 mi_row, mi_col); |
| 231 filter_mbd->plane[0].pre[0].stride = denoiser->running_avg_y[frame].y_stride; |
| 232 |
| 233 filter_mbd->plane[1].pre[0].buf = |
| 234 block_start(denoiser->running_avg_y[frame].u_buffer, |
| 235 denoiser->running_avg_y[frame].uv_stride, |
| 236 mi_row, mi_col); |
| 237 filter_mbd->plane[1].pre[0].stride = denoiser->running_avg_y[frame].uv_stride; |
| 238 |
| 239 filter_mbd->plane[2].pre[0].buf = |
| 240 block_start(denoiser->running_avg_y[frame].v_buffer, |
| 241 denoiser->running_avg_y[frame].uv_stride, |
| 242 mi_row, mi_col); |
| 243 filter_mbd->plane[2].pre[0].stride = denoiser->running_avg_y[frame].uv_stride; |
| 244 |
| 245 filter_mbd->plane[0].pre[1].buf = |
| 246 block_start(denoiser->running_avg_y[frame].y_buffer, |
| 247 denoiser->running_avg_y[frame].y_stride, |
| 248 mi_row, mi_col); |
| 249 filter_mbd->plane[0].pre[1].stride = denoiser->running_avg_y[frame].y_stride; |
| 250 |
| 251 filter_mbd->plane[1].pre[1].buf = |
| 252 block_start(denoiser->running_avg_y[frame].u_buffer, |
| 253 denoiser->running_avg_y[frame].uv_stride, |
| 254 mi_row, mi_col); |
| 255 filter_mbd->plane[1].pre[1].stride = denoiser->running_avg_y[frame].uv_stride; |
| 256 |
| 257 filter_mbd->plane[2].pre[1].buf = |
| 258 block_start(denoiser->running_avg_y[frame].v_buffer, |
| 259 denoiser->running_avg_y[frame].uv_stride, |
| 260 mi_row, mi_col); |
| 261 filter_mbd->plane[2].pre[1].stride = denoiser->running_avg_y[frame].uv_stride; |
| 262 |
| 263 filter_mbd->plane[0].dst.buf = |
| 264 block_start(denoiser->mc_running_avg_y.y_buffer, |
| 265 denoiser->mc_running_avg_y.y_stride, |
| 266 mi_row, mi_col); |
| 267 filter_mbd->plane[0].dst.stride = denoiser->mc_running_avg_y.y_stride; |
| 268 |
| 269 filter_mbd->plane[1].dst.buf = |
| 270 block_start(denoiser->mc_running_avg_y.u_buffer, |
| 271 denoiser->mc_running_avg_y.uv_stride, |
| 272 mi_row, mi_col); |
| 273 filter_mbd->plane[1].dst.stride = denoiser->mc_running_avg_y.y_stride; |
| 274 |
| 275 filter_mbd->plane[2].dst.buf = |
| 276 block_start(denoiser->mc_running_avg_y.v_buffer, |
| 277 denoiser->mc_running_avg_y.uv_stride, |
| 278 mi_row, mi_col); |
| 279 filter_mbd->plane[2].dst.stride = denoiser->mc_running_avg_y.y_stride; |
| 280 |
| 281 vp9_build_inter_predictors_sby(filter_mbd, mv_row, mv_col, bs); |
| 282 |
| 283 // Restore everything to its original state |
| 284 filter_mbd->plane[0].pre[0] = saved_pre[0]; |
| 285 filter_mbd->plane[0].pre[1] = saved_pre[1]; |
| 286 filter_mbd->plane[0].dst = saved_dst; |
| 287 *mbmi = saved_mbmi; |
| 288 |
| 289 mv_row = denoiser->best_sse_mv.as_mv.row; |
| 290 mv_col = denoiser->best_sse_mv.as_mv.col; |
| 291 |
| 292 if (denoiser->best_sse > sse_thresh(bs, increase_denoising)) { |
| 293 return COPY_BLOCK; |
| 294 } |
| 295 if (mv_row * mv_row + mv_col * mv_col > |
| 296 8 * noise_motion_thresh(bs, increase_denoising)) { |
| 297 return COPY_BLOCK; |
| 298 } |
| 299 return FILTER_BLOCK; |
| 300 } |
| 301 |
91 void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, | 302 void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, |
92 int mi_row, int mi_col, BLOCK_SIZE bs) { | 303 int mi_row, int mi_col, BLOCK_SIZE bs) { |
93 int decision = COPY_BLOCK; | 304 VP9_DENOISER_DECISION decision = FILTER_BLOCK; |
94 | |
95 YV12_BUFFER_CONFIG avg = denoiser->running_avg_y[INTRA_FRAME]; | 305 YV12_BUFFER_CONFIG avg = denoiser->running_avg_y[INTRA_FRAME]; |
| 306 YV12_BUFFER_CONFIG mc_avg = denoiser->mc_running_avg_y; |
| 307 uint8_t *avg_start = block_start(avg.y_buffer, avg.y_stride, mi_row, mi_col); |
| 308 uint8_t *mc_avg_start = block_start(mc_avg.y_buffer, mc_avg.y_stride, |
| 309 mi_row, mi_col); |
96 struct buf_2d src = mb->plane[0].src; | 310 struct buf_2d src = mb->plane[0].src; |
97 | 311 |
98 update_running_avg(denoiser->mc_running_avg_y.y_buffer, | 312 decision = perform_motion_compensation(denoiser, mb, bs, |
99 denoiser->mc_running_avg_y.y_stride, | 313 denoiser->increase_denoising, |
100 denoiser->running_avg_y[INTRA_FRAME].y_buffer, | 314 mi_row, mi_col); |
101 denoiser->running_avg_y[INTRA_FRAME].y_stride, | |
102 mb->plane[0].src.buf, mb->plane[0].src.stride, 0, bs); | |
103 | 315 |
104 if (decision == FILTER_BLOCK) { | 316 if (decision == FILTER_BLOCK) { |
105 // TODO(tkopp) | 317 decision = denoiser_filter(src.buf, src.stride, |
| 318 mc_avg_start, mc_avg.y_stride, |
| 319 avg_start, avg.y_stride, |
| 320 0, bs); |
106 } | 321 } |
107 if (decision == COPY_BLOCK) { | 322 |
108 copy_block(block_start(avg.y_buffer, avg.y_stride, mi_row, mi_col), | 323 if (decision == FILTER_BLOCK) { |
109 avg.y_stride, src.buf, src.stride, bs); | 324 copy_block(src.buf, src.stride, avg_start, avg.y_stride, bs); |
| 325 } else { // COPY_BLOCK |
| 326 copy_block(avg_start, avg.y_stride, src.buf, src.stride, bs); |
110 } | 327 } |
111 } | 328 } |
112 | 329 |
113 static void copy_frame(YV12_BUFFER_CONFIG dest, const YV12_BUFFER_CONFIG src) { | 330 static void copy_frame(YV12_BUFFER_CONFIG dest, const YV12_BUFFER_CONFIG src) { |
114 int r, c; | 331 int r; |
115 const uint8_t *srcbuf = src.y_buffer; | 332 const uint8_t *srcbuf = src.y_buffer; |
116 uint8_t *destbuf = dest.y_buffer; | 333 uint8_t *destbuf = dest.y_buffer; |
117 assert(dest.y_width == src.y_width); | 334 assert(dest.y_width == src.y_width); |
118 assert(dest.y_height == src.y_height); | 335 assert(dest.y_height == src.y_height); |
119 | 336 |
120 for (r = 0; r < dest.y_height; ++r) { | 337 for (r = 0; r < dest.y_height; ++r) { |
121 for (c = 0; c < dest.y_width; ++c) { | 338 vpx_memcpy(destbuf, srcbuf, dest.y_width); |
122 destbuf[c] = srcbuf[c]; | |
123 } | |
124 destbuf += dest.y_stride; | 339 destbuf += dest.y_stride; |
125 srcbuf += src.y_stride; | 340 srcbuf += src.y_stride; |
126 } | 341 } |
127 } | 342 } |
128 | 343 |
129 void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, | 344 void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, |
130 YV12_BUFFER_CONFIG src, | 345 YV12_BUFFER_CONFIG src, |
131 FRAME_TYPE frame_type, | 346 FRAME_TYPE frame_type, |
132 int refresh_alt_ref_frame, | 347 int refresh_alt_ref_frame, |
133 int refresh_golden_frame, | 348 int refresh_golden_frame, |
(...skipping 14 matching lines...) Expand all Loading... |
148 copy_frame(denoiser->running_avg_y[GOLDEN_FRAME], | 363 copy_frame(denoiser->running_avg_y[GOLDEN_FRAME], |
149 denoiser->running_avg_y[INTRA_FRAME]); | 364 denoiser->running_avg_y[INTRA_FRAME]); |
150 } | 365 } |
151 if (refresh_last_frame) { | 366 if (refresh_last_frame) { |
152 copy_frame(denoiser->running_avg_y[LAST_FRAME], | 367 copy_frame(denoiser->running_avg_y[LAST_FRAME], |
153 denoiser->running_avg_y[INTRA_FRAME]); | 368 denoiser->running_avg_y[INTRA_FRAME]); |
154 } | 369 } |
155 } | 370 } |
156 } | 371 } |
157 | 372 |
158 void vp9_denoiser_update_frame_stats() { | 373 void vp9_denoiser_reset_frame_stats(VP9_DENOISER *denoiser) { |
| 374 denoiser->zero_mv_sse = UINT_MAX; |
| 375 denoiser->best_sse = UINT_MAX; |
| 376 } |
| 377 |
| 378 void vp9_denoiser_update_frame_stats(VP9_DENOISER *denoiser, MB_MODE_INFO *mbmi, |
| 379 unsigned int sse, PREDICTION_MODE mode) { |
| 380 // TODO(tkopp): Use both MVs if possible |
| 381 if (mbmi->mv[0].as_int == 0 && sse < denoiser->zero_mv_sse) { |
| 382 denoiser->zero_mv_sse = sse; |
| 383 denoiser->best_zeromv_reference_frame = mbmi->ref_frame[0]; |
| 384 } |
| 385 |
| 386 if (mbmi->mv[0].as_int != 0 && sse < denoiser->best_sse) { |
| 387 denoiser->best_sse = sse; |
| 388 denoiser->best_sse_inter_mode = mode; |
| 389 denoiser->best_sse_mv = mbmi->mv[0]; |
| 390 denoiser->best_reference_frame = mbmi->ref_frame[0]; |
| 391 } |
159 } | 392 } |
160 | 393 |
161 int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height, | 394 int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height, |
162 int ssx, int ssy, int border) { | 395 int ssx, int ssy, int border) { |
163 int i, fail; | 396 int i, fail; |
164 assert(denoiser != NULL); | 397 assert(denoiser != NULL); |
165 | 398 |
166 for (i = 0; i < MAX_REF_FRAMES; ++i) { | 399 for (i = 0; i < MAX_REF_FRAMES; ++i) { |
167 fail = vp9_alloc_frame_buffer(&denoiser->running_avg_y[i], width, height, | 400 fail = vp9_alloc_frame_buffer(&denoiser->running_avg_y[i], width, height, |
168 ssx, ssy, border); | 401 ssx, ssy, border); |
169 if (fail) { | 402 if (fail) { |
170 vp9_denoiser_free(denoiser); | 403 vp9_denoiser_free(denoiser); |
171 return 1; | 404 return 1; |
172 } | 405 } |
| 406 #ifdef OUTPUT_YUV_DENOISED |
| 407 make_grayscale(&denoiser->running_avg_y[i]); |
| 408 #endif |
173 } | 409 } |
174 | 410 |
175 fail = vp9_alloc_frame_buffer(&denoiser->mc_running_avg_y, width, height, | 411 fail = vp9_alloc_frame_buffer(&denoiser->mc_running_avg_y, width, height, |
176 ssx, ssy, border); | 412 ssx, ssy, border); |
177 if (fail) { | 413 if (fail) { |
178 vp9_denoiser_free(denoiser); | 414 vp9_denoiser_free(denoiser); |
179 return 1; | 415 return 1; |
180 } | 416 } |
| 417 #ifdef OUTPUT_YUV_DENOISED |
| 418 make_grayscale(&denoiser->running_avg_y[i]); |
| 419 #endif |
| 420 denoiser->increase_denoising = 0; |
181 | 421 |
182 return 0; | 422 return 0; |
183 } | 423 } |
184 | 424 |
185 void vp9_denoiser_free(VP9_DENOISER *denoiser) { | 425 void vp9_denoiser_free(VP9_DENOISER *denoiser) { |
186 int i; | 426 int i; |
187 if (denoiser == NULL) { | 427 if (denoiser == NULL) { |
188 return; | 428 return; |
189 } | 429 } |
190 for (i = 0; i < MAX_REF_FRAMES; ++i) { | 430 for (i = 0; i < MAX_REF_FRAMES; ++i) { |
191 if (&denoiser->running_avg_y[i] != NULL) { | 431 if (&denoiser->running_avg_y[i] != NULL) { |
192 vp9_free_frame_buffer(&denoiser->running_avg_y[i]); | 432 vp9_free_frame_buffer(&denoiser->running_avg_y[i]); |
193 } | 433 } |
194 } | 434 } |
195 if (&denoiser->mc_running_avg_y != NULL) { | 435 if (&denoiser->mc_running_avg_y != NULL) { |
196 vp9_free_frame_buffer(&denoiser->mc_running_avg_y); | 436 vp9_free_frame_buffer(&denoiser->mc_running_avg_y); |
197 } | 437 } |
198 } | 438 } |
| 439 |
| 440 #ifdef OUTPUT_YUV_DENOISED |
| 441 static void make_grayscale(YV12_BUFFER_CONFIG *yuv) { |
| 442 int r, c; |
| 443 uint8_t *u = yuv->u_buffer; |
| 444 uint8_t *v = yuv->v_buffer; |
| 445 |
| 446 // The '/2's are there because we have a 440 buffer, but we want to output |
| 447 // 420. |
| 448 for (r = 0; r < yuv->uv_height / 2; ++r) { |
| 449 for (c = 0; c < yuv->uv_width / 2; ++c) { |
| 450 u[c] = UINT8_MAX / 2; |
| 451 v[c] = UINT8_MAX / 2; |
| 452 } |
| 453 u += yuv->uv_stride + yuv->uv_width / 2; |
| 454 v += yuv->uv_stride + yuv->uv_width / 2; |
| 455 } |
| 456 } |
| 457 #endif |
OLD | NEW |