2 * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at>
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.
29 #include "cpudetect.h"
35 #include "img_format.h"
38 #include "libvo/fastmemcpy.h"
40 #define MAX_NOISE 4096
41 #define MAX_SHIFT 1024
42 #define MAX_RES (MAX_NOISE-MAX_SHIFT)
44 //===========================================================================//
46 static inline void lineNoise_C(uint8_t *dst
, uint8_t *src
, int8_t *noise
, int len
, int shift
);
47 static inline void lineNoiseAvg_C(uint8_t *dst
, uint8_t *src
, int len
, int8_t **shift
);
49 static void (*lineNoise
)(uint8_t *dst
, uint8_t *src
, int8_t *noise
, int len
, int shift
)= lineNoise_C
;
50 static void (*lineNoiseAvg
)(uint8_t *dst
, uint8_t *src
, int len
, int8_t **shift
)= lineNoiseAvg_C
;
52 typedef struct FilterParam
{
61 int8_t *prev_shift
[MAX_RES
][3];
65 FilterParam lumaParam
;
66 FilterParam chromaParam
;
70 static int nonTempRandShift_init
;
71 static int nonTempRandShift
[MAX_RES
];
73 static int patt
[4] = {
77 #define RAND_N(range) ((int) ((double)range*rand()/(RAND_MAX+1.0)))
78 static int8_t *initNoise(FilterParam
*fp
){
79 int strength
= fp
->strength
;
80 int uniform
= fp
->uniform
;
81 int averaged
= fp
->averaged
;
82 int pattern
= fp
->pattern
;
83 int8_t *noise
= memalign(16, MAX_NOISE
*sizeof(int8_t));
88 for(i
=0,j
=0; i
<MAX_NOISE
; i
++,j
++)
93 noise
[i
]= (RAND_N(strength
) - strength
/2)/6
94 +patt
[j
%4]*strength
*0.25/3;
96 noise
[i
]= (RAND_N(strength
) - strength
/2)/3;
100 noise
[i
]= (RAND_N(strength
) - strength
/2)/2
101 + patt
[j
%4]*strength
*0.25;
103 noise
[i
]= RAND_N(strength
) - strength
/2;
107 double x1
, x2
, w
, y1
;
109 x1
= 2.0 * rand()/(float)RAND_MAX
- 1.0;
110 x2
= 2.0 * rand()/(float)RAND_MAX
- 1.0;
111 w
= x1
* x1
+ x2
* x2
;
112 } while ( w
>= 1.0 );
114 w
= sqrt( (-2.0 * log( w
) ) / w
);
116 y1
*= strength
/ sqrt(3.0);
119 y1
+= patt
[j
%4]*strength
*0.35;
121 if (y1
<-128) y1
=-128;
122 else if(y1
> 127) y1
= 127;
123 if (averaged
) y1
/= 3.0;
126 if (RAND_N(6) == 0) j
--;
130 for (i
= 0; i
< MAX_RES
; i
++)
131 for (j
= 0; j
< 3; j
++)
132 fp
->prev_shift
[i
][j
] = noise
+ (rand()&(MAX_SHIFT
-1));
134 if(!nonTempRandShift_init
){
135 for(i
=0; i
<MAX_RES
; i
++){
136 nonTempRandShift
[i
]= rand()&(MAX_SHIFT
-1);
138 nonTempRandShift_init
= 1;
146 /***************************************************************************/
149 static inline void lineNoise_MMX(uint8_t *dst
, uint8_t *src
, int8_t *noise
, int len
, int shift
){
150 x86_reg mmx_len
= len
&(~7);
154 "mov %3, %%"REG_a
" \n\t"
155 "pcmpeqb %%mm7, %%mm7 \n\t"
156 "psllw $15, %%mm7 \n\t"
157 "packsswb %%mm7, %%mm7 \n\t"
160 "movq (%0, %%"REG_a
"), %%mm0 \n\t"
161 "movq (%1, %%"REG_a
"), %%mm1 \n\t"
162 "pxor %%mm7, %%mm0 \n\t"
163 "paddsb %%mm1, %%mm0 \n\t"
164 "pxor %%mm7, %%mm0 \n\t"
165 "movq %%mm0, (%2, %%"REG_a
") \n\t"
166 "add $8, %%"REG_a
" \n\t"
168 :: "r" (src
+mmx_len
), "r" (noise
+mmx_len
), "r" (dst
+mmx_len
), "g" (-mmx_len
)
172 lineNoise_C(dst
+mmx_len
, src
+mmx_len
, noise
+mmx_len
, len
-mmx_len
, 0);
176 //duplicate of previous except movntq
178 static inline void lineNoise_MMX2(uint8_t *dst
, uint8_t *src
, int8_t *noise
, int len
, int shift
){
179 x86_reg mmx_len
= len
&(~7);
183 "mov %3, %%"REG_a
" \n\t"
184 "pcmpeqb %%mm7, %%mm7 \n\t"
185 "psllw $15, %%mm7 \n\t"
186 "packsswb %%mm7, %%mm7 \n\t"
189 "movq (%0, %%"REG_a
"), %%mm0 \n\t"
190 "movq (%1, %%"REG_a
"), %%mm1 \n\t"
191 "pxor %%mm7, %%mm0 \n\t"
192 "paddsb %%mm1, %%mm0 \n\t"
193 "pxor %%mm7, %%mm0 \n\t"
194 "movntq %%mm0, (%2, %%"REG_a
") \n\t"
195 "add $8, %%"REG_a
" \n\t"
197 :: "r" (src
+mmx_len
), "r" (noise
+mmx_len
), "r" (dst
+mmx_len
), "g" (-mmx_len
)
201 lineNoise_C(dst
+mmx_len
, src
+mmx_len
, noise
+mmx_len
, len
-mmx_len
, 0);
205 static inline void lineNoise_C(uint8_t *dst
, uint8_t *src
, int8_t *noise
, int len
, int shift
){
210 int v
= src
[i
]+ noise
[i
];
211 if(v
>255) dst
[i
]=255; //FIXME optimize
212 else if(v
<0) dst
[i
]=0;
217 /***************************************************************************/
220 static inline void lineNoiseAvg_MMX(uint8_t *dst
, uint8_t *src
, int len
, int8_t **shift
){
221 x86_reg mmx_len
= len
&(~7);
224 "mov %5, %%"REG_a
" \n\t"
227 "movq (%1, %%"REG_a
"), %%mm1 \n\t"
228 "movq (%0, %%"REG_a
"), %%mm0 \n\t"
229 "paddb (%2, %%"REG_a
"), %%mm1 \n\t"
230 "paddb (%3, %%"REG_a
"), %%mm1 \n\t"
231 "movq %%mm0, %%mm2 \n\t"
232 "movq %%mm1, %%mm3 \n\t"
233 "punpcklbw %%mm0, %%mm0 \n\t"
234 "punpckhbw %%mm2, %%mm2 \n\t"
235 "punpcklbw %%mm1, %%mm1 \n\t"
236 "punpckhbw %%mm3, %%mm3 \n\t"
237 "pmulhw %%mm0, %%mm1 \n\t"
238 "pmulhw %%mm2, %%mm3 \n\t"
239 "paddw %%mm1, %%mm1 \n\t"
240 "paddw %%mm3, %%mm3 \n\t"
241 "paddw %%mm0, %%mm1 \n\t"
242 "paddw %%mm2, %%mm3 \n\t"
243 "psrlw $8, %%mm1 \n\t"
244 "psrlw $8, %%mm3 \n\t"
245 "packuswb %%mm3, %%mm1 \n\t"
246 "movq %%mm1, (%4, %%"REG_a
") \n\t"
247 "add $8, %%"REG_a
" \n\t"
249 :: "r" (src
+mmx_len
), "r" (shift
[0]+mmx_len
), "r" (shift
[1]+mmx_len
), "r" (shift
[2]+mmx_len
),
250 "r" (dst
+mmx_len
), "g" (-mmx_len
)
255 int8_t *shift2
[3]={shift
[0]+mmx_len
, shift
[1]+mmx_len
, shift
[2]+mmx_len
};
256 lineNoiseAvg_C(dst
+mmx_len
, src
+mmx_len
, len
-mmx_len
, shift2
);
261 static inline void lineNoiseAvg_C(uint8_t *dst
, uint8_t *src
, int len
, int8_t **shift
){
263 int8_t *src2
= (int8_t*)src
;
267 const int n
= shift
[0][i
] + shift
[1][i
] + shift
[2][i
];
268 dst
[i
]= src2
[i
]+((n
*src2
[i
])>>7);
272 /***************************************************************************/
274 static void noise(uint8_t *dst
, uint8_t *src
, int dstStride
, int srcStride
, int width
, int height
, FilterParam
*fp
){
275 int8_t *noise
= fp
->noise
;
283 if(dstStride
==srcStride
) fast_memcpy(dst
, src
, srcStride
*height
);
286 for(y
=0; y
<height
; y
++)
288 fast_memcpy(dst
, src
, width
);
296 for(y
=0; y
<height
; y
++)
298 if(fp
->temporal
) shift
= rand()&(MAX_SHIFT
-1);
299 else shift
= nonTempRandShift
[y
];
301 if(fp
->quality
==0) shift
&= ~7;
303 lineNoiseAvg(dst
, src
, width
, fp
->prev_shift
[y
]);
304 fp
->prev_shift
[y
][fp
->shiftptr
] = noise
+ shift
;
306 lineNoise(dst
, src
, noise
, width
, shift
);
312 if (fp
->shiftptr
== 3) fp
->shiftptr
= 0;
315 static int config(struct vf_instance
* vf
,
316 int width
, int height
, int d_width
, int d_height
,
317 unsigned int flags
, unsigned int outfmt
){
319 return vf_next_config(vf
,width
,height
,d_width
,d_height
,flags
,outfmt
);
322 static void get_image(struct vf_instance
* vf
, mp_image_t
*mpi
){
323 if(mpi
->flags
&MP_IMGFLAG_PRESERVE
) return; // don't change
324 if(mpi
->imgfmt
!=vf
->priv
->outfmt
) return; // colorspace differ
325 // ok, we can do pp in-place (or pp disabled):
326 vf
->dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
327 mpi
->type
, mpi
->flags
, mpi
->w
, mpi
->h
);
328 mpi
->planes
[0]=vf
->dmpi
->planes
[0];
329 mpi
->stride
[0]=vf
->dmpi
->stride
[0];
330 mpi
->width
=vf
->dmpi
->width
;
331 if(mpi
->flags
&MP_IMGFLAG_PLANAR
){
332 mpi
->planes
[1]=vf
->dmpi
->planes
[1];
333 mpi
->planes
[2]=vf
->dmpi
->planes
[2];
334 mpi
->stride
[1]=vf
->dmpi
->stride
[1];
335 mpi
->stride
[2]=vf
->dmpi
->stride
[2];
337 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
340 static int put_image(struct vf_instance
* vf
, mp_image_t
*mpi
, double pts
){
343 if(!(mpi
->flags
&MP_IMGFLAG_DIRECT
)){
344 // no DR, so get a new image! hope we'll get DR buffer:
345 vf
->dmpi
=vf_get_image(vf
->next
,vf
->priv
->outfmt
,
346 MP_IMGTYPE_TEMP
, MP_IMGFLAG_ACCEPT_STRIDE
,
350 //else printf("dr\n");
353 noise(dmpi
->planes
[0], mpi
->planes
[0], dmpi
->stride
[0], mpi
->stride
[0], mpi
->w
, mpi
->h
, &vf
->priv
->lumaParam
);
354 noise(dmpi
->planes
[1], mpi
->planes
[1], dmpi
->stride
[1], mpi
->stride
[1], mpi
->w
/2, mpi
->h
/2, &vf
->priv
->chromaParam
);
355 noise(dmpi
->planes
[2], mpi
->planes
[2], dmpi
->stride
[2], mpi
->stride
[2], mpi
->w
/2, mpi
->h
/2, &vf
->priv
->chromaParam
);
357 vf_clone_mpi_attributes(dmpi
, mpi
);
360 if(gCpuCaps
.hasMMX
) __asm__
volatile ("emms\n\t");
363 if(gCpuCaps
.hasMMX2
) __asm__
volatile ("sfence\n\t");
366 return vf_next_put_image(vf
,dmpi
, pts
);
369 static void uninit(struct vf_instance
* vf
){
370 if(!vf
->priv
) return;
372 if(vf
->priv
->chromaParam
.noise
) free(vf
->priv
->chromaParam
.noise
);
373 vf
->priv
->chromaParam
.noise
= NULL
;
375 if(vf
->priv
->lumaParam
.noise
) free(vf
->priv
->lumaParam
.noise
);
376 vf
->priv
->lumaParam
.noise
= NULL
;
382 //===========================================================================//
384 static int query_format(struct vf_instance
* vf
, unsigned int fmt
){
390 return vf_next_query_format(vf
,vf
->priv
->outfmt
);
395 static void parse(FilterParam
*fp
, char* args
){
397 char *max
= strchr(args
, ':');
399 if(!max
) max
= args
+ strlen(args
);
401 fp
->strength
= atoi(args
);
402 pos
= strchr(args
, 'u');
403 if(pos
&& pos
<max
) fp
->uniform
=1;
404 pos
= strchr(args
, 't');
405 if(pos
&& pos
<max
) fp
->temporal
=1;
406 pos
= strchr(args
, 'h');
407 if(pos
&& pos
<max
) fp
->quality
=1;
408 pos
= strchr(args
, 'p');
409 if(pos
&& pos
<max
) fp
->pattern
=1;
410 pos
= strchr(args
, 'a');
416 if(fp
->strength
) initNoise(fp
);
419 static const unsigned int fmt_list
[]={
426 static int open(vf_instance_t
*vf
, char* args
){
428 vf
->put_image
=put_image
;
429 vf
->get_image
=get_image
;
430 vf
->query_format
=query_format
;
432 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
433 memset(vf
->priv
, 0, sizeof(struct vf_priv_s
));
436 char *arg2
= strchr(args
,':');
437 if(arg2
) parse(&vf
->priv
->chromaParam
, arg2
+1);
438 parse(&vf
->priv
->lumaParam
, args
);
442 vf
->priv
->outfmt
=vf_match_csp(&vf
->next
,fmt_list
,IMGFMT_YV12
);
443 if(!vf
->priv
->outfmt
)
446 return 0; // no csp match :(
452 lineNoise
= lineNoise_MMX
;
453 lineNoiseAvg
= lineNoiseAvg_MMX
;
457 if(gCpuCaps
.hasMMX2
) lineNoise
= lineNoise_MMX2
;
458 // if(gCpuCaps.hasMMX) lineNoiseAvg= lineNoiseAvg_MMX2;
464 const vf_info_t vf_info_noise
= {
467 "Michael Niedermayer",
473 //===========================================================================//