OSDN Git Service

fix CLI version reader, and translate some x264 panel's tooltip
[handbrake-jp/handbrake-jp.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 "hbffmpeg.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     /*
309      * Clear the memory to avoid freeing uninitialised memory later.
310      */
311     memset( pv, 0, sizeof( struct hb_filter_private_s ) );
312
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;
318
319     double spatial_luma, temporal_luma, spatial_chroma, temporal_chroma;
320
321     if( settings )
322     {
323         switch( sscanf( settings, "%lf:%lf:%lf:%lf",
324                         &spatial_luma, &spatial_chroma,
325                         &temporal_luma, &temporal_chroma ) )
326         {
327             case 0:
328                 spatial_luma    = HQDN3D_SPATIAL_LUMA_DEFAULT;
329
330                 spatial_chroma  = HQDN3D_SPATIAL_CHROMA_DEFAULT;
331
332                 temporal_luma   = HQDN3D_TEMPORAL_LUMA_DEFAULT;
333
334                 temporal_chroma = temporal_luma *
335                                   spatial_chroma / spatial_luma;
336                 break;
337
338             case 1:
339                 spatial_chroma = HQDN3D_SPATIAL_CHROMA_DEFAULT *
340                                  spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
341
342                 temporal_luma   = HQDN3D_TEMPORAL_LUMA_DEFAULT *
343                                   spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
344
345                 temporal_chroma = temporal_luma *
346                                   spatial_chroma / spatial_luma;
347                 break;
348
349             case 2:
350                 temporal_luma   = HQDN3D_TEMPORAL_LUMA_DEFAULT *
351                                   spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT;
352
353                 temporal_chroma = temporal_luma *
354                                   spatial_chroma / spatial_luma;
355                 break;
356
357             case 3:
358                 temporal_chroma = temporal_luma *
359                                   spatial_chroma / spatial_luma;
360                 break;
361         }
362     }
363
364     pv->hqdn3d_line = malloc( width * sizeof(int) );
365
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 );
370
371     pv->buf_out = hb_video_buffer_init( width, height );
372
373     return pv;
374 }
375
376 void hb_denoise_close( hb_filter_private_t * pv )
377 {
378     if( !pv )
379     {
380         return;
381     }
382
383         if( pv->hqdn3d_line )
384     {
385         free( pv->hqdn3d_line );
386         pv->hqdn3d_line = NULL;
387     }
388         if( pv->hqdn3d_frame[0] )
389     {
390         free( pv->hqdn3d_frame[0] );
391         pv->hqdn3d_frame[0] = NULL;
392     }
393         if( pv->hqdn3d_frame[1] )
394     {
395         free( pv->hqdn3d_frame[1] );
396         pv->hqdn3d_frame[1] = NULL;
397     }
398         if( pv->hqdn3d_frame[2] )
399     {
400         free( pv->hqdn3d_frame[2] );
401         pv->hqdn3d_frame[2] = NULL;
402     }
403     if( pv->buf_out )
404     {
405         hb_buffer_close( &pv->buf_out );
406     }
407
408     free( pv );
409 }
410
411 int hb_denoise_work( const hb_buffer_t * buf_in,
412                      hb_buffer_t ** buf_out,
413                      int pix_fmt,
414                      int width,
415                      int height,
416                      hb_filter_private_t * pv )
417 {
418     if( !pv ||
419         pix_fmt != pv->pix_fmt ||
420         width != pv->width[0] ||
421         height != pv->height[0] )
422     {
423         return FILTER_FAILED;
424     }
425
426     avpicture_fill( &pv->pic_in, buf_in->data,
427                     pix_fmt, width, height );
428
429     avpicture_fill( &pv->pic_out, pv->buf_out->data,
430                     pix_fmt, width, height );
431
432     hqdn3d_denoise( pv->pic_in.data[0],
433                     pv->pic_out.data[0],
434                     pv->hqdn3d_line,
435                     &pv->hqdn3d_frame[0],
436                     pv->width[0],
437                     pv->height[0],
438                     pv->hqdn3d_coef[0],
439                     pv->hqdn3d_coef[0],
440                     pv->hqdn3d_coef[1] );
441
442     hqdn3d_denoise( pv->pic_in.data[1],
443                     pv->pic_out.data[1],
444                     pv->hqdn3d_line,
445                     &pv->hqdn3d_frame[1],
446                     pv->width[1],
447                     pv->height[1],
448                     pv->hqdn3d_coef[2],
449                     pv->hqdn3d_coef[2],
450                     pv->hqdn3d_coef[3] );
451
452     hqdn3d_denoise( pv->pic_in.data[2],
453                     pv->pic_out.data[2],
454                     pv->hqdn3d_line,
455                     &pv->hqdn3d_frame[2],
456                     pv->width[2],
457                     pv->height[2],
458                     pv->hqdn3d_coef[2],
459                     pv->hqdn3d_coef[2],
460                     pv->hqdn3d_coef[3] );
461
462     hb_buffer_copy_settings( pv->buf_out, buf_in );
463
464     *buf_out = pv->buf_out;
465
466     return FILTER_OK;
467 }