• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/channel_layout.h"
22 #include "libavutil/common.h"
23 #include "libavutil/float_dsp.h"
24 #include "libavutil/opt.h"
25 
26 #include "audio.h"
27 #include "avfilter.h"
28 #include "formats.h"
29 #include "filters.h"
30 #include "internal.h"
31 
32 typedef struct AudioMultiplyContext {
33     const AVClass *class;
34 
35     AVFrame *frames[2];
36     int planes;
37     int channels;
38     int samples_align;
39 
40     AVFloatDSPContext *fdsp;
41 } AudioMultiplyContext;
42 
activate(AVFilterContext * ctx)43 static int activate(AVFilterContext *ctx)
44 {
45     AudioMultiplyContext *s = ctx->priv;
46     int i, ret, status;
47     int nb_samples;
48     int64_t pts;
49 
50     FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
51 
52     nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[0]),
53                        ff_inlink_queued_samples(ctx->inputs[1]));
54     for (i = 0; i < ctx->nb_inputs && nb_samples > 0; i++) {
55         if (s->frames[i])
56             continue;
57 
58         if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) {
59             ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->frames[i]);
60             if (ret < 0)
61                 return ret;
62         }
63     }
64 
65     if (s->frames[0] && s->frames[1]) {
66         AVFrame *out;
67         int plane_samples;
68 
69         if (av_sample_fmt_is_planar(ctx->inputs[0]->format))
70             plane_samples = FFALIGN(s->frames[0]->nb_samples, s->samples_align);
71         else
72             plane_samples = FFALIGN(s->frames[0]->nb_samples * s->channels, s->samples_align);
73 
74         out = ff_get_audio_buffer(ctx->outputs[0], s->frames[0]->nb_samples);
75         if (!out)
76             return AVERROR(ENOMEM);
77 
78         out->pts = s->frames[0]->pts;
79 
80         if (av_get_packed_sample_fmt(ctx->inputs[0]->format) == AV_SAMPLE_FMT_FLT) {
81             for (i = 0; i < s->planes; i++) {
82                 s->fdsp->vector_fmul((float *)out->extended_data[i],
83                                      (const float *)s->frames[0]->extended_data[i],
84                                      (const float *)s->frames[1]->extended_data[i],
85                                      plane_samples);
86             }
87         } else {
88             for (i = 0; i < s->planes; i++) {
89                 s->fdsp->vector_dmul((double *)out->extended_data[i],
90                                      (const double *)s->frames[0]->extended_data[i],
91                                      (const double *)s->frames[1]->extended_data[i],
92                                      plane_samples);
93             }
94         }
95         emms_c();
96 
97         av_frame_free(&s->frames[0]);
98         av_frame_free(&s->frames[1]);
99 
100         ret = ff_filter_frame(ctx->outputs[0], out);
101         if (ret < 0)
102             return ret;
103     }
104 
105     if (!nb_samples) {
106         for (i = 0; i < 2; i++) {
107             if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
108                 ff_outlink_set_status(ctx->outputs[0], status, pts);
109                 return 0;
110             }
111         }
112     }
113 
114     if (ff_outlink_frame_wanted(ctx->outputs[0])) {
115         for (i = 0; i < 2; i++) {
116             if (ff_inlink_queued_samples(ctx->inputs[i]) > 0)
117                 continue;
118             ff_inlink_request_frame(ctx->inputs[i]);
119             return 0;
120         }
121     }
122     return 0;
123 }
124 
config_output(AVFilterLink * outlink)125 static int config_output(AVFilterLink *outlink)
126 {
127     AVFilterContext *ctx = outlink->src;
128     AudioMultiplyContext *s = ctx->priv;
129     AVFilterLink *inlink = ctx->inputs[0];
130 
131     s->channels = inlink->ch_layout.nb_channels;
132     s->planes = av_sample_fmt_is_planar(inlink->format) ? inlink->ch_layout.nb_channels : 1;
133     s->samples_align = 16;
134 
135     return 0;
136 }
137 
init(AVFilterContext * ctx)138 static av_cold int init(AVFilterContext *ctx)
139 {
140     AudioMultiplyContext *s = ctx->priv;
141 
142     s->fdsp = avpriv_float_dsp_alloc(0);
143     if (!s->fdsp)
144         return AVERROR(ENOMEM);
145 
146     return 0;
147 }
148 
uninit(AVFilterContext * ctx)149 static av_cold void uninit(AVFilterContext *ctx)
150 {
151     AudioMultiplyContext *s = ctx->priv;
152     av_freep(&s->fdsp);
153 }
154 
155 static const AVFilterPad inputs[] = {
156     {
157         .name = "multiply0",
158         .type = AVMEDIA_TYPE_AUDIO,
159     },
160     {
161         .name = "multiply1",
162         .type = AVMEDIA_TYPE_AUDIO,
163     },
164 };
165 
166 static const AVFilterPad outputs[] = {
167     {
168         .name         = "default",
169         .type         = AVMEDIA_TYPE_AUDIO,
170         .config_props = config_output,
171     },
172 };
173 
174 const AVFilter ff_af_amultiply = {
175     .name           = "amultiply",
176     .description    = NULL_IF_CONFIG_SMALL("Multiply two audio streams."),
177     .priv_size      = sizeof(AudioMultiplyContext),
178     .init           = init,
179     .uninit         = uninit,
180     .activate       = activate,
181     FILTER_INPUTS(inputs),
182     FILTER_OUTPUTS(outputs),
183     FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
184                       AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP),
185 };
186