Statistics
| Branch: | Revision:

ffmpeg / libavfilter / libmpcodecs / vf_noise.c @ e4852fb3

History | View | Annotate | Download (15.7 KB)

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

    
41
#define MAX_NOISE 4096
42
#define MAX_SHIFT 1024
43
#define MAX_RES (MAX_NOISE-MAX_SHIFT)
44

    
45
//===========================================================================//
46

    
47
static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift);
48
static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift);
49

    
50
static void (*lineNoise)(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift)= lineNoise_C;
51
static void (*lineNoiseAvg)(uint8_t *dst, uint8_t *src, int len, int8_t **shift)= lineNoiseAvg_C;
52

    
53
typedef struct FilterParam{
54
        int strength;
55
        int uniform;
56
        int temporal;
57
        int quality;
58
        int averaged;
59
        int pattern;
60
        int shiftptr;
61
        int8_t *noise;
62
        int8_t *prev_shift[MAX_RES][3];
63
}FilterParam;
64

    
65
struct vf_priv_s {
66
        FilterParam lumaParam;
67
        FilterParam chromaParam;
68
        unsigned int outfmt;
69
};
70

    
71
static int nonTempRandShift_init;
72
static int nonTempRandShift[MAX_RES];
73

    
74
static int patt[4] = {
75
    -1,0,1,0
76
};
77

    
78
#define RAND_N(range) ((int) ((double)range*rand()/(RAND_MAX+1.0)))
79
static int8_t *initNoise(FilterParam *fp){
80
        int strength= fp->strength;
81
        int uniform= fp->uniform;
82
        int averaged= fp->averaged;
83
        int pattern= fp->pattern;
84
        int8_t *noise= av_malloc(MAX_NOISE*sizeof(int8_t));
85
        int i, j;
86

    
87
        srand(123457);
88

    
89
        for(i=0,j=0; i<MAX_NOISE; i++,j++)
90
        {
91
                if(uniform) {
92
                        if (averaged) {
93
                                    if (pattern) {
94
                                        noise[i]= (RAND_N(strength) - strength/2)/6
95
                                                +patt[j%4]*strength*0.25/3;
96
                                } else {
97
                                        noise[i]= (RAND_N(strength) - strength/2)/3;
98
                                    }
99
                        } else {
100
                                    if (pattern) {
101
                                    noise[i]= (RAND_N(strength) - strength/2)/2
102
                                            + patt[j%4]*strength*0.25;
103
                                } else {
104
                                        noise[i]= RAND_N(strength) - strength/2;
105
                                    }
106
                        }
107
                    } else {
108
                        double x1, x2, w, y1;
109
                        do {
110
                                x1 = 2.0 * rand()/(float)RAND_MAX - 1.0;
111
                                x2 = 2.0 * rand()/(float)RAND_MAX - 1.0;
112
                                w = x1 * x1 + x2 * x2;
113
                        } while ( w >= 1.0 );
114

    
115
                        w = sqrt( (-2.0 * log( w ) ) / w );
116
                        y1= x1 * w;
117
                        y1*= strength / sqrt(3.0);
118
                        if (pattern) {
119
                            y1 /= 2;
120
                            y1 += patt[j%4]*strength*0.35;
121
                        }
122
                        if     (y1<-128) y1=-128;
123
                        else if(y1> 127) y1= 127;
124
                        if (averaged) y1 /= 3.0;
125
                        noise[i]= (int)y1;
126
                }
127
                if (RAND_N(6) == 0) j--;
128
        }
129

    
130

    
131
        for (i = 0; i < MAX_RES; i++)
132
            for (j = 0; j < 3; j++)
133
                fp->prev_shift[i][j] = noise + (rand()&(MAX_SHIFT-1));
134

    
135
        if(!nonTempRandShift_init){
136
                for(i=0; i<MAX_RES; i++){
137
                        nonTempRandShift[i]= rand()&(MAX_SHIFT-1);
138
                }
139
                nonTempRandShift_init = 1;
140
        }
141

    
142
        fp->noise= noise;
143
        fp->shiftptr= 0;
144
        return noise;
145
}
146

    
147
/***************************************************************************/
148

    
149
#if HAVE_MMX
150
static inline void lineNoise_MMX(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
151
        x86_reg mmx_len= len&(~7);
152
        noise+=shift;
153

    
154
        __asm__ volatile(
155
                "mov %3, %%"REG_a"                \n\t"
156
                "pcmpeqb %%mm7, %%mm7                \n\t"
157
                "psllw $15, %%mm7                \n\t"
158
                "packsswb %%mm7, %%mm7                \n\t"
159
                ASMALIGN(4)
160
                "1:                                \n\t"
161
                "movq (%0, %%"REG_a"), %%mm0        \n\t"
162
                "movq (%1, %%"REG_a"), %%mm1        \n\t"
163
                "pxor %%mm7, %%mm0                \n\t"
164
                "paddsb %%mm1, %%mm0                \n\t"
165
                "pxor %%mm7, %%mm0                \n\t"
166
                "movq %%mm0, (%2, %%"REG_a")        \n\t"
167
                "add $8, %%"REG_a"                \n\t"
168
                " js 1b                                \n\t"
169
                :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
170
                : "%"REG_a
171
        );
172
        if(mmx_len!=len)
173
                lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
174
}
175
#endif
176

    
177
//duplicate of previous except movntq
178
#if HAVE_MMX2
179
static inline void lineNoise_MMX2(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
180
        x86_reg mmx_len= len&(~7);
181
        noise+=shift;
182

    
183
        __asm__ volatile(
184
                "mov %3, %%"REG_a"                \n\t"
185
                "pcmpeqb %%mm7, %%mm7                \n\t"
186
                "psllw $15, %%mm7                \n\t"
187
                "packsswb %%mm7, %%mm7                \n\t"
188
                ASMALIGN(4)
189
                "1:                                \n\t"
190
                "movq (%0, %%"REG_a"), %%mm0        \n\t"
191
                "movq (%1, %%"REG_a"), %%mm1        \n\t"
192
                "pxor %%mm7, %%mm0                \n\t"
193
                "paddsb %%mm1, %%mm0                \n\t"
194
                "pxor %%mm7, %%mm0                \n\t"
195
                "movntq %%mm0, (%2, %%"REG_a")        \n\t"
196
                "add $8, %%"REG_a"                \n\t"
197
                " js 1b                                \n\t"
198
                :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
199
                : "%"REG_a
200
        );
201
        if(mmx_len!=len)
202
                lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
203
}
204
#endif
205

    
206
static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){
207
        int i;
208
        noise+= shift;
209
        for(i=0; i<len; i++)
210
        {
211
                int v= src[i]+ noise[i];
212
                if(v>255)         dst[i]=255; //FIXME optimize
213
                else if(v<0)         dst[i]=0;
214
                else                dst[i]=v;
215
        }
216
}
217

    
218
/***************************************************************************/
219

    
220
#if HAVE_MMX
221
static inline void lineNoiseAvg_MMX(uint8_t *dst, uint8_t *src, int len, int8_t **shift){
222
        x86_reg mmx_len= len&(~7);
223

    
224
        __asm__ volatile(
225
                "mov %5, %%"REG_a"                \n\t"
226
                ASMALIGN(4)
227
                "1:                                \n\t"
228
                "movq (%1, %%"REG_a"), %%mm1        \n\t"
229
                "movq (%0, %%"REG_a"), %%mm0        \n\t"
230
                "paddb (%2, %%"REG_a"), %%mm1        \n\t"
231
                "paddb (%3, %%"REG_a"), %%mm1        \n\t"
232
                "movq %%mm0, %%mm2                \n\t"
233
                "movq %%mm1, %%mm3                \n\t"
234
                "punpcklbw %%mm0, %%mm0                \n\t"
235
                "punpckhbw %%mm2, %%mm2                \n\t"
236
                "punpcklbw %%mm1, %%mm1                \n\t"
237
                "punpckhbw %%mm3, %%mm3                \n\t"
238
                "pmulhw %%mm0, %%mm1                \n\t"
239
                "pmulhw %%mm2, %%mm3                \n\t"
240
                "paddw %%mm1, %%mm1                \n\t"
241
                "paddw %%mm3, %%mm3                \n\t"
242
                "paddw %%mm0, %%mm1                \n\t"
243
                "paddw %%mm2, %%mm3                \n\t"
244
                "psrlw $8, %%mm1                \n\t"
245
                "psrlw $8, %%mm3                \n\t"
246
                "packuswb %%mm3, %%mm1                \n\t"
247
                "movq %%mm1, (%4, %%"REG_a")        \n\t"
248
                "add $8, %%"REG_a"                \n\t"
249
                " js 1b                                \n\t"
250
                :: "r" (src+mmx_len), "r" (shift[0]+mmx_len), "r" (shift[1]+mmx_len), "r" (shift[2]+mmx_len),
251
                   "r" (dst+mmx_len), "g" (-mmx_len)
252
                : "%"REG_a
253
        );
254

    
255
        if(mmx_len!=len){
256
                int8_t *shift2[3]={shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len};
257
                lineNoiseAvg_C(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
258
        }
259
}
260
#endif
261

    
262
static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift){
263
        int i;
264
        int8_t *src2= (int8_t*)src;
265

    
266
        for(i=0; i<len; i++)
267
        {
268
            const int n= shift[0][i] + shift[1][i] + shift[2][i];
269
            dst[i]= src2[i]+((n*src2[i])>>7);
270
        }
271
}
272

    
273
/***************************************************************************/
274

    
275
static void noise(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp){
276
        int8_t *noise= fp->noise;
277
        int y;
278
        int shift=0;
279

    
280
        if(!noise)
281
        {
282
                if(src==dst) return;
283

    
284
                if(dstStride==srcStride) fast_memcpy(dst, src, srcStride*height);
285
                else
286
                {
287
                        for(y=0; y<height; y++)
288
                        {
289
                                fast_memcpy(dst, src, width);
290
                                dst+= dstStride;
291
                                src+= srcStride;
292
                        }
293
                }
294
                return;
295
        }
296

    
297
        for(y=0; y<height; y++)
298
        {
299
                if(fp->temporal)        shift=  rand()&(MAX_SHIFT  -1);
300
                else                        shift= nonTempRandShift[y];
301

    
302
                if(fp->quality==0) shift&= ~7;
303
                if (fp->averaged) {
304
                    lineNoiseAvg(dst, src, width, fp->prev_shift[y]);
305
                    fp->prev_shift[y][fp->shiftptr] = noise + shift;
306
                } else {
307
                    lineNoise(dst, src, noise, width, shift);
308
                }
309
                dst+= dstStride;
310
                src+= srcStride;
311
        }
312
        fp->shiftptr++;
313
        if (fp->shiftptr == 3) fp->shiftptr = 0;
314
}
315

    
316
static int config(struct vf_instance *vf,
317
        int width, int height, int d_width, int d_height,
318
        unsigned int flags, unsigned int outfmt){
319

    
320
        return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
321
}
322

    
323
static void get_image(struct vf_instance *vf, mp_image_t *mpi){
324
    if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
325
    if(mpi->imgfmt!=vf->priv->outfmt) return; // colorspace differ
326
    // ok, we can do pp in-place (or pp disabled):
327
    vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
328
        mpi->type, mpi->flags, mpi->w, mpi->h);
329
    mpi->planes[0]=vf->dmpi->planes[0];
330
    mpi->stride[0]=vf->dmpi->stride[0];
331
    mpi->width=vf->dmpi->width;
332
    if(mpi->flags&MP_IMGFLAG_PLANAR){
333
        mpi->planes[1]=vf->dmpi->planes[1];
334
        mpi->planes[2]=vf->dmpi->planes[2];
335
        mpi->stride[1]=vf->dmpi->stride[1];
336
        mpi->stride[2]=vf->dmpi->stride[2];
337
    }
338
    mpi->flags|=MP_IMGFLAG_DIRECT;
339
}
340

    
341
static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
342
        mp_image_t *dmpi;
343

    
344
        if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
345
                // no DR, so get a new image! hope we'll get DR buffer:
346
                vf->dmpi=vf_get_image(vf->next,vf->priv->outfmt,
347
                MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
348
                mpi->w,mpi->h);
349
//printf("nodr\n");
350
        }
351
//else printf("dr\n");
352
        dmpi= vf->dmpi;
353

    
354
        noise(dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam);
355
        noise(dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam);
356
        noise(dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam);
357

    
358
        vf_clone_mpi_attributes(dmpi, mpi);
359

    
360
#if HAVE_MMX
361
        if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
362
#endif
363
#if HAVE_MMX2
364
        if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
365
#endif
366

    
367
        return vf_next_put_image(vf,dmpi, pts);
368
}
369

    
370
static void uninit(struct vf_instance *vf){
371
        if(!vf->priv) return;
372

    
373
        av_free(vf->priv->chromaParam.noise);
374
        vf->priv->chromaParam.noise= NULL;
375

    
376
        av_free(vf->priv->lumaParam.noise);
377
        vf->priv->lumaParam.noise= NULL;
378

    
379
        free(vf->priv);
380
        vf->priv=NULL;
381
}
382

    
383
//===========================================================================//
384

    
385
static int query_format(struct vf_instance *vf, unsigned int fmt){
386
        switch(fmt)
387
        {
388
        case IMGFMT_YV12:
389
        case IMGFMT_I420:
390
        case IMGFMT_IYUV:
391
                return vf_next_query_format(vf,vf->priv->outfmt);
392
        }
393
        return 0;
394
}
395

    
396
static void parse(FilterParam *fp, char* args){
397
        char *pos;
398
        char *max= strchr(args, ':');
399

    
400
        if(!max) max= args + strlen(args);
401

    
402
        fp->strength= atoi(args);
403
        pos= strchr(args, 'u');
404
        if(pos && pos<max) fp->uniform=1;
405
        pos= strchr(args, 't');
406
        if(pos && pos<max) fp->temporal=1;
407
        pos= strchr(args, 'h');
408
        if(pos && pos<max) fp->quality=1;
409
        pos= strchr(args, 'p');
410
        if(pos && pos<max) fp->pattern=1;
411
        pos= strchr(args, 'a');
412
        if(pos && pos<max) {
413
            fp->temporal=1;
414
            fp->averaged=1;
415
        }
416

    
417
        if(fp->strength) initNoise(fp);
418
}
419

    
420
static const unsigned int fmt_list[]={
421
    IMGFMT_YV12,
422
    IMGFMT_I420,
423
    IMGFMT_IYUV,
424
    0
425
};
426

    
427
static int vf_open(vf_instance_t *vf, char *args){
428
    vf->config=config;
429
    vf->put_image=put_image;
430
    vf->get_image=get_image;
431
    vf->query_format=query_format;
432
    vf->uninit=uninit;
433
    vf->priv=malloc(sizeof(struct vf_priv_s));
434
    memset(vf->priv, 0, sizeof(struct vf_priv_s));
435
    if(args)
436
    {
437
        char *arg2= strchr(args,':');
438
        if(arg2) parse(&vf->priv->chromaParam, arg2+1);
439
        parse(&vf->priv->lumaParam, args);
440
    }
441

    
442
    // check csp:
443
    vf->priv->outfmt=vf_match_csp(&vf->next,fmt_list,IMGFMT_YV12);
444
    if(!vf->priv->outfmt)
445
    {
446
        uninit(vf);
447
        return 0; // no csp match :(
448
    }
449

    
450

    
451
#if HAVE_MMX
452
    if(gCpuCaps.hasMMX){
453
        lineNoise= lineNoise_MMX;
454
        lineNoiseAvg= lineNoiseAvg_MMX;
455
    }
456
#endif
457
#if HAVE_MMX2
458
    if(gCpuCaps.hasMMX2) lineNoise= lineNoise_MMX2;
459
//    if(gCpuCaps.hasMMX) lineNoiseAvg= lineNoiseAvg_MMX2;
460
#endif
461

    
462
    return 1;
463
}
464

    
465
const vf_info_t vf_info_noise = {
466
    "noise generator",
467
    "noise",
468
    "Michael Niedermayer",
469
    "",
470
    vf_open,
471
    NULL
472
};
473

    
474
//===========================================================================//