GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/af_crystalizer.c Lines: 0 148 0.0 %
Date: 2020-10-23 17:01:47 Branches: 0 51 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}, 0, 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
    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
    float 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
    float 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 config_input(AVFilterLink *inlink)
224
{
225
    AVFilterContext *ctx = inlink->dst;
226
    CrystalizerContext *s = ctx->priv;
227
228
    switch (inlink->format) {
229
    case AV_SAMPLE_FMT_FLT:  s->filter = filter_flt;  break;
230
    case AV_SAMPLE_FMT_DBL:  s->filter = filter_dbl;  break;
231
    case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break;
232
    case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break;
233
    }
234
235
    return 0;
236
}
237
238
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
239
{
240
    AVFilterContext *ctx = inlink->dst;
241
    AVFilterLink *outlink = ctx->outputs[0];
242
    CrystalizerContext *s = ctx->priv;
243
    AVFrame *out;
244
    ThreadData td;
245
246
    if (!s->prev) {
247
        s->prev = ff_get_audio_buffer(inlink, 1);
248
        if (!s->prev) {
249
            av_frame_free(&in);
250
            return AVERROR(ENOMEM);
251
        }
252
    }
253
254
    if (av_frame_is_writable(in)) {
255
        out = in;
256
    } else {
257
        out = ff_get_audio_buffer(outlink, in->nb_samples);
258
        if (!out) {
259
            av_frame_free(&in);
260
            return AVERROR(ENOMEM);
261
        }
262
        av_frame_copy_props(out, in);
263
    }
264
265
    td.d = (void **)out->extended_data;
266
    td.s = (const void **)in->extended_data;
267
    td.p = (void **)s->prev->extended_data;
268
    td.nb_samples = in->nb_samples;
269
    td.channels = in->channels;
270
    td.mult = ctx->is_disabled ? 0.f : s->mult;
271
    td.clip = s->clip;
272
    ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN(inlink->channels,
273
                                                            ff_filter_get_nb_threads(ctx)));
274
275
    if (out != in)
276
        av_frame_free(&in);
277
278
    return ff_filter_frame(outlink, out);
279
}
280
281
static av_cold void uninit(AVFilterContext *ctx)
282
{
283
    CrystalizerContext *s = ctx->priv;
284
285
    av_frame_free(&s->prev);
286
}
287
288
static const AVFilterPad inputs[] = {
289
    {
290
        .name         = "default",
291
        .type         = AVMEDIA_TYPE_AUDIO,
292
        .filter_frame = filter_frame,
293
        .config_props = config_input,
294
    },
295
    { NULL }
296
};
297
298
static const AVFilterPad outputs[] = {
299
    {
300
        .name = "default",
301
        .type = AVMEDIA_TYPE_AUDIO,
302
    },
303
    { NULL }
304
};
305
306
AVFilter ff_af_crystalizer = {
307
    .name           = "crystalizer",
308
    .description    = NULL_IF_CONFIG_SMALL("Simple expand audio dynamic range filter."),
309
    .query_formats  = query_formats,
310
    .priv_size      = sizeof(CrystalizerContext),
311
    .priv_class     = &crystalizer_class,
312
    .uninit         = uninit,
313
    .inputs         = inputs,
314
    .outputs        = outputs,
315
    .process_command = ff_filter_process_command,
316
    .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
317
                      AVFILTER_FLAG_SLICE_THREADS,
318
};