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