OSDN Git Service

Added progress marking for when doing the subtitle scan
[handbrake-jp/handbrake-jp-git.git] / libhb / denoise.c
1 /*
2  Copyright (C) 2003 Daniel Moreno <comac@comac.darktech.org>
3  
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.
8  
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.
13  
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
17 */
18
19 #include "hb.h"
20 #include "ffmpeg/avcodec.h"
21 #include "mpeg2dec/mpeg2.h"
22
23 #define HQDN3D_SPATIAL_LUMA_DEFAULT    4.0f
24 #define HQDN3D_SPATIAL_CHROMA_DEFAULT  3.0f
25 #define HQDN3D_TEMPORAL_LUMA_DEFAULT   6.0f
26
27 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
28
29 struct hb_filter_private_s 
30 {
31     int              pix_fmt;
32     int              width[3];
33     int              height[3];   
34     
35     int              hqdn3d_coef[4][512*16];
36     unsigned int   * hqdn3d_line;
37         unsigned short * hqdn3d_frame[3];
38     
39     AVPicture        pic_in;
40     AVPicture        pic_out;            
41     hb_buffer_t    * buf_out;
42 };
43
44 hb_filter_private_t * hb_denoise_init( int pix_fmt, 
45                                        int width, 
46                                        int height,
47                                        char * settings );
48
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 );
55
56 void hb_denoise_close( hb_filter_private_t * pv );
57
58 hb_filter_object_t hb_filter_denoise =
59 {   
60     FILTER_DENOISE,
61     "Denoise (hqdn3d)",
62     NULL,
63     hb_denoise_init,
64     hb_denoise_work,
65     hb_denoise_close,
66 };
67
68 static void hqdn3d_precalc_coef( int * ct, 
69                                  double dist25 )
70 {
71     int i;
72     double gamma, simil, c;
73     
74     gamma = log( 0.25 ) / log( 1.0 - dist25/255.0 - 0.00001 );
75     
76     for( i = -255*16; i <= 255*16; i++ )
77     {
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);
81     }
82     
83     ct[0] = (dist25 != 0);
84 }
85
86 static inline unsigned int hqdn3d_lowpass_mul( unsigned int prev_mul, 
87                                                unsigned int curr_mul, 
88                                                int * coef )
89 {
90     int diff_mul = prev_mul - curr_mul;
91     int d = ((diff_mul+0x10007FF)>>12);
92     return curr_mul + coef[d];
93 }
94
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)
100 {
101     int x, y;
102     unsigned int pixel_dst;
103     
104     for( y = 0; y < h; y++ )
105     {
106         for( x = 0; x < w; x++ )
107         {
108             pixel_dst = hqdn3d_lowpass_mul( frame_ant[x]<<8, 
109                                             frame_src[x]<<16, 
110                                             temporal );
111             
112             frame_ant[x] = ((pixel_dst+0x1000007F)>>8);
113             frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
114         }
115         
116         frame_src += w;
117         frame_dst += w;
118         frame_ant += w;
119     }
120 }
121
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 )
128 {
129     int x, y;
130     int line_offset_src = 0, line_offset_dst = 0;
131     unsigned int pixel_ant;
132     unsigned int pixel_dst;
133     
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);
137     
138     /* First line has no top neighbor, only left. */
139     for( x = 1; x < w; x++ )
140     {
141         pixel_dst = line_ant[x] = hqdn3d_lowpass_mul(pixel_ant, 
142                                                      frame_src[x]<<16, 
143                                                      horizontal);
144         
145         frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
146     }
147     
148     for( y = 1; y < h; y++ )
149     {
150         unsigned int pixel_ant;
151         line_offset_src += w, line_offset_dst += w;
152         
153         /* First pixel on each line doesn't have previous pixel */
154         pixel_ant = frame_src[line_offset_src]<<16;
155         
156         pixel_dst = line_ant[0] = hqdn3d_lowpass_mul( line_ant[0], 
157                                                       pixel_ant, 
158                                                       vertical);
159         
160         frame_dst[line_offset_dst] = ((pixel_dst+0x10007FFF)>>16);
161         
162         /* The rest of the pixels in the line are normal */
163         for( x = 1; x < w; x++ )
164         {
165             unsigned int pixel_dst;
166
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 );
173
174             frame_dst[line_offset_dst+x]= ((pixel_dst+0x10007FFF)>>16);
175         }
176     }
177 }
178
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)
188 {
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);
194     
195     if( !frame_ant)
196     {
197         (*frame_ant_ptr) = frame_ant = malloc( w*h*sizeof(unsigned short) );
198         for( y = 0; y < h; y++ )
199         {
200             unsigned short* dst = &frame_ant[y*w];
201             unsigned char*  src = frame_src + y*w;
202             
203             for( x = 0; x < w; x++ )
204             {
205                 dst[x] = src[x] << 8;
206             }
207         }
208     }
209     
210     /* If no spatial coefficients, do temporal denoise only */
211     if( !horizontal[0] && !vertical[0] )
212     {
213         hqdn3d_denoise_temporal( frame_src, 
214                                  frame_dst, 
215                                  frame_ant,
216                                  w, h, 
217                                  temporal);
218         return;
219     }
220     
221     /* If no temporal coefficients, do spatial denoise only */
222     if( !temporal[0] )
223     {
224         hqdn3d_denoise_spatial( frame_src, 
225                                 frame_dst, 
226                                 line_ant,
227                                 w, h, 
228                                 horizontal, 
229                                 vertical);
230         return;
231     }
232     
233     /* First pixel has no left nor top neighbor. Only previous frame */
234     line_ant[0]  = pixel_ant = frame_src[0] << 16;
235     
236     pixel_dst    = hqdn3d_lowpass_mul( frame_ant[0]<<8, 
237                                        pixel_ant, 
238                                        temporal );
239     
240     frame_ant[0] = ((pixel_dst+0x1000007F)>>8);
241     frame_dst[0] = ((pixel_dst+0x10007FFF)>>16);
242     
243     /* First line has no top neighbor. Only left one for each pixel and last frame */
244     for( x = 1; x < w; x++ )
245     {
246         line_ant[x]  = pixel_ant = hqdn3d_lowpass_mul( pixel_ant, 
247                                                        frame_src[x]<<16, 
248                                                        horizontal);
249         
250         pixel_dst    = hqdn3d_lowpass_mul( frame_ant[x]<<8, 
251                                            pixel_ant, 
252                                            temporal);
253         
254         frame_ant[x] = ((pixel_dst+0x1000007F)>>8);
255         frame_dst[x] = ((pixel_dst+0x10007FFF)>>16);
256     }
257     
258     /* The rest of the lines in the frame are normal */
259     for( y = 1; y < h; y++ )
260     {
261         unsigned int pixel_ant;
262         unsigned short * line_prev = &frame_ant[y*w];
263         line_offset_src += w, line_offset_dst += w;
264         
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);
274
275         frame_dst[line_offset_dst] = ((pixel_dst+0x10007FFF)>>16);
276         
277         /* The rest of the pixels in the line are normal */
278         for( x = 1; x < w; x++ )
279         {
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);
290             
291             frame_dst[line_offset_dst+x] = ((pixel_dst+0x10007FFF)>>16);
292         }
293     }
294 }
295
296 hb_filter_private_t * hb_denoise_init( int pix_fmt, 
297                                        int width, 
298                                        int height,
299                                        char * settings )
300 {
301     if( pix_fmt != PIX_FMT_YUV420P )
302     {
303         return 0;
304     }
305     
306     hb_filter_private_t * pv = malloc( sizeof(struct hb_filter_private_s) );
307     
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;    
313   
314     double spatial_luma, temporal_luma, spatial_chroma, temporal_chroma;
315
316     if( settings )
317     {
318         switch( sscanf( settings, "%lf:%lf:%lf:%lf", 
319                         &spatial_luma, &spatial_chroma, 
320                         &temporal_luma, &temporal_chroma ) )
321         {                
322             case 0:
323                 spatial_luma    = HQDN3D_SPATIAL_LUMA_DEFAULT;
324                 
325                 spatial_chroma  = HQDN3D_SPATIAL_CHROMA_DEFAULT;
326                 
327                 temporal_luma   = HQDN3D_TEMPORAL_LUMA_DEFAULT;                
328                 
329                 temporal_chroma = temporal_luma * 
330                                   spatial_chroma / spatial_luma;
331                 break;
332                 
333             case 1:
334                 spatial_chroma = HQDN3D_SPATIAL_CHROMA_DEFAULT * 
335                                  spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
336                 
337                 temporal_luma   = HQDN3D_TEMPORAL_LUMA_DEFAULT * 
338                                   spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
339
340                 temporal_chroma = temporal_luma * 
341                                   spatial_chroma / spatial_luma;
342                 break;
343                 
344             case 2:
345                 temporal_luma   = HQDN3D_TEMPORAL_LUMA_DEFAULT * 
346                                   spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
347                 
348                 temporal_chroma = temporal_luma * 
349                                   spatial_chroma / spatial_luma;
350                 break;
351                 
352             case 3:
353                 temporal_chroma = temporal_luma * 
354                                   spatial_chroma / spatial_luma;
355                 break;
356         }
357     }
358     
359     pv->hqdn3d_line = malloc( width * sizeof(int) );
360
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 );
365     
366     int buf_size = 3 * width * height / 2;    
367     pv->buf_out = hb_buffer_init( buf_size );
368     
369     return pv;
370 }
371
372 void hb_denoise_close( hb_filter_private_t * pv )
373 {
374     if( !pv )
375     {
376         return;
377     }
378     
379         if( pv->hqdn3d_line )
380     {
381         free( pv->hqdn3d_line );
382         pv->hqdn3d_line = NULL;
383     }
384         if( pv->hqdn3d_frame[0] )
385     {
386         free( pv->hqdn3d_frame[0] );
387         pv->hqdn3d_frame[0] = NULL;
388     }
389         if( pv->hqdn3d_frame[1] )
390     {
391         free( pv->hqdn3d_frame[1] );
392         pv->hqdn3d_frame[1] = NULL;
393     }
394         if( pv->hqdn3d_frame[2] )
395     {
396         free( pv->hqdn3d_frame[2] );
397         pv->hqdn3d_frame[2] = NULL;
398     }
399     if( pv->buf_out )
400     {
401         hb_buffer_close( &pv->buf_out );
402     }
403     
404     free( pv );
405 }
406
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 )
413 {
414     if( !pv || 
415         pix_fmt != pv->pix_fmt ||
416         width != pv->width[0] ||
417         height != pv->height[0] )
418     {
419         return FILTER_FAILED;
420     }
421     
422     avpicture_fill( &pv->pic_in, buf_in->data, 
423                     pix_fmt, width, height );
424     
425     avpicture_fill( &pv->pic_out, pv->buf_out->data, 
426                     pix_fmt, width, height );
427     
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] );
437     
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] );
447     
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] );
457     
458     hb_buffer_copy_settings( pv->buf_out, buf_in );
459
460     *buf_out = pv->buf_out;
461     
462     return FILTER_OK;
463 }