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
){
48 if(vf
->priv
->Line
){free(vf
->priv
->Line
);vf
->priv
->Line
=NULL
;}
49 if(vf
->priv
->Frame
[0]){free(vf
->priv
->Frame
[0]);vf
->priv
->Frame
[0]=NULL
;}
50 if(vf
->priv
->Frame
[1]){free(vf
->priv
->Frame
[1]);vf
->priv
->Frame
[1]=NULL
;}
51 if(vf
->priv
->Frame
[2]){free(vf
->priv
->Frame
[2]);vf
->priv
->Frame
[2]=NULL
;}
54 static int config(struct vf_instance
* vf
,
55 int width
, int height
, int d_width
, int d_height
,
56 unsigned int flags
, unsigned int outfmt
){
59 vf
->priv
->Line
= malloc(width
*sizeof(int));
61 return vf_next_config(vf
,width
,height
,d_width
,d_height
,flags
,outfmt
);
64 static inline unsigned int LowPassMul(unsigned int PrevMul
, unsigned int CurrMul
, int* Coef
){
65 // int dMul= (PrevMul&0xFFFFFF)-(CurrMul&0xFFFFFF);
66 int dMul
= PrevMul
-CurrMul
;
67 unsigned int d
=((dMul
+0x10007FF)>>12);
68 return CurrMul
+ Coef
[d
];
71 static void deNoiseTemporal(
72 unsigned char *Frame
, // mpi->planes[x]
73 unsigned char *FrameDest
, // dmpi->planes[x]
74 unsigned short *FrameAnt
,
75 int W
, int H
, int sStride
, int dStride
,
79 unsigned int PixelDst
;
81 for (Y
= 0; Y
< H
; Y
++){
82 for (X
= 0; X
< W
; X
++){
83 PixelDst
= LowPassMul(FrameAnt
[X
]<<8, Frame
[X
]<<16, Temporal
);
84 FrameAnt
[X
] = ((PixelDst
+0x1000007F)>>8);
85 FrameDest
[X
]= ((PixelDst
+0x10007FFF)>>16);
93 static void deNoiseSpacial(
94 unsigned char *Frame
, // mpi->planes[x]
95 unsigned char *FrameDest
, // dmpi->planes[x]
96 unsigned int *LineAnt
, // vf->priv->Line (width bytes)
97 int W
, int H
, int sStride
, int dStride
,
98 int *Horizontal
, int *Vertical
)
101 long sLineOffs
= 0, dLineOffs
= 0;
102 unsigned int PixelAnt
;
103 unsigned int PixelDst
;
105 /* First pixel has no left nor top neighbor. */
106 PixelDst
= LineAnt
[0] = PixelAnt
= Frame
[0]<<16;
107 FrameDest
[0]= ((PixelDst
+0x10007FFF)>>16);
109 /* First line has no top neighbor, only left. */
110 for (X
= 1; X
< W
; X
++){
111 PixelDst
= LineAnt
[X
] = LowPassMul(PixelAnt
, Frame
[X
]<<16, Horizontal
);
112 FrameDest
[X
]= ((PixelDst
+0x10007FFF)>>16);
115 for (Y
= 1; Y
< H
; Y
++){
116 unsigned int PixelAnt
;
117 sLineOffs
+= sStride
, dLineOffs
+= dStride
;
118 /* First pixel on each line doesn't have previous pixel */
119 PixelAnt
= Frame
[sLineOffs
]<<16;
120 PixelDst
= LineAnt
[0] = LowPassMul(LineAnt
[0], PixelAnt
, Vertical
);
121 FrameDest
[dLineOffs
]= ((PixelDst
+0x10007FFF)>>16);
123 for (X
= 1; X
< W
; X
++){
124 unsigned int PixelDst
;
125 /* The rest are normal */
126 PixelAnt
= LowPassMul(PixelAnt
, Frame
[sLineOffs
+X
]<<16, Horizontal
);
127 PixelDst
= LineAnt
[X
] = LowPassMul(LineAnt
[X
], PixelAnt
, Vertical
);
128 FrameDest
[dLineOffs
+X
]= ((PixelDst
+0x10007FFF)>>16);
133 static void deNoise(unsigned char *Frame
, // mpi->planes[x]
134 unsigned char *FrameDest
, // dmpi->planes[x]
135 unsigned int *LineAnt
, // vf->priv->Line (width bytes)
136 unsigned short **FrameAntPtr
,
137 int W
, int H
, int sStride
, int dStride
,
138 int *Horizontal
, int *Vertical
, int *Temporal
)
141 long sLineOffs
= 0, dLineOffs
= 0;
142 unsigned int PixelAnt
;
143 unsigned int PixelDst
;
144 unsigned short* FrameAnt
=(*FrameAntPtr
);
147 (*FrameAntPtr
)=FrameAnt
=malloc(W
*H
*sizeof(unsigned short));
148 for (Y
= 0; Y
< H
; Y
++){
149 unsigned short* dst
=&FrameAnt
[Y
*W
];
150 unsigned char* src
=Frame
+Y
*sStride
;
151 for (X
= 0; X
< W
; X
++) dst
[X
]=src
[X
]<<8;
155 if(!Horizontal
[0] && !Vertical
[0]){
156 deNoiseTemporal(Frame
, FrameDest
, FrameAnt
,
157 W
, H
, sStride
, dStride
, Temporal
);
161 deNoiseSpacial(Frame
, FrameDest
, LineAnt
,
162 W
, H
, sStride
, dStride
, Horizontal
, Vertical
);
166 /* First pixel has no left nor top neighbor. Only previous frame */
167 LineAnt
[0] = PixelAnt
= Frame
[0]<<16;
168 PixelDst
= LowPassMul(FrameAnt
[0]<<8, PixelAnt
, Temporal
);
169 FrameAnt
[0] = ((PixelDst
+0x1000007F)>>8);
170 FrameDest
[0]= ((PixelDst
+0x10007FFF)>>16);
172 /* First line has no top neighbor. Only left one for each pixel and
174 for (X
= 1; X
< W
; X
++){
175 LineAnt
[X
] = PixelAnt
= LowPassMul(PixelAnt
, Frame
[X
]<<16, Horizontal
);
176 PixelDst
= LowPassMul(FrameAnt
[X
]<<8, PixelAnt
, Temporal
);
177 FrameAnt
[X
] = ((PixelDst
+0x1000007F)>>8);
178 FrameDest
[X
]= ((PixelDst
+0x10007FFF)>>16);
181 for (Y
= 1; Y
< H
; Y
++){
182 unsigned int PixelAnt
;
183 unsigned short* LinePrev
=&FrameAnt
[Y
*W
];
184 sLineOffs
+= sStride
, dLineOffs
+= dStride
;
185 /* First pixel on each line doesn't have previous pixel */
186 PixelAnt
= Frame
[sLineOffs
]<<16;
187 LineAnt
[0] = LowPassMul(LineAnt
[0], PixelAnt
, Vertical
);
188 PixelDst
= LowPassMul(LinePrev
[0]<<8, LineAnt
[0], Temporal
);
189 LinePrev
[0] = ((PixelDst
+0x1000007F)>>8);
190 FrameDest
[dLineOffs
]= ((PixelDst
+0x10007FFF)>>16);
192 for (X
= 1; X
< W
; X
++){
193 unsigned int PixelDst
;
194 /* The rest are normal */
195 PixelAnt
= LowPassMul(PixelAnt
, Frame
[sLineOffs
+X
]<<16, Horizontal
);
196 LineAnt
[X
] = LowPassMul(LineAnt
[X
], PixelAnt
, Vertical
);
197 PixelDst
= LowPassMul(LinePrev
[X
]<<8, LineAnt
[X
], Temporal
);
198 LinePrev
[X
] = ((PixelDst
+0x1000007F)>>8);
199 FrameDest
[dLineOffs
+X
]= ((PixelDst
+0x10007FFF)>>16);
205 static int put_image(struct vf_instance
* vf
, mp_image_t
*mpi
, double pts
){
206 int cw
= mpi
->w
>> mpi
->chroma_x_shift
;
207 int ch
= mpi
->h
>> mpi
->chroma_y_shift
;
208 int W
= mpi
->w
, H
= mpi
->h
;
210 mp_image_t
*dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
211 MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
216 deNoise(mpi
->planes
[0], dmpi
->planes
[0],
217 vf
->priv
->Line
, &vf
->priv
->Frame
[0], W
, H
,
218 mpi
->stride
[0], dmpi
->stride
[0],
222 deNoise(mpi
->planes
[1], dmpi
->planes
[1],
223 vf
->priv
->Line
, &vf
->priv
->Frame
[1], cw
, ch
,
224 mpi
->stride
[1], dmpi
->stride
[1],
228 deNoise(mpi
->planes
[2], dmpi
->planes
[2],
229 vf
->priv
->Line
, &vf
->priv
->Frame
[2], cw
, ch
,
230 mpi
->stride
[2], dmpi
->stride
[2],
235 return vf_next_put_image(vf
,dmpi
, pts
);
238 //===========================================================================//
240 static int query_format(struct vf_instance
* vf
, unsigned int fmt
){
250 return vf_next_query_format(vf
, fmt
);
256 #define ABS(A) ( (A) > 0 ? (A) : -(A) )
258 static void PrecalcCoefs(int *Ct
, double Dist25
)
261 double Gamma
, Simil
, C
;
263 Gamma
= log(0.25) / log(1.0 - Dist25
/255.0 - 0.00001);
265 for (i
= -255*16; i
<= 255*16; i
++)
267 Simil
= 1.0 - ABS(i
) / (16*255.0);
268 C
= pow(Simil
, Gamma
) * 65536.0 * (double)i
/ 16.0;
269 Ct
[16*256+i
] = (C
<0) ? (C
-0.5) : (C
+0.5);
272 Ct
[0] = (Dist25
!= 0);
276 static int open(vf_instance_t
*vf
, char* args
){
277 double LumSpac
, LumTmp
, ChromSpac
, ChromTmp
;
278 double Param1
, Param2
, Param3
, Param4
;
281 vf
->put_image
=put_image
;
282 vf
->query_format
=query_format
;
284 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
285 memset(vf
->priv
, 0, sizeof(struct vf_priv_s
));
289 switch(sscanf(args
, "%lf:%lf:%lf:%lf",
290 &Param1
, &Param2
, &Param3
, &Param4
294 LumSpac
= PARAM1_DEFAULT
;
295 LumTmp
= PARAM3_DEFAULT
;
297 ChromSpac
= PARAM2_DEFAULT
;
298 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
303 LumTmp
= PARAM3_DEFAULT
* Param1
/ PARAM1_DEFAULT
;
305 ChromSpac
= PARAM2_DEFAULT
* Param1
/ PARAM1_DEFAULT
;
306 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
311 LumTmp
= PARAM3_DEFAULT
* Param1
/ PARAM1_DEFAULT
;
314 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
322 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
334 LumSpac
= PARAM1_DEFAULT
;
335 LumTmp
= PARAM3_DEFAULT
;
337 ChromSpac
= PARAM2_DEFAULT
;
338 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
343 LumSpac
= PARAM1_DEFAULT
;
344 LumTmp
= PARAM3_DEFAULT
;
346 ChromSpac
= PARAM2_DEFAULT
;
347 ChromTmp
= LumTmp
* ChromSpac
/ LumSpac
;
350 PrecalcCoefs(vf
->priv
->Coefs
[0], LumSpac
);
351 PrecalcCoefs(vf
->priv
->Coefs
[1], LumTmp
);
352 PrecalcCoefs(vf
->priv
->Coefs
[2], ChromSpac
);
353 PrecalcCoefs(vf
->priv
->Coefs
[3], ChromTmp
);
358 const vf_info_t vf_info_hqdn3d
= {
359 "High Quality 3D Denoiser",
361 "Daniel Moreno & A'rpi",
367 //===========================================================================//