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,¶m))
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,¶m);
331
332 }
333
setCoupledConf(CONFcouple * couples)334 void ADMVideoMPD3D::setCoupledConf(CONFcouple *couples)
335 {
336 ADM_paramLoad(couples, denoise3dhq_param, ¶m);
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