Browse code

avfilter: add rubberband wrapper

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

Paul B Mahol authored on 2015/09/19 05:22:05
Showing 7 changed files
... ...
@@ -8,6 +8,7 @@ version <next>:
8 8
 - alimiter filter
9 9
 - stereowiden filter
10 10
 - stereotools filter
11
+- rubberband filter
11 12
 
12 13
 
13 14
 version 2.8:
... ...
@@ -85,6 +85,7 @@ compatible libraries
85 85
 The following libraries are under GPL:
86 86
 - frei0r
87 87
 - libcdio
88
+- librubberband
88 89
 - libutvideo
89 90
 - libvidstab
90 91
 - libx264
... ...
@@ -236,6 +236,7 @@ External library support:
236 236
   --enable-libopenjpeg     enable JPEG 2000 de/encoding via OpenJPEG [no]
237 237
   --enable-libopus         enable Opus de/encoding via libopus [no]
238 238
   --enable-libpulse        enable Pulseaudio input via libpulse [no]
239
+  --enable-librubberband   enable rubberband needed for rubberband filter [no]
239 240
   --enable-libquvi         enable quvi input via libquvi [no]
240 241
   --enable-librtmp         enable RTMP[E] support via librtmp [no]
241 242
   --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no]
... ...
@@ -1405,6 +1406,7 @@ EXTERNAL_LIBRARY_LIST="
1405 1405
     libpulse
1406 1406
     libquvi
1407 1407
     librtmp
1408
+    librubberband
1408 1409
     libschroedinger
1409 1410
     libshine
1410 1411
     libsmbclient
... ...
@@ -2789,6 +2791,7 @@ pullup_filter_deps="gpl"
2789 2789
 removelogo_filter_deps="avcodec avformat swscale"
2790 2790
 repeatfields_filter_deps="gpl"
2791 2791
 resample_filter_deps="avresample"
2792
+rubberband_filter_deps="librubberband"
2792 2793
 sab_filter_deps="gpl swscale"
2793 2794
 scale_filter_deps="swscale"
2794 2795
 scale2ref_filter_deps="swscale"
... ...
@@ -4661,6 +4664,7 @@ die_license_disabled_gpl() {
4661 4661
 
4662 4662
 die_license_disabled gpl frei0r
4663 4663
 die_license_disabled gpl libcdio
4664
+die_license_disabled gpl librubberband
4664 4665
 die_license_disabled gpl libsmbclient
4665 4666
 die_license_disabled gpl libutvideo
4666 4667
 die_license_disabled gpl libvidstab
... ...
@@ -5271,6 +5275,7 @@ enabled libopus           && require_pkg_config opus opus_multistream.h opus_mul
5271 5271
 enabled libpulse          && require_pkg_config libpulse pulse/pulseaudio.h pa_context_new
5272 5272
 enabled libquvi           && require_pkg_config libquvi quvi/quvi.h quvi_init
5273 5273
 enabled librtmp           && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket
5274
+enabled librubberband     && require_pkg_config rubberband rubberband/rubberband-c.h rubberband_new
5274 5275
 enabled libschroedinger   && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init
5275 5276
 enabled libshine          && require_pkg_config shine shine/layer3.h shine_encode_buffer
5276 5277
 enabled libsmbclient      && { use_pkg_config smbclient libsmbclient.h smbc_init ||
... ...
@@ -77,6 +77,7 @@ OBJS-$(CONFIG_LOWPASS_FILTER)                += af_biquads.o
77 77
 OBJS-$(CONFIG_PAN_FILTER)                    += af_pan.o
78 78
 OBJS-$(CONFIG_REPLAYGAIN_FILTER)             += af_replaygain.o
79 79
 OBJS-$(CONFIG_RESAMPLE_FILTER)               += af_resample.o
80
+OBJS-$(CONFIG_RUBBERBAND_FILTER)             += af_rubberband.o
80 81
 OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER)      += af_sidechaincompress.o
81 82
 OBJS-$(CONFIG_SILENCEDETECT_FILTER)          += af_silencedetect.o
82 83
 OBJS-$(CONFIG_SILENCEREMOVE_FILTER)          += af_silenceremove.o
83 84
new file mode 100644
... ...
@@ -0,0 +1,236 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg 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
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include <rubberband/rubberband-c.h>
19
+
20
+#include "libavutil/channel_layout.h"
21
+#include "libavutil/common.h"
22
+#include "libavutil/opt.h"
23
+
24
+#include "audio.h"
25
+#include "avfilter.h"
26
+#include "formats.h"
27
+#include "internal.h"
28
+
29
+typedef struct RubberBandContext {
30
+    const AVClass *class;
31
+    RubberBandState rbs;
32
+
33
+    double tempo, pitch;
34
+    int transients, detector, phase, window,
35
+        smoothing, formant, opitch, channels;
36
+    int64_t nb_samples_out;
37
+    int64_t nb_samples_in;
38
+    int flushed;
39
+} RubberBandContext;
40
+
41
+#define OFFSET(x) offsetof(RubberBandContext, x)
42
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
43
+
44
+static const AVOption rubberband_options[] = {
45
+    { "tempo",      "set tempo scale factor", OFFSET(tempo), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, A },
46
+    { "pitch",      "set pitch scale factor", OFFSET(pitch), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, A },
47
+    { "transients", "set transients", OFFSET(transients), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "transients" },
48
+        { "crisp",  0,                0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsCrisp},  0, 0, A, "transients" },
49
+        { "mixed",  0,                0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsMixed},  0, 0, A, "transients" },
50
+        { "smooth", 0,                0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsSmooth}, 0, 0, A, "transients" },
51
+    { "detector",   "set detector",   OFFSET(detector),   AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "detector" },
52
+        { "compound",   0,            0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionDetectorCompound},   0, 0, A, "detector" },
53
+        { "percussive", 0,            0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionDetectorPercussive}, 0, 0, A, "detector" },
54
+        { "soft",       0,            0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionDetectorSoft},       0, 0, A, "detector" },
55
+    { "phase",      "set phase",      OFFSET(phase),      AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "phase" },
56
+        { "laminar",     0,           0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPhaseLaminar},     0, 0, A, "phase" },
57
+        { "independent", 0,           0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPhaseIndependent}, 0, 0, A, "phase" },
58
+    { "window",     "set window",     OFFSET(window),     AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "window" },
59
+        { "standard", 0,              0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionWindowStandard}, 0, 0, A, "window" },
60
+        { "short",    0,              0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionWindowShort},    0, 0, A, "window" },
61
+        { "long",     0,              0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionWindowLong},     0, 0, A, "window" },
62
+    { "smoothing",  "set smoothing",  OFFSET(smoothing),  AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "smoothing" },
63
+        { "off",    0,                0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionSmoothingOff}, 0, 0, A, "smoothing" },
64
+        { "on",     0,                0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionSmoothingOn},  0, 0, A, "smoothing" },
65
+    { "formant",    "set formant",    OFFSET(formant),    AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "formant" },
66
+        { "shifted",    0,            0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionFormantShifted},   0, 0, A, "formant" },
67
+        { "preserved",  0,            0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionFormantPreserved}, 0, 0, A, "formant" },
68
+    { "pitch",      "set pitch",      OFFSET(opitch),     AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "pitch" },
69
+        { "quality",     0,           0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPitchHighQuality},     0, 0, A, "pitch" },
70
+        { "speed",       0,           0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPitchHighSpeed},       0, 0, A, "pitch" },
71
+        { "consistency", 0,           0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionPitchHighConsistency}, 0, 0, A, "pitch" },
72
+    { "channels",   "set channels",   OFFSET(channels),   AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "channels" },
73
+        { "apart",    0,              0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionChannelsApart},    0, 0, A, "channels" },
74
+        { "together", 0,              0,                  AV_OPT_TYPE_CONST, {.i64=RubberBandOptionChannelsTogether}, 0, 0, A, "channels" },
75
+    { NULL },
76
+};
77
+
78
+AVFILTER_DEFINE_CLASS(rubberband);
79
+
80
+static av_cold void uninit(AVFilterContext *ctx)
81
+{
82
+    RubberBandContext *s = ctx->priv;
83
+
84
+    if (s->rbs)
85
+        rubberband_delete(s->rbs);
86
+}
87
+
88
+static int query_formats(AVFilterContext *ctx)
89
+{
90
+    AVFilterFormats *formats = NULL;
91
+    AVFilterChannelLayouts *layouts = NULL;
92
+    static const enum AVSampleFormat sample_fmts[] = {
93
+        AV_SAMPLE_FMT_FLTP,
94
+        AV_SAMPLE_FMT_NONE,
95
+    };
96
+    int ret;
97
+
98
+    layouts = ff_all_channel_counts();
99
+    if (!layouts)
100
+        return AVERROR(ENOMEM);
101
+    ret = ff_set_common_channel_layouts(ctx, layouts);
102
+    if (ret < 0)
103
+        return ret;
104
+
105
+    formats = ff_make_format_list(sample_fmts);
106
+    if (!formats)
107
+        return AVERROR(ENOMEM);
108
+    ret = ff_set_common_formats(ctx, formats);
109
+    if (ret < 0)
110
+        return ret;
111
+
112
+    formats = ff_all_samplerates();
113
+    if (!formats)
114
+        return AVERROR(ENOMEM);
115
+    return ff_set_common_samplerates(ctx, formats);
116
+}
117
+
118
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
119
+{
120
+    RubberBandContext *s = inlink->dst->priv;
121
+    AVFilterLink *outlink = inlink->dst->outputs[0];
122
+    AVFrame *out;
123
+    int ret = 0, nb_samples;
124
+
125
+    rubberband_process(s->rbs, (const float *const *)in->data, in->nb_samples, 0);
126
+    s->nb_samples_in += in->nb_samples;
127
+
128
+    nb_samples = rubberband_available(s->rbs);
129
+    if (nb_samples > 0) {
130
+        out = ff_get_audio_buffer(inlink, nb_samples);
131
+        if (!out) {
132
+            av_frame_free(&in);
133
+            return AVERROR(ENOMEM);
134
+        }
135
+        out->pts = av_rescale_q(s->nb_samples_out,
136
+                     (AVRational){ 1, outlink->sample_rate },
137
+                     outlink->time_base);
138
+        nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples);
139
+        out->nb_samples = nb_samples;
140
+        ret = ff_filter_frame(outlink, out);
141
+        s->nb_samples_out += nb_samples;
142
+    }
143
+
144
+    av_frame_free(&in);
145
+    return ret;
146
+}
147
+
148
+static int config_input(AVFilterLink *inlink)
149
+{
150
+    AVFilterContext *ctx = inlink->dst;
151
+    RubberBandContext *s = ctx->priv;
152
+    int opts = s->transients|s->detector|s->phase|s->window|
153
+               s->smoothing|s->formant|s->opitch|s->channels|
154
+               RubberBandOptionProcessRealTime;
155
+
156
+    if (s->rbs)
157
+        rubberband_delete(s->rbs);
158
+    s->rbs = rubberband_new(inlink->sample_rate, inlink->channels, opts, 1. / s->tempo, s->pitch);
159
+
160
+    inlink->partial_buf_size =
161
+    inlink->min_samples =
162
+    inlink->max_samples = rubberband_get_samples_required(s->rbs);
163
+
164
+    return 0;
165
+}
166
+
167
+static int request_frame(AVFilterLink *outlink)
168
+{
169
+    AVFilterContext *ctx = outlink->src;
170
+    RubberBandContext *s = ctx->priv;
171
+    AVFilterLink *inlink = ctx->inputs[0];
172
+    int ret = 0;
173
+
174
+    ret = ff_request_frame(ctx->inputs[0]);
175
+
176
+    if (ret == AVERROR_EOF && !s->flushed) {
177
+        AVFrame *out = ff_get_audio_buffer(inlink, 1);
178
+        int nb_samples;
179
+
180
+        if (!out)
181
+            return AVERROR(ENOMEM);
182
+
183
+        rubberband_process(s->rbs, (const float *const *)out->data, 1, 1);
184
+        av_frame_free(&out);
185
+        s->flushed = 1;
186
+        nb_samples = rubberband_available(s->rbs);
187
+
188
+        if (nb_samples > 0) {
189
+            out = ff_get_audio_buffer(inlink, nb_samples);
190
+            if (!out)
191
+                return AVERROR(ENOMEM);
192
+            out->pts = av_rescale_q(s->nb_samples_out,
193
+                         (AVRational){ 1, outlink->sample_rate },
194
+                         outlink->time_base);
195
+            nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples);
196
+            out->nb_samples = nb_samples;
197
+            ret = ff_filter_frame(outlink, out);
198
+            s->nb_samples_out += nb_samples;
199
+        }
200
+        av_log(ctx, AV_LOG_DEBUG, "nb_samples_in %"PRId64" nb_samples_out %"PRId64"\n",
201
+                                   s->nb_samples_in, s->nb_samples_out);
202
+    }
203
+
204
+    return ret;
205
+}
206
+
207
+static const AVFilterPad rubberband_inputs[] = {
208
+    {
209
+        .name          = "default",
210
+        .type          = AVMEDIA_TYPE_AUDIO,
211
+        .config_props  = config_input,
212
+        .filter_frame  = filter_frame,
213
+    },
214
+    { NULL }
215
+};
216
+
217
+static const AVFilterPad rubberband_outputs[] = {
218
+    {
219
+        .name          = "default",
220
+        .type          = AVMEDIA_TYPE_AUDIO,
221
+        .request_frame = request_frame,
222
+    },
223
+    { NULL }
224
+};
225
+
226
+AVFilter ff_af_rubberband = {
227
+    .name          = "rubberband",
228
+    .description   = NULL_IF_CONFIG_SMALL("Apply time-stretching and pitch-shifting."),
229
+    .query_formats = query_formats,
230
+    .priv_size     = sizeof(RubberBandContext),
231
+    .priv_class    = &rubberband_class,
232
+    .uninit        = uninit,
233
+    .inputs        = rubberband_inputs,
234
+    .outputs       = rubberband_outputs,
235
+};
... ...
@@ -99,6 +99,7 @@ void avfilter_register_all(void)
99 99
     REGISTER_FILTER(PAN,            pan,            af);
100 100
     REGISTER_FILTER(REPLAYGAIN,     replaygain,     af);
101 101
     REGISTER_FILTER(RESAMPLE,       resample,       af);
102
+    REGISTER_FILTER(RUBBERBAND,     rubberband,     af);
102 103
     REGISTER_FILTER(SIDECHAINCOMPRESS, sidechaincompress, af);
103 104
     REGISTER_FILTER(SILENCEDETECT,  silencedetect,  af);
104 105
     REGISTER_FILTER(SILENCEREMOVE,  silenceremove,  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   5
33
+#define LIBAVFILTER_VERSION_MINOR   6
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \