Fix multi-resolution threaded encoding
[profile/ivi/libvpx.git] / vp8 / encoder / denoising.c
1 /*
2  *  Copyright (c) 2012 The WebM 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 "denoising.h"
12
13 #include "vp8/common/reconinter.h"
14 #include "vpx/vpx_integer.h"
15 #include "vpx_mem/vpx_mem.h"
16 #include "vpx_rtcd.h"
17
18 const unsigned int NOISE_MOTION_THRESHOLD = 20*20;
19 const unsigned int NOISE_DIFF2_THRESHOLD = 75;
20 // SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming var(noise) ~= 100.
21 const unsigned int SSE_DIFF_THRESHOLD = 16*16*20;
22 const unsigned int SSE_THRESHOLD = 16*16*40;
23
24 static uint8_t blend(uint8_t state, uint8_t sample, uint8_t factor_q8)
25 {
26   return (uint8_t)(
27       (((uint16_t)factor_q8 * ((uint16_t)state) +  // Q8
28         (uint16_t)(256 - factor_q8) * ((uint16_t)sample)) + 128)  // Q8
29       >> 8);
30 }
31
32 static unsigned int denoiser_motion_compensate(YV12_BUFFER_CONFIG* src,
33                                                YV12_BUFFER_CONFIG* dst,
34                                                MACROBLOCK* x,
35                                                unsigned int best_sse,
36                                                unsigned int zero_mv_sse,
37                                                int recon_yoffset,
38                                                int recon_uvoffset)
39 {
40   MACROBLOCKD filter_xd = x->e_mbd;
41   int mv_col;
42   int mv_row;
43   int sse_diff = zero_mv_sse - best_sse;
44   // Compensate the running average.
45   filter_xd.pre.y_buffer = src->y_buffer + recon_yoffset;
46   filter_xd.pre.u_buffer = src->u_buffer + recon_uvoffset;
47   filter_xd.pre.v_buffer = src->v_buffer + recon_uvoffset;
48   // Write the compensated running average to the destination buffer.
49   filter_xd.dst.y_buffer = dst->y_buffer + recon_yoffset;
50   filter_xd.dst.u_buffer = dst->u_buffer + recon_uvoffset;
51   filter_xd.dst.v_buffer = dst->v_buffer + recon_uvoffset;
52   // Use the best MV for the compensation.
53   filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME;
54   filter_xd.mode_info_context->mbmi.mode = filter_xd.best_sse_inter_mode;
55   filter_xd.mode_info_context->mbmi.mv = filter_xd.best_sse_mv;
56   filter_xd.mode_info_context->mbmi.need_to_clamp_mvs =
57       filter_xd.need_to_clamp_best_mvs;
58   mv_col = filter_xd.best_sse_mv.as_mv.col;
59   mv_row = filter_xd.best_sse_mv.as_mv.row;
60   if (filter_xd.mode_info_context->mbmi.mode <= B_PRED ||
61       (mv_row*mv_row + mv_col*mv_col <= NOISE_MOTION_THRESHOLD &&
62        sse_diff < SSE_DIFF_THRESHOLD))
63   {
64     // Handle intra blocks as referring to last frame with zero motion and
65     // let the absolute pixel difference affect the filter factor.
66     // Also consider small amount of motion as being random walk due to noise,
67     // if it doesn't mean that we get a much bigger error.
68     // Note that any changes to the mode info only affects the denoising.
69     filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME;
70     filter_xd.mode_info_context->mbmi.mode = ZEROMV;
71     filter_xd.mode_info_context->mbmi.mv.as_int = 0;
72     x->e_mbd.best_sse_inter_mode = ZEROMV;
73     x->e_mbd.best_sse_mv.as_int = 0;
74     best_sse = zero_mv_sse;
75   }
76   if (!x->skip)
77   {
78     vp8_build_inter_predictors_mb(&filter_xd);
79   }
80   else
81   {
82     vp8_build_inter16x16_predictors_mb(&filter_xd,
83                                        filter_xd.dst.y_buffer,
84                                        filter_xd.dst.u_buffer,
85                                        filter_xd.dst.v_buffer,
86                                        filter_xd.dst.y_stride,
87                                        filter_xd.dst.uv_stride);
88   }
89   return best_sse;
90 }
91
92 static void denoiser_filter(YV12_BUFFER_CONFIG* mc_running_avg,
93                             YV12_BUFFER_CONFIG* running_avg,
94                             MACROBLOCK* signal,
95                             unsigned int motion_magnitude2,
96                             int y_offset,
97                             int uv_offset)
98 {
99   unsigned char* sig = signal->thismb;
100   int sig_stride = 16;
101   unsigned char* mc_running_avg_y = mc_running_avg->y_buffer + y_offset;
102   int mc_avg_y_stride = mc_running_avg->y_stride;
103   unsigned char* running_avg_y = running_avg->y_buffer + y_offset;
104   int avg_y_stride = running_avg->y_stride;
105   int r, c;
106   for (r = 0; r < 16; r++)
107   {
108     for (c = 0; c < 16; c++)
109     {
110       int diff;
111       int absdiff = 0;
112       unsigned int filter_coefficient;
113       absdiff = sig[c] - mc_running_avg_y[c];
114       absdiff = absdiff > 0 ? absdiff : -absdiff;
115       assert(absdiff >= 0 && absdiff < 256);
116       filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3));
117       // Allow some additional filtering of static blocks, or blocks with very
118       // small motion vectors.
119       filter_coefficient += filter_coefficient / (3 + (motion_magnitude2 >> 3));
120       filter_coefficient = filter_coefficient > 255 ? 255 : filter_coefficient;
121
122       running_avg_y[c] = blend(mc_running_avg_y[c], sig[c], filter_coefficient);
123       diff = sig[c] - running_avg_y[c];
124
125       if (diff * diff < NOISE_DIFF2_THRESHOLD)
126       {
127         // Replace with mean to suppress the noise.
128         sig[c] = running_avg_y[c];
129       }
130       else
131       {
132         // Replace the filter state with the signal since the change in this
133         // pixel isn't classified as noise.
134         running_avg_y[c] = sig[c];
135       }
136     }
137     sig += sig_stride;
138     mc_running_avg_y += mc_avg_y_stride;
139     running_avg_y += avg_y_stride;
140   }
141 }
142
143 int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height)
144 {
145   assert(denoiser);
146   denoiser->yv12_running_avg.flags = 0;
147   if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg), width,
148                                   height, VP8BORDERINPIXELS) < 0)
149   {
150       vp8_denoiser_free(denoiser);
151       return 1;
152   }
153   denoiser->yv12_mc_running_avg.flags = 0;
154   if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width,
155                                   height, VP8BORDERINPIXELS) < 0)
156   {
157       vp8_denoiser_free(denoiser);
158       return 1;
159   }
160   vpx_memset(denoiser->yv12_running_avg.buffer_alloc, 0,
161              denoiser->yv12_running_avg.frame_size);
162   vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0,
163              denoiser->yv12_mc_running_avg.frame_size);
164   return 0;
165 }
166
167 void vp8_denoiser_free(VP8_DENOISER *denoiser)
168 {
169   assert(denoiser);
170   vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg);
171   vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
172 }
173
174 void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser,
175                              MACROBLOCK *x,
176                              unsigned int best_sse,
177                              unsigned int zero_mv_sse,
178                              int recon_yoffset,
179                              int recon_uvoffset) {
180   int mv_row;
181   int mv_col;
182   unsigned int motion_magnitude2;
183   // Motion compensate the running average.
184   best_sse = denoiser_motion_compensate(&denoiser->yv12_running_avg,
185                                         &denoiser->yv12_mc_running_avg,
186                                         x,
187                                         best_sse,
188                                         zero_mv_sse,
189                                         recon_yoffset,
190                                         recon_uvoffset);
191
192   mv_row = x->e_mbd.best_sse_mv.as_mv.row;
193   mv_col = x->e_mbd.best_sse_mv.as_mv.col;
194   motion_magnitude2 = mv_row*mv_row + mv_col*mv_col;
195   if (best_sse > SSE_THRESHOLD ||
196       motion_magnitude2 > 8 * NOISE_MOTION_THRESHOLD)
197   {
198     // No filtering of this block since it differs too much from the predictor,
199     // or the motion vector magnitude is considered too big.
200     vp8_copy_mem16x16(x->thismb, 16,
201                       denoiser->yv12_running_avg.y_buffer + recon_yoffset,
202                       denoiser->yv12_running_avg.y_stride);
203     return;
204   }
205   // Filter.
206   denoiser_filter(&denoiser->yv12_mc_running_avg,
207                   &denoiser->yv12_running_avg,
208                   x,
209                   motion_magnitude2,
210                   recon_yoffset,
211                   recon_uvoffset);
212 }