Browse code

lavfi: add Bauer stereo-to-binaural audio filter

Signed-off-by: Anton Khirnov <anton@khirnov.net>

Alessandro Ghedini authored on 2014/04/30 01:53:16
Showing 7 changed files
... ...
@@ -24,6 +24,7 @@ version <next>:
24 24
 - Silicon Graphics Movie demuxer
25 25
 - On2 AVC (Audio for Video) decoder
26 26
 - support for decoding through DXVA2 in avconv
27
+- libbs2b-based stereo-to-binaural audio filter
27 28
 
28 29
 
29 30
 version 10:
... ...
@@ -178,6 +178,7 @@ External library support:
178 178
   --enable-bzlib           enable bzlib [autodetect]
179 179
   --enable-frei0r          enable frei0r video filtering
180 180
   --enable-gnutls          enable gnutls [no]
181
+  --enable-libbs2b         enable bs2b DSP library [no]
181 182
   --enable-libcdio         enable audio CD grabbing with libcdio
182 183
   --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394
183 184
                            and libraw1394 [no]
... ...
@@ -1124,6 +1125,7 @@ EXTERNAL_LIBRARY_LIST="
1124 1124
     bzlib
1125 1125
     frei0r
1126 1126
     gnutls
1127
+    libbs2b
1127 1128
     libcdio
1128 1129
     libdc1394
1129 1130
     libfaac
... ...
@@ -2085,6 +2087,7 @@ unix_protocol_select="network"
2085 2085
 # filters
2086 2086
 blackframe_filter_deps="gpl"
2087 2087
 boxblur_filter_deps="gpl"
2088
+bs2b_filter_deps="libbs2b"
2088 2089
 cropdetect_filter_deps="gpl"
2089 2090
 delogo_filter_deps="gpl"
2090 2091
 drawtext_filter_deps="libfreetype"
... ...
@@ -4027,6 +4030,7 @@ enabled avisynth          && { { check_header "avisynth/avisynth_c.h" && check_l
4027 4027
                                die "ERROR: LoadLibrary/dlopen not found, or avisynth header not found"; }
4028 4028
 enabled frei0r            && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; }
4029 4029
 enabled gnutls            && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
4030
+enabled libbs2b           && require_pkg_config libbs2b bs2b.h bs2b_open
4030 4031
 enabled libfaac           && require2 libfaac "stdint.h faac.h" faacEncGetVersion -lfaac
4031 4032
 enabled libfdk_aac        && require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac
4032 4033
 enabled libfontconfig     && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit
... ...
@@ -445,6 +445,36 @@ avconv -i INPUT -af atrim=end_sample=1000
445 445
 
446 446
 @end itemize
447 447
 
448
+@section bs2b
449
+Bauer stereo to binaural transformation, which improves headphone listening of
450
+stereo audio records.
451
+
452
+It accepts the following parameters:
453
+@table @option
454
+
455
+@item profile
456
+Pre-defined crossfeed level.
457
+@table @option
458
+
459
+@item default
460
+Default level (fcut=700, feed=50).
461
+
462
+@item cmoy
463
+Chu Moy circuit (fcut=700, feed=60).
464
+
465
+@item jmeier
466
+Jan Meier circuit (fcut=650, feed=95).
467
+
468
+@end table
469
+
470
+@item fcut
471
+Cut frequency (in Hz).
472
+
473
+@item feed
474
+Feed level (in Hz).
475
+
476
+@end table
477
+
448 478
 @section channelsplit
449 479
 Split each channel from an input audio stream into a separate output stream.
450 480
 
... ...
@@ -33,6 +33,7 @@ OBJS-$(CONFIG_ASHOWINFO_FILTER)              += af_ashowinfo.o
33 33
 OBJS-$(CONFIG_ASPLIT_FILTER)                 += split.o
34 34
 OBJS-$(CONFIG_ASYNCTS_FILTER)                += af_asyncts.o
35 35
 OBJS-$(CONFIG_ATRIM_FILTER)                  += trim.o
36
+OBJS-$(CONFIG_BS2B_FILTER)                   += af_bs2b.o
36 37
 OBJS-$(CONFIG_CHANNELMAP_FILTER)             += af_channelmap.o
37 38
 OBJS-$(CONFIG_CHANNELSPLIT_FILTER)           += af_channelsplit.o
38 39
 OBJS-$(CONFIG_COMPAND_FILTER)                += af_compand.o
39 40
new file mode 100644
... ...
@@ -0,0 +1,222 @@
0
+/*
1
+ * This file is part of Libav.
2
+ *
3
+ * Libav is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * Libav is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with Libav; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+/**
19
+ * @file
20
+ * Bauer stereo-to-binaural filter
21
+ */
22
+
23
+#include <bs2b.h>
24
+
25
+#include "libavutil/channel_layout.h"
26
+#include "libavutil/common.h"
27
+#include "libavutil/opt.h"
28
+
29
+#include "audio.h"
30
+#include "avfilter.h"
31
+#include "formats.h"
32
+#include "internal.h"
33
+
34
+typedef struct Bs2bContext {
35
+    const AVClass *class;
36
+
37
+    int profile;
38
+    int fcut;
39
+    int feed;
40
+
41
+    t_bs2bdp bs2bp;
42
+
43
+    void (*filter)(t_bs2bdp bs2bdp, uint8_t *sample, int n);
44
+} Bs2bContext;
45
+
46
+#define OFFSET(x) offsetof(Bs2bContext, x)
47
+#define A AV_OPT_FLAG_AUDIO_PARAM
48
+
49
+static const AVOption options[] = {
50
+    { "profile", "Apply a pre-defined crossfeed level",
51
+            OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = BS2B_DEFAULT_CLEVEL }, 0, INT_MAX, A, "profile" },
52
+        { "default", "default profile", 0, AV_OPT_TYPE_CONST, { .i64 = BS2B_DEFAULT_CLEVEL }, 0, 0, A, "profile" },
53
+        { "cmoy",    "Chu Moy circuit", 0, AV_OPT_TYPE_CONST, { .i64 = BS2B_CMOY_CLEVEL    }, 0, 0, A, "profile" },
54
+        { "jmeier",  "Jan Meier circuit", 0, AV_OPT_TYPE_CONST, { .i64 = BS2B_JMEIER_CLEVEL  }, 0, 0, A, "profile" },
55
+    { "fcut", "Set cut frequency (in Hz)",
56
+            OFFSET(fcut), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, BS2B_MAXFCUT, A },
57
+    { "feed", "Set feed level (in Hz)",
58
+            OFFSET(feed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, BS2B_MAXFEED, A },
59
+    { NULL },
60
+};
61
+
62
+static const AVClass bs2b_class = {
63
+    .class_name = "bs2b filter",
64
+    .item_name  = av_default_item_name,
65
+    .option     = options,
66
+    .version    = LIBAVUTIL_VERSION_INT,
67
+};
68
+
69
+static av_cold int init(AVFilterContext *ctx)
70
+{
71
+    Bs2bContext *bs2b = ctx->priv;
72
+
73
+    if (!(bs2b->bs2bp = bs2b_open()))
74
+        return AVERROR(ENOMEM);
75
+
76
+    bs2b_set_level(bs2b->bs2bp, bs2b->profile);
77
+
78
+    if (bs2b->fcut)
79
+        bs2b_set_level_fcut(bs2b->bs2bp, bs2b->fcut);
80
+
81
+    if (bs2b->feed)
82
+        bs2b_set_level_feed(bs2b->bs2bp, bs2b->feed);
83
+
84
+    return 0;
85
+}
86
+
87
+static av_cold void uninit(AVFilterContext *ctx)
88
+{
89
+    Bs2bContext *bs2b = ctx->priv;
90
+
91
+    if (bs2b->bs2bp)
92
+        bs2b_close(bs2b->bs2bp);
93
+}
94
+
95
+static int query_formats(AVFilterContext *ctx)
96
+{
97
+    AVFilterFormats *formats = NULL;
98
+    AVFilterChannelLayouts *layouts = NULL;
99
+
100
+    static const enum AVSampleFormat sample_fmts[] = {
101
+        AV_SAMPLE_FMT_U8,
102
+        AV_SAMPLE_FMT_S16,
103
+        AV_SAMPLE_FMT_S32,
104
+        AV_SAMPLE_FMT_FLT,
105
+        AV_SAMPLE_FMT_DBL,
106
+        AV_SAMPLE_FMT_NONE,
107
+    };
108
+
109
+    if (ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO) != 0)
110
+        return AVERROR(ENOMEM);
111
+    ff_set_common_channel_layouts(ctx, layouts);
112
+
113
+    formats = ff_make_format_list(sample_fmts);
114
+    if (!formats)
115
+        return AVERROR(ENOMEM);
116
+    ff_set_common_formats(ctx, formats);
117
+
118
+    formats = ff_all_samplerates();
119
+    if (!formats)
120
+        return AVERROR(ENOMEM);
121
+    ff_set_common_samplerates(ctx, formats);
122
+
123
+    return 0;
124
+}
125
+
126
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
127
+{
128
+    int ret;
129
+    AVFrame *out_frame;
130
+
131
+    Bs2bContext     *bs2b = inlink->dst->priv;
132
+    AVFilterLink *outlink = inlink->dst->outputs[0];
133
+
134
+    if (av_frame_is_writable(frame)) {
135
+        out_frame = frame;
136
+    } else {
137
+        out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
138
+        if (!out_frame)
139
+            return AVERROR(ENOMEM);
140
+        av_frame_copy(out_frame, frame);
141
+        ret = av_frame_copy_props(out_frame, frame);
142
+        if (ret < 0) {
143
+            av_frame_free(&out_frame);
144
+            av_frame_free(&frame);
145
+            return ret;
146
+        }
147
+    }
148
+
149
+    bs2b->filter(bs2b->bs2bp, out_frame->extended_data[0], out_frame->nb_samples);
150
+
151
+    if (frame != out_frame)
152
+        av_frame_free(&frame);
153
+
154
+    return ff_filter_frame(outlink, out_frame);
155
+}
156
+
157
+static int config_output(AVFilterLink *outlink)
158
+{
159
+    AVFilterContext *ctx = outlink->src;
160
+    Bs2bContext    *bs2b = ctx->priv;
161
+    AVFilterLink *inlink = ctx->inputs[0];
162
+
163
+    int srate = inlink->sample_rate;
164
+
165
+    switch (inlink->format) {
166
+    case AV_SAMPLE_FMT_U8:
167
+        bs2b->filter = bs2b_cross_feed_u8;
168
+        break;
169
+    case AV_SAMPLE_FMT_S16:
170
+        bs2b->filter = bs2b_cross_feed_s16;
171
+        break;
172
+    case AV_SAMPLE_FMT_S32:
173
+        bs2b->filter = bs2b_cross_feed_s32;
174
+        break;
175
+    case AV_SAMPLE_FMT_FLT:
176
+        bs2b->filter = bs2b_cross_feed_f;
177
+        break;
178
+    case AV_SAMPLE_FMT_DBL:
179
+        bs2b->filter = bs2b_cross_feed_d;
180
+        break;
181
+    default:
182
+        return AVERROR_BUG;
183
+    }
184
+
185
+    if ((srate < BS2B_MINSRATE) || (srate > BS2B_MAXSRATE))
186
+        return AVERROR(ENOSYS);
187
+
188
+    bs2b_set_srate(bs2b->bs2bp, srate);
189
+
190
+    return 0;
191
+}
192
+
193
+static const AVFilterPad bs2b_inputs[] = {
194
+    {
195
+        .name           = "default",
196
+        .type           = AVMEDIA_TYPE_AUDIO,
197
+        .filter_frame   = filter_frame,
198
+    },
199
+    { NULL }
200
+};
201
+
202
+static const AVFilterPad bs2b_outputs[] = {
203
+    {
204
+        .name           = "default",
205
+        .type           = AVMEDIA_TYPE_AUDIO,
206
+        .config_props   = config_output,
207
+    },
208
+    { NULL }
209
+};
210
+
211
+AVFilter ff_af_bs2b = {
212
+    .name           = "bs2b",
213
+    .description    = NULL_IF_CONFIG_SMALL("Bauer stereo-to-binaural filter."),
214
+    .query_formats  = query_formats,
215
+    .priv_size      = sizeof(Bs2bContext),
216
+    .priv_class     = &bs2b_class,
217
+    .init           = init,
218
+    .uninit         = uninit,
219
+    .inputs         = bs2b_inputs,
220
+    .outputs        = bs2b_outputs,
221
+};
... ...
@@ -53,6 +53,7 @@ void avfilter_register_all(void)
53 53
     REGISTER_FILTER(ASPLIT,         asplit,         af);
54 54
     REGISTER_FILTER(ASYNCTS,        asyncts,        af);
55 55
     REGISTER_FILTER(ATRIM,          atrim,          af);
56
+    REGISTER_FILTER(BS2B,           bs2b,           af);
56 57
     REGISTER_FILTER(CHANNELMAP,     channelmap,     af);
57 58
     REGISTER_FILTER(CHANNELSPLIT,   channelsplit,   af);
58 59
     REGISTER_FILTER(COMPAND,        compand,        af);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR  4
33
-#define LIBAVFILTER_VERSION_MINOR  4
33
+#define LIBAVFILTER_VERSION_MINOR  5
34 34
 #define LIBAVFILTER_VERSION_MICRO  0
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \