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
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
,
50 .name
= "Denoise (hqdn3d)",
52 .init
= hb_denoise_init
,
53 .work
= hb_denoise_work
,
54 .close
= hb_denoise_close
,
57 static void hqdn3d_precalc_coef( short * ct
,
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
,
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
,
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
],
103 frame_dst
[x
] = (tmp
+0x7F)>>8;
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
,
121 unsigned int pixel_ant
;
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
,
134 frame_ant
[x
] = tmp
= hqdn3d_lowpass_mul( frame_ant
[x
],
137 frame_dst
[x
] = (tmp
+0x7F)>>8;
140 for( y
= 1; y
< h
; y
++ )
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
],
151 pixel_ant
= hqdn3d_lowpass_mul( pixel_ant
,
154 frame_ant
[x
] = tmp
= hqdn3d_lowpass_mul( frame_ant
[x
],
157 frame_dst
[x
] = (tmp
+0x7F)>>8;
159 line_ant
[x
] = tmp
= hqdn3d_lowpass_mul( line_ant
[x
],
162 frame_ant
[x
] = tmp
= hqdn3d_lowpass_mul( frame_ant
[x
],
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
,
179 unsigned short* frame_ant
= (*frame_ant_ptr
);
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;
193 frame_ant
= *frame_ant_ptr
;
196 /* If no spatial coefficients, do temporal denoise only */
199 hqdn3d_denoise_spatial( frame_src
,
209 hqdn3d_denoise_temporal( frame_src
,
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
) )
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
;
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
;
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
;
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
;
275 temporal_chroma_b
= temporal_luma
*
276 spatial_chroma_b
/ spatial_luma
;
277 temporal_chroma_r
= temporal_chroma_b
;
281 temporal_chroma_r
= temporal_chroma_b
;
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
);
296 static void hb_denoise_close( hb_filter_object_t
* filter
)
298 hb_filter_private_t
* pv
= filter
->private_data
;
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
;
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
)
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) );
353 for ( c
= 0; c
< 3; c
++ )
356 hqdn3d_denoise( in
->plane
[c
].data
,
359 &pv
->hqdn3d_frame
[c
],
362 pv
->hqdn3d_coef
[coef_index
],
363 pv
->hqdn3d_coef
[coef_index
+1] );
367 hb_buffer_move_subs( out
, in
);