]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_amultiply.c
Merge commit '37394ef01b040605f8e1c98e73aa12b1c0bcba07'
[ffmpeg] / libavfilter / af_amultiply.c
1 /*
2  * Copyright (c) 2018 Paul B Mahol
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/avassert.h"
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/common.h"
24 #include "libavutil/float_dsp.h"
25 #include "libavutil/opt.h"
26
27 #include "audio.h"
28 #include "avfilter.h"
29 #include "formats.h"
30 #include "filters.h"
31 #include "internal.h"
32
33 typedef struct AudioMultiplyContext {
34     const AVClass *class;
35
36     AVFrame *frames[2];
37     int64_t pts;
38     int planes;
39     int channels;
40     int samples_align;
41
42     AVFloatDSPContext *fdsp;
43 } AudioMultiplyContext;
44
45 static int query_formats(AVFilterContext *ctx)
46 {
47     AVFilterFormats *formats;
48     AVFilterChannelLayouts *layouts;
49     static const enum AVSampleFormat sample_fmts[] = {
50         AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
51         AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
52         AV_SAMPLE_FMT_NONE
53     };
54     int ret;
55
56     layouts = ff_all_channel_counts();
57     if (!layouts)
58         return AVERROR(ENOMEM);
59     ret = ff_set_common_channel_layouts(ctx, layouts);
60     if (ret < 0)
61         return ret;
62
63     formats = ff_make_format_list(sample_fmts);
64     if (!formats)
65         return AVERROR(ENOMEM);
66     ret = ff_set_common_formats(ctx, formats);
67     if (ret < 0)
68         return ret;
69
70     formats = ff_all_samplerates();
71     if (!formats)
72         return AVERROR(ENOMEM);
73     return ff_set_common_samplerates(ctx, formats);
74 }
75
76 static int activate(AVFilterContext *ctx)
77 {
78     AudioMultiplyContext *s = ctx->priv;
79     int i, ret, status;
80     int nb_samples;
81     int64_t pts;
82
83     FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
84
85     nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[0]),
86                        ff_inlink_queued_samples(ctx->inputs[1]));
87     for (i = 0; i < ctx->nb_inputs && nb_samples > 0; i++) {
88         if (s->frames[i])
89             continue;
90
91         if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) {
92             ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->frames[i]);
93             if (ret < 0)
94                 return ret;
95         }
96     }
97
98     if (nb_samples > 0 && s->frames[0] && s->frames[1]) {
99         AVFrame *out;
100         int plane_samples;
101
102         if (av_sample_fmt_is_planar(ctx->inputs[0]->format))
103             plane_samples = FFALIGN(nb_samples, s->samples_align);
104         else
105             plane_samples = FFALIGN(nb_samples * s->channels, s->samples_align);
106
107         out = ff_get_audio_buffer(ctx->outputs[0], nb_samples);
108         if (!out)
109             return AVERROR(ENOMEM);
110
111         out->pts = s->pts;
112         s->pts += nb_samples;
113
114         if (av_get_packed_sample_fmt(ctx->inputs[0]->format) == AV_SAMPLE_FMT_FLT) {
115             for (i = 0; i < s->planes; i++) {
116                 s->fdsp->vector_fmul((float *)out->extended_data[i],
117                                      (const float *)s->frames[0]->extended_data[i],
118                                      (const float *)s->frames[1]->extended_data[i],
119                                      plane_samples);
120             }
121         } else {
122             for (i = 0; i < s->planes; i++) {
123                 s->fdsp->vector_dmul((double *)out->extended_data[i],
124                                      (const double *)s->frames[0]->extended_data[i],
125                                      (const double *)s->frames[1]->extended_data[i],
126                                      plane_samples);
127             }
128         }
129         emms_c();
130
131         av_frame_free(&s->frames[0]);
132         av_frame_free(&s->frames[1]);
133
134         ret = ff_filter_frame(ctx->outputs[0], out);
135         if (ret < 0)
136             return ret;
137     }
138
139     if (!nb_samples) {
140         for (i = 0; i < 2; i++) {
141             if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
142                 ff_outlink_set_status(ctx->outputs[0], status, pts);
143                 return 0;
144             }
145         }
146     }
147
148     if (ff_outlink_frame_wanted(ctx->outputs[0])) {
149         for (i = 0; i < 2; i++) {
150             if (ff_inlink_queued_samples(ctx->inputs[i]) > 0)
151                 continue;
152             ff_inlink_request_frame(ctx->inputs[i]);
153             return 0;
154         }
155     }
156     return 0;
157 }
158
159 static int config_output(AVFilterLink *outlink)
160 {
161     AVFilterContext *ctx = outlink->src;
162     AudioMultiplyContext *s = ctx->priv;
163     AVFilterLink *inlink = ctx->inputs[0];
164
165     s->channels = inlink->channels;
166     s->planes = av_sample_fmt_is_planar(inlink->format) ? inlink->channels : 1;
167     s->samples_align = 16;
168
169     return 0;
170 }
171
172 static av_cold int init(AVFilterContext *ctx)
173 {
174     AudioMultiplyContext *s = ctx->priv;
175
176     s->fdsp = avpriv_float_dsp_alloc(0);
177     if (!s->fdsp)
178         return AVERROR(ENOMEM);
179
180     return 0;
181 }
182
183 static av_cold void uninit(AVFilterContext *ctx)
184 {
185     AudioMultiplyContext *s = ctx->priv;
186     av_freep(&s->fdsp);
187 }
188
189 static const AVFilterPad inputs[] = {
190     {
191         .name = "multiply0",
192         .type = AVMEDIA_TYPE_AUDIO,
193     },
194     {
195         .name = "multiply1",
196         .type = AVMEDIA_TYPE_AUDIO,
197     },
198     { NULL }
199 };
200
201 static const AVFilterPad outputs[] = {
202     {
203         .name         = "default",
204         .type         = AVMEDIA_TYPE_AUDIO,
205         .config_props = config_output,
206     },
207     { NULL }
208 };
209
210 AVFilter ff_af_amultiply = {
211     .name           = "amultiply",
212     .description    = NULL_IF_CONFIG_SMALL("Multiply two audio streams."),
213     .priv_size      = sizeof(AudioMultiplyContext),
214     .init           = init,
215     .uninit         = uninit,
216     .activate       = activate,
217     .query_formats  = query_formats,
218     .inputs         = inputs,
219     .outputs        = outputs,
220 };