2 * Copyright (C) 2003 Daniel Moreno <comac@comac.darktech.org>
4 * This file is part of MPlayer.
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.
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.
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.
28 #include "img_format.h"
32 #define PARAM1_DEFAULT 4.0
33 #define PARAM2_DEFAULT 3.0
34 #define PARAM3_DEFAULT 6.0
36 //===========================================================================//
41 unsigned short *Frame
[3];
45 /***************************************************************************/
47 static void uninit(struct vf_instance
*vf
)
50 free(vf
->priv
->Frame
[0]);
51 free(vf
->priv
->Frame
[1]);
52 free(vf
->priv
->Frame
[2]);
54 vf
->priv
->Line
= NULL
;
55 vf
->priv
->Frame
[0] = NULL
;
56 vf
->priv
->Frame
[1] = NULL
;
57 vf
->priv
->Frame
[2] = NULL
;
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
){
65 vf
->priv
->Line
= malloc(width
*sizeof(int));
67 return vf_next_config(vf
,width
,height
,d_width
,d_height
,flags
,outfmt
);
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
];
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
,
85 unsigned int PixelDst
;
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);
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
)
107 long sLineOffs
= 0, dLineOffs
= 0;
108 unsigned int PixelAnt
;
109 unsigned int PixelDst
;
111 /* First pixel has no left nor top neighbor. */
112 PixelDst
= LineAnt
[0] = PixelAnt
= Frame
[0]<<16;
113 FrameDest
[0]= ((PixelDst
+0x10007FFF)>>16);
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);
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);
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);
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
)
147 long sLineOffs
= 0, dLineOffs
= 0;
148 unsigned int PixelAnt
;
149 unsigned int PixelDst
;
150 unsigned short* FrameAnt
=(*FrameAntPtr
);
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;
161 if(!Horizontal
[0] && !Vertical
[0]){
162 deNoiseTemporal(Frame
, FrameDest
, FrameAnt
,
163 W
, H
, sStride
, dStride
, Temporal
);
167 deNoiseSpacial(Frame
, FrameDest
, LineAnt
,
168 W
, H
, sStride
, dStride
, Horizontal
, Vertical
);
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);
178 /* First line has no top neighbor. Only left one for each pixel and
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);
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);
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);
211 static int put_image(struct vf_instance
*vf
, mp_image_t
*mpi
, double pts
){
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
;
216 mp_image_t
*dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
217 MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
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],
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],
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],
241 return vf_next_put_image(vf
,dmpi
, pts
);
244 //===========================================================================//
246 static int query_format(struct vf_instance
*vf
, unsigned int fmt
){
256 return vf_next_query_format(vf
, fmt
);
262 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
264 static void PrecalcCoefs(int *Ct
, double Dist25
)
267 double Gamma
, Simil
, C
;
269 Gamma
= log(0.25) / log(1.0 - Dist25
/255.0 - 0.00001);
271 for (i
= -255*16; i
<= 255*16; i
++)
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);
278 Ct
[0] = (Dist25
!= 0);
282 static int vf_open(vf_instance_t
*vf
, char *args
){
283 double LumSpac
, LumTmp
, ChromSpac
, ChromTmp
;
284 double Param1
, Param2
, Param3
, Param4
;
287 vf
->put_image
=put_image
;
288 vf
->query_format
=query_format
;
290 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
291 memset(vf
->priv
, 0, sizeof(struct vf_priv_s
));
295 switch(sscanf(args
, "%lf:%lf:%lf:%lf",
296 &Param1
, &Param2
, &Param3
, &Param4
300 LumSpac
= PARAM1_DEFAULT
;
301 LumTmp
= PARAM3_DEFAULT
;
303 ChromSpac
= PARAM2_DEFAULT
;
304 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
309 LumTmp
= PARAM3_DEFAULT
* Param1
/ PARAM1_DEFAULT
;
311 ChromSpac
= PARAM2_DEFAULT
* Param1
/ PARAM1_DEFAULT
;
312 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
317 LumTmp
= PARAM3_DEFAULT
* Param1
/ PARAM1_DEFAULT
;
320 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
328 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
340 LumSpac
= PARAM1_DEFAULT
;
341 LumTmp
= PARAM3_DEFAULT
;
343 ChromSpac
= PARAM2_DEFAULT
;
344 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
349 LumSpac
= PARAM1_DEFAULT
;
350 LumTmp
= PARAM3_DEFAULT
;
352 ChromSpac
= PARAM2_DEFAULT
;
353 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
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
);
364 const vf_info_t vf_info_hqdn3d
= {
365 "High Quality 3D Denoiser",
367 "Daniel Moreno & A'rpi",
373 //===========================================================================//