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 "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
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
) );
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
;
318 switch( sscanf( settings
, "%lf:%lf:%lf:%lf",
319 &spatial_luma
, &spatial_chroma
,
320 &temporal_luma
, &temporal_chroma
) )
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
;
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
;
345 temporal_luma
= HQDN3D_TEMPORAL_LUMA_DEFAULT
*
346 spatial_luma
/ HQDN3D_SPATIAL_LUMA_DEFAULT
;
348 temporal_chroma
= temporal_luma
*
349 spatial_chroma
/ spatial_luma
;
353 temporal_chroma
= temporal_luma
*
354 spatial_chroma
/ spatial_luma
;
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
);
372 void hb_denoise_close( hb_filter_private_t
* pv
)
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
;
401 hb_buffer_close( &pv
->buf_out
);
407 int hb_denoise_work( const hb_buffer_t
* buf_in
,
408 hb_buffer_t
** buf_out
,
412 hb_filter_private_t
* 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],
431 &pv
->hqdn3d_frame
[0],
436 pv
->hqdn3d_coef
[1] );
438 hqdn3d_denoise( pv
->pic_in
.data
[1],
441 &pv
->hqdn3d_frame
[1],
446 pv
->hqdn3d_coef
[3] );
448 hqdn3d_denoise( pv
->pic_in
.data
[2],
451 &pv
->hqdn3d_frame
[2],
456 pv
->hqdn3d_coef
[3] );
458 hb_buffer_copy_settings( pv
->buf_out
, buf_in
);
460 *buf_out
= pv
->buf_out
;