Browse code

lavfi: rename asrc_aevalsrc.c to aeval.c

The file now contains both source and filter, the new name looks more
appropriate.

Stefano Sabatini authored on 2013/12/06 18:33:55
Showing 3 changed files
... ...
@@ -53,7 +53,7 @@ OBJS-$(CONFIG_AVCODEC)                       += avcodec.o
53 53
 OBJS-$(CONFIG_ACONVERT_FILTER)               += af_aconvert.o
54 54
 OBJS-$(CONFIG_ADELAY_FILTER)                 += af_adelay.o
55 55
 OBJS-$(CONFIG_AECHO_FILTER)                  += af_aecho.o
56
-OBJS-$(CONFIG_AEVAL_FILTER)                  += asrc_aevalsrc.o
56
+OBJS-$(CONFIG_AEVAL_FILTER)                  += aeval.o
57 57
 OBJS-$(CONFIG_AFADE_FILTER)                  += af_afade.o
58 58
 OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
59 59
 OBJS-$(CONFIG_AINTERLEAVE_FILTER)            += f_interleave.o
... ...
@@ -101,7 +101,7 @@ OBJS-$(CONFIG_TREBLE_FILTER)                 += af_biquads.o
101 101
 OBJS-$(CONFIG_VOLUME_FILTER)                 += af_volume.o
102 102
 OBJS-$(CONFIG_VOLUMEDETECT_FILTER)           += af_volumedetect.o
103 103
 
104
-OBJS-$(CONFIG_AEVALSRC_FILTER)               += asrc_aevalsrc.o
104
+OBJS-$(CONFIG_AEVALSRC_FILTER)               += aeval.o
105 105
 OBJS-$(CONFIG_ANULLSRC_FILTER)               += asrc_anullsrc.o
106 106
 OBJS-$(CONFIG_FLITE_FILTER)                  += asrc_flite.o
107 107
 OBJS-$(CONFIG_SINE_FILTER)                   += asrc_sine.o
108 108
new file mode 100644
... ...
@@ -0,0 +1,466 @@
0
+/*
1
+ * Copyright (c) 2011 Stefano Sabatini
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+/**
21
+ * @file
22
+ * eval audio source
23
+ */
24
+
25
+#include "libavutil/avassert.h"
26
+#include "libavutil/avstring.h"
27
+#include "libavutil/channel_layout.h"
28
+#include "libavutil/eval.h"
29
+#include "libavutil/opt.h"
30
+#include "libavutil/parseutils.h"
31
+#include "avfilter.h"
32
+#include "audio.h"
33
+#include "internal.h"
34
+
35
+static const char * const var_names[] = {
36
+    "ch",           ///< the value of the current channel
37
+    "n",            ///< number of frame
38
+    "nb_in_channels",
39
+    "nb_out_channels",
40
+    "t",            ///< timestamp expressed in seconds
41
+    "s",            ///< sample rate
42
+    NULL
43
+};
44
+
45
+enum var_name {
46
+    VAR_CH,
47
+    VAR_N,
48
+    VAR_NB_IN_CHANNELS,
49
+    VAR_NB_OUT_CHANNELS,
50
+    VAR_T,
51
+    VAR_S,
52
+    VAR_VARS_NB
53
+};
54
+
55
+typedef struct {
56
+    const AVClass *class;
57
+    char *sample_rate_str;
58
+    int sample_rate;
59
+    int64_t chlayout;
60
+    char *chlayout_str;
61
+    int nb_channels;            ///< number of output channels
62
+    int nb_in_channels;         ///< number of input channels
63
+    int same_chlayout;          ///< set output as input channel layout
64
+    int64_t pts;
65
+    AVExpr **expr;
66
+    char *exprs;
67
+    int nb_samples;             ///< number of samples per requested frame
68
+    int64_t duration;
69
+    uint64_t n;
70
+    double var_values[VAR_VARS_NB];
71
+    double *channel_values;
72
+    int64_t out_channel_layout;
73
+} EvalContext;
74
+
75
+static double val(void *priv, double ch)
76
+{
77
+    EvalContext *eval = priv;
78
+    return eval->channel_values[FFMIN((int)ch, eval->nb_in_channels-1)];
79
+}
80
+
81
+static double (* const aeval_func1[])(void *, double) = { val, NULL };
82
+static const char * const aeval_func1_names[] = { "val", NULL };
83
+
84
+#define OFFSET(x) offsetof(EvalContext, x)
85
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
86
+
87
+static const AVOption aevalsrc_options[]= {
88
+    { "exprs",       "set the '|'-separated list of channels expressions", OFFSET(exprs), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
89
+    { "nb_samples",  "set the number of samples per requested frame", OFFSET(nb_samples),      AV_OPT_TYPE_INT,    {.i64 = 1024},    0,        INT_MAX, FLAGS },
90
+    { "n",           "set the number of samples per requested frame", OFFSET(nb_samples),      AV_OPT_TYPE_INT,    {.i64 = 1024},    0,        INT_MAX, FLAGS },
91
+    { "sample_rate", "set the sample rate",                           OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX, FLAGS },
92
+    { "s",           "set the sample rate",                           OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX, FLAGS },
93
+    { "duration",    "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
94
+    { "d",           "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
95
+    { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
96
+    { "c",              "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
97
+    { NULL }
98
+};
99
+
100
+AVFILTER_DEFINE_CLASS(aevalsrc);
101
+
102
+static int parse_channel_expressions(AVFilterContext *ctx,
103
+                                     int expected_nb_channels)
104
+{
105
+    EvalContext *eval = ctx->priv;
106
+    char *args1 = av_strdup(eval->exprs);
107
+    char *expr, *last_expr, *buf;
108
+    double (* const *func1)(void *, double) = NULL;
109
+    const char * const *func1_names = NULL;
110
+    int i, ret = 0;
111
+
112
+    if (!args1)
113
+        return AVERROR(ENOMEM);
114
+
115
+    if (!eval->exprs) {
116
+        av_log(ctx, AV_LOG_ERROR, "Channels expressions list is empty\n");
117
+        return AVERROR(EINVAL);
118
+    }
119
+
120
+    if (!strcmp(ctx->filter->name, "aeval")) {
121
+        func1 = aeval_func1;
122
+        func1_names = aeval_func1_names;
123
+    }
124
+
125
+#define ADD_EXPRESSION(expr_) do {                                      \
126
+        if (!av_dynarray2_add((void **)&eval->expr, &eval->nb_channels, \
127
+                              sizeof(*eval->expr), NULL)) {             \
128
+            ret = AVERROR(ENOMEM);                                      \
129
+            goto end;                                                   \
130
+        }                                                               \
131
+        eval->expr[eval->nb_channels-1] = NULL;                         \
132
+        ret = av_expr_parse(&eval->expr[eval->nb_channels - 1], expr_,  \
133
+                            var_names, func1_names, func1,              \
134
+                            NULL, NULL, 0, ctx);                        \
135
+        if (ret < 0)                                                    \
136
+            goto end;                                                   \
137
+    } while (0)
138
+
139
+    /* reset expressions */
140
+    for (i = 0; i < eval->nb_channels; i++) {
141
+        av_expr_free(eval->expr[i]);
142
+        eval->expr[i] = NULL;
143
+    }
144
+    av_freep(&eval->expr);
145
+    eval->nb_channels = 0;
146
+
147
+    buf = args1;
148
+    while (expr = av_strtok(buf, "|", &buf)) {
149
+        ADD_EXPRESSION(expr);
150
+        last_expr = expr;
151
+    }
152
+
153
+    if (expected_nb_channels > eval->nb_channels)
154
+        for (i = eval->nb_channels; i < expected_nb_channels; i++)
155
+            ADD_EXPRESSION(last_expr);
156
+
157
+    if (expected_nb_channels > 0 && eval->nb_channels != expected_nb_channels) {
158
+        av_log(ctx, AV_LOG_ERROR,
159
+               "Mismatch between the specified number of channel expressions '%d' "
160
+               "and the number of expected output channels '%d' for the specified channel layout\n",
161
+               eval->nb_channels, expected_nb_channels);
162
+        ret = AVERROR(EINVAL);
163
+        goto end;
164
+    }
165
+
166
+end:
167
+    av_free(args1);
168
+    return ret;
169
+}
170
+
171
+static av_cold int init(AVFilterContext *ctx)
172
+{
173
+    EvalContext *eval = ctx->priv;
174
+    int ret;
175
+
176
+    if (eval->chlayout_str) {
177
+        if (!strcmp(eval->chlayout_str, "same") && !strcmp(ctx->filter->name, "aeval")) {
178
+            eval->same_chlayout = 1;
179
+        } else {
180
+            ret = ff_parse_channel_layout(&eval->chlayout, NULL, eval->chlayout_str, ctx);
181
+            if (ret < 0)
182
+                return ret;
183
+
184
+            ret = parse_channel_expressions(ctx, av_get_channel_layout_nb_channels(eval->chlayout));
185
+            if (ret < 0)
186
+                return ret;
187
+        }
188
+    } else {
189
+        /* guess channel layout from nb expressions/channels */
190
+        if ((ret = parse_channel_expressions(ctx, -1)) < 0)
191
+            return ret;
192
+
193
+        eval->chlayout = av_get_default_channel_layout(eval->nb_channels);
194
+        if (!eval->chlayout && eval->nb_channels <= 0) {
195
+            av_log(ctx, AV_LOG_ERROR, "Invalid number of channels '%d' provided\n",
196
+                   eval->nb_channels);
197
+            return AVERROR(EINVAL);
198
+        }
199
+    }
200
+
201
+    if (eval->sample_rate_str)
202
+        if ((ret = ff_parse_sample_rate(&eval->sample_rate, eval->sample_rate_str, ctx)))
203
+            return ret;
204
+    eval->n = 0;
205
+
206
+    return ret;
207
+}
208
+
209
+static av_cold void uninit(AVFilterContext *ctx)
210
+{
211
+    EvalContext *eval = ctx->priv;
212
+    int i;
213
+
214
+    for (i = 0; i < eval->nb_channels; i++) {
215
+        av_expr_free(eval->expr[i]);
216
+        eval->expr[i] = NULL;
217
+    }
218
+    av_freep(&eval->expr);
219
+}
220
+
221
+static int config_props(AVFilterLink *outlink)
222
+{
223
+    EvalContext *eval = outlink->src->priv;
224
+    char buf[128];
225
+
226
+    outlink->time_base = (AVRational){1, eval->sample_rate};
227
+    outlink->sample_rate = eval->sample_rate;
228
+
229
+    eval->var_values[VAR_S] = eval->sample_rate;
230
+    eval->var_values[VAR_NB_IN_CHANNELS] = NAN;
231
+    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
232
+
233
+    av_get_channel_layout_string(buf, sizeof(buf), 0, eval->chlayout);
234
+
235
+    av_log(outlink->src, AV_LOG_VERBOSE,
236
+           "sample_rate:%d chlayout:%s duration:%"PRId64"\n",
237
+           eval->sample_rate, buf, eval->duration);
238
+
239
+    return 0;
240
+}
241
+
242
+static int query_formats(AVFilterContext *ctx)
243
+{
244
+    EvalContext *eval = ctx->priv;
245
+    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE };
246
+    int64_t chlayouts[] = { eval->chlayout ? eval->chlayout : FF_COUNT2LAYOUT(eval->nb_channels) , -1 };
247
+    int sample_rates[] = { eval->sample_rate, -1 };
248
+
249
+    ff_set_common_formats (ctx, ff_make_format_list(sample_fmts));
250
+    ff_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts));
251
+    ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
252
+
253
+    return 0;
254
+}
255
+
256
+static int request_frame(AVFilterLink *outlink)
257
+{
258
+    EvalContext *eval = outlink->src->priv;
259
+    AVFrame *samplesref;
260
+    int i, j;
261
+    int64_t t = av_rescale(eval->n, AV_TIME_BASE, eval->sample_rate);
262
+
263
+    if (eval->duration >= 0 && t >= eval->duration)
264
+        return AVERROR_EOF;
265
+
266
+    samplesref = ff_get_audio_buffer(outlink, eval->nb_samples);
267
+    if (!samplesref)
268
+        return AVERROR(ENOMEM);
269
+
270
+    /* evaluate expression for each single sample and for each channel */
271
+    for (i = 0; i < eval->nb_samples; i++, eval->n++) {
272
+        eval->var_values[VAR_N] = eval->n;
273
+        eval->var_values[VAR_T] = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
274
+
275
+        for (j = 0; j < eval->nb_channels; j++) {
276
+            *((double *) samplesref->extended_data[j] + i) =
277
+                av_expr_eval(eval->expr[j], eval->var_values, NULL);
278
+        }
279
+    }
280
+
281
+    samplesref->pts = eval->pts;
282
+    samplesref->sample_rate = eval->sample_rate;
283
+    eval->pts += eval->nb_samples;
284
+
285
+    return ff_filter_frame(outlink, samplesref);
286
+}
287
+
288
+#if CONFIG_AEVALSRC_FILTER
289
+static const AVFilterPad aevalsrc_outputs[] = {
290
+    {
291
+        .name          = "default",
292
+        .type          = AVMEDIA_TYPE_AUDIO,
293
+        .config_props  = config_props,
294
+        .request_frame = request_frame,
295
+    },
296
+    { NULL }
297
+};
298
+
299
+AVFilter ff_asrc_aevalsrc = {
300
+    .name          = "aevalsrc",
301
+    .description   = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."),
302
+    .query_formats = query_formats,
303
+    .init          = init,
304
+    .uninit        = uninit,
305
+    .priv_size     = sizeof(EvalContext),
306
+    .inputs        = NULL,
307
+    .outputs       = aevalsrc_outputs,
308
+    .priv_class    = &aevalsrc_class,
309
+};
310
+
311
+#endif /* CONFIG_AEVALSRC_FILTER */
312
+
313
+#define OFFSET(x) offsetof(EvalContext, x)
314
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
315
+
316
+static const AVOption aeval_options[]= {
317
+    { "exprs", "set the '|'-separated list of channels expressions", OFFSET(exprs), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
318
+    { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
319
+    { "c",              "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
320
+    { NULL }
321
+};
322
+
323
+AVFILTER_DEFINE_CLASS(aeval);
324
+
325
+static int aeval_query_formats(AVFilterContext *ctx)
326
+{
327
+    AVFilterFormats *formats = NULL;
328
+    AVFilterChannelLayouts *layouts;
329
+    AVFilterLink *inlink  = ctx->inputs[0];
330
+    AVFilterLink *outlink  = ctx->outputs[0];
331
+    EvalContext *eval = ctx->priv;
332
+    static const enum AVSampleFormat sample_fmts[] = {
333
+        AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE
334
+    };
335
+
336
+    // inlink supports any channel layout
337
+    layouts = ff_all_channel_counts();
338
+    ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
339
+
340
+    if (eval->same_chlayout) {
341
+        layouts = ff_all_channel_counts();
342
+        if (!layouts)
343
+            return AVERROR(ENOMEM);
344
+            ff_set_common_channel_layouts(ctx, layouts);
345
+    } else {
346
+        // outlink supports only requested output channel layout
347
+        layouts = NULL;
348
+        ff_add_channel_layout(&layouts,
349
+                              eval->out_channel_layout ? eval->out_channel_layout :
350
+                              FF_COUNT2LAYOUT(eval->nb_channels));
351
+        ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
352
+    }
353
+
354
+    formats = ff_make_format_list(sample_fmts);
355
+    if (!formats)
356
+        return AVERROR(ENOMEM);
357
+    ff_set_common_formats(ctx, formats);
358
+
359
+    formats = ff_all_samplerates();
360
+    if (!formats)
361
+        return AVERROR(ENOMEM);
362
+    ff_set_common_samplerates(ctx, formats);
363
+
364
+    return 0;
365
+}
366
+
367
+static int aeval_config_output(AVFilterLink *outlink)
368
+{
369
+    AVFilterContext *ctx = outlink->src;
370
+    EvalContext *eval = ctx->priv;
371
+    AVFilterLink *inlink = ctx->inputs[0];
372
+    int ret;
373
+
374
+    if (eval->same_chlayout) {
375
+        eval->chlayout = inlink->channel_layout;
376
+
377
+        if ((ret = parse_channel_expressions(ctx, inlink->channels)) < 0)
378
+            return ret;
379
+    }
380
+
381
+    eval->n = 0;
382
+    eval->nb_in_channels = eval->var_values[VAR_NB_IN_CHANNELS] = inlink->channels;
383
+    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
384
+    eval->var_values[VAR_S] = inlink->sample_rate;
385
+    eval->var_values[VAR_T] = NAN;
386
+
387
+    eval->channel_values = av_realloc_f(eval->channel_values,
388
+                                        inlink->channels, sizeof(*eval->channel_values));
389
+    if (!eval->channel_values)
390
+        return AVERROR(ENOMEM);
391
+
392
+    return 0;
393
+}
394
+
395
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)*av_q2d(tb))
396
+
397
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
398
+{
399
+    EvalContext *eval     = inlink->dst->priv;
400
+    AVFilterLink *outlink = inlink->dst->outputs[0];
401
+    int nb_samples        = in->nb_samples;
402
+    AVFrame *out;
403
+    double t0;
404
+    int i, j;
405
+
406
+    /* do volume scaling in-place if input buffer is writable */
407
+    out = ff_get_audio_buffer(outlink, nb_samples);
408
+    if (!out)
409
+        return AVERROR(ENOMEM);
410
+    av_frame_copy_props(out, in);
411
+
412
+    t0 = TS2T(in->pts, inlink->time_base);
413
+
414
+    /* evaluate expression for each single sample and for each channel */
415
+    for (i = 0; i < nb_samples; i++, eval->n++) {
416
+        eval->var_values[VAR_N] = eval->n;
417
+        eval->var_values[VAR_T] = t0 + i * (double)1/inlink->sample_rate;
418
+
419
+        for (j = 0; j < inlink->channels; j++)
420
+            eval->channel_values[j] = *((double *) in->extended_data[j] + i);
421
+
422
+        for (j = 0; j < outlink->channels; j++) {
423
+            eval->var_values[VAR_CH] = j;
424
+            *((double *) out->extended_data[j] + i) =
425
+                av_expr_eval(eval->expr[j], eval->var_values, eval);
426
+        }
427
+    }
428
+
429
+    av_frame_free(&in);
430
+    return ff_filter_frame(outlink, out);
431
+}
432
+
433
+#if CONFIG_AEVAL_FILTER
434
+
435
+static const AVFilterPad aeval_inputs[] = {
436
+    {
437
+        .name           = "default",
438
+        .type           = AVMEDIA_TYPE_AUDIO,
439
+        .filter_frame   = filter_frame,
440
+    },
441
+    { NULL }
442
+};
443
+
444
+static const AVFilterPad aeval_outputs[] = {
445
+    {
446
+        .name          = "default",
447
+        .type          = AVMEDIA_TYPE_AUDIO,
448
+        .config_props  = aeval_config_output,
449
+    },
450
+    { NULL }
451
+};
452
+
453
+AVFilter ff_af_aeval = {
454
+    .name          = "aeval",
455
+    .description   = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."),
456
+    .query_formats = aeval_query_formats,
457
+    .init          = init,
458
+    .uninit        = uninit,
459
+    .priv_size     = sizeof(EvalContext),
460
+    .inputs        = aeval_inputs,
461
+    .outputs       = aeval_outputs,
462
+    .priv_class    = &aeval_class,
463
+};
464
+
465
+#endif /* CONFIG_AEVAL_FILTER */
0 466
deleted file mode 100644
... ...
@@ -1,466 +0,0 @@
1
-/*
2
- * Copyright (c) 2011 Stefano Sabatini
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
-/**
22
- * @file
23
- * eval audio source
24
- */
25
-
26
-#include "libavutil/avassert.h"
27
-#include "libavutil/avstring.h"
28
-#include "libavutil/channel_layout.h"
29
-#include "libavutil/eval.h"
30
-#include "libavutil/opt.h"
31
-#include "libavutil/parseutils.h"
32
-#include "avfilter.h"
33
-#include "audio.h"
34
-#include "internal.h"
35
-
36
-static const char * const var_names[] = {
37
-    "ch",           ///< the value of the current channel
38
-    "n",            ///< number of frame
39
-    "nb_in_channels",
40
-    "nb_out_channels",
41
-    "t",            ///< timestamp expressed in seconds
42
-    "s",            ///< sample rate
43
-    NULL
44
-};
45
-
46
-enum var_name {
47
-    VAR_CH,
48
-    VAR_N,
49
-    VAR_NB_IN_CHANNELS,
50
-    VAR_NB_OUT_CHANNELS,
51
-    VAR_T,
52
-    VAR_S,
53
-    VAR_VARS_NB
54
-};
55
-
56
-typedef struct {
57
-    const AVClass *class;
58
-    char *sample_rate_str;
59
-    int sample_rate;
60
-    int64_t chlayout;
61
-    char *chlayout_str;
62
-    int nb_channels;            ///< number of output channels
63
-    int nb_in_channels;         ///< number of input channels
64
-    int same_chlayout;          ///< set output as input channel layout
65
-    int64_t pts;
66
-    AVExpr **expr;
67
-    char *exprs;
68
-    int nb_samples;             ///< number of samples per requested frame
69
-    int64_t duration;
70
-    uint64_t n;
71
-    double var_values[VAR_VARS_NB];
72
-    double *channel_values;
73
-    int64_t out_channel_layout;
74
-} EvalContext;
75
-
76
-static double val(void *priv, double ch)
77
-{
78
-    EvalContext *eval = priv;
79
-    return eval->channel_values[FFMIN((int)ch, eval->nb_in_channels-1)];
80
-}
81
-
82
-static double (* const aeval_func1[])(void *, double) = { val, NULL };
83
-static const char * const aeval_func1_names[] = { "val", NULL };
84
-
85
-#define OFFSET(x) offsetof(EvalContext, x)
86
-#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
87
-
88
-static const AVOption aevalsrc_options[]= {
89
-    { "exprs",       "set the '|'-separated list of channels expressions", OFFSET(exprs), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
90
-    { "nb_samples",  "set the number of samples per requested frame", OFFSET(nb_samples),      AV_OPT_TYPE_INT,    {.i64 = 1024},    0,        INT_MAX, FLAGS },
91
-    { "n",           "set the number of samples per requested frame", OFFSET(nb_samples),      AV_OPT_TYPE_INT,    {.i64 = 1024},    0,        INT_MAX, FLAGS },
92
-    { "sample_rate", "set the sample rate",                           OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX, FLAGS },
93
-    { "s",           "set the sample rate",                           OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX, FLAGS },
94
-    { "duration",    "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
95
-    { "d",           "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
96
-    { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
97
-    { "c",              "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
98
-    { NULL }
99
-};
100
-
101
-AVFILTER_DEFINE_CLASS(aevalsrc);
102
-
103
-static int parse_channel_expressions(AVFilterContext *ctx,
104
-                                     int expected_nb_channels)
105
-{
106
-    EvalContext *eval = ctx->priv;
107
-    char *args1 = av_strdup(eval->exprs);
108
-    char *expr, *last_expr, *buf;
109
-    double (* const *func1)(void *, double) = NULL;
110
-    const char * const *func1_names = NULL;
111
-    int i, ret = 0;
112
-
113
-    if (!args1)
114
-        return AVERROR(ENOMEM);
115
-
116
-    if (!eval->exprs) {
117
-        av_log(ctx, AV_LOG_ERROR, "Channels expressions list is empty\n");
118
-        return AVERROR(EINVAL);
119
-    }
120
-
121
-    if (!strcmp(ctx->filter->name, "aeval")) {
122
-        func1 = aeval_func1;
123
-        func1_names = aeval_func1_names;
124
-    }
125
-
126
-#define ADD_EXPRESSION(expr_) do {                                      \
127
-        if (!av_dynarray2_add((void **)&eval->expr, &eval->nb_channels, \
128
-                              sizeof(*eval->expr), NULL)) {             \
129
-            ret = AVERROR(ENOMEM);                                      \
130
-            goto end;                                                   \
131
-        }                                                               \
132
-        eval->expr[eval->nb_channels-1] = NULL;                         \
133
-        ret = av_expr_parse(&eval->expr[eval->nb_channels - 1], expr_,  \
134
-                            var_names, func1_names, func1,              \
135
-                            NULL, NULL, 0, ctx);                        \
136
-        if (ret < 0)                                                    \
137
-            goto end;                                                   \
138
-    } while (0)
139
-
140
-    /* reset expressions */
141
-    for (i = 0; i < eval->nb_channels; i++) {
142
-        av_expr_free(eval->expr[i]);
143
-        eval->expr[i] = NULL;
144
-    }
145
-    av_freep(&eval->expr);
146
-    eval->nb_channels = 0;
147
-
148
-    buf = args1;
149
-    while (expr = av_strtok(buf, "|", &buf)) {
150
-        ADD_EXPRESSION(expr);
151
-        last_expr = expr;
152
-    }
153
-
154
-    if (expected_nb_channels > eval->nb_channels)
155
-        for (i = eval->nb_channels; i < expected_nb_channels; i++)
156
-            ADD_EXPRESSION(last_expr);
157
-
158
-    if (expected_nb_channels > 0 && eval->nb_channels != expected_nb_channels) {
159
-        av_log(ctx, AV_LOG_ERROR,
160
-               "Mismatch between the specified number of channel expressions '%d' "
161
-               "and the number of expected output channels '%d' for the specified channel layout\n",
162
-               eval->nb_channels, expected_nb_channels);
163
-        ret = AVERROR(EINVAL);
164
-        goto end;
165
-    }
166
-
167
-end:
168
-    av_free(args1);
169
-    return ret;
170
-}
171
-
172
-static av_cold int init(AVFilterContext *ctx)
173
-{
174
-    EvalContext *eval = ctx->priv;
175
-    int ret;
176
-
177
-    if (eval->chlayout_str) {
178
-        if (!strcmp(eval->chlayout_str, "same") && !strcmp(ctx->filter->name, "aeval")) {
179
-            eval->same_chlayout = 1;
180
-        } else {
181
-            ret = ff_parse_channel_layout(&eval->chlayout, NULL, eval->chlayout_str, ctx);
182
-            if (ret < 0)
183
-                return ret;
184
-
185
-            ret = parse_channel_expressions(ctx, av_get_channel_layout_nb_channels(eval->chlayout));
186
-            if (ret < 0)
187
-                return ret;
188
-        }
189
-    } else {
190
-        /* guess channel layout from nb expressions/channels */
191
-        if ((ret = parse_channel_expressions(ctx, -1)) < 0)
192
-            return ret;
193
-
194
-        eval->chlayout = av_get_default_channel_layout(eval->nb_channels);
195
-        if (!eval->chlayout && eval->nb_channels <= 0) {
196
-            av_log(ctx, AV_LOG_ERROR, "Invalid number of channels '%d' provided\n",
197
-                   eval->nb_channels);
198
-            return AVERROR(EINVAL);
199
-        }
200
-    }
201
-
202
-    if (eval->sample_rate_str)
203
-        if ((ret = ff_parse_sample_rate(&eval->sample_rate, eval->sample_rate_str, ctx)))
204
-            return ret;
205
-    eval->n = 0;
206
-
207
-    return ret;
208
-}
209
-
210
-static av_cold void uninit(AVFilterContext *ctx)
211
-{
212
-    EvalContext *eval = ctx->priv;
213
-    int i;
214
-
215
-    for (i = 0; i < eval->nb_channels; i++) {
216
-        av_expr_free(eval->expr[i]);
217
-        eval->expr[i] = NULL;
218
-    }
219
-    av_freep(&eval->expr);
220
-}
221
-
222
-static int config_props(AVFilterLink *outlink)
223
-{
224
-    EvalContext *eval = outlink->src->priv;
225
-    char buf[128];
226
-
227
-    outlink->time_base = (AVRational){1, eval->sample_rate};
228
-    outlink->sample_rate = eval->sample_rate;
229
-
230
-    eval->var_values[VAR_S] = eval->sample_rate;
231
-    eval->var_values[VAR_NB_IN_CHANNELS] = NAN;
232
-    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
233
-
234
-    av_get_channel_layout_string(buf, sizeof(buf), 0, eval->chlayout);
235
-
236
-    av_log(outlink->src, AV_LOG_VERBOSE,
237
-           "sample_rate:%d chlayout:%s duration:%"PRId64"\n",
238
-           eval->sample_rate, buf, eval->duration);
239
-
240
-    return 0;
241
-}
242
-
243
-static int query_formats(AVFilterContext *ctx)
244
-{
245
-    EvalContext *eval = ctx->priv;
246
-    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE };
247
-    int64_t chlayouts[] = { eval->chlayout ? eval->chlayout : FF_COUNT2LAYOUT(eval->nb_channels) , -1 };
248
-    int sample_rates[] = { eval->sample_rate, -1 };
249
-
250
-    ff_set_common_formats (ctx, ff_make_format_list(sample_fmts));
251
-    ff_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts));
252
-    ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
253
-
254
-    return 0;
255
-}
256
-
257
-static int request_frame(AVFilterLink *outlink)
258
-{
259
-    EvalContext *eval = outlink->src->priv;
260
-    AVFrame *samplesref;
261
-    int i, j;
262
-    int64_t t = av_rescale(eval->n, AV_TIME_BASE, eval->sample_rate);
263
-
264
-    if (eval->duration >= 0 && t >= eval->duration)
265
-        return AVERROR_EOF;
266
-
267
-    samplesref = ff_get_audio_buffer(outlink, eval->nb_samples);
268
-    if (!samplesref)
269
-        return AVERROR(ENOMEM);
270
-
271
-    /* evaluate expression for each single sample and for each channel */
272
-    for (i = 0; i < eval->nb_samples; i++, eval->n++) {
273
-        eval->var_values[VAR_N] = eval->n;
274
-        eval->var_values[VAR_T] = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
275
-
276
-        for (j = 0; j < eval->nb_channels; j++) {
277
-            *((double *) samplesref->extended_data[j] + i) =
278
-                av_expr_eval(eval->expr[j], eval->var_values, NULL);
279
-        }
280
-    }
281
-
282
-    samplesref->pts = eval->pts;
283
-    samplesref->sample_rate = eval->sample_rate;
284
-    eval->pts += eval->nb_samples;
285
-
286
-    return ff_filter_frame(outlink, samplesref);
287
-}
288
-
289
-#if CONFIG_AEVALSRC_FILTER
290
-static const AVFilterPad aevalsrc_outputs[] = {
291
-    {
292
-        .name          = "default",
293
-        .type          = AVMEDIA_TYPE_AUDIO,
294
-        .config_props  = config_props,
295
-        .request_frame = request_frame,
296
-    },
297
-    { NULL }
298
-};
299
-
300
-AVFilter ff_asrc_aevalsrc = {
301
-    .name          = "aevalsrc",
302
-    .description   = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."),
303
-    .query_formats = query_formats,
304
-    .init          = init,
305
-    .uninit        = uninit,
306
-    .priv_size     = sizeof(EvalContext),
307
-    .inputs        = NULL,
308
-    .outputs       = aevalsrc_outputs,
309
-    .priv_class    = &aevalsrc_class,
310
-};
311
-
312
-#endif /* CONFIG_AEVALSRC_FILTER */
313
-
314
-#define OFFSET(x) offsetof(EvalContext, x)
315
-#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
316
-
317
-static const AVOption aeval_options[]= {
318
-    { "exprs", "set the '|'-separated list of channels expressions", OFFSET(exprs), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
319
-    { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
320
-    { "c",              "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
321
-    { NULL }
322
-};
323
-
324
-AVFILTER_DEFINE_CLASS(aeval);
325
-
326
-static int aeval_query_formats(AVFilterContext *ctx)
327
-{
328
-    AVFilterFormats *formats = NULL;
329
-    AVFilterChannelLayouts *layouts;
330
-    AVFilterLink *inlink  = ctx->inputs[0];
331
-    AVFilterLink *outlink  = ctx->outputs[0];
332
-    EvalContext *eval = ctx->priv;
333
-    static const enum AVSampleFormat sample_fmts[] = {
334
-        AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE
335
-    };
336
-
337
-    // inlink supports any channel layout
338
-    layouts = ff_all_channel_counts();
339
-    ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
340
-
341
-    if (eval->same_chlayout) {
342
-        layouts = ff_all_channel_counts();
343
-        if (!layouts)
344
-            return AVERROR(ENOMEM);
345
-            ff_set_common_channel_layouts(ctx, layouts);
346
-    } else {
347
-        // outlink supports only requested output channel layout
348
-        layouts = NULL;
349
-        ff_add_channel_layout(&layouts,
350
-                              eval->out_channel_layout ? eval->out_channel_layout :
351
-                              FF_COUNT2LAYOUT(eval->nb_channels));
352
-        ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
353
-    }
354
-
355
-    formats = ff_make_format_list(sample_fmts);
356
-    if (!formats)
357
-        return AVERROR(ENOMEM);
358
-    ff_set_common_formats(ctx, formats);
359
-
360
-    formats = ff_all_samplerates();
361
-    if (!formats)
362
-        return AVERROR(ENOMEM);
363
-    ff_set_common_samplerates(ctx, formats);
364
-
365
-    return 0;
366
-}
367
-
368
-static int aeval_config_output(AVFilterLink *outlink)
369
-{
370
-    AVFilterContext *ctx = outlink->src;
371
-    EvalContext *eval = ctx->priv;
372
-    AVFilterLink *inlink = ctx->inputs[0];
373
-    int ret;
374
-
375
-    if (eval->same_chlayout) {
376
-        eval->chlayout = inlink->channel_layout;
377
-
378
-        if ((ret = parse_channel_expressions(ctx, inlink->channels)) < 0)
379
-            return ret;
380
-    }
381
-
382
-    eval->n = 0;
383
-    eval->nb_in_channels = eval->var_values[VAR_NB_IN_CHANNELS] = inlink->channels;
384
-    eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
385
-    eval->var_values[VAR_S] = inlink->sample_rate;
386
-    eval->var_values[VAR_T] = NAN;
387
-
388
-    eval->channel_values = av_realloc_f(eval->channel_values,
389
-                                        inlink->channels, sizeof(*eval->channel_values));
390
-    if (!eval->channel_values)
391
-        return AVERROR(ENOMEM);
392
-
393
-    return 0;
394
-}
395
-
396
-#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)*av_q2d(tb))
397
-
398
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
399
-{
400
-    EvalContext *eval     = inlink->dst->priv;
401
-    AVFilterLink *outlink = inlink->dst->outputs[0];
402
-    int nb_samples        = in->nb_samples;
403
-    AVFrame *out;
404
-    double t0;
405
-    int i, j;
406
-
407
-    /* do volume scaling in-place if input buffer is writable */
408
-    out = ff_get_audio_buffer(outlink, nb_samples);
409
-    if (!out)
410
-        return AVERROR(ENOMEM);
411
-    av_frame_copy_props(out, in);
412
-
413
-    t0 = TS2T(in->pts, inlink->time_base);
414
-
415
-    /* evaluate expression for each single sample and for each channel */
416
-    for (i = 0; i < nb_samples; i++, eval->n++) {
417
-        eval->var_values[VAR_N] = eval->n;
418
-        eval->var_values[VAR_T] = t0 + i * (double)1/inlink->sample_rate;
419
-
420
-        for (j = 0; j < inlink->channels; j++)
421
-            eval->channel_values[j] = *((double *) in->extended_data[j] + i);
422
-
423
-        for (j = 0; j < outlink->channels; j++) {
424
-            eval->var_values[VAR_CH] = j;
425
-            *((double *) out->extended_data[j] + i) =
426
-                av_expr_eval(eval->expr[j], eval->var_values, eval);
427
-        }
428
-    }
429
-
430
-    av_frame_free(&in);
431
-    return ff_filter_frame(outlink, out);
432
-}
433
-
434
-#if CONFIG_AEVAL_FILTER
435
-
436
-static const AVFilterPad aeval_inputs[] = {
437
-    {
438
-        .name           = "default",
439
-        .type           = AVMEDIA_TYPE_AUDIO,
440
-        .filter_frame   = filter_frame,
441
-    },
442
-    { NULL }
443
-};
444
-
445
-static const AVFilterPad aeval_outputs[] = {
446
-    {
447
-        .name          = "default",
448
-        .type          = AVMEDIA_TYPE_AUDIO,
449
-        .config_props  = aeval_config_output,
450
-    },
451
-    { NULL }
452
-};
453
-
454
-AVFilter ff_af_aeval = {
455
-    .name          = "aeval",
456
-    .description   = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."),
457
-    .query_formats = aeval_query_formats,
458
-    .init          = init,
459
-    .uninit        = uninit,
460
-    .priv_size     = sizeof(EvalContext),
461
-    .inputs        = aeval_inputs,
462
-    .outputs       = aeval_outputs,
463
-    .priv_class    = &aeval_class,
464
-};
465
-
466
-#endif /* CONFIG_AEVAL_FILTER */