FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_noise.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at>
3  *
4  * This file is part of MPlayer.
5  *
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.
10  *
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.
15  *
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.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <math.h>
26 
27 #include "config.h"
28 #include "mp_msg.h"
29 #include "cpudetect.h"
30 
31 #if HAVE_MALLOC_H
32 #include <malloc.h>
33 #endif
34 
35 #include "img_format.h"
36 #include "mp_image.h"
37 #include "vf.h"
38 #include "libvo/fastmemcpy.h"
39 #include "libavutil/mem.h"
40 #include "libavutil/x86/asm.h"
41 
42 #define MAX_NOISE 4096
43 #define MAX_SHIFT 1024
44 #define MAX_RES (MAX_NOISE-MAX_SHIFT)
45 
46 //===========================================================================//
47 
48 static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift);
49 static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift);
50 
51 static void (*lineNoise)(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift)= lineNoise_C;
52 static void (*lineNoiseAvg)(uint8_t *dst, uint8_t *src, int len, int8_t **shift)= lineNoiseAvg_C;
53 
54 typedef struct FilterParam{
55  int strength;
56  int uniform;
57  int temporal;
58  int quality;
59  int averaged;
60  int pattern;
61  int shiftptr;
62  int8_t *noise;
63  int8_t *prev_shift[MAX_RES][3];
65 
66 struct vf_priv_s {
69  unsigned int outfmt;
70 };
71 
74 
75 static int patt[4] = {
76  -1,0,1,0
77 };
78 
79 #define RAND_N(range) ((int) ((double)range*rand()/(RAND_MAX+1.0)))
80 static int8_t *initNoise(FilterParam *fp){
81  int strength= fp->strength;
82  int uniform= fp->uniform;
83  int averaged= fp->averaged;
84  int pattern= fp->pattern;
85  int8_t *noise= av_malloc(MAX_NOISE*sizeof(int8_t));
86  int i, j;
87 
88  srand(123457);
89 
90  for(i=0,j=0; i<MAX_NOISE; i++,j++)
91  {
92  if(uniform) {
93  if (averaged) {
94  if (pattern) {
95  noise[i]= (RAND_N(strength) - strength/2)/6
96  +patt[j%4]*strength*0.25/3;
97  } else {
98  noise[i]= (RAND_N(strength) - strength/2)/3;
99  }
100  } else {
101  if (pattern) {
102  noise[i]= (RAND_N(strength) - strength/2)/2
103  + patt[j%4]*strength*0.25;
104  } else {
105  noise[i]= RAND_N(strength) - strength/2;
106  }
107  }
108  } else {
109  double x1, x2, w, y1;
110  do {
111  x1 = 2.0 * rand()/(float)RAND_MAX - 1.0;
112  x2 = 2.0 * rand()/(float)RAND_MAX - 1.0;
113  w = x1 * x1 + x2 * x2;
114  } while ( w >= 1.0 );
115 
116  w = sqrt( (-2.0 * log( w ) ) / w );
117  y1= x1 * w;
118  y1*= strength / sqrt(3.0);
119  if (pattern) {
120  y1 /= 2;
121  y1 += patt[j%4]*strength*0.35;
122  }
123  if (y1<-128) y1=-128;
124  else if(y1> 127) y1= 127;
125  if (averaged) y1 /= 3.0;
126  noise[i]= (int)y1;
127  }
128  if (RAND_N(6) == 0) j--;
129  }
130 
131 
132  for (i = 0; i < MAX_RES; i++)
133  for (j = 0; j < 3; j++)
134  fp->prev_shift[i][j] = noise + (rand()&(MAX_SHIFT-1));
135 
137  for(i=0; i<MAX_RES; i++){
138  nonTempRandShift[i]= rand()&(MAX_SHIFT-1);
139  }
141  }
142 
143  fp->noise= noise;
144  fp->shiftptr= 0;
145  return noise;
146 }
147 
148 /***************************************************************************/
149 
150 #if HAVE_MMX
151 static inline void lineNoise_MMX(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
152  x86_reg mmx_len= len&(~7);
153  noise+=shift;
154 
155  __asm__ volatile(
156  "mov %3, %%"REG_a" \n\t"
157  "pcmpeqb %%mm7, %%mm7 \n\t"
158  "psllw $15, %%mm7 \n\t"
159  "packsswb %%mm7, %%mm7 \n\t"
160  ASMALIGN(4)
161  "1: \n\t"
162  "movq (%0, %%"REG_a"), %%mm0 \n\t"
163  "movq (%1, %%"REG_a"), %%mm1 \n\t"
164  "pxor %%mm7, %%mm0 \n\t"
165  "paddsb %%mm1, %%mm0 \n\t"
166  "pxor %%mm7, %%mm0 \n\t"
167  "movq %%mm0, (%2, %%"REG_a") \n\t"
168  "add $8, %%"REG_a" \n\t"
169  " js 1b \n\t"
170  :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
171  : "%"REG_a
172  );
173  if(mmx_len!=len)
174  lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
175 }
176 #endif
177 
178 //duplicate of previous except movntq
179 #if HAVE_MMX2
180 static inline void lineNoise_MMX2(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
181  x86_reg mmx_len= len&(~7);
182  noise+=shift;
183 
184  __asm__ volatile(
185  "mov %3, %%"REG_a" \n\t"
186  "pcmpeqb %%mm7, %%mm7 \n\t"
187  "psllw $15, %%mm7 \n\t"
188  "packsswb %%mm7, %%mm7 \n\t"
189  ASMALIGN(4)
190  "1: \n\t"
191  "movq (%0, %%"REG_a"), %%mm0 \n\t"
192  "movq (%1, %%"REG_a"), %%mm1 \n\t"
193  "pxor %%mm7, %%mm0 \n\t"
194  "paddsb %%mm1, %%mm0 \n\t"
195  "pxor %%mm7, %%mm0 \n\t"
196  "movntq %%mm0, (%2, %%"REG_a") \n\t"
197  "add $8, %%"REG_a" \n\t"
198  " js 1b \n\t"
199  :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
200  : "%"REG_a
201  );
202  if(mmx_len!=len)
203  lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
204 }
205 #endif
206 
207 static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
208  int i;
209  noise+= shift;
210  for(i=0; i<len; i++)
211  {
212  int v= src[i]+ noise[i];
213  if(v>255) dst[i]=255; //FIXME optimize
214  else if(v<0) dst[i]=0;
215  else dst[i]=v;
216  }
217 }
218 
219 /***************************************************************************/
220 
221 #if HAVE_MMX
222 static inline void lineNoiseAvg_MMX(uint8_t *dst, uint8_t *src, int len, int8_t **shift){
223  x86_reg mmx_len= len&(~7);
224 
225  __asm__ volatile(
226  "mov %5, %%"REG_a" \n\t"
227  ASMALIGN(4)
228  "1: \n\t"
229  "movq (%1, %%"REG_a"), %%mm1 \n\t"
230  "movq (%0, %%"REG_a"), %%mm0 \n\t"
231  "paddb (%2, %%"REG_a"), %%mm1 \n\t"
232  "paddb (%3, %%"REG_a"), %%mm1 \n\t"
233  "movq %%mm0, %%mm2 \n\t"
234  "movq %%mm1, %%mm3 \n\t"
235  "punpcklbw %%mm0, %%mm0 \n\t"
236  "punpckhbw %%mm2, %%mm2 \n\t"
237  "punpcklbw %%mm1, %%mm1 \n\t"
238  "punpckhbw %%mm3, %%mm3 \n\t"
239  "pmulhw %%mm0, %%mm1 \n\t"
240  "pmulhw %%mm2, %%mm3 \n\t"
241  "paddw %%mm1, %%mm1 \n\t"
242  "paddw %%mm3, %%mm3 \n\t"
243  "paddw %%mm0, %%mm1 \n\t"
244  "paddw %%mm2, %%mm3 \n\t"
245  "psrlw $8, %%mm1 \n\t"
246  "psrlw $8, %%mm3 \n\t"
247  "packuswb %%mm3, %%mm1 \n\t"
248  "movq %%mm1, (%4, %%"REG_a") \n\t"
249  "add $8, %%"REG_a" \n\t"
250  " js 1b \n\t"
251  :: "r" (src+mmx_len), "r" (shift[0]+mmx_len), "r" (shift[1]+mmx_len), "r" (shift[2]+mmx_len),
252  "r" (dst+mmx_len), "g" (-mmx_len)
253  : "%"REG_a
254  );
255 
256  if(mmx_len!=len){
257  int8_t *shift2[3]={shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len};
258  lineNoiseAvg_C(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
259  }
260 }
261 #endif
262 
263 static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift){
264  int i;
265  int8_t *src2= (int8_t*)src;
266 
267  for(i=0; i<len; i++)
268  {
269  const int n= shift[0][i] + shift[1][i] + shift[2][i];
270  dst[i]= src2[i]+((n*src2[i])>>7);
271  }
272 }
273 
274 /***************************************************************************/
275 
276 static void noise(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp){
277  int8_t *noise= fp->noise;
278  int y;
279  int shift=0;
280 
281  if(!noise)
282  {
283  if(src==dst) return;
284 
285  if(dstStride==srcStride) fast_memcpy(dst, src, srcStride*height);
286  else
287  {
288  for(y=0; y<height; y++)
289  {
290  fast_memcpy(dst, src, width);
291  dst+= dstStride;
292  src+= srcStride;
293  }
294  }
295  return;
296  }
297 
298  for(y=0; y<height; y++)
299  {
300  if(fp->temporal) shift= rand()&(MAX_SHIFT -1);
301  else shift= nonTempRandShift[y];
302 
303  if(fp->quality==0) shift&= ~7;
304  if (fp->averaged) {
305  lineNoiseAvg(dst, src, width, fp->prev_shift[y]);
306  fp->prev_shift[y][fp->shiftptr] = noise + shift;
307  } else {
308  lineNoise(dst, src, noise, width, shift);
309  }
310  dst+= dstStride;
311  src+= srcStride;
312  }
313  fp->shiftptr++;
314  if (fp->shiftptr == 3) fp->shiftptr = 0;
315 }
316 
317 static int config(struct vf_instance *vf,
318  int width, int height, int d_width, int d_height,
319  unsigned int flags, unsigned int outfmt){
320 
321  return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
322 }
323 
324 static void get_image(struct vf_instance *vf, mp_image_t *mpi){
325  if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
326  if(mpi->imgfmt!=vf->priv->outfmt) return; // colorspace differ
327  // ok, we can do pp in-place (or pp disabled):
328  vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
329  mpi->type, mpi->flags, mpi->w, mpi->h);
330  mpi->planes[0]=vf->dmpi->planes[0];
331  mpi->stride[0]=vf->dmpi->stride[0];
332  mpi->width=vf->dmpi->width;
333  if(mpi->flags&MP_IMGFLAG_PLANAR){
334  mpi->planes[1]=vf->dmpi->planes[1];
335  mpi->planes[2]=vf->dmpi->planes[2];
336  mpi->stride[1]=vf->dmpi->stride[1];
337  mpi->stride[2]=vf->dmpi->stride[2];
338  }
339  mpi->flags|=MP_IMGFLAG_DIRECT;
340 }
341 
342 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
343  mp_image_t *dmpi;
344 
345  if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
346  // no DR, so get a new image! hope we'll get DR buffer:
347  vf->dmpi=ff_vf_get_image(vf->next,vf->priv->outfmt,
349  mpi->w,mpi->h);
350 //printf("nodr\n");
351  }
352 //else printf("dr\n");
353  dmpi= vf->dmpi;
354 
355  noise(dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam);
356  noise(dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam);
357  noise(dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam);
358 
359  ff_vf_clone_mpi_attributes(dmpi, mpi);
360 
361 #if HAVE_MMX
362  if(ff_gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
363 #endif
364 #if HAVE_MMX2
365  if(ff_gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
366 #endif
367 
368  return ff_vf_next_put_image(vf,dmpi, pts);
369 }
370 
371 static void uninit(struct vf_instance *vf){
372  if(!vf->priv) return;
373 
374  av_free(vf->priv->chromaParam.noise);
375  vf->priv->chromaParam.noise= NULL;
376 
377  av_free(vf->priv->lumaParam.noise);
378  vf->priv->lumaParam.noise= NULL;
379 
380  free(vf->priv);
381  vf->priv=NULL;
382 }
383 
384 //===========================================================================//
385 
386 static int query_format(struct vf_instance *vf, unsigned int fmt){
387  switch(fmt)
388  {
389  case IMGFMT_YV12:
390  case IMGFMT_I420:
391  case IMGFMT_IYUV:
392  return ff_vf_next_query_format(vf,vf->priv->outfmt);
393  }
394  return 0;
395 }
396 
397 static void parse(FilterParam *fp, char* args){
398  char *pos;
399  char *max= strchr(args, ':');
400 
401  if(!max) max= args + strlen(args);
402 
403  fp->strength= atoi(args);
404  pos= strchr(args, 'u');
405  if(pos && pos<max) fp->uniform=1;
406  pos= strchr(args, 't');
407  if(pos && pos<max) fp->temporal=1;
408  pos= strchr(args, 'h');
409  if(pos && pos<max) fp->quality=1;
410  pos= strchr(args, 'p');
411  if(pos && pos<max) fp->pattern=1;
412  pos= strchr(args, 'a');
413  if(pos && pos<max) {
414  fp->temporal=1;
415  fp->averaged=1;
416  }
417 
418  if(fp->strength) initNoise(fp);
419 }
420 
421 static const unsigned int fmt_list[]={
422  IMGFMT_YV12,
423  IMGFMT_I420,
424  IMGFMT_IYUV,
425  0
426 };
427 
428 static int vf_open(vf_instance_t *vf, char *args){
429  vf->config=config;
430  vf->put_image=put_image;
431  vf->get_image=get_image;
433  vf->uninit=uninit;
434  vf->priv=malloc(sizeof(struct vf_priv_s));
435  memset(vf->priv, 0, sizeof(struct vf_priv_s));
436  if(args)
437  {
438  char *arg2= strchr(args,':');
439  if(arg2) parse(&vf->priv->chromaParam, arg2+1);
440  parse(&vf->priv->lumaParam, args);
441  }
442 
443  // check csp:
444  vf->priv->outfmt=ff_vf_match_csp(&vf->next,fmt_list,IMGFMT_YV12);
445  if(!vf->priv->outfmt)
446  {
447  uninit(vf);
448  return 0; // no csp match :(
449  }
450 
451 
452 #if HAVE_MMX
453  if(ff_gCpuCaps.hasMMX){
456  }
457 #endif
458 #if HAVE_MMX2
459  if(ff_gCpuCaps.hasMMX2) lineNoise= lineNoise_MMX2;
460 // if(ff_gCpuCaps.hasMMX) lineNoiseAvg= lineNoiseAvg_MMX2;
461 #endif
462 
463  return 1;
464 }
465 
467  "noise generator",
468  "noise",
469  "Michael Niedermayer",
470  "",
471  vf_open,
472  NULL
473 };
474 
475 //===========================================================================//