1 /***************************************************************************
2 ADM_vidDenoise.cpp - description
3 -------------------
4 begin : Mon Nov 25 2002
5 copyright : (C) 2002 by mean
6 email : fixounet@free.fr
7
8 Denoiser inspired from DNR in transcode
9 Ported to YV12 and simplified
10
11 Original code Copyright (C) Gerhard Monzel - November 2001
12
13
14 ***************************************************************************/
15
16 /***************************************************************************
17 * *
18 * This program is free software; you can redistribute it and/or modify *
19 * it under the terms of the GNU General Public License as published by *
20 * the Free Software Foundation; either version 2 of the License, or *
21 * (at your option) any later version. *
22 * *
23 ***************************************************************************/
24
25 #include "ADM_default.h"
26
27 #include "ADM_videoFilterDynamic.h"
28 #include "ADM_vidDenoise.h"
29
30
31 #include "DIA_factory.h"
32
33 static FILTER_PARAM denoiseParam={5,{"lumaLock","lumaThreshold","chromaLock","chromaThreshold",
34 "sceneChange"}};
35
36 //********** Register chunk ************
37
38 VF_DEFINE_FILTER(ADMVideoDenoise,denoiseParam,
39 denoise,
40 QT_TR_NOOP("Denoise"),
41 1,
42 VF_NOISE,
43 QT_TR_NOOP("Port of Transcode DNR."));
44 //********** Register chunk ************
45
46
47 //static uint8_t matrixReady=0;
48 //static uint8_t doOnePix(uint8_t *in,uint8_t *out,uint8_t *lock,uint8_t *nb);
49
50
printConf(void)51 char *ADMVideoDenoise::printConf( void )
52 {
53 ADM_FILTER_DECLARE_CONF(" Denoise : Lum :%02ld/:%02ld / Chm :%02ld/%02ld",
54 _param->lumaLock,
55 _param->lumaThreshold,
56 _param->chromaLock,
57 _param->chromaThreshold);
58
59 }
60 static uint8_t distMatrix[256][256];
61 static uint32_t fixMul[16];
62 static bool distMatrixDone=false;
63
buildDistMatrix(void)64 static void buildDistMatrix( void )
65 {
66 int d;
67 for(uint32_t y=255;y>0;y--)
68 for(uint32_t x=255;x>0;x--)
69 {
70 d=x-y;
71 if(d<0) d=-d;
72 distMatrix[x][y]=d;
73
74 }
75
76 for(int i=1;i<16;i++)
77 {
78 fixMul[i]=(1<<16)/i;
79 }
80
81 }
82
83 //_______________________________________________________________
84
ADMVideoDenoise(AVDMGenericVideoStream * in,CONFcouple * couples)85 ADMVideoDenoise::ADMVideoDenoise(
86 AVDMGenericVideoStream *in,CONFcouple *couples)
87 {
88
89 if(distMatrixDone==false)
90 {
91 buildDistMatrix();
92 distMatrixDone=true;
93 }
94 _in=in;
95 memcpy(&_info,_in->getInfo(),sizeof(_info));
96 uint32_t page;
97
98 _info.encoding=1;
99
100 page= _in->getInfo()->width*_in->getInfo()->height;
101
102 // _uncompressed=new uint8_t [page];
103 _uncompressed=new ADMImage(_in->getInfo()->width,_in->getInfo()->height);
104 ADM_assert(_uncompressed);
105
106 // _locked=new uint8_t [page];
107 _locked=new ADMImage(_in->getInfo()->width,_in->getInfo()->height);
108 ADM_assert(_locked);
109
110 // _lockcount=new uint8_t [page];
111
112
113
114 _lockcount=new ADMImage(_in->getInfo()->width,_in->getInfo()->height);
115 memset(YPLANE(_lockcount),0,page);
116 memset(UPLANE(_lockcount),0,page>>2);
117 memset(VPLANE(_lockcount),0,page>>2);
118
119 _param=NULL;
120
121 if(couples)
122 {
123 _param=NEW(NOISE_PARAM);
124 GET(lumaLock);
125 GET(lumaThreshold);
126 GET(chromaLock);
127 GET(chromaThreshold);
128 GET(sceneChange);
129 }
130 else
131 {
132 #define XXX 1
133 _param=NEW(NOISE_PARAM);
134 _param->lumaLock= 4*XXX;
135 _param->lumaThreshold= 10*XXX;
136 _param->chromaLock= 8*XXX;
137 _param->chromaThreshold= 16*XXX;
138 _param->sceneChange= 30*XXX;
139 }
140 _lastFrame=0xfffffff0;
141 }
142
143
getCoupledConf(CONFcouple ** couples)144 uint8_t ADMVideoDenoise::getCoupledConf( CONFcouple **couples)
145 {
146
147 ADM_assert(_param);
148 *couples=new CONFcouple(5);
149
150 #define CSET(x) (*couples)->setCouple((char *)#x,(_param->x))
151 CSET(lumaLock);
152 CSET(lumaThreshold);
153 CSET(chromaLock);
154 CSET(chromaThreshold);
155 CSET(sceneChange);
156
157 return 1;
158
159 }
~ADMVideoDenoise()160 ADMVideoDenoise::~ADMVideoDenoise()
161 {
162
163 delete _uncompressed;
164 delete _locked;
165 delete _lockcount;
166 DELETE(_param);
167
168 _uncompressed=_locked=_lockcount=NULL;
169 }
170
171 //
172 // Remove y and v just keep U and expand it
173 //
getFrameNumberNoAlloc(uint32_t frame,uint32_t * len,ADMImage * data,uint32_t * flags)174 uint8_t ADMVideoDenoise::getFrameNumberNoAlloc(uint32_t frame,
175 uint32_t *len,
176 ADMImage *data,
177 uint32_t *flags)
178 {
179 //uint32_t x,w;
180 uint32_t page;
181 ADM_assert(_param);
182 if(frame>= _info.nb_frames) return 0;
183
184
185 if(!_in->getFrameNumberNoAlloc(frame, len,_uncompressed,flags)) return 0;
186
187
188 page=_info.width*_info.height;
189 *len=(page*3)>>1;
190
191 if((_lastFrame+1)!=frame) // async jump
192 {
193 // just copy it
194 memcpy(YPLANE(data),YPLANE(_uncompressed),page);
195 memcpy(UPLANE(data),UPLANE(_uncompressed),page>>2);
196 memcpy(VPLANE(data),VPLANE(_uncompressed),page>>2);
197
198 memcpy(YPLANE(_locked),YPLANE(_uncompressed),page);
199 memcpy(UPLANE(_locked),UPLANE(_uncompressed),page>>2);
200 memcpy(VPLANE(_locked),VPLANE(_uncompressed),page>>2);
201
202 _lastFrame=frame;
203 return 1;
204 }
205 _lastFrame=frame;
206
207 // copy chroma for now
208
209
210
211 //
212 //uint32_t count=0;
213 //uint32_t cell=page*4; // size of luma
214 uint8_t *in,*out,*lock,*nb;
215 uint8_t *uin,*uout,*ulock,*unb;
216 uint8_t *vin,*vout,*vlock,*vnb;
217
218
219 //uint32_t d;
220 // init all
221
222 // luma
223 nb=YPLANE(_lockcount);
224 lock=YPLANE(_locked);
225 in=YPLANE(_uncompressed);
226 out=YPLANE(data);
227 // u
228 unb=UPLANE(_lockcount);
229 ulock=UPLANE(_locked);
230 uin=UPLANE(_uncompressed);
231 uout=UPLANE(data);
232 // v
233 vnb=VPLANE(_lockcount);
234 vlock=VPLANE(_locked);
235 vin=VPLANE(_uncompressed);
236 vout=VPLANE(data);
237
238
239 uint32_t xx,yy/*,dl*/,du,dv;
240 uint32_t locked=0;
241 for(yy=_info.height>>1;yy>0;yy--)
242 {
243 for(xx=_info.width>>1;xx>0;xx--)
244 {
245 du=distMatrix[*uin][*ulock];
246 dv=distMatrix[*vin][*vlock];
247
248 // if chroma is locked , we try to lock luma
249 if( (du<_param->chromaLock)
250 && (dv<_param->chromaLock))
251 {
252 *uout=*ulock;
253 *vout=*vlock;
254
255 #define PIX(z) doOnePix(in+z,out+z,lock+z,nb+z)
256 locked+=PIX(0)+ PIX(1)+ PIX(_info.width)+PIX(_info.width+1);
257 }
258 else
259 // if chroma is blended, we blend luma
260 #undef PIX
261 #define PIX(z) doBlend(in+z,out+z,lock+z,nb+z)
262 if( (du<_param->chromaThreshold)
263 && (dv<_param->chromaThreshold))
264 {
265 PIX(0);
266 PIX(1);
267 PIX(_info.width);
268 PIX(_info.width+1);
269 *uout=*ulock=(*uin+*uin)>>1;
270 *vout=*vlock=(*vin+*vin)>>1;
271 }
272 #undef PIX
273
274 else
275 {
276 #define PIX(z) *(out+z)=*(lock+z)=*(in+z);*(nb+z)=0
277
278 PIX(0);
279 PIX(1);
280 PIX(_info.width);
281 PIX(_info.width+1);
282 *uout=*ulock=*uin;
283 *vout=*vlock=*vin;
284
285 #undef PIX
286 }
287
288
289 uin++;uout++;ulock++;unb++;
290 vin++;vout++;vlock++;vnb++;
291 in++;out++;lock++;nb++;
292 in++;out++;lock++;nb++;
293
294 }
295 //
296 in+=_info.width;
297 out+=_info.width;
298 lock+=_info.width;
299 nb+=_info.width;
300 };
301
302 if(locked>((page*3)>>2)) // if more than 75% pixel not locked -> scene change
303 {
304 memcpy(YPLANE(data),YPLANE(_uncompressed),page);
305 memcpy(UPLANE(data),UPLANE(_uncompressed),page>>2);
306 memcpy(VPLANE(data),VPLANE(_uncompressed),page>>2);
307
308 memcpy(YPLANE(_locked),YPLANE(_uncompressed),page);
309 memcpy(UPLANE(_locked),UPLANE(_uncompressed),page>>2);
310 memcpy(VPLANE(_locked),VPLANE(_uncompressed),page>>2);
311 }
312 data->copyInfo(_uncompressed);
313 return 1;
314 }
315
316 //
317 // 0 copy
318 // 1 lock
319 // 2 threshold
320 //
doOnePix(uint8_t * in,uint8_t * out,uint8_t * lock,uint8_t * nb)321 uint8_t ADMVideoDenoise::doOnePix(uint8_t *in,uint8_t *out,uint8_t *lock,uint8_t *nb)
322 {
323 unsigned int d;
324 d=distMatrix[*(in)][*(lock)];
325 if(d<_param->lumaLock)
326 {
327 if(*(nb)>30) // out of scope -> copy new
328 { // too much copy ->
329 *(nb)=0;
330 *(out)=(*(in)+*(lock))>>1;
331 *(lock)=*(out);
332 return DN_COPY;
333 }
334 else
335 {
336 *(out)=*(lock);
337 *nb += 1; // *(nb)++;
338 return DN_LOCK;
339 }
340 }
341 else if(d< _param->lumaThreshold)
342 {
343 *(nb)=0;
344 *(out)=(*(in)+*(lock))>>1;
345 return DN_BLEND;
346 }
347 else // too big delta
348 {
349 *(nb)=0;
350 *(out)=*(in);
351 *(lock)=*(in);
352 return DN_COPY;
353 }
354
355 ADM_assert(0);
356 return 0;
357
358 }
doBlend(uint8_t * in,uint8_t * out,uint8_t * lock,uint8_t * nb)359 uint8_t ADMVideoDenoise::doBlend(uint8_t *in,uint8_t *out,uint8_t *lock,uint8_t *nb)
360 {
361 unsigned int d;
362 d=distMatrix[*(in)][*(lock)];
363 *nb=0;
364
365 if(d<_param->lumaThreshold)
366 {
367 *(out)=(*(in)+*(lock))>>1;
368 }
369 else
370 *out=*in;
371 return 0;
372
373 }
374
375
configure(AVDMGenericVideoStream * instream)376 uint8_t ADMVideoDenoise::configure(AVDMGenericVideoStream * instream)
377 {
378 UNUSED_ARG(instream);
379
380 #define PX(x) &(_param->x)
381
382 diaElemUInteger lumaLock(PX(lumaLock),QT_TR_NOOP("_Luma lock:"),0,255);
383 diaElemUInteger chromaLock(PX(chromaLock),QT_TR_NOOP("C_hroma lock:"),0,255);
384 diaElemUInteger lumaThreshold(PX(lumaThreshold),QT_TR_NOOP("L_uma threshold:"),0,255);
385 diaElemUInteger chromaThreshold(PX(chromaThreshold),QT_TR_NOOP("Ch_roma threshold:"),0,255);
386
387 diaElemUInteger sceneChange(PX(sceneChange),QT_TR_NOOP("_Scene change:"),0,100);
388
389
390
391 diaElem *elems[5]={&lumaLock,&chromaLock,&lumaThreshold,&chromaThreshold,&sceneChange};
392
393 return diaFactoryRun(QT_TR_NOOP("Denoise"),5,elems);
394 }
395
396 // EOF
397