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*16];
40         unsigned int *Line;
41         unsigned short *Frame[3];
42 };
43 
44 
45 /***************************************************************************/
46 
uninit(struct vf_instance * vf)47 static void uninit(struct vf_instance *vf)
48 {
49         free(vf->priv->Line);
50         free(vf->priv->Frame[0]);
51         free(vf->priv->Frame[1]);
52         free(vf->priv->Frame[2]);
53 
54         vf->priv->Line     = NULL;
55         vf->priv->Frame[0] = NULL;
56         vf->priv->Frame[1] = NULL;
57         vf->priv->Frame[2] = NULL;
58 }
59 
config(struct vf_instance * vf,int width,int height,int d_width,int d_height,unsigned int flags,unsigned int outfmt)60 static int config(struct vf_instance *vf,
61         int width, int height, int d_width, int d_height,
62         unsigned int flags, unsigned int outfmt){
63 
64         uninit(vf);
65         vf->priv->Line = malloc(width*sizeof(int));
66 
67         return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
68 }
69 
LowPassMul(unsigned int PrevMul,unsigned int CurrMul,int * Coef)70 static inline unsigned int LowPassMul(unsigned int PrevMul, unsigned int CurrMul, int* Coef){
71 //    int dMul= (PrevMul&0xFFFFFF)-(CurrMul&0xFFFFFF);
72     int dMul= PrevMul-CurrMul;
73     unsigned int d=((dMul+0x10007FF)>>12);
74     return CurrMul + Coef[d];
75 }
76 
deNoiseTemporal(unsigned char * Frame,unsigned char * FrameDest,unsigned short * FrameAnt,int W,int H,int sStride,int dStride,int * Temporal)77 static void deNoiseTemporal(
78                     unsigned char *Frame,        // mpi->planes[x]
79                     unsigned char *FrameDest,    // dmpi->planes[x]
80                     unsigned short *FrameAnt,
81                     int W, int H, int sStride, int dStride,
82                     int *Temporal)
83 {
84     long X, Y;
85     unsigned int PixelDst;
86 
87     for (Y = 0; Y < H; Y++){
88         for (X = 0; X < W; X++){
89             PixelDst = LowPassMul(FrameAnt[X]<<8, Frame[X]<<16, Temporal);
90             FrameAnt[X] = ((PixelDst+0x1000007F)>>8);
91             FrameDest[X]= ((PixelDst+0x10007FFF)>>16);
92         }
93         Frame += sStride;
94         FrameDest += dStride;
95         FrameAnt += W;
96     }
97 }
98 
deNoiseSpacial(unsigned char * Frame,unsigned char * FrameDest,unsigned int * LineAnt,int W,int H,int sStride,int dStride,int * Horizontal,int * Vertical)99 static void deNoiseSpacial(
100                     unsigned char *Frame,        // mpi->planes[x]
101                     unsigned char *FrameDest,    // dmpi->planes[x]
102                     unsigned int *LineAnt,       // vf->priv->Line (width bytes)
103                     int W, int H, int sStride, int dStride,
104                     int *Horizontal, int *Vertical)
105 {
106     long X, Y;
107     long sLineOffs = 0, dLineOffs = 0;
108     unsigned int PixelAnt;
109     unsigned int PixelDst;
110 
111     /* First pixel has no left nor top neighbor. */
112     PixelDst = LineAnt[0] = PixelAnt = Frame[0]<<16;
113     FrameDest[0]= ((PixelDst+0x10007FFF)>>16);
114 
115     /* First line has no top neighbor, only left. */
116     for (X = 1; X < W; X++){
117         PixelDst = LineAnt[X] = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal);
118         FrameDest[X]= ((PixelDst+0x10007FFF)>>16);
119     }
120 
121     for (Y = 1; Y < H; Y++){
122         unsigned int PixelAnt;
123         sLineOffs += sStride, dLineOffs += dStride;
124         /* First pixel on each line doesn't have previous pixel */
125         PixelAnt = Frame[sLineOffs]<<16;
126         PixelDst = LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical);
127         FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16);
128 
129         for (X = 1; X < W; X++){
130             unsigned int PixelDst;
131             /* The rest are normal */
132             PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal);
133             PixelDst = LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical);
134             FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16);
135         }
136     }
137 }
138 
deNoise(unsigned char * Frame,unsigned char * FrameDest,unsigned int * LineAnt,unsigned short ** FrameAntPtr,int W,int H,int sStride,int dStride,int * Horizontal,int * Vertical,int * Temporal)139 static void deNoise(unsigned char *Frame,        // mpi->planes[x]
140                     unsigned char *FrameDest,    // dmpi->planes[x]
141                     unsigned int *LineAnt,      // vf->priv->Line (width bytes)
142                     unsigned short **FrameAntPtr,
143                     int W, int H, int sStride, int dStride,
144                     int *Horizontal, int *Vertical, int *Temporal)
145 {
146     long X, Y;
147     long sLineOffs = 0, dLineOffs = 0;
148     unsigned int PixelAnt;
149     unsigned int PixelDst;
150     unsigned short* FrameAnt=(*FrameAntPtr);
151 
152     if(!FrameAnt){
153         (*FrameAntPtr)=FrameAnt=malloc(W*H*sizeof(unsigned short));
154         for (Y = 0; Y < H; Y++){
155             unsigned short* dst=&FrameAnt[Y*W];
156             unsigned char* src=Frame+Y*sStride;
157             for (X = 0; X < W; X++) dst[X]=src[X]<<8;
158         }
159     }
160 
161     if(!Horizontal[0] && !Vertical[0]){
162         deNoiseTemporal(Frame, FrameDest, FrameAnt,
163                         W, H, sStride, dStride, Temporal);
164         return;
165     }
166     if(!Temporal[0]){
167         deNoiseSpacial(Frame, FrameDest, LineAnt,
168                        W, H, sStride, dStride, Horizontal, Vertical);
169         return;
170     }
171 
172     /* First pixel has no left nor top neighbor. Only previous frame */
173     LineAnt[0] = PixelAnt = Frame[0]<<16;
174     PixelDst = LowPassMul(FrameAnt[0]<<8, PixelAnt, Temporal);
175     FrameAnt[0] = ((PixelDst+0x1000007F)>>8);
176     FrameDest[0]= ((PixelDst+0x10007FFF)>>16);
177 
178     /* First line has no top neighbor. Only left one for each pixel and
179      * last frame */
180     for (X = 1; X < W; X++){
181         LineAnt[X] = PixelAnt = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal);
182         PixelDst = LowPassMul(FrameAnt[X]<<8, PixelAnt, Temporal);
183         FrameAnt[X] = ((PixelDst+0x1000007F)>>8);
184         FrameDest[X]= ((PixelDst+0x10007FFF)>>16);
185     }
186 
187     for (Y = 1; Y < H; Y++){
188         unsigned int PixelAnt;
189         unsigned short* LinePrev=&FrameAnt[Y*W];
190         sLineOffs += sStride, dLineOffs += dStride;
191         /* First pixel on each line doesn't have previous pixel */
192         PixelAnt = Frame[sLineOffs]<<16;
193         LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical);
194         PixelDst = LowPassMul(LinePrev[0]<<8, LineAnt[0], Temporal);
195         LinePrev[0] = ((PixelDst+0x1000007F)>>8);
196         FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16);
197 
198         for (X = 1; X < W; X++){
199             unsigned int PixelDst;
200             /* The rest are normal */
201             PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal);
202             LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical);
203             PixelDst = LowPassMul(LinePrev[X]<<8, LineAnt[X], Temporal);
204             LinePrev[X] = ((PixelDst+0x1000007F)>>8);
205             FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16);
206         }
207     }
208 }
209 
210 
put_image(struct vf_instance * vf,mp_image_t * mpi,double pts,double endpts)211 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts, double endpts){
212         int cw= mpi->w >> mpi->chroma_x_shift;
213         int ch= mpi->h >> mpi->chroma_y_shift;
214         int W = mpi->w, H = mpi->h;
215 
216         mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt,
217                 MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
218                 mpi->w,mpi->h);
219 
220         if(!dmpi) return 0;
221 
222         deNoise(mpi->planes[0], dmpi->planes[0],
223                 vf->priv->Line, &vf->priv->Frame[0], W, H,
224                 mpi->stride[0], dmpi->stride[0],
225                 vf->priv->Coefs[0],
226                 vf->priv->Coefs[0],
227                 vf->priv->Coefs[1]);
228         deNoise(mpi->planes[1], dmpi->planes[1],
229                 vf->priv->Line, &vf->priv->Frame[1], cw, ch,
230                 mpi->stride[1], dmpi->stride[1],
231                 vf->priv->Coefs[2],
232                 vf->priv->Coefs[2],
233                 vf->priv->Coefs[3]);
234         deNoise(mpi->planes[2], dmpi->planes[2],
235                 vf->priv->Line, &vf->priv->Frame[2], cw, ch,
236                 mpi->stride[2], dmpi->stride[2],
237                 vf->priv->Coefs[2],
238                 vf->priv->Coefs[2],
239                 vf->priv->Coefs[3]);
240 
241         return vf_next_put_image(vf, dmpi, pts, endpts);
242 }
243 
244 //===========================================================================//
245 
query_format(struct vf_instance * vf,unsigned int fmt)246 static int query_format(struct vf_instance *vf, unsigned int fmt){
247         switch(fmt)
248         {
249         case IMGFMT_YV12:
250         case IMGFMT_I420:
251         case IMGFMT_IYUV:
252         case IMGFMT_YVU9:
253         case IMGFMT_444P:
254         case IMGFMT_422P:
255         case IMGFMT_411P:
256                 return vf_next_query_format(vf, fmt);
257         }
258         return 0;
259 }
260 
261 
262 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
263 
PrecalcCoefs(int * Ct,double Dist25)264 static void PrecalcCoefs(int *Ct, double Dist25)
265 {
266     int i;
267     double Gamma, Simil, C;
268 
269     Gamma = log(0.25) / log(1.0 - Dist25/255.0 - 0.00001);
270 
271     for (i = -255*16; i <= 255*16; i++)
272     {
273         Simil = 1.0 - ABS(i) / (16*255.0);
274         C = pow(Simil, Gamma) * 65536.0 * (double)i / 16.0;
275         Ct[16*256+i] = (C<0) ? (C-0.5) : (C+0.5);
276     }
277 
278     Ct[0] = (Dist25 != 0);
279 }
280 
281 
vf_open(vf_instance_t * vf,char * args)282 static int vf_open(vf_instance_t *vf, char *args){
283         double LumSpac, LumTmp, ChromSpac, ChromTmp;
284         double Param1, Param2, Param3, Param4;
285 
286         vf->config=config;
287         vf->put_image=put_image;
288         vf->query_format=query_format;
289         vf->uninit=uninit;
290         vf->priv=malloc(sizeof(struct vf_priv_s));
291         memset(vf->priv, 0, sizeof(struct vf_priv_s));
292 
293         if (args)
294         {
295             switch(sscanf(args, "%lf:%lf:%lf:%lf",
296                           &Param1, &Param2, &Param3, &Param4
297                          ))
298             {
299             case 0:
300                 LumSpac = PARAM1_DEFAULT;
301                 LumTmp = PARAM3_DEFAULT;
302 
303                 ChromSpac = PARAM2_DEFAULT;
304                 ChromTmp = LumTmp * ChromSpac / LumSpac;
305                 break;
306 
307             case 1:
308                 LumSpac = Param1;
309                 LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT;
310 
311                 ChromSpac = PARAM2_DEFAULT * Param1 / PARAM1_DEFAULT;
312                 ChromTmp = LumTmp * ChromSpac / LumSpac;
313                 break;
314 
315             case 2:
316                 LumSpac = Param1;
317                 LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT;
318 
319                 ChromSpac = Param2;
320                 ChromTmp = LumTmp * ChromSpac / LumSpac;
321                 break;
322 
323             case 3:
324                 LumSpac = Param1;
325                 LumTmp = Param3;
326 
327                 ChromSpac = Param2;
328                 ChromTmp = LumTmp * ChromSpac / LumSpac;
329                 break;
330 
331             case 4:
332                 LumSpac = Param1;
333                 LumTmp = Param3;
334 
335                 ChromSpac = Param2;
336                 ChromTmp = Param4;
337                 break;
338 
339             default:
340                 LumSpac = PARAM1_DEFAULT;
341                 LumTmp = PARAM3_DEFAULT;
342 
343                 ChromSpac = PARAM2_DEFAULT;
344                 ChromTmp = LumTmp * ChromSpac / LumSpac;
345             }
346         }
347         else
348         {
349             LumSpac = PARAM1_DEFAULT;
350             LumTmp = PARAM3_DEFAULT;
351 
352             ChromSpac = PARAM2_DEFAULT;
353             ChromTmp = LumTmp * ChromSpac / LumSpac;
354         }
355 
356         PrecalcCoefs(vf->priv->Coefs[0], LumSpac);
357         PrecalcCoefs(vf->priv->Coefs[1], LumTmp);
358         PrecalcCoefs(vf->priv->Coefs[2], ChromSpac);
359         PrecalcCoefs(vf->priv->Coefs[3], ChromTmp);
360 
361         return 1;
362 }
363 
364 const vf_info_t vf_info_hqdn3d = {
365     "High Quality 3D Denoiser",
366     "hqdn3d",
367     "Daniel Moreno & A'rpi",
368     "",
369     vf_open,
370     NULL
371 };
372 
373 //===========================================================================//
374