Git init
[framework/multimedia/ffmpeg.git] / libavfilter / libmpcodecs / vf_denoise3d.c
1 /*
2  * Copyright (C) 2003 Daniel Moreno <comac@comac.darktech.org>
3  *
4  * This file is part of MPlayer.
5  *
6  * MPlayer is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * MPlayer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <math.h>
26
27 #include "mp_msg.h"
28 #include "img_format.h"
29 #include "mp_image.h"
30 #include "vf.h"
31
32 #define PARAM1_DEFAULT 4.0
33 #define PARAM2_DEFAULT 3.0
34 #define PARAM3_DEFAULT 6.0
35
36 //===========================================================================//
37
38 struct vf_priv_s {
39         int Coefs[4][512];
40         unsigned char *Line;
41         mp_image_t *pmpi;
42 };
43
44
45 /***************************************************************************/
46
47
48 static int config(struct vf_instance *vf,
49         int width, int height, int d_width, int d_height,
50         unsigned int flags, unsigned int outfmt){
51
52         free(vf->priv->Line);
53         vf->priv->Line = malloc(width);
54         vf->priv->pmpi=NULL;
55 //        vf->default_caps &= !VFCAP_ACCEPT_STRIDE;
56
57         return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
58 }
59
60
61 static void uninit(struct vf_instance *vf)
62 {
63     free(vf->priv->Line);
64 }
65
66 #define LowPass(Prev, Curr, Coef) (Curr + Coef[Prev - Curr])
67
68 static void deNoise(unsigned char *Frame,        // mpi->planes[x]
69                     unsigned char *FramePrev,    // pmpi->planes[x]
70                     unsigned char *FrameDest,    // dmpi->planes[x]
71                     unsigned char *LineAnt,      // vf->priv->Line (width bytes)
72                     int W, int H, int sStride, int pStride, int dStride,
73                     int *Horizontal, int *Vertical, int *Temporal)
74 {
75     int X, Y;
76     int sLineOffs = 0, pLineOffs = 0, dLineOffs = 0;
77     unsigned char PixelAnt;
78
79     /* First pixel has no left nor top neighbor. Only previous frame */
80     LineAnt[0] = PixelAnt = Frame[0];
81     FrameDest[0] = LowPass(FramePrev[0], LineAnt[0], Temporal);
82
83     /* Fist line has no top neighbor. Only left one for each pixel and
84      * last frame */
85     for (X = 1; X < W; X++)
86     {
87         PixelAnt = LowPass(PixelAnt, Frame[X], Horizontal);
88         LineAnt[X] = PixelAnt;
89         FrameDest[X] = LowPass(FramePrev[X], LineAnt[X], Temporal);
90     }
91
92     for (Y = 1; Y < H; Y++)
93     {
94         sLineOffs += sStride, pLineOffs += pStride, dLineOffs += dStride;
95         /* First pixel on each line doesn't have previous pixel */
96         PixelAnt = Frame[sLineOffs];
97         LineAnt[0] = LowPass(LineAnt[0], PixelAnt, Vertical);
98         FrameDest[dLineOffs] = LowPass(FramePrev[pLineOffs], LineAnt[0], Temporal);
99
100         for (X = 1; X < W; X++)
101         {
102             /* The rest are normal */
103             PixelAnt = LowPass(PixelAnt, Frame[sLineOffs+X], Horizontal);
104             LineAnt[X] = LowPass(LineAnt[X], PixelAnt, Vertical);
105             FrameDest[dLineOffs+X] = LowPass(FramePrev[pLineOffs+X], LineAnt[X], Temporal);
106         }
107     }
108 }
109
110
111
112 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
113         int cw= mpi->w >> mpi->chroma_x_shift;
114         int ch= mpi->h >> mpi->chroma_y_shift;
115         int W = mpi->w, H = mpi->h;
116
117         mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt,
118                 MP_IMGTYPE_IP, MP_IMGFLAG_ACCEPT_STRIDE |
119                 MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE,
120                 mpi->w,mpi->h);
121
122         if(!dmpi) return 0;
123         if (!vf->priv->pmpi) vf->priv->pmpi=mpi;
124
125         deNoise(mpi->planes[0], vf->priv->pmpi->planes[0], dmpi->planes[0],
126                 vf->priv->Line, W, H,
127                 mpi->stride[0], vf->priv->pmpi->stride[0], dmpi->stride[0],
128                 vf->priv->Coefs[0] + 256,
129                 vf->priv->Coefs[0] + 256,
130                 vf->priv->Coefs[1] + 256);
131         deNoise(mpi->planes[1], vf->priv->pmpi->planes[1], dmpi->planes[1],
132                 vf->priv->Line, cw, ch,
133                 mpi->stride[1], vf->priv->pmpi->stride[1], dmpi->stride[1],
134                 vf->priv->Coefs[2] + 256,
135                 vf->priv->Coefs[2] + 256,
136                 vf->priv->Coefs[3] + 256);
137         deNoise(mpi->planes[2], vf->priv->pmpi->planes[2], dmpi->planes[2],
138                 vf->priv->Line, cw, ch,
139                 mpi->stride[2], vf->priv->pmpi->stride[2], dmpi->stride[2],
140                 vf->priv->Coefs[2] + 256,
141                 vf->priv->Coefs[2] + 256,
142                 vf->priv->Coefs[3] + 256);
143
144         vf->priv->pmpi=dmpi; // save reference image
145         return vf_next_put_image(vf,dmpi, pts);
146 }
147
148 //===========================================================================//
149
150 static int query_format(struct vf_instance *vf, unsigned int fmt){
151         switch(fmt)
152         {
153         case IMGFMT_YV12:
154         case IMGFMT_I420:
155         case IMGFMT_IYUV:
156         case IMGFMT_YVU9:
157         case IMGFMT_444P:
158         case IMGFMT_422P:
159         case IMGFMT_411P:
160                 return vf_next_query_format(vf, fmt);
161         }
162         return 0;
163 }
164
165
166 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
167
168 static void PrecalcCoefs(int *Ct, double Dist25)
169 {
170     int i;
171     double Gamma, Simil, C;
172
173     Gamma = log(0.25) / log(1.0 - Dist25/255.0);
174
175     for (i = -256; i <= 255; i++)
176     {
177         Simil = 1.0 - ABS(i) / 255.0;
178 //        Ct[256+i] = lround(pow(Simil, Gamma) * (double)i);
179         C = pow(Simil, Gamma) * (double)i;
180         Ct[256+i] = (C<0) ? (C-0.5) : (C+0.5);
181     }
182 }
183
184
185 static int vf_open(vf_instance_t *vf, char *args){
186         double LumSpac, LumTmp, ChromSpac, ChromTmp;
187         double Param1, Param2, Param3;
188
189         vf->config=config;
190         vf->put_image=put_image;
191         vf->query_format=query_format;
192         vf->uninit=uninit;
193         vf->priv=malloc(sizeof(struct vf_priv_s));
194         memset(vf->priv, 0, sizeof(struct vf_priv_s));
195
196         if (args)
197         {
198             switch(sscanf(args, "%lf:%lf:%lf",
199                           &Param1, &Param2, &Param3
200                          ))
201             {
202             case 0:
203                 LumSpac = PARAM1_DEFAULT;
204                 LumTmp = PARAM3_DEFAULT;
205
206                 ChromSpac = PARAM2_DEFAULT;
207                 ChromTmp = LumTmp * ChromSpac / LumSpac;
208                 break;
209
210             case 1:
211                 LumSpac = Param1;
212                 LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT;
213
214                 ChromSpac = PARAM2_DEFAULT * Param1 / PARAM1_DEFAULT;
215                 ChromTmp = LumTmp * ChromSpac / LumSpac;
216                 break;
217
218             case 2:
219                 LumSpac = Param1;
220                 LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT;
221
222                 ChromSpac = Param2;
223                 ChromTmp = LumTmp * ChromSpac / LumSpac;
224                 break;
225
226             case 3:
227                 LumSpac = Param1;
228                 LumTmp = Param3;
229
230                 ChromSpac = Param2;
231                 ChromTmp = LumTmp * ChromSpac / LumSpac;
232                 break;
233
234             default:
235                 LumSpac = PARAM1_DEFAULT;
236                 LumTmp = PARAM3_DEFAULT;
237
238                 ChromSpac = PARAM2_DEFAULT;
239                 ChromTmp = LumTmp * ChromSpac / LumSpac;
240             }
241         }
242         else
243         {
244             LumSpac = PARAM1_DEFAULT;
245             LumTmp = PARAM3_DEFAULT;
246
247             ChromSpac = PARAM2_DEFAULT;
248             ChromTmp = LumTmp * ChromSpac / LumSpac;
249         }
250
251         PrecalcCoefs(vf->priv->Coefs[0], LumSpac);
252         PrecalcCoefs(vf->priv->Coefs[1], LumTmp);
253         PrecalcCoefs(vf->priv->Coefs[2], ChromSpac);
254         PrecalcCoefs(vf->priv->Coefs[3], ChromTmp);
255
256         return 1;
257 }
258
259 const vf_info_t vf_info_denoise3d = {
260     "3D Denoiser (variable lowpass filter)",
261     "denoise3d",
262     "Daniel Moreno",
263     "",
264     vf_open,
265     NULL
266 };
267
268 //===========================================================================//