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
20 #include "libavcodec/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
35 int hqdn3d_coef[4][512*16];
36 unsigned int * hqdn3d_line;
37 unsigned short * hqdn3d_frame[3];
41 hb_buffer_t * buf_out;
44 hb_filter_private_t * hb_denoise_init( int pix_fmt,
49 int hb_denoise_work( const hb_buffer_t * buf_in,
50 hb_buffer_t ** buf_out,
54 hb_filter_private_t * pv );
56 void hb_denoise_close( hb_filter_private_t * pv );
58 hb_filter_object_t hb_filter_denoise =
68 static void hqdn3d_precalc_coef( int * ct,
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,
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,
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,
112 frame_ant[x] = ((pixel_dst+0x1000007F)>>8);
113 frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
122 static void hqdn3d_denoise_spatial( unsigned char * frame_src,
123 unsigned char * frame_dst,
124 unsigned int * line_ant,
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,
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],
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,
170 pixel_dst = line_ant[x] = hqdn3d_lowpass_mul( line_ant[x],
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,
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);
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,
221 /* If no temporal coefficients, do spatial denoise only */
224 hqdn3d_denoise_spatial( frame_src,
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,
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,
250 pixel_dst = hqdn3d_lowpass_mul( frame_ant[x]<<8,
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],
270 pixel_dst = hqdn3d_lowpass_mul( line_prev[0]<<8,
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,
284 line_ant[x] = hqdn3d_lowpass_mul( line_ant[x],
285 pixel_ant, vertical);
286 pixel_dst = hqdn3d_lowpass_mul( line_prev[x]<<8,
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,
301 if( pix_fmt != PIX_FMT_YUV420P )
306 hb_filter_private_t * pv = malloc( sizeof(struct hb_filter_private_s) );
309 * Clear the memory to avoid freeing uninitialised memory later.
311 memset( pv, 0, sizeof( struct hb_filter_private_s ) );
313 pv->pix_fmt = pix_fmt;
314 pv->width[0] = width;
315 pv->height[0] = height;
316 pv->width[1] = pv->width[2] = width >> 1;
317 pv->height[1] = pv->height[2] = height >> 1;
319 double spatial_luma, temporal_luma, spatial_chroma, temporal_chroma;
323 switch( sscanf( settings, "%lf:%lf:%lf:%lf",
324 &spatial_luma, &spatial_chroma,
325 &temporal_luma, &temporal_chroma ) )
328 spatial_luma = HQDN3D_SPATIAL_LUMA_DEFAULT;
330 spatial_chroma = HQDN3D_SPATIAL_CHROMA_DEFAULT;
332 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT;
334 temporal_chroma = temporal_luma *
335 spatial_chroma / spatial_luma;
339 spatial_chroma = HQDN3D_SPATIAL_CHROMA_DEFAULT *
340 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
342 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
343 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
345 temporal_chroma = temporal_luma *
346 spatial_chroma / spatial_luma;
350 temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT *
351 spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
353 temporal_chroma = temporal_luma *
354 spatial_chroma / spatial_luma;
358 temporal_chroma = temporal_luma *
359 spatial_chroma / spatial_luma;
364 pv->hqdn3d_line = malloc( width * sizeof(int) );
366 hqdn3d_precalc_coef( pv->hqdn3d_coef[0], spatial_luma );
367 hqdn3d_precalc_coef( pv->hqdn3d_coef[1], temporal_luma );
368 hqdn3d_precalc_coef( pv->hqdn3d_coef[2], spatial_chroma );
369 hqdn3d_precalc_coef( pv->hqdn3d_coef[3], temporal_chroma );
371 int buf_size = 3 * width * height / 2;
372 pv->buf_out = hb_buffer_init( buf_size );
377 void hb_denoise_close( hb_filter_private_t * pv )
384 if( pv->hqdn3d_line )
386 free( pv->hqdn3d_line );
387 pv->hqdn3d_line = NULL;
389 if( pv->hqdn3d_frame[0] )
391 free( pv->hqdn3d_frame[0] );
392 pv->hqdn3d_frame[0] = NULL;
394 if( pv->hqdn3d_frame[1] )
396 free( pv->hqdn3d_frame[1] );
397 pv->hqdn3d_frame[1] = NULL;
399 if( pv->hqdn3d_frame[2] )
401 free( pv->hqdn3d_frame[2] );
402 pv->hqdn3d_frame[2] = NULL;
406 hb_buffer_close( &pv->buf_out );
412 int hb_denoise_work( const hb_buffer_t * buf_in,
413 hb_buffer_t ** buf_out,
417 hb_filter_private_t * pv )
420 pix_fmt != pv->pix_fmt ||
421 width != pv->width[0] ||
422 height != pv->height[0] )
424 return FILTER_FAILED;
427 avpicture_fill( &pv->pic_in, buf_in->data,
428 pix_fmt, width, height );
430 avpicture_fill( &pv->pic_out, pv->buf_out->data,
431 pix_fmt, width, height );
433 hqdn3d_denoise( pv->pic_in.data[0],
436 &pv->hqdn3d_frame[0],
441 pv->hqdn3d_coef[1] );
443 hqdn3d_denoise( pv->pic_in.data[1],
446 &pv->hqdn3d_frame[1],
451 pv->hqdn3d_coef[3] );
453 hqdn3d_denoise( pv->pic_in.data[2],
456 &pv->hqdn3d_frame[2],
461 pv->hqdn3d_coef[3] );
463 hb_buffer_copy_settings( pv->buf_out, buf_in );
465 *buf_out = pv->buf_out;