WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / denoise.c
blob8057b6c7df9093da7e13ccd42bd919f02e69b4e7
1 /*
2 Copyright (c) 2003 Daniel Moreno <comac AT comac DOT darktech DOT org>
3 Copyright (c) 2012 Loren Merritt
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "hb.h"
21 #include "hbffmpeg.h"
23 #define HQDN3D_SPATIAL_LUMA_DEFAULT 4.0f
24 #define HQDN3D_SPATIAL_CHROMA_DEFAULT 3.0f
25 #define HQDN3D_TEMPORAL_LUMA_DEFAULT 6.0f
27 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
28 #define MIN( a, b ) ( (a) > (b) ? (b) : (a) )
30 struct hb_filter_private_s
32 short hqdn3d_coef[6][512*16];
33 unsigned short * hqdn3d_line;
34 unsigned short * hqdn3d_frame[3];
37 static int hb_denoise_init( hb_filter_object_t * filter,
38 hb_filter_init_t * init );
40 static int hb_denoise_work( hb_filter_object_t * filter,
41 hb_buffer_t ** buf_in,
42 hb_buffer_t ** buf_out );
44 static void hb_denoise_close( hb_filter_object_t * filter );
46 hb_filter_object_t hb_filter_denoise =
48 .id = HB_FILTER_DENOISE,
49 .enforce_order = 1,
50 .name = "Denoise (hqdn3d)",
51 .settings = NULL,
52 .init = hb_denoise_init,
53 .work = hb_denoise_work,
54 .close = hb_denoise_close,
57 static void hqdn3d_precalc_coef( short * ct,
58 double dist25 )
60 int i;
61 double gamma, simil, c;
63 gamma = log( 0.25 ) / log( 1.0 - MIN(dist25,252.0)/255.0 - 0.00001 );
65 for( i = -255*16; i <= 255*16; i++ )
67 /* hqdn3d_lowpass_mul() truncates (not rounds) the diff, use +15/32 as midpoint */
68 double f = (i + 15.0/32.0) / 16.0;
69 simil = 1.0 - ABS(f) / 255.0;
70 c = pow(simil, gamma) * 256.0 * f;
71 ct[16*256+i] = (c<0) ? (c-0.5) : (c+0.5);
74 ct[0] = (dist25 != 0);
77 static inline unsigned int hqdn3d_lowpass_mul( int prev_mul,
78 int curr_mul,
79 short * coef )
81 int d = (prev_mul - curr_mul)>>4;
82 return curr_mul + coef[d];
85 static void hqdn3d_denoise_temporal( unsigned char * frame_src,
86 unsigned char * frame_dst,
87 unsigned short * frame_ant,
88 int w, int h,
89 short * temporal)
91 int x, y;
92 unsigned int tmp;
94 temporal += 0x1000;
96 for( y = 0; y < h; y++ )
98 for( x = 0; x < w; x++ )
100 frame_ant[x] = tmp = hqdn3d_lowpass_mul( frame_ant[x],
101 frame_src[x]<<8,
102 temporal );
103 frame_dst[x] = (tmp+0x7F)>>8;
106 frame_src += w;
107 frame_dst += w;
108 frame_ant += w;
112 static void hqdn3d_denoise_spatial( unsigned char * frame_src,
113 unsigned char * frame_dst,
114 unsigned short * line_ant,
115 unsigned short * frame_ant,
116 int w, int h,
117 short * spatial,
118 short * temporal )
120 int x, y;
121 unsigned int pixel_ant;
122 unsigned int tmp;
124 spatial += 0x1000;
125 temporal += 0x1000;
127 /* First line has no top neighbor. Only left one for each tmp and last frame */
128 pixel_ant = frame_src[0]<<8;
129 for ( x = 0; x < w; x++)
131 line_ant[x] = tmp = pixel_ant = hqdn3d_lowpass_mul( pixel_ant,
132 frame_src[x]<<8,
133 spatial );
134 frame_ant[x] = tmp = hqdn3d_lowpass_mul( frame_ant[x],
135 tmp,
136 temporal );
137 frame_dst[x] = (tmp+0x7F)>>8;
140 for( y = 1; y < h; y++ )
142 frame_src += w;
143 frame_dst += w;
144 frame_ant += w;
145 pixel_ant = frame_src[0]<<8;
146 for ( x = 0; x < w-1; x++ )
148 line_ant[x] = tmp = hqdn3d_lowpass_mul( line_ant[x],
149 pixel_ant,
150 spatial );
151 pixel_ant = hqdn3d_lowpass_mul( pixel_ant,
152 frame_src[x+1]<<8,
153 spatial );
154 frame_ant[x] = tmp = hqdn3d_lowpass_mul( frame_ant[x],
155 tmp,
156 temporal );
157 frame_dst[x] = (tmp+0x7F)>>8;
159 line_ant[x] = tmp = hqdn3d_lowpass_mul( line_ant[x],
160 pixel_ant,
161 spatial );
162 frame_ant[x] = tmp = hqdn3d_lowpass_mul( frame_ant[x],
163 tmp,
164 temporal );
165 frame_dst[x] = (tmp+0x7F)>>8;
169 static void hqdn3d_denoise( unsigned char * frame_src,
170 unsigned char * frame_dst,
171 unsigned short * line_ant,
172 unsigned short ** frame_ant_ptr,
173 int w,
174 int h,
175 short * spatial,
176 short * temporal )
178 int x, y;
179 unsigned short* frame_ant = (*frame_ant_ptr);
181 if( !frame_ant)
183 unsigned char * src = frame_src;
184 (*frame_ant_ptr) = frame_ant = malloc( w*h*sizeof(unsigned short) );
185 for ( y = 0; y < h; y++, frame_src += w, frame_ant += w )
187 for( x = 0; x < w; x++ )
189 frame_ant[x] = frame_src[x]<<8;
192 frame_src = src;
193 frame_ant = *frame_ant_ptr;
196 /* If no spatial coefficients, do temporal denoise only */
197 if( spatial[0] )
199 hqdn3d_denoise_spatial( frame_src,
200 frame_dst,
201 line_ant,
202 frame_ant,
203 w, h,
204 spatial,
205 temporal );
207 else
209 hqdn3d_denoise_temporal( frame_src,
210 frame_dst,
211 frame_ant,
212 w, h,
213 temporal);
217 static int hb_denoise_init( hb_filter_object_t * filter,
218 hb_filter_init_t * init )
220 filter->private_data = calloc( sizeof(struct hb_filter_private_s), 1 );
221 hb_filter_private_t * pv = filter->private_data;
223 double spatial_luma = 0.0f,
224 spatial_chroma_b = 0.0f,
225 spatial_chroma_r = 0.0f,
226 temporal_luma = 0.0f,
227 temporal_chroma_b = 0.0f,
228 temporal_chroma_r = 0.0f;
230 if (filter->settings != NULL)
232 switch( sscanf( filter->settings, "%lf:%lf:%lf:%lf:%lf:%lf",
233 &spatial_luma, &spatial_chroma_b, &spatial_chroma_r,
234 &temporal_luma, &temporal_chroma_b, &temporal_chroma_r ) )
236 case 0:
237 spatial_luma = HQDN3D_SPATIAL_LUMA_DEFAULT;
238 spatial_chroma_b = HQDN3D_SPATIAL_CHROMA_DEFAULT;
239 spatial_chroma_r = spatial_chroma_b;
240 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT;
241 temporal_chroma_b = temporal_luma *
242 spatial_chroma_b / spatial_luma;
243 temporal_chroma_r = temporal_chroma_b;
244 break;
246 case 1:
247 spatial_chroma_b = HQDN3D_SPATIAL_CHROMA_DEFAULT *
248 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
249 spatial_chroma_r = spatial_chroma_b;
250 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
251 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
252 temporal_chroma_b = temporal_luma *
253 spatial_chroma_b / spatial_luma;
254 temporal_chroma_r = temporal_chroma_b;
255 break;
257 case 2:
258 spatial_chroma_r = spatial_chroma_b;
259 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
260 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
261 temporal_chroma_b = temporal_luma *
262 spatial_chroma_b / spatial_luma;
263 temporal_chroma_r = temporal_chroma_b;
264 break;
266 case 3:
267 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
268 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
269 temporal_chroma_b = temporal_luma *
270 spatial_chroma_b / spatial_luma;
271 temporal_chroma_r = temporal_chroma_b;
272 break;
274 case 4:
275 temporal_chroma_b = temporal_luma *
276 spatial_chroma_b / spatial_luma;
277 temporal_chroma_r = temporal_chroma_b;
278 break;
280 case 5:
281 temporal_chroma_r = temporal_chroma_b;
282 break;
286 hqdn3d_precalc_coef( pv->hqdn3d_coef[0], spatial_luma );
287 hqdn3d_precalc_coef( pv->hqdn3d_coef[1], temporal_luma );
288 hqdn3d_precalc_coef( pv->hqdn3d_coef[2], spatial_chroma_b );
289 hqdn3d_precalc_coef( pv->hqdn3d_coef[3], temporal_chroma_b );
290 hqdn3d_precalc_coef( pv->hqdn3d_coef[4], spatial_chroma_r );
291 hqdn3d_precalc_coef( pv->hqdn3d_coef[5], temporal_chroma_r );
293 return 0;
296 static void hb_denoise_close( hb_filter_object_t * filter )
298 hb_filter_private_t * pv = filter->private_data;
300 if( !pv )
302 return;
305 if( pv->hqdn3d_line )
307 free( pv->hqdn3d_line );
308 pv->hqdn3d_line = NULL;
310 if( pv->hqdn3d_frame[0] )
312 free( pv->hqdn3d_frame[0] );
313 pv->hqdn3d_frame[0] = NULL;
315 if( pv->hqdn3d_frame[1] )
317 free( pv->hqdn3d_frame[1] );
318 pv->hqdn3d_frame[1] = NULL;
320 if( pv->hqdn3d_frame[2] )
322 free( pv->hqdn3d_frame[2] );
323 pv->hqdn3d_frame[2] = NULL;
326 free( pv );
327 filter->private_data = NULL;
330 static int hb_denoise_work( hb_filter_object_t * filter,
331 hb_buffer_t ** buf_in,
332 hb_buffer_t ** buf_out )
334 hb_filter_private_t * pv = filter->private_data;
335 hb_buffer_t * in = *buf_in, * out;
337 if (in->s.flags & HB_BUF_FLAG_EOF)
339 *buf_out = in;
340 *buf_in = NULL;
341 return HB_FILTER_DONE;
344 out = hb_video_buffer_init( in->f.width, in->f.height );
346 if( !pv->hqdn3d_line )
348 pv->hqdn3d_line = malloc( in->plane[0].stride * sizeof(unsigned short) );
351 int c, coef_index;
353 for ( c = 0; c < 3; c++ )
355 coef_index = c * 2;
356 hqdn3d_denoise( in->plane[c].data,
357 out->plane[c].data,
358 pv->hqdn3d_line,
359 &pv->hqdn3d_frame[c],
360 in->plane[c].stride,
361 in->plane[c].height,
362 pv->hqdn3d_coef[coef_index],
363 pv->hqdn3d_coef[coef_index+1] );
366 out->s = in->s;
367 hb_buffer_move_subs( out, in );
369 *buf_out = out;
371 return HB_FILTER_OK;