Browse code

avfilter: add stereowiden filter

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

Paul B Mahol authored on 2015/09/12 13:01:18
Showing 6 changed files
... ...
@@ -6,6 +6,7 @@ version <next>:
6 6
 - extrastereo filter
7 7
 - ocr filter
8 8
 - alimiter filter
9
+- stereowiden filter
9 10
 
10 11
 
11 12
 version 2.8:
... ...
@@ -2394,6 +2394,33 @@ silenceremove=1:5:0.02
2394 2394
 @end example
2395 2395
 @end itemize
2396 2396
 
2397
+@section stereowiden
2398
+
2399
+This filter enhance the stereo effect by suppressing signal common to both
2400
+channels and by delaying the signal of left into right and vice versa,
2401
+thereby widening the stereo effect.
2402
+
2403
+The filter accepts the following options:
2404
+
2405
+@table @option
2406
+@item delay
2407
+Time in milliseconds of the delay of left signal into right and vice versa.
2408
+Default is 20 milliseconds.
2409
+
2410
+@item feedback
2411
+Amount of gain in delayed signal into right and vice versa. Gives a delay
2412
+effect of left signal in right output and vice versa which gives widening
2413
+effect. Default is 0.3.
2414
+
2415
+@item crossfeed
2416
+Cross feed of left into right with inverted phase. This helps in suppressing
2417
+the mono. If the value is 1 it will cancel all the signal common to both
2418
+channels. Default is 0.3.
2419
+
2420
+@item drymix
2421
+Set level of input signal of original channel. Default is 0.8.
2422
+@end table
2423
+
2397 2424
 @section treble
2398 2425
 
2399 2426
 Boost or cut treble (upper) frequencies of the audio using a two-pole
... ...
@@ -80,6 +80,7 @@ OBJS-$(CONFIG_RESAMPLE_FILTER)               += af_resample.o
80 80
 OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER)      += af_sidechaincompress.o
81 81
 OBJS-$(CONFIG_SILENCEDETECT_FILTER)          += af_silencedetect.o
82 82
 OBJS-$(CONFIG_SILENCEREMOVE_FILTER)          += af_silenceremove.o
83
+OBJS-$(CONFIG_STEREOWIDEN_FILTER)            += af_stereowiden.o
83 84
 OBJS-$(CONFIG_TREBLE_FILTER)                 += af_biquads.o
84 85
 OBJS-$(CONFIG_VOLUME_FILTER)                 += af_volume.o
85 86
 OBJS-$(CONFIG_VOLUMEDETECT_FILTER)           += af_volumedetect.o
86 87
new file mode 100644
... ...
@@ -0,0 +1,167 @@
0
+/*
1
+ * Copyright (C) 2012 VLC authors and VideoLAN
2
+ * Author : Sukrit Sangwan < sukritsangwan at gmail dot com >
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 Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 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 GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along 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
+#include "libavutil/channel_layout.h"
22
+#include "libavutil/opt.h"
23
+#include "avfilter.h"
24
+#include "audio.h"
25
+#include "formats.h"
26
+
27
+typedef struct StereoWidenContext {
28
+    const AVClass *class;
29
+
30
+    float delay;
31
+    float feedback;
32
+    float crossfeed;
33
+    float drymix;
34
+
35
+    float *buffer;
36
+    float *write;
37
+    int length;
38
+} StereoWidenContext;
39
+
40
+#define OFFSET(x) offsetof(StereoWidenContext, x)
41
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
42
+
43
+static const AVOption stereowiden_options[] = {
44
+    { "delay",     "set delay time",    OFFSET(delay),     AV_OPT_TYPE_FLOAT, {.dbl=20}, 1, 100, A },
45
+    { "feedback",  "set feedback gain", OFFSET(feedback),  AV_OPT_TYPE_FLOAT, {.dbl=.3}, 0, 0.9, A },
46
+    { "crossfeed", "set cross feed",    OFFSET(crossfeed), AV_OPT_TYPE_FLOAT, {.dbl=.3}, 0, 0.8, A },
47
+    { "drymix",    "set dry-mix",       OFFSET(drymix),    AV_OPT_TYPE_FLOAT, {.dbl=.8}, 0, 1.0, A },
48
+    { NULL }
49
+};
50
+
51
+AVFILTER_DEFINE_CLASS(stereowiden);
52
+
53
+static int query_formats(AVFilterContext *ctx)
54
+{
55
+    AVFilterFormats *formats = NULL;
56
+    AVFilterChannelLayouts *layout = NULL;
57
+
58
+    ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
59
+    ff_set_common_formats(ctx, formats);
60
+    ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
61
+    ff_set_common_channel_layouts(ctx, layout);
62
+
63
+    formats = ff_all_samplerates();
64
+    if (!formats)
65
+        return AVERROR(ENOMEM);
66
+    return ff_set_common_samplerates(ctx, formats);
67
+}
68
+
69
+static int config_input(AVFilterLink *inlink)
70
+{
71
+    AVFilterContext *ctx = inlink->dst;
72
+    StereoWidenContext *s = ctx->priv;
73
+
74
+    s->length = 2 * s->delay * inlink->sample_rate / 1000;
75
+    s->buffer = av_calloc(s->length, sizeof(s->buffer));
76
+    if (!s->buffer)
77
+        return AVERROR(ENOMEM);
78
+    s->write = s->buffer;
79
+
80
+    return 0;
81
+}
82
+
83
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
84
+{
85
+    AVFilterContext *ctx = inlink->dst;
86
+    AVFilterLink *outlink = ctx->outputs[0];
87
+    StereoWidenContext *s = ctx->priv;
88
+    const float *src = (const float *)in->data[0];
89
+    const float drymix = s->drymix;
90
+    const float crossfeed = s->crossfeed;
91
+    const float feedback = s->feedback;
92
+    AVFrame *out = NULL;
93
+    float *dst;
94
+    int n;
95
+
96
+    if (av_frame_is_writable(in)) {
97
+        out = in;
98
+    } else {
99
+        AVFrame *out = ff_get_audio_buffer(inlink, in->nb_samples);
100
+        if (!out) {
101
+            av_frame_free(&in);
102
+            return AVERROR(ENOMEM);
103
+        }
104
+        av_frame_copy_props(out, in);
105
+    }
106
+    dst = (float *)out->data[0];
107
+
108
+    for (n = 0; n < in->nb_samples; n++, src += 2, dst += 2) {
109
+        const float left = src[0], right = src[1];
110
+        float *read = s->write + 2;
111
+
112
+        if (read > s->buffer + s->length)
113
+            read = s->buffer;
114
+
115
+        dst[0] = drymix * left - crossfeed * right - feedback * read[1];
116
+        dst[1] = drymix * right - crossfeed * left - feedback * read[0];
117
+
118
+        s->write[0] = left;
119
+        s->write[1] = right;
120
+
121
+        if (s->write == s->buffer + s->length)
122
+            s->write = s->buffer;
123
+        else
124
+            s->write += 2;
125
+    }
126
+
127
+    if (out != in)
128
+        av_frame_free(&in);
129
+    return ff_filter_frame(outlink, out);
130
+}
131
+
132
+static av_cold void uninit(AVFilterContext *ctx)
133
+{
134
+    StereoWidenContext *s = ctx->priv;
135
+
136
+    av_freep(&s->buffer);
137
+}
138
+
139
+static const AVFilterPad inputs[] = {
140
+    {
141
+        .name         = "default",
142
+        .type         = AVMEDIA_TYPE_AUDIO,
143
+        .filter_frame = filter_frame,
144
+        .config_props = config_input,
145
+    },
146
+    { NULL }
147
+};
148
+
149
+static const AVFilterPad outputs[] = {
150
+    {
151
+        .name = "default",
152
+        .type = AVMEDIA_TYPE_AUDIO,
153
+    },
154
+    { NULL }
155
+};
156
+
157
+AVFilter ff_af_stereowiden = {
158
+    .name           = "stereowiden",
159
+    .description    = NULL_IF_CONFIG_SMALL("Apply stereo widening effect."),
160
+    .query_formats  = query_formats,
161
+    .priv_size      = sizeof(StereoWidenContext),
162
+    .priv_class     = &stereowiden_class,
163
+    .uninit         = uninit,
164
+    .inputs         = inputs,
165
+    .outputs        = outputs,
166
+};
... ...
@@ -102,6 +102,7 @@ void avfilter_register_all(void)
102 102
     REGISTER_FILTER(SIDECHAINCOMPRESS, sidechaincompress, af);
103 103
     REGISTER_FILTER(SILENCEDETECT,  silencedetect,  af);
104 104
     REGISTER_FILTER(SILENCEREMOVE,  silenceremove,  af);
105
+    REGISTER_FILTER(STEREOWIDEN,    stereowiden,    af);
105 106
     REGISTER_FILTER(TREBLE,         treble,         af);
106 107
     REGISTER_FILTER(VOLUME,         volume,         af);
107 108
     REGISTER_FILTER(VOLUMEDETECT,   volumedetect,   af);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   6
33
-#define LIBAVFILTER_VERSION_MINOR   3
33
+#define LIBAVFILTER_VERSION_MINOR   4
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \