]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_crystalizer.c
Merge commit '0676de935b1e81bc5b5698fef3e7d48ff2ea77ff'
[ffmpeg] / libavfilter / af_crystalizer.c
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     void (*filter)(void **dst, void **prv, const void **src,
33                    int nb_samples, int channels, float mult, int clip);
34 } CrystalizerContext;
35
36 #define OFFSET(x) offsetof(CrystalizerContext, x)
37 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
38
39 static const AVOption crystalizer_options[] = {
40     { "i", "set intensity",    OFFSET(mult), AV_OPT_TYPE_FLOAT, {.dbl=2.0}, 0, 10, A },
41     { "c", "enable clipping",  OFFSET(clip), AV_OPT_TYPE_BOOL,  {.i64=1},   0,  1, A },
42     { NULL }
43 };
44
45 AVFILTER_DEFINE_CLASS(crystalizer);
46
47 static int query_formats(AVFilterContext *ctx)
48 {
49     AVFilterFormats *formats = NULL;
50     AVFilterChannelLayouts *layouts = NULL;
51     static const enum AVSampleFormat sample_fmts[] = {
52         AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
53         AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
54         AV_SAMPLE_FMT_NONE
55     };
56     int ret;
57
58     formats = ff_make_format_list(sample_fmts);
59     if (!formats)
60         return AVERROR(ENOMEM);
61     ret = ff_set_common_formats(ctx, formats);
62     if (ret < 0)
63         return ret;
64
65     layouts = ff_all_channel_counts();
66     if (!layouts)
67         return AVERROR(ENOMEM);
68
69     ret = ff_set_common_channel_layouts(ctx, layouts);
70     if (ret < 0)
71         return ret;
72
73     formats = ff_all_samplerates();
74     return ff_set_common_samplerates(ctx, formats);
75 }
76
77 static void filter_flt(void **d, void **p, const void **s,
78                        int nb_samples, int channels,
79                        float mult, int clip)
80 {
81     const float *src = s[0];
82     float *dst = d[0];
83     float *prv = p[0];
84     int n, c;
85
86     for (n = 0; n < nb_samples; n++) {
87         for (c = 0; c < channels; c++) {
88             float current = src[c];
89
90             dst[c] = current + (current - prv[c]) * mult;
91             prv[c] = current;
92             if (clip) {
93                 dst[c] = av_clipf(dst[c], -1, 1);
94             }
95         }
96
97         dst += c;
98         src += c;
99     }
100 }
101
102 static void filter_dbl(void **d, void **p, const void **s,
103                        int nb_samples, int channels,
104                        float mult, int clip)
105 {
106     const double *src = s[0];
107     double *dst = d[0];
108     double *prv = p[0];
109     int n, c;
110
111     for (n = 0; n < nb_samples; n++) {
112         for (c = 0; c < channels; c++) {
113             double current = src[c];
114
115             dst[c] = current + (current - prv[c]) * mult;
116             prv[c] = current;
117             if (clip) {
118                 dst[c] = av_clipd(dst[c], -1, 1);
119             }
120         }
121
122         dst += c;
123         src += c;
124     }
125 }
126
127 static void filter_fltp(void **d, void **p, const void **s,
128                         int nb_samples, int channels,
129                         float mult, int clip)
130 {
131     int n, c;
132
133     for (c = 0; c < channels; c++) {
134         const float *src = s[c];
135         float *dst = d[c];
136         float *prv = p[c];
137
138         for (n = 0; n < nb_samples; n++) {
139             float current = src[n];
140
141             dst[n] = current + (current - prv[0]) * mult;
142             prv[0] = current;
143             if (clip) {
144                 dst[n] = av_clipf(dst[n], -1, 1);
145             }
146         }
147     }
148 }
149
150 static void filter_dblp(void **d, void **p, const void **s,
151                         int nb_samples, int channels,
152                         float mult, int clip)
153 {
154     int n, c;
155
156     for (c = 0; c < channels; c++) {
157         const double *src = s[c];
158         double *dst = d[c];
159         double *prv = p[c];
160
161         for (n = 0; n < nb_samples; n++) {
162             double current = src[n];
163
164             dst[n] = current + (current - prv[0]) * mult;
165             prv[0] = current;
166             if (clip) {
167                 dst[n] = av_clipd(dst[n], -1, 1);
168             }
169         }
170     }
171 }
172
173 static int config_input(AVFilterLink *inlink)
174 {
175     AVFilterContext *ctx = inlink->dst;
176     CrystalizerContext *s = ctx->priv;
177
178     switch (inlink->format) {
179     case AV_SAMPLE_FMT_FLT:  s->filter = filter_flt;  break;
180     case AV_SAMPLE_FMT_DBL:  s->filter = filter_dbl;  break;
181     case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break;
182     case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break;
183     }
184
185     return 0;
186 }
187
188 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
189 {
190     AVFilterContext *ctx = inlink->dst;
191     AVFilterLink *outlink = ctx->outputs[0];
192     CrystalizerContext *s = ctx->priv;
193     AVFrame *out;
194
195     if (!s->prev) {
196         s->prev = ff_get_audio_buffer(inlink, 1);
197         if (!s->prev) {
198             av_frame_free(&in);
199             return AVERROR(ENOMEM);
200         }
201     }
202
203     if (av_frame_is_writable(in)) {
204         out = in;
205     } else {
206         out = ff_get_audio_buffer(outlink, in->nb_samples);
207         if (!out) {
208             av_frame_free(&in);
209             return AVERROR(ENOMEM);
210         }
211         av_frame_copy_props(out, in);
212     }
213
214     s->filter((void **)out->extended_data, (void **)s->prev->extended_data, (const void **)in->extended_data,
215               in->nb_samples, in->channels, s->mult, s->clip);
216
217     if (out != in)
218         av_frame_free(&in);
219
220     return ff_filter_frame(outlink, out);
221 }
222
223 static av_cold void uninit(AVFilterContext *ctx)
224 {
225     CrystalizerContext *s = ctx->priv;
226
227     av_frame_free(&s->prev);
228 }
229
230 static const AVFilterPad inputs[] = {
231     {
232         .name         = "default",
233         .type         = AVMEDIA_TYPE_AUDIO,
234         .filter_frame = filter_frame,
235         .config_props = config_input,
236     },
237     { NULL }
238 };
239
240 static const AVFilterPad outputs[] = {
241     {
242         .name = "default",
243         .type = AVMEDIA_TYPE_AUDIO,
244     },
245     { NULL }
246 };
247
248 AVFilter ff_af_crystalizer = {
249     .name           = "crystalizer",
250     .description    = NULL_IF_CONFIG_SMALL("Simple expand audio dynamic range filter."),
251     .query_formats  = query_formats,
252     .priv_size      = sizeof(CrystalizerContext),
253     .priv_class     = &crystalizer_class,
254     .uninit         = uninit,
255     .inputs         = inputs,
256     .outputs        = outputs,
257 };