Moves the filters' logging info to work.c, adds parameter info. I also changed the...
[HandBrake.git] / libhb / denoise.c
blob5022d4721f18aed62f8f8de366158b4d432ccd4c
1 /*
2 Copyright (C) 2003 Daniel Moreno <comac@comac.darktech.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "hb.h"
20 #include "ffmpeg/avcodec.h"
21 #include "mpeg2dec/mpeg2.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) )
29 struct hb_filter_private_s
31 int pix_fmt;
32 int width[3];
33 int height[3];
35 int hqdn3d_coef[4][512*16];
36 unsigned int * hqdn3d_line;
37 unsigned short * hqdn3d_frame[3];
39 AVPicture pic_in;
40 AVPicture pic_out;
41 hb_buffer_t * buf_out;
44 hb_filter_private_t * hb_denoise_init( int pix_fmt,
45 int width,
46 int height,
47 char * settings );
49 int hb_denoise_work( const hb_buffer_t * buf_in,
50 hb_buffer_t ** buf_out,
51 int pix_fmt,
52 int width,
53 int height,
54 hb_filter_private_t * pv );
56 void hb_denoise_close( hb_filter_private_t * pv );
58 hb_filter_object_t hb_filter_denoise =
60 FILTER_DENOISE,
61 "Denoise (hqdn3d)",
62 NULL,
63 hb_denoise_init,
64 hb_denoise_work,
65 hb_denoise_close,
68 static void hqdn3d_precalc_coef( int * ct,
69 double dist25 )
71 int i;
72 double gamma, simil, c;
74 gamma = log( 0.25 ) / log( 1.0 - dist25/255.0 - 0.00001 );
76 for( i = -255*16; i <= 255*16; i++ )
78 simil = 1.0 - ABS(i) / (16*255.0);
79 c = pow( simil, gamma ) * 65536.0 * (double)i / 16.0;
80 ct[16*256+i] = (c<0) ? (c-0.5) : (c+0.5);
83 ct[0] = (dist25 != 0);
86 static inline unsigned int hqdn3d_lowpass_mul( unsigned int prev_mul,
87 unsigned int curr_mul,
88 int * coef )
90 int diff_mul = prev_mul - curr_mul;
91 int d = ((diff_mul+0x10007FF)>>12);
92 return curr_mul + coef[d];
95 static void hqdn3d_denoise_temporal( unsigned char * frame_src,
96 unsigned char * frame_dst,
97 unsigned short * frame_ant,
98 int w, int h,
99 int * temporal)
101 int x, y;
102 unsigned int pixel_dst;
104 for( y = 0; y < h; y++ )
106 for( x = 0; x < w; x++ )
108 pixel_dst = hqdn3d_lowpass_mul( frame_ant[x]<<8,
109 frame_src[x]<<16,
110 temporal );
112 frame_ant[x] = ((pixel_dst+0x1000007F)>>8);
113 frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
116 frame_src += w;
117 frame_dst += w;
118 frame_ant += w;
122 static void hqdn3d_denoise_spatial( unsigned char * frame_src,
123 unsigned char * frame_dst,
124 unsigned int * line_ant,
125 int w, int h,
126 int * horizontal,
127 int * vertical )
129 int x, y;
130 int line_offset_src = 0, line_offset_dst = 0;
131 unsigned int pixel_ant;
132 unsigned int pixel_dst;
134 /* First pixel has no left nor top neighbor. */
135 pixel_dst = line_ant[0] = pixel_ant = frame_src[0]<<16;
136 frame_dst[0] = ((pixel_dst+0x10007FFF)>>16);
138 /* First line has no top neighbor, only left. */
139 for( x = 1; x < w; x++ )
141 pixel_dst = line_ant[x] = hqdn3d_lowpass_mul(pixel_ant,
142 frame_src[x]<<16,
143 horizontal);
145 frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
148 for( y = 1; y < h; y++ )
150 unsigned int pixel_ant;
151 line_offset_src += w, line_offset_dst += w;
153 /* First pixel on each line doesn't have previous pixel */
154 pixel_ant = frame_src[line_offset_src]<<16;
156 pixel_dst = line_ant[0] = hqdn3d_lowpass_mul( line_ant[0],
157 pixel_ant,
158 vertical);
160 frame_dst[line_offset_dst] = ((pixel_dst+0x10007FFF)>>16);
162 /* The rest of the pixels in the line are normal */
163 for( x = 1; x < w; x++ )
165 unsigned int pixel_dst;
167 pixel_ant = hqdn3d_lowpass_mul( pixel_ant,
168 frame_src[line_offset_src+x]<<16,
169 horizontal );
170 pixel_dst = line_ant[x] = hqdn3d_lowpass_mul( line_ant[x],
171 pixel_ant,
172 vertical );
174 frame_dst[line_offset_dst+x]= ((pixel_dst+0x10007FFF)>>16);
179 static void hqdn3d_denoise( unsigned char * frame_src,
180 unsigned char * frame_dst,
181 unsigned int * line_ant,
182 unsigned short ** frame_ant_ptr,
183 int w,
184 int h,
185 int * horizontal,
186 int * vertical,
187 int * temporal)
189 int x, y;
190 int line_offset_src = 0, line_offset_dst = 0;
191 unsigned int pixel_ant;
192 unsigned int pixel_dst;
193 unsigned short* frame_ant = (*frame_ant_ptr);
195 if( !frame_ant)
197 (*frame_ant_ptr) = frame_ant = malloc( w*h*sizeof(unsigned short) );
198 for( y = 0; y < h; y++ )
200 unsigned short* dst = &frame_ant[y*w];
201 unsigned char* src = frame_src + y*w;
203 for( x = 0; x < w; x++ )
205 dst[x] = src[x] << 8;
210 /* If no spatial coefficients, do temporal denoise only */
211 if( !horizontal[0] && !vertical[0] )
213 hqdn3d_denoise_temporal( frame_src,
214 frame_dst,
215 frame_ant,
216 w, h,
217 temporal);
218 return;
221 /* If no temporal coefficients, do spatial denoise only */
222 if( !temporal[0] )
224 hqdn3d_denoise_spatial( frame_src,
225 frame_dst,
226 line_ant,
227 w, h,
228 horizontal,
229 vertical);
230 return;
233 /* First pixel has no left nor top neighbor. Only previous frame */
234 line_ant[0] = pixel_ant = frame_src[0] << 16;
236 pixel_dst = hqdn3d_lowpass_mul( frame_ant[0]<<8,
237 pixel_ant,
238 temporal );
240 frame_ant[0] = ((pixel_dst+0x1000007F)>>8);
241 frame_dst[0] = ((pixel_dst+0x10007FFF)>>16);
243 /* First line has no top neighbor. Only left one for each pixel and last frame */
244 for( x = 1; x < w; x++ )
246 line_ant[x] = pixel_ant = hqdn3d_lowpass_mul( pixel_ant,
247 frame_src[x]<<16,
248 horizontal);
250 pixel_dst = hqdn3d_lowpass_mul( frame_ant[x]<<8,
251 pixel_ant,
252 temporal);
254 frame_ant[x] = ((pixel_dst+0x1000007F)>>8);
255 frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
258 /* The rest of the lines in the frame are normal */
259 for( y = 1; y < h; y++ )
261 unsigned int pixel_ant;
262 unsigned short * line_prev = &frame_ant[y*w];
263 line_offset_src += w, line_offset_dst += w;
265 /* First pixel on each line doesn't have previous pixel */
266 pixel_ant = frame_src[line_offset_src]<<16;
267 line_ant[0] = hqdn3d_lowpass_mul( line_ant[0],
268 pixel_ant,
269 vertical);
270 pixel_dst = hqdn3d_lowpass_mul( line_prev[0]<<8,
271 line_ant[0],
272 temporal);
273 line_prev[0] = ((pixel_dst+0x1000007F)>>8);
275 frame_dst[line_offset_dst] = ((pixel_dst+0x10007FFF)>>16);
277 /* The rest of the pixels in the line are normal */
278 for( x = 1; x < w; x++ )
280 unsigned int pixel_dst;
281 pixel_ant = hqdn3d_lowpass_mul( pixel_ant,
282 frame_src[line_offset_src+x]<<16,
283 horizontal );
284 line_ant[x] = hqdn3d_lowpass_mul( line_ant[x],
285 pixel_ant, vertical);
286 pixel_dst = hqdn3d_lowpass_mul( line_prev[x]<<8,
287 line_ant[x],
288 temporal );
289 line_prev[x] = ((pixel_dst+0x1000007F)>>8);
291 frame_dst[line_offset_dst+x] = ((pixel_dst+0x10007FFF)>>16);
296 hb_filter_private_t * hb_denoise_init( int pix_fmt,
297 int width,
298 int height,
299 char * settings )
301 if( pix_fmt != PIX_FMT_YUV420P )
303 return 0;
306 hb_filter_private_t * pv = malloc( sizeof(struct hb_filter_private_s) );
308 pv->pix_fmt = pix_fmt;
309 pv->width[0] = width;
310 pv->height[0] = height;
311 pv->width[1] = pv->width[2] = width >> 1;
312 pv->height[1] = pv->height[2] = height >> 1;
314 double spatial_luma, temporal_luma, spatial_chroma, temporal_chroma;
316 if( settings )
318 switch( sscanf( settings, "%lf:%lf:%lf:%lf",
319 &spatial_luma, &spatial_chroma,
320 &temporal_luma, &temporal_chroma ) )
322 case 0:
323 spatial_luma = HQDN3D_SPATIAL_LUMA_DEFAULT;
325 spatial_chroma = HQDN3D_SPATIAL_CHROMA_DEFAULT;
327 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT;
329 temporal_chroma = temporal_luma *
330 spatial_chroma / spatial_luma;
331 break;
333 case 1:
334 spatial_chroma = HQDN3D_SPATIAL_CHROMA_DEFAULT *
335 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
337 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
338 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
340 temporal_chroma = temporal_luma *
341 spatial_chroma / spatial_luma;
342 break;
344 case 2:
345 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
346 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
348 temporal_chroma = temporal_luma *
349 spatial_chroma / spatial_luma;
350 break;
352 case 3:
353 temporal_chroma = temporal_luma *
354 spatial_chroma / spatial_luma;
355 break;
359 pv->hqdn3d_line = malloc( width * sizeof(int) );
361 hqdn3d_precalc_coef( pv->hqdn3d_coef[0], spatial_luma );
362 hqdn3d_precalc_coef( pv->hqdn3d_coef[1], temporal_luma );
363 hqdn3d_precalc_coef( pv->hqdn3d_coef[2], spatial_chroma );
364 hqdn3d_precalc_coef( pv->hqdn3d_coef[3], temporal_chroma );
366 int buf_size = 3 * width * height / 2;
367 pv->buf_out = hb_buffer_init( buf_size );
369 return pv;
372 void hb_denoise_close( hb_filter_private_t * pv )
374 if( !pv )
376 return;
379 if( pv->hqdn3d_line )
381 free( pv->hqdn3d_line );
382 pv->hqdn3d_line = NULL;
384 if( pv->hqdn3d_frame[0] )
386 free( pv->hqdn3d_frame[0] );
387 pv->hqdn3d_frame[0] = NULL;
389 if( pv->hqdn3d_frame[1] )
391 free( pv->hqdn3d_frame[1] );
392 pv->hqdn3d_frame[1] = NULL;
394 if( pv->hqdn3d_frame[2] )
396 free( pv->hqdn3d_frame[2] );
397 pv->hqdn3d_frame[2] = NULL;
399 if( pv->buf_out )
401 hb_buffer_close( &pv->buf_out );
404 free( pv );
407 int hb_denoise_work( const hb_buffer_t * buf_in,
408 hb_buffer_t ** buf_out,
409 int pix_fmt,
410 int width,
411 int height,
412 hb_filter_private_t * pv )
414 if( !pv ||
415 pix_fmt != pv->pix_fmt ||
416 width != pv->width[0] ||
417 height != pv->height[0] )
419 return FILTER_FAILED;
422 avpicture_fill( &pv->pic_in, buf_in->data,
423 pix_fmt, width, height );
425 avpicture_fill( &pv->pic_out, pv->buf_out->data,
426 pix_fmt, width, height );
428 hqdn3d_denoise( pv->pic_in.data[0],
429 pv->pic_out.data[0],
430 pv->hqdn3d_line,
431 &pv->hqdn3d_frame[0],
432 pv->width[0],
433 pv->height[0],
434 pv->hqdn3d_coef[0],
435 pv->hqdn3d_coef[0],
436 pv->hqdn3d_coef[1] );
438 hqdn3d_denoise( pv->pic_in.data[1],
439 pv->pic_out.data[1],
440 pv->hqdn3d_line,
441 &pv->hqdn3d_frame[1],
442 pv->width[1],
443 pv->height[1],
444 pv->hqdn3d_coef[2],
445 pv->hqdn3d_coef[2],
446 pv->hqdn3d_coef[3] );
448 hqdn3d_denoise( pv->pic_in.data[2],
449 pv->pic_out.data[2],
450 pv->hqdn3d_line,
451 &pv->hqdn3d_frame[2],
452 pv->width[2],
453 pv->height[2],
454 pv->hqdn3d_coef[2],
455 pv->hqdn3d_coef[2],
456 pv->hqdn3d_coef[3] );
458 hb_buffer_copy_settings( pv->buf_out, buf_in );
460 *buf_out = pv->buf_out;
462 return FILTER_OK;