Browse code

lavfi: port MP noise filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2013/02/11 00:18:30
Showing 8 changed files
... ...
@@ -18,6 +18,7 @@ version <next>:
18 18
 - il filter ported from libmpcodecs
19 19
 - support ID3v2 tags in ASF files
20 20
 - RF64 support in WAV muxer
21
+- noise filter ported from libmpcodecs
21 22
 
22 23
 
23 24
 version 1.1:
... ...
@@ -36,6 +36,7 @@ Specifically, the GPL parts of FFmpeg are
36 36
     - vf_hue.c
37 37
     - vf_kerndeint.c
38 38
     - vf_mp.c
39
+    - vf_noise.c
39 40
     - vf_pp.c
40 41
     - vf_smartblur.c
41 42
     - vf_super2xsai.c
... ...
@@ -2012,6 +2012,7 @@ movie_filter_deps="avcodec avformat"
2012 2012
 mp_filter_deps="gpl avcodec swscale inline_asm"
2013 2013
 mptestsrc_filter_deps="gpl"
2014 2014
 negate_filter_deps="lut_filter"
2015
+noise_filter_deps="gpl"
2015 2016
 resample_filter_deps="avresample"
2016 2017
 ocv_filter_deps="libopencv"
2017 2018
 pan_filter_deps="swresample"
... ...
@@ -3630,7 +3630,6 @@ The list of the currently supported filters follows:
3630 3630
 @item ivtc
3631 3631
 @item kerndeint
3632 3632
 @item mcdeint
3633
-@item noise
3634 3633
 @item ow
3635 3634
 @item perspective
3636 3635
 @item phase
... ...
@@ -3657,12 +3656,6 @@ Adjust gamma, brightness, contrast:
3657 3657
 @example
3658 3658
 mp=eq2=1.0:2:0.5
3659 3659
 @end example
3660
-
3661
-@item
3662
-Add temporal noise to input video:
3663
-@example
3664
-mp=noise=20t
3665
-@end example
3666 3660
 @end itemize
3667 3661
 
3668 3662
 See also mplayer(1), @url{http://www.mplayerhq.hu/}.
... ...
@@ -3692,6 +3685,57 @@ noformat=yuv420p,vflip
3692 3692
 noformat=yuv420p:yuv444p:yuv410p
3693 3693
 @end example
3694 3694
 
3695
+@section noise
3696
+
3697
+Add noise on video input frame.
3698
+
3699
+This filter accepts a list of options in the form of @var{key}=@var{value}
3700
+pairs separated by ":". A description of the accepted options follows.
3701
+
3702
+@table @option
3703
+@item all_seed
3704
+@item c0_seed
3705
+@item c1_seed
3706
+@item c2_seed
3707
+@item c3_seed
3708
+Set noise seed for specific pixel component or all pixel components in case
3709
+of @var{all_seed}. Default value is @code{123457}.
3710
+
3711
+@item all_strength, as
3712
+@item c0_strength, c0s
3713
+@item c1_strength, c1s
3714
+@item c2_strength, c2s
3715
+@item c3_strength, c3s
3716
+Set noise strength for specific pixel component or all pixel components in case
3717
+@var{all_strength}. Default value is @code{0}. Allowed range is [0, 100].
3718
+
3719
+@item all_flags, af
3720
+@item c0_flags, c0f
3721
+@item c1_flags, c1f
3722
+@item c2_flags, c2f
3723
+@item c3_flags, c3f
3724
+Set pixel component flags or set flags for all components if @var{all_flags}.
3725
+Available values for component flags are:
3726
+@table @samp
3727
+@item a
3728
+averaged temporal noise (smoother)
3729
+@item p
3730
+mix random noise with a (semi)regular pattern
3731
+@item q
3732
+higher quality (slightly better looking, slightly slower)
3733
+@item t
3734
+temporal noise (noise pattern changes between frames)
3735
+@item u
3736
+uniform noise (gaussian otherwise)
3737
+@end table
3738
+@end table
3739
+
3740
+Some examples follow:
3741
+@example
3742
+Add temporal and uniform noise to input video:
3743
+noise=alls=20:allf=t+u
3744
+@end example
3745
+
3695 3746
 @section null
3696 3747
 
3697 3748
 Pass the video source unchanged to the output.
... ...
@@ -134,6 +134,7 @@ OBJS-$(CONFIG_LUTYUV_FILTER)                 += vf_lut.o
134 134
 OBJS-$(CONFIG_MP_FILTER)                     += vf_mp.o
135 135
 OBJS-$(CONFIG_NEGATE_FILTER)                 += vf_lut.o
136 136
 OBJS-$(CONFIG_NOFORMAT_FILTER)               += vf_format.o
137
+OBJS-$(CONFIG_NOISE_FILTER)                  += vf_noise.o
137 138
 OBJS-$(CONFIG_NULL_FILTER)                   += vf_null.o
138 139
 OBJS-$(CONFIG_OCV_FILTER)                    += vf_libopencv.o
139 140
 OBJS-$(CONFIG_OVERLAY_FILTER)                += vf_overlay.o
... ...
@@ -128,6 +128,7 @@ void avfilter_register_all(void)
128 128
     REGISTER_FILTER(MP,             mp,             vf);
129 129
     REGISTER_FILTER(NEGATE,         negate,         vf);
130 130
     REGISTER_FILTER(NOFORMAT,       noformat,       vf);
131
+    REGISTER_FILTER(NOISE,          noise,          vf);
131 132
     REGISTER_FILTER(NULL,           null,           vf);
132 133
     REGISTER_FILTER(OCV,            ocv,            vf);
133 134
     REGISTER_FILTER(OVERLAY,        overlay,        vf);
... ...
@@ -29,8 +29,8 @@
29 29
 #include "libavutil/avutil.h"
30 30
 
31 31
 #define LIBAVFILTER_VERSION_MAJOR  3
32
-#define LIBAVFILTER_VERSION_MINOR  37
33
-#define LIBAVFILTER_VERSION_MICRO 103
32
+#define LIBAVFILTER_VERSION_MINOR  38
33
+#define LIBAVFILTER_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
36 36
                                                LIBAVFILTER_VERSION_MINOR, \
37 37
new file mode 100644
... ...
@@ -0,0 +1,365 @@
0
+/*
1
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
2
+ * Copyright (c) 2013 Paul B Mahol
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * noise generator
24
+ */
25
+
26
+#include "libavutil/opt.h"
27
+#include "libavutil/imgutils.h"
28
+#include "libavutil/parseutils.h"
29
+#include "libavutil/pixdesc.h"
30
+#include "avfilter.h"
31
+#include "formats.h"
32
+#include "internal.h"
33
+#include "video.h"
34
+
35
+#define MAX_NOISE 4096
36
+#define MAX_SHIFT 1024
37
+#define MAX_RES (MAX_NOISE-MAX_SHIFT)
38
+
39
+#define NOISE_UNIFORM  1
40
+#define NOISE_TEMPORAL 2
41
+#define NOISE_QUALITY  4
42
+#define NOISE_AVERAGED 8
43
+#define NOISE_PATTERN  16
44
+
45
+typedef struct {
46
+    int strength;
47
+    unsigned flags;
48
+    int shiftptr;
49
+    int seed;
50
+    int8_t *noise;
51
+    int8_t *prev_shift[MAX_RES][3];
52
+} FilterParams;
53
+
54
+typedef struct {
55
+    const AVClass *class;
56
+    int nb_planes;
57
+    int linesize[4];
58
+    int height[4];
59
+    FilterParams all;
60
+    FilterParams param[4];
61
+    int rand_shift[MAX_RES];
62
+    int rand_shift_init;
63
+} NoiseContext;
64
+
65
+#define OFFSET(x) offsetof(NoiseContext, x)
66
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
67
+
68
+#define NOISE_PARAMS(name, x, param)                                                                                             \
69
+    {#name"_seed", "set component #"#x" noise seed", OFFSET(param.seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS},        \
70
+    {#name"_strength", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS},        \
71
+    {#name"s",         "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS},        \
72
+    {#name"_flags", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
73
+    {#name"f", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"},      \
74
+    {"a", "averaged noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_AVERAGED}, 0, 0, FLAGS, #name"_flags"},                            \
75
+    {"p", "(semi)regular pattern", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_PATTERN},  0, 0, FLAGS, #name"_flags"},                     \
76
+    {"q", "high quality",   0, AV_OPT_TYPE_CONST, {.i64=NOISE_QUALITY},  0, 0, FLAGS, #name"_flags"},                            \
77
+    {"t", "temporal noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_TEMPORAL}, 0, 0, FLAGS, #name"_flags"},                            \
78
+    {"u", "uniform noise",  0, AV_OPT_TYPE_CONST, {.i64=NOISE_UNIFORM},  0, 0, FLAGS, #name"_flags"},
79
+
80
+static const AVOption noise_options[] = {
81
+    NOISE_PARAMS(all, 0, all)
82
+    NOISE_PARAMS(c0,  0, param[0])
83
+    NOISE_PARAMS(c1,  1, param[1])
84
+    NOISE_PARAMS(c2,  2, param[2])
85
+    NOISE_PARAMS(c3,  3, param[3])
86
+    {NULL}
87
+};
88
+
89
+AVFILTER_DEFINE_CLASS(noise);
90
+
91
+static const int8_t patt[4] = { -1, 0, 1, 0 };
92
+
93
+#define RAND_N(range) ((int) ((double) range * rand() / (RAND_MAX + 1.0)))
94
+static int init_noise(NoiseContext *n, int comp)
95
+{
96
+    int8_t *noise = av_malloc(MAX_NOISE * sizeof(int8_t));
97
+    FilterParams *fp = &n->param[comp];
98
+    int strength = fp->strength;
99
+    int flags = fp->flags;
100
+    int i, j;
101
+
102
+    if (!noise)
103
+        return AVERROR(ENOMEM);
104
+
105
+    srand(fp->seed);
106
+
107
+    for (i = 0, j = 0; i < MAX_NOISE; i++, j++) {
108
+        if (flags & NOISE_UNIFORM) {
109
+            if (flags & NOISE_AVERAGED) {
110
+                if (flags & NOISE_PATTERN) {
111
+                    noise[i] = (RAND_N(strength) - strength / 2) / 6
112
+                        + patt[j % 4] * strength * 0.25 / 3;
113
+                } else {
114
+                    noise[i] = (RAND_N(strength) - strength / 2) / 3;
115
+                }
116
+            } else {
117
+                if (flags & NOISE_PATTERN) {
118
+                    noise[i] = (RAND_N(strength) - strength / 2) / 2
119
+                        + patt[j % 4] * strength * 0.25;
120
+                } else {
121
+                    noise[i] = RAND_N(strength) - strength / 2;
122
+                }
123
+            }
124
+        } else {
125
+            double x1, x2, w, y1;
126
+            do {
127
+                x1 = 2.0 * rand() / (float)RAND_MAX - 1.0;
128
+                x2 = 2.0 * rand() / (float)RAND_MAX - 1.0;
129
+                w = x1 * x1 + x2 * x2;
130
+            } while (w >= 1.0);
131
+
132
+            w   = sqrt((-2.0 * log(w)) / w);
133
+            y1  = x1 * w;
134
+            y1 *= strength / sqrt(3.0);
135
+            if (flags & NOISE_PATTERN) {
136
+                y1 /= 2;
137
+                y1 += patt[j % 4] * strength * 0.35;
138
+            }
139
+            y1 = av_clipf(y1, -128, 127);
140
+            if (flags & NOISE_AVERAGED)
141
+                y1 /= 3.0;
142
+            noise[i] = (int)y1;
143
+        }
144
+        if (RAND_N(6) == 0)
145
+            j--;
146
+    }
147
+
148
+    for (i = 0; i < MAX_RES; i++)
149
+        for (j = 0; j < 3; j++)
150
+            fp->prev_shift[i][j] = noise + (rand() & (MAX_SHIFT - 1));
151
+
152
+    if (!n->rand_shift_init) {
153
+        for (i = 0; i < MAX_RES; i++)
154
+            n->rand_shift[i] = rand() & (MAX_SHIFT - 1);
155
+        n->rand_shift_init = 1;
156
+    }
157
+
158
+    fp->noise = noise;
159
+    fp->shiftptr = 0;
160
+    return 0;
161
+}
162
+
163
+static av_cold int init(AVFilterContext *ctx, const char *args)
164
+{
165
+    NoiseContext *n = ctx->priv;
166
+    int ret, i;
167
+
168
+    n->class = &noise_class;
169
+    av_opt_set_defaults(n);
170
+
171
+    if ((ret = av_set_options_string(n, args, "=", ":")) < 0)
172
+        return ret;
173
+
174
+    for (i = 0; i < 4; i++) {
175
+        if (n->all.seed >= 0)
176
+            n->param[i].seed = n->all.seed;
177
+        else
178
+            n->param[i].seed = 123457;
179
+        if (n->all.strength)
180
+            n->param[i].strength = n->all.strength;
181
+        if (n->all.flags)
182
+            n->param[i].flags = n->all.flags;
183
+    }
184
+
185
+    for (i = 0; i < 4; i++) {
186
+        if (n->param[i].strength && ((ret = init_noise(n, i)) < 0))
187
+            return ret;
188
+    }
189
+
190
+    return 0;
191
+}
192
+
193
+static int query_formats(AVFilterContext *ctx)
194
+{
195
+    AVFilterFormats *formats = NULL;
196
+    int fmt;
197
+
198
+    for (fmt = 0; fmt < AV_PIX_FMT_NB; fmt++) {
199
+        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
200
+        if (desc->flags & PIX_FMT_PLANAR && !((desc->comp[0].depth_minus1 + 1) & 7))
201
+            ff_add_format(&formats, fmt);
202
+    }
203
+
204
+    ff_set_common_formats(ctx, formats);
205
+    return 0;
206
+}
207
+
208
+static int config_input(AVFilterLink *inlink)
209
+{
210
+    NoiseContext *n = inlink->dst->priv;
211
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
212
+    int i, ret;
213
+
214
+    for (i = 0; i < desc->nb_components; i++)
215
+        n->nb_planes = FFMAX(n->nb_planes, desc->comp[i].plane);
216
+    n->nb_planes++;
217
+
218
+    if ((ret = av_image_fill_linesizes(n->linesize, inlink->format, inlink->w)) < 0)
219
+        return ret;
220
+
221
+    n->height[1] = n->height[2] = inlink->h >> desc->log2_chroma_h;
222
+    n->height[0] = n->height[3] = inlink->h;
223
+
224
+    return 0;
225
+}
226
+
227
+static void line_noise(uint8_t *dst, const uint8_t *src, int8_t *noise,
228
+                       int len, int shift)
229
+{
230
+    int i;
231
+
232
+    noise += shift;
233
+    for (i = 0; i < len; i++) {
234
+        int v = src[i] + noise[i];
235
+
236
+        dst[i] = av_clip_uint8(v);
237
+    }
238
+}
239
+
240
+static void line_noise_avg(uint8_t *dst, const uint8_t *src,
241
+                           int len, int8_t **shift)
242
+{
243
+    int i;
244
+    int8_t *src2 = (int8_t*)src;
245
+
246
+    for (i = 0; i < len; i++) {
247
+        const int n = shift[0][i] + shift[1][i] + shift[2][i];
248
+        dst[i] = src2[i] + ((n * src2[i]) >> 7);
249
+    }
250
+}
251
+
252
+static void noise(uint8_t *dst, const uint8_t *src,
253
+                  int dst_linesize, int src_linesize,
254
+                  int width, int height, NoiseContext *n, int comp)
255
+{
256
+    int8_t *noise = n->param[comp].noise;
257
+    int flags = n->param[comp].flags;
258
+    int shift, y;
259
+
260
+    if (!noise) {
261
+        if (dst != src) {
262
+            for (y = 0; y < height; y++) {
263
+                memcpy(dst, src, width);
264
+                dst += dst_linesize;
265
+                src += src_linesize;
266
+            }
267
+        }
268
+
269
+        return;
270
+    }
271
+
272
+    for (y = 0; y < height; y++) {
273
+        if (flags & NOISE_TEMPORAL)
274
+            shift = rand() & (MAX_SHIFT - 1);
275
+        else
276
+            shift = n->rand_shift[y];
277
+
278
+        if (!(flags & NOISE_QUALITY))
279
+            shift &= ~7;
280
+
281
+        if (flags & NOISE_AVERAGED) {
282
+            line_noise_avg(dst, src, width, n->param[comp].prev_shift[y]);
283
+            n->param[comp].prev_shift[y][n->param[comp].shiftptr] = noise + shift;
284
+        } else {
285
+            line_noise(dst, src, noise, width, shift);
286
+        }
287
+        dst += dst_linesize;
288
+        src += src_linesize;
289
+    }
290
+
291
+    n->param[comp].shiftptr++;
292
+    if (n->param[comp].shiftptr == 3)
293
+        n->param[comp].shiftptr = 0;
294
+}
295
+
296
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
297
+{
298
+    NoiseContext *n = inlink->dst->priv;
299
+    AVFilterLink *outlink = inlink->dst->outputs[0];
300
+    AVFilterBufferRef *out;
301
+    int ret, i;
302
+
303
+    if (inpicref->perms & AV_PERM_WRITE) {
304
+        out = inpicref;
305
+    } else {
306
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
307
+        if (!out) {
308
+            avfilter_unref_bufferp(&inpicref);
309
+            return AVERROR(ENOMEM);
310
+        }
311
+        avfilter_copy_buffer_ref_props(out, inpicref);
312
+    }
313
+
314
+    for (i = 0; i < n->nb_planes; i++)
315
+        noise(out->data[i], inpicref->data[i], out->linesize[i],
316
+              inpicref->linesize[i], n->linesize[i], n->height[i], n, i);
317
+
318
+    ret = ff_filter_frame(outlink, out);
319
+    if (inpicref != out)
320
+        avfilter_unref_buffer(inpicref);
321
+    return ret;
322
+}
323
+
324
+static av_cold void uninit(AVFilterContext *ctx)
325
+{
326
+    NoiseContext *n = ctx->priv;
327
+    int i;
328
+
329
+    for (i = 0; i < 4; i++)
330
+        av_freep(&n->param[i].noise);
331
+    av_opt_free(n);
332
+}
333
+
334
+static const AVFilterPad noise_inputs[] = {
335
+    {
336
+        .name             = "default",
337
+        .type             = AVMEDIA_TYPE_VIDEO,
338
+        .get_video_buffer = ff_null_get_video_buffer,
339
+        .filter_frame     = filter_frame,
340
+        .config_props     = config_input,
341
+        .min_perms        = AV_PERM_READ,
342
+    },
343
+    { NULL }
344
+};
345
+
346
+static const AVFilterPad noise_outputs[] = {
347
+    {
348
+        .name          = "default",
349
+        .type          = AVMEDIA_TYPE_VIDEO,
350
+    },
351
+    { NULL }
352
+};
353
+
354
+AVFilter avfilter_vf_noise = {
355
+    .name          = "noise",
356
+    .description   = NULL_IF_CONFIG_SMALL("Add noise."),
357
+    .priv_size     = sizeof(NoiseContext),
358
+    .init          = init,
359
+    .uninit        = uninit,
360
+    .query_formats = query_formats,
361
+    .inputs        = noise_inputs,
362
+    .outputs       = noise_outputs,
363
+    .priv_class    = &noise_class,
364
+};