1 /***************************************************************************
2                           ADM_vidMPLD3D.cpp  -  description
3                              -------------------
4 Mplayer HQDenoise3d port to avidemux2
5 Original Authors
6 Copyright (C) 2003
7 Daniel Moreno <comac@comac.darktech.org>
8         & A'rpi
9 Resynced with ffmpeg lavfilter
10  * Copyright (c) 2003 Daniel Moreno <comac AT comac DOT darktech DOT org>
11  * Copyright (c) 2010 Baptiste Coudurier
12 
13  ***************************************************************************/
14 
15 /***************************************************************************
16  *                                                                         *
17  *   This program is free software; you can redistribute it and/or modify  *
18  *   it under the terms of the GNU General Public License as published by  *
19  *   the Free Software Foundation; either version 2 of the License, or     *
20  *   (at your option) any later version.                                   *
21  *                                                                         *
22  ***************************************************************************/
23 #include <math.h>
24 #include "ADM_default.h"
25 #include "ADM_coreVideoFilter.h"
26 #include "ADM_videoFilterCache.h"
27 #include "DIA_factory.h"
28 
29 #include "ADM_vidMPLD3D.h"
30 #include "denoise3dHQ_desc.cpp"
31 
32 #include "DIA_factory.h"
33 #define aprintf(...) {}
34 // -- ffmpeg start
35 #define av_malloc ADM_alloc
36 #define av_free   ADM_dezalloc
37 #define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
38 
LowPassMul(unsigned int PrevMul,unsigned int CurrMul,int * Coef)39 static inline unsigned int LowPassMul(unsigned int PrevMul, unsigned int CurrMul, int *Coef)
40 {
41     //    int dMul= (PrevMul&0xFFFFFF)-(CurrMul&0xFFFFFF);
42     int dMul= PrevMul-CurrMul;
43     unsigned int d=((dMul+0x10007FF)>>12);
44     return CurrMul + Coef[d];
45 }
46 
deNoiseTemporal(unsigned char * FrameSrc,unsigned char * FrameDest,unsigned short * FrameAnt,int W,int H,int sStride,int dStride,int * Temporal)47 static void deNoiseTemporal(unsigned char *FrameSrc,
48                             unsigned char *FrameDest,
49                             unsigned short *FrameAnt,
50                             int W, int H, int sStride, int dStride,
51                             int *Temporal)
52 {
53     long X, Y;
54     unsigned int PixelDst;
55 
56     for (Y = 0; Y < H; Y++) {
57         for (X = 0; X < W; X++) {
58             PixelDst = LowPassMul(FrameAnt[X]<<8, FrameSrc[X]<<16, Temporal);
59             FrameAnt[X] = ((PixelDst+0x1000007F)>>8);
60             FrameDest[X]= ((PixelDst+0x10007FFF)>>16);
61         }
62         FrameSrc  += sStride;
63         FrameDest += dStride;
64         FrameAnt += W;
65     }
66 }
67 
deNoiseSpacial(unsigned char * Frame,unsigned char * FrameDest,unsigned int * LineAnt,int W,int H,int sStride,int dStride,int * Horizontal,int * Vertical)68 static void deNoiseSpacial(unsigned char *Frame,
69                            unsigned char *FrameDest,
70                            unsigned int *LineAnt,
71                            int W, int H, int sStride, int dStride,
72                            int *Horizontal, int *Vertical)
73 {
74     long X, Y;
75     long sLineOffs = 0, dLineOffs = 0;
76     unsigned int PixelAnt;
77     unsigned int PixelDst;
78 
79     /* First pixel has no left nor top neighbor. */
80     PixelDst = LineAnt[0] = PixelAnt = Frame[0]<<16;
81     FrameDest[0]= ((PixelDst+0x10007FFF)>>16);
82 
83     /* First line has no top neighbor, only left. */
84     for (X = 1; X < W; X++) {
85         PixelDst = LineAnt[X] = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal);
86         FrameDest[X]= ((PixelDst+0x10007FFF)>>16);
87     }
88 
89     for (Y = 1; Y < H; Y++) {
90         unsigned int PixelAnt;
91         sLineOffs += sStride, dLineOffs += dStride;
92         /* First pixel on each line doesn't have previous pixel */
93         PixelAnt = Frame[sLineOffs]<<16;
94         PixelDst = LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical);
95         FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16);
96 
97         for (X = 1; X < W; X++) {
98             unsigned int PixelDst;
99             /* The rest are normal */
100             PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal);
101             PixelDst = LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical);
102             FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16);
103         }
104     }
105 }
106 
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)107 static void deNoise(unsigned char *Frame,
108                     unsigned char *FrameDest,
109                     unsigned int *LineAnt,
110                     unsigned short **FrameAntPtr,
111                     int W, int H, int sStride, int dStride,
112                     int *Horizontal, int *Vertical, int *Temporal)
113 {
114     long X, Y;
115     long sLineOffs = 0, dLineOffs = 0;
116     unsigned int PixelAnt;
117     unsigned int PixelDst;
118     unsigned short* FrameAnt=(*FrameAntPtr);
119 
120     if (!FrameAnt) {
121         (*FrameAntPtr) = FrameAnt = (unsigned short *)av_malloc(W*H*sizeof(unsigned short));
122         for (Y = 0; Y < H; Y++) {
123             unsigned short* dst=&FrameAnt[Y*W];
124             unsigned char* src=Frame+Y*sStride;
125             for (X = 0; X < W; X++) dst[X]=src[X]<<8;
126         }
127     }
128 
129     if (!Horizontal[0] && !Vertical[0]) {
130         deNoiseTemporal(Frame, FrameDest, FrameAnt,
131                         W, H, sStride, dStride, Temporal);
132         return;
133     }
134     if (!Temporal[0]) {
135         deNoiseSpacial(Frame, FrameDest, LineAnt,
136                        W, H, sStride, dStride, Horizontal, Vertical);
137         return;
138     }
139 
140     /* First pixel has no left nor top neighbor. Only previous frame */
141     LineAnt[0] = PixelAnt = Frame[0]<<16;
142     PixelDst = LowPassMul(FrameAnt[0]<<8, PixelAnt, Temporal);
143     FrameAnt[0] = ((PixelDst+0x1000007F)>>8);
144     FrameDest[0]= ((PixelDst+0x10007FFF)>>16);
145 
146     /* First line has no top neighbor. Only left one for each pixel and
147      * last frame */
148     for (X = 1; X < W; X++) {
149         LineAnt[X] = PixelAnt = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal);
150         PixelDst = LowPassMul(FrameAnt[X]<<8, PixelAnt, Temporal);
151         FrameAnt[X] = ((PixelDst+0x1000007F)>>8);
152         FrameDest[X]= ((PixelDst+0x10007FFF)>>16);
153     }
154 
155     for (Y = 1; Y < H; Y++) {
156         unsigned int PixelAnt;
157         unsigned short* LinePrev=&FrameAnt[Y*W];
158         sLineOffs += sStride, dLineOffs += dStride;
159         /* First pixel on each line doesn't have previous pixel */
160         PixelAnt = Frame[sLineOffs]<<16;
161         LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical);
162         PixelDst = LowPassMul(LinePrev[0]<<8, LineAnt[0], Temporal);
163         LinePrev[0] = ((PixelDst+0x1000007F)>>8);
164         FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16);
165 
166         for (X = 1; X < W; X++) {
167             unsigned int PixelDst;
168             /* The rest are normal */
169             PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal);
170             LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical);
171             PixelDst = LowPassMul(LinePrev[X]<<8, LineAnt[X], Temporal);
172             LinePrev[X] = ((PixelDst+0x1000007F)>>8);
173             FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16);
174         }
175     }
176 }
177 
PrecalcCoefs(int * Ct,double Dist25)178 static void PrecalcCoefs(int *Ct, double Dist25)
179 {
180     int i;
181     double Gamma, Simil, C;
182 
183     Gamma = log(0.25) / log(1.0 - Dist25/255.0 - 0.00001);
184 
185     for (i = -255*16; i <= 255*16; i++) {
186         Simil = 1.0 - FFABS(i) / (16*255.0);
187         C = pow(Simil, Gamma) * 65536.0 * i / 16.0;
188         Ct[16*256+i] = lrint(C);
189     }
190 
191     Ct[0] = !!Dist25;
192 }
193 
194 
195 //--------
196 DECLARE_VIDEO_FILTER(   ADMVideoMPD3D,   // Class
197                         1,0,0,              // Version
198                         ADM_UI_ALL,         // UI
199                         VF_NOISE,            // Category
200                         "MplayerDenoise3DHQ",            // internal name (must be uniq!)
201                         QT_TRANSLATE_NOOP("mp3d","Mplayer Denoise 3D HQ"),            // Display name
202                         QT_TRANSLATE_NOOP("mp3d","Reduce noise, smooth image, increase compressibility. HQ Version.") // Description
203                     );
204 
205 #define PARAM1_DEFAULT 4.0
206 #define PARAM2_DEFAULT 3.0
207 #define PARAM3_DEFAULT 6.0
208 /**
209     \fn getConfiguration
210 */
getConfiguration(void)211 const char 	*ADMVideoMPD3D::getConfiguration(void)
212  {
213       static char str[1024];
214 
215       snprintf(str,1023," MPlayer hqdn3d (Sp : %2.1f - %2.1f, Tmp:%2.1f - %2.1f)'",
216                                                 param.luma_spatial,param.chroma_spatial,param.luma_temporal,param.chroma_temporal);
217       return str;
218 
219 }
220 /**
221     \fn configure
222 */
configure(void)223 bool ADMVideoMPD3D::configure(void)
224 {
225         ELEM_TYPE_FLOAT fluma_spatial,fchroma_spatial,fluma_temporal,fchroma_temporal;
226 #define PX(x) &x
227 #define OOP(x,y) f##x=(ELEM_TYPE_FLOAT )param.x;
228 
229         OOP(luma_spatial,Luma);
230         OOP(chroma_spatial,Chroma);
231         OOP(luma_temporal,LumaTemporal);
232         OOP(chroma_temporal,ChromaTemporal);
233 
234         diaElemFloat   luma(PX(fluma_spatial),QT_TRANSLATE_NOOP("mp3d","_Spatial luma strength:"),0.1,100.);
235         diaElemFloat   chroma(PX(fchroma_spatial),QT_TRANSLATE_NOOP("mp3d","S_patial chroma strength:"),0.,100.);
236         diaElemFloat   lumaTemporal(PX(fluma_temporal),QT_TRANSLATE_NOOP("mp3d","_Temporal luma strength:"),0.,100.);
237         diaElemFloat   chromaTemporal(PX(fchroma_temporal),QT_TRANSLATE_NOOP("mp3d","T_emporal chroma strength:"),0.,100.);
238 
239         diaElem *elems[4]={&luma,&chroma,&lumaTemporal,&chromaTemporal};
240 
241         if(  diaFactoryRun(QT_TRANSLATE_NOOP("mp3d","MPlayer Denoise 3D HQ"),4,elems))
242         {
243 #undef OOP
244 #define OOP(x,y) param.x=(float) f##x
245             OOP(luma_spatial,Luma);
246             OOP(chroma_spatial,Chroma);
247             OOP(luma_temporal,LumaTemporal);
248             OOP(chroma_temporal,ChromaTemporal);
249 
250             setup();
251             return 1;
252         }
253         return 0;
254 }
255 /**
256     \fn dtor
257 */
~ADMVideoMPD3D()258 ADMVideoMPD3D::~ADMVideoMPD3D()
259 {
260     if (context.Line)
261     {
262         delete [] context.Line;
263         context.Line=NULL;
264     }
265 
266     for(int i=0;i<3;i++)
267     {
268         unsigned short *t=context.Frame[i];
269         context.Frame[i]=NULL;
270         if(t) av_free(t);
271     }
272 }
273 
274 
275 /**
276     \fn setup
277 */
setup(void)278 uint8_t  ADMVideoMPD3D::setup(void)
279 {
280     double LumSpac, LumTmp, ChromSpac, ChromTmp;
281     double Param1, Param2, Param3, Param4;
282 
283     Param1=param.luma_spatial;
284     Param2=param.chroma_spatial;
285     Param3=param.luma_temporal;
286     Param4=param.chroma_temporal;
287 
288     if(Param1<0.1) Param1=0.1;
289     LumSpac   = Param1;
290     ChromSpac = Param2 * Param1 / Param1;
291     LumTmp    = Param3 * Param1 / Param1;
292     ChromTmp  = LumTmp * ChromSpac / LumSpac;
293 
294     PrecalcCoefs(context.Coefs[0], LumSpac);
295     PrecalcCoefs(context.Coefs[1], LumTmp);
296     PrecalcCoefs(context.Coefs[2], ChromSpac);
297     PrecalcCoefs(context.Coefs[3], ChromTmp);
298 
299    return 1;
300 }
301 /**
302     \fn ctor
303 */
ADMVideoMPD3D(ADM_coreVideoFilter * in,CONFcouple * couples)304 ADMVideoMPD3D::ADMVideoMPD3D(	ADM_coreVideoFilter *in,CONFcouple *couples)
305         : ADM_coreVideoFilterCached(3,in,couples)
306 {
307 uint32_t page;
308   memset(&context,0,sizeof(context));
309 
310   context.Line=new unsigned int [in->getInfo()->width];
311   page=info.width*info.height;
312 
313   if(!couples || !ADM_paramLoad(couples,denoise3dhq_param,&param))
314   {
315         param.mode=4;
316         param.luma_spatial=PARAM1_DEFAULT;
317         param.chroma_spatial=PARAM2_DEFAULT;
318         param.luma_temporal=PARAM3_DEFAULT;
319         param.chroma_temporal=PARAM3_DEFAULT*PARAM2_DEFAULT/PARAM1_DEFAULT; //   ChromTmp  = LumTmp * ChromSpac / LumSpac;
320   }
321   setup();
322 
323 }
324 
325 /**
326     \fn getCoupledConf
327 */
getCoupledConf(CONFcouple ** couples)328 bool	ADMVideoMPD3D::getCoupledConf( CONFcouple **couples)
329 {
330     return ADM_paramSave(couples, denoise3dhq_param,&param);
331 
332 }
333 
setCoupledConf(CONFcouple * couples)334 void ADMVideoMPD3D::setCoupledConf(CONFcouple *couples)
335 {
336     ADM_paramLoad(couples, denoise3dhq_param, &param);
337 }
338 
339 /**
340     \fn getNextFrame
341 */
getNextFrame(uint32_t * fn,ADMImage * image)342 bool ADMVideoMPD3D::getNextFrame(uint32_t *fn,ADMImage *image)
343 {
344         int cw= info.width>>1;
345         int ch= info.height>>1;
346         int W = info.width;
347         int H  = info.height;
348         uint32_t dlen,dflags;
349 
350         ADMImage *src, *dst;
351 
352         *fn=nextFrame;
353         uint32_t n = nextFrame;
354         printf("MP3d: next frame= %d\n",(int)n);
355         src = vidCache->getImage(n);
356         if(!src) return false;
357 
358         uint8_t *c,*d;
359 
360         d=YPLANE(image);
361         c=YPLANE(src);
362 
363         deNoise(c,d,
364                 context.Line,
365                 &context.Frame[0],
366                 W,H,
367                 image->GetPitch(PLANAR_Y),
368                 src->GetPitch(PLANAR_Y),
369                 context.Coefs[0],
370                 context.Coefs[0],
371                 context.Coefs[1]);
372 
373 
374         d=UPLANE(image);
375         c=UPLANE(src);
376 
377        deNoise(c,d,
378                 context.Line,
379                 &context.Frame[1],
380                 cw,ch,
381                 image->GetPitch(PLANAR_U),
382                 src->GetPitch(PLANAR_U),
383                 context.Coefs[2],
384                 context.Coefs[2],
385                 context.Coefs[3]);
386 
387         d=VPLANE(image);
388         c=VPLANE(src);
389 
390          deNoise(c,d,
391                 context.Line,
392                 &context.Frame[1],
393                 cw,ch,
394                 image->GetPitch(PLANAR_V),
395                 src->GetPitch(PLANAR_V),
396                 context.Coefs[2],
397                 context.Coefs[2],
398                 context.Coefs[3]);
399 
400 
401         nextFrame++;
402         image->copyInfo(src);
403         vidCache->unlockAll();
404         return 1;
405 }
406 /**
407     \fn goToTime
408     \brief flush acc if seeking
409 */
goToTime(uint64_t usSeek)410 bool         ADMVideoMPD3D::goToTime(uint64_t usSeek)
411 {
412     for(int i=0;i<3;i++)
413     {
414         unsigned short *t=context.Frame[i];
415         context.Frame[i]=NULL;
416         if(t) av_free(t);
417     }
418 
419     // Flush
420     return ADM_coreVideoFilterCached::goToTime(usSeek);
421 }
422 // EOF
423 
424 
425