GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/af_crystalizer.c Lines: 0 249 0.0 %
Date: 2021-04-15 16:04:23 Branches: 0 85 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 2016 The FFmpeg Project
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 CrystalizerContext {
28
    const AVClass *class;
29
    float mult;
30
    int clip;
31
    AVFrame *prev;
32
    int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
33
} CrystalizerContext;
34
35
#define OFFSET(x) offsetof(CrystalizerContext, x)
36
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
37
38
static const AVOption crystalizer_options[] = {
39
    { "i", "set intensity",    OFFSET(mult), AV_OPT_TYPE_FLOAT, {.dbl=2.0},-10, 10, A },
40
    { "c", "enable clipping",  OFFSET(clip), AV_OPT_TYPE_BOOL,  {.i64=1},   0,  1, A },
41
    { NULL }
42
};
43
44
AVFILTER_DEFINE_CLASS(crystalizer);
45
46
static int query_formats(AVFilterContext *ctx)
47
{
48
    AVFilterFormats *formats = NULL;
49
    AVFilterChannelLayouts *layouts = NULL;
50
    static const enum AVSampleFormat sample_fmts[] = {
51
        AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
52
        AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
53
        AV_SAMPLE_FMT_NONE
54
    };
55
    int ret;
56
57
    formats = ff_make_format_list(sample_fmts);
58
    if (!formats)
59
        return AVERROR(ENOMEM);
60
    ret = ff_set_common_formats(ctx, formats);
61
    if (ret < 0)
62
        return ret;
63
64
    layouts = ff_all_channel_counts();
65
    if (!layouts)
66
        return AVERROR(ENOMEM);
67
68
    ret = ff_set_common_channel_layouts(ctx, layouts);
69
    if (ret < 0)
70
        return ret;
71
72
    formats = ff_all_samplerates();
73
    return ff_set_common_samplerates(ctx, formats);
74
}
75
76
typedef struct ThreadData {
77
    void **d;
78
    void **p;
79
    const void **s;
80
    int nb_samples;
81
    int channels;
82
    float mult;
83
    int clip;
84
} ThreadData;
85
86
static int filter_flt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
87
{
88
    ThreadData *td = arg;
89
    void **d = td->d;
90
    void **p = td->p;
91
    const void **s = td->s;
92
    const int nb_samples = td->nb_samples;
93
    const int channels = td->channels;
94
    const float mult = td->mult;
95
    const int clip = td->clip;
96
    const int start = (channels * jobnr) / nb_jobs;
97
    const int end = (channels * (jobnr+1)) / nb_jobs;
98
    float *prv = p[0];
99
    int n, c;
100
101
    for (c = start; c < end; c++) {
102
        const float *src = s[0];
103
        float *dst = d[0];
104
105
        for (n = 0; n < nb_samples; n++) {
106
            float current = src[c];
107
            dst[c] = current + (current - prv[c]) * mult;
108
            prv[c] = current;
109
            if (clip) {
110
                dst[c] = av_clipf(dst[c], -1, 1);
111
            }
112
113
            dst += channels;
114
            src += channels;
115
        }
116
    }
117
118
    return 0;
119
}
120
121
static int filter_dbl(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
122
{
123
    ThreadData *td = arg;
124
    void **d = td->d;
125
    void **p = td->p;
126
    const void **s = td->s;
127
    const int nb_samples = td->nb_samples;
128
    const int channels = td->channels;
129
    double mult = td->mult;
130
    const int clip = td->clip;
131
    const int start = (channels * jobnr) / nb_jobs;
132
    const int end = (channels * (jobnr+1)) / nb_jobs;
133
    double *prv = p[0];
134
    int n, c;
135
136
    for (c = start; c < end; c++) {
137
        const double *src = s[0];
138
        double *dst = d[0];
139
140
        for (n = 0; n < nb_samples; n++) {
141
            double current = src[c];
142
143
            dst[c] = current + (current - prv[c]) * mult;
144
            prv[c] = current;
145
            if (clip) {
146
                dst[c] = av_clipd(dst[c], -1, 1);
147
            }
148
149
            dst += channels;
150
            src += channels;
151
        }
152
    }
153
154
    return 0;
155
}
156
157
static int filter_fltp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
158
{
159
    ThreadData *td = arg;
160
    void **d = td->d;
161
    void **p = td->p;
162
    const void **s = td->s;
163
    const int nb_samples = td->nb_samples;
164
    const int channels = td->channels;
165
    float mult = td->mult;
166
    const int clip = td->clip;
167
    const int start = (channels * jobnr) / nb_jobs;
168
    const int end = (channels * (jobnr+1)) / nb_jobs;
169
    int n, c;
170
171
    for (c = start; c < end; c++) {
172
        const float *src = s[c];
173
        float *dst = d[c];
174
        float *prv = p[c];
175
176
        for (n = 0; n < nb_samples; n++) {
177
            float current = src[n];
178
179
            dst[n] = current + (current - prv[0]) * mult;
180
            prv[0] = current;
181
            if (clip) {
182
                dst[n] = av_clipf(dst[n], -1, 1);
183
            }
184
        }
185
    }
186
187
    return 0;
188
}
189
190
static int filter_dblp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
191
{
192
    ThreadData *td = arg;
193
    void **d = td->d;
194
    void **p = td->p;
195
    const void **s = td->s;
196
    const int nb_samples = td->nb_samples;
197
    const int channels = td->channels;
198
    const double mult = td->mult;
199
    const int clip = td->clip;
200
    const int start = (channels * jobnr) / nb_jobs;
201
    const int end = (channels * (jobnr+1)) / nb_jobs;
202
    int n, c;
203
204
    for (c = start; c < end; c++) {
205
        const double *src = s[c];
206
        double *dst = d[c];
207
        double *prv = p[c];
208
209
        for (n = 0; n < nb_samples; n++) {
210
            double current = src[n];
211
212
            dst[n] = current + (current - prv[0]) * mult;
213
            prv[0] = current;
214
            if (clip) {
215
                dst[n] = av_clipd(dst[n], -1, 1);
216
            }
217
        }
218
    }
219
220
    return 0;
221
}
222
223
static int ifilter_flt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
224
{
225
    ThreadData *td = arg;
226
    void **d = td->d;
227
    void **p = td->p;
228
    const void **s = td->s;
229
    const int nb_samples = td->nb_samples;
230
    const int channels = td->channels;
231
    const float mult = -td->mult;
232
    const float div = -td->mult + 1.f;
233
    const int clip = td->clip;
234
    const int start = (channels * jobnr) / nb_jobs;
235
    const int end = (channels * (jobnr+1)) / nb_jobs;
236
    float *prv = p[0];
237
    int n, c;
238
239
    for (c = start; c < end; c++) {
240
        const float *src = s[0];
241
        float *dst = d[0];
242
243
        for (n = 0; n < nb_samples; n++) {
244
            float current = src[c];
245
            dst[c] = (current + prv[c] * mult) / div;
246
            prv[c] = dst[c];
247
            if (clip) {
248
                dst[c] = av_clipf(dst[c], -1, 1);
249
            }
250
251
            dst += channels;
252
            src += channels;
253
        }
254
    }
255
256
    return 0;
257
}
258
259
static int ifilter_dbl(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
260
{
261
    ThreadData *td = arg;
262
    void **d = td->d;
263
    void **p = td->p;
264
    const void **s = td->s;
265
    const int nb_samples = td->nb_samples;
266
    const int channels = td->channels;
267
    const double mult = -td->mult;
268
    const double div = -td->mult + 1.f;
269
    const int clip = td->clip;
270
    const int start = (channels * jobnr) / nb_jobs;
271
    const int end = (channels * (jobnr+1)) / nb_jobs;
272
    double *prv = p[0];
273
    int n, c;
274
275
    for (c = start; c < end; c++) {
276
        const double *src = s[0];
277
        double *dst = d[0];
278
279
        for (n = 0; n < nb_samples; n++) {
280
            double current = src[c];
281
282
            dst[c] = (current + prv[c] * mult) / div;
283
            prv[c] = dst[c];
284
            if (clip) {
285
                dst[c] = av_clipd(dst[c], -1, 1);
286
            }
287
288
            dst += channels;
289
            src += channels;
290
        }
291
    }
292
293
    return 0;
294
}
295
296
static int ifilter_fltp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
297
{
298
    ThreadData *td = arg;
299
    void **d = td->d;
300
    void **p = td->p;
301
    const void **s = td->s;
302
    const int nb_samples = td->nb_samples;
303
    const int channels = td->channels;
304
    const float mult = -td->mult;
305
    const float div = -td->mult + 1.f;
306
    const int clip = td->clip;
307
    const int start = (channels * jobnr) / nb_jobs;
308
    const int end = (channels * (jobnr+1)) / nb_jobs;
309
    int n, c;
310
311
    for (c = start; c < end; c++) {
312
        const float *src = s[c];
313
        float *dst = d[c];
314
        float *prv = p[c];
315
316
        for (n = 0; n < nb_samples; n++) {
317
            float current = src[n];
318
319
            dst[n] = (current + prv[0] * mult) / div;
320
            prv[0] = dst[n];
321
            if (clip) {
322
                dst[n] = av_clipf(dst[n], -1, 1);
323
            }
324
        }
325
    }
326
327
    return 0;
328
}
329
330
static int ifilter_dblp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
331
{
332
    ThreadData *td = arg;
333
    void **d = td->d;
334
    void **p = td->p;
335
    const void **s = td->s;
336
    const int nb_samples = td->nb_samples;
337
    const int channels = td->channels;
338
    const double mult = -td->mult;
339
    const double div = -td->mult + 1.f;
340
    const int clip = td->clip;
341
    const int start = (channels * jobnr) / nb_jobs;
342
    const int end = (channels * (jobnr+1)) / nb_jobs;
343
    int n, c;
344
345
    for (c = start; c < end; c++) {
346
        const double *src = s[c];
347
        double *dst = d[c];
348
        double *prv = p[c];
349
350
        for (n = 0; n < nb_samples; n++) {
351
            double current = src[n];
352
353
            dst[n] = (current + prv[0] * mult) / div;
354
            prv[0] = dst[n];
355
            if (clip) {
356
                dst[n] = av_clipd(dst[n], -1, 1);
357
            }
358
        }
359
    }
360
361
    return 0;
362
}
363
364
static int config_input(AVFilterLink *inlink)
365
{
366
    AVFilterContext *ctx = inlink->dst;
367
    CrystalizerContext *s = ctx->priv;
368
369
    switch (inlink->format) {
370
    case AV_SAMPLE_FMT_FLT:  s->filter = s->mult >= 0.f ? filter_flt  : ifilter_flt;  break;
371
    case AV_SAMPLE_FMT_DBL:  s->filter = s->mult >= 0.f ? filter_dbl  : ifilter_dbl;  break;
372
    case AV_SAMPLE_FMT_FLTP: s->filter = s->mult >= 0.f ? filter_fltp : ifilter_fltp; break;
373
    case AV_SAMPLE_FMT_DBLP: s->filter = s->mult >= 0.f ? filter_dblp : ifilter_dblp; break;
374
    }
375
376
    return 0;
377
}
378
379
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
380
{
381
    AVFilterContext *ctx = inlink->dst;
382
    AVFilterLink *outlink = ctx->outputs[0];
383
    CrystalizerContext *s = ctx->priv;
384
    AVFrame *out;
385
    ThreadData td;
386
387
    if (!s->prev) {
388
        s->prev = ff_get_audio_buffer(inlink, 1);
389
        if (!s->prev) {
390
            av_frame_free(&in);
391
            return AVERROR(ENOMEM);
392
        }
393
    }
394
395
    if (av_frame_is_writable(in)) {
396
        out = in;
397
    } else {
398
        out = ff_get_audio_buffer(outlink, in->nb_samples);
399
        if (!out) {
400
            av_frame_free(&in);
401
            return AVERROR(ENOMEM);
402
        }
403
        av_frame_copy_props(out, in);
404
    }
405
406
    td.d = (void **)out->extended_data;
407
    td.s = (const void **)in->extended_data;
408
    td.p = (void **)s->prev->extended_data;
409
    td.nb_samples = in->nb_samples;
410
    td.channels = in->channels;
411
    td.mult = ctx->is_disabled ? 0.f : s->mult;
412
    td.clip = s->clip;
413
    ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN(inlink->channels,
414
                                                            ff_filter_get_nb_threads(ctx)));
415
416
    if (out != in)
417
        av_frame_free(&in);
418
419
    return ff_filter_frame(outlink, out);
420
}
421
422
static av_cold void uninit(AVFilterContext *ctx)
423
{
424
    CrystalizerContext *s = ctx->priv;
425
426
    av_frame_free(&s->prev);
427
}
428
429
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
430
                           char *res, int res_len, int flags)
431
{
432
    int ret;
433
434
    ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
435
    if (ret < 0)
436
        return ret;
437
438
    return config_input(ctx->inputs[0]);
439
}
440
441
static const AVFilterPad inputs[] = {
442
    {
443
        .name         = "default",
444
        .type         = AVMEDIA_TYPE_AUDIO,
445
        .filter_frame = filter_frame,
446
        .config_props = config_input,
447
    },
448
    { NULL }
449
};
450
451
static const AVFilterPad outputs[] = {
452
    {
453
        .name = "default",
454
        .type = AVMEDIA_TYPE_AUDIO,
455
    },
456
    { NULL }
457
};
458
459
AVFilter ff_af_crystalizer = {
460
    .name           = "crystalizer",
461
    .description    = NULL_IF_CONFIG_SMALL("Simple audio noise sharpening filter."),
462
    .query_formats  = query_formats,
463
    .priv_size      = sizeof(CrystalizerContext),
464
    .priv_class     = &crystalizer_class,
465
    .uninit         = uninit,
466
    .inputs         = inputs,
467
    .outputs        = outputs,
468
    .process_command = process_command,
469
    .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
470
                      AVFILTER_FLAG_SLICE_THREADS,
471
};