Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2013 Paul B Mahol | |
3 | * Copyright (c) 2011 Mina Nagy Zaki | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | /** | |
23 | * @file | |
24 | * LADSPA wrapper | |
25 | */ | |
26 | ||
27 | #include <dlfcn.h> | |
28 | #include <ladspa.h> | |
29 | #include "libavutil/avstring.h" | |
30 | #include "libavutil/channel_layout.h" | |
31 | #include "libavutil/opt.h" | |
32 | #include "audio.h" | |
33 | #include "avfilter.h" | |
34 | #include "internal.h" | |
35 | ||
36 | typedef struct LADSPAContext { | |
37 | const AVClass *class; | |
38 | char *dl_name; | |
39 | char *plugin; | |
40 | char *options; | |
41 | void *dl_handle; | |
42 | ||
43 | unsigned long nb_inputs; | |
44 | unsigned long *ipmap; /* map input number to port number */ | |
45 | ||
46 | unsigned long nb_inputcontrols; | |
47 | unsigned long *icmap; /* map input control number to port number */ | |
48 | LADSPA_Data *ictlv; /* input controls values */ | |
49 | ||
50 | unsigned long nb_outputs; | |
51 | unsigned long *opmap; /* map output number to port number */ | |
52 | ||
53 | unsigned long nb_outputcontrols; | |
54 | unsigned long *ocmap; /* map output control number to port number */ | |
55 | LADSPA_Data *octlv; /* output controls values */ | |
56 | ||
57 | const LADSPA_Descriptor *desc; | |
58 | int *ctl_needs_value; | |
59 | int nb_handles; | |
60 | LADSPA_Handle *handles; | |
61 | ||
62 | int sample_rate; | |
63 | int nb_samples; | |
64 | int64_t pts; | |
65 | int64_t duration; | |
66 | } LADSPAContext; | |
67 | ||
68 | #define OFFSET(x) offsetof(LADSPAContext, x) | |
69 | #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |
70 | static const AVOption ladspa_options[] = { | |
71 | { "file", "set library name or full path", OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS }, | |
72 | { "f", "set library name or full path", OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS }, | |
73 | { "plugin", "set plugin name", OFFSET(plugin), AV_OPT_TYPE_STRING, .flags = FLAGS }, | |
74 | { "p", "set plugin name", OFFSET(plugin), AV_OPT_TYPE_STRING, .flags = FLAGS }, | |
75 | { "controls", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS }, | |
76 | { "c", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS }, | |
77 | { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS }, | |
78 | { "s", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS }, | |
79 | { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, | |
80 | { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, | |
81 | { "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, | |
82 | { "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, | |
83 | { NULL } | |
84 | }; | |
85 | ||
86 | AVFILTER_DEFINE_CLASS(ladspa); | |
87 | ||
88 | static void print_ctl_info(AVFilterContext *ctx, int level, | |
89 | LADSPAContext *s, int ctl, unsigned long *map, | |
90 | LADSPA_Data *values, int print) | |
91 | { | |
92 | const LADSPA_PortRangeHint *h = s->desc->PortRangeHints + map[ctl]; | |
93 | ||
94 | av_log(ctx, level, "c%i: %s [", ctl, s->desc->PortNames[map[ctl]]); | |
95 | ||
96 | if (LADSPA_IS_HINT_TOGGLED(h->HintDescriptor)) { | |
97 | av_log(ctx, level, "toggled (1 or 0)"); | |
98 | ||
99 | if (LADSPA_IS_HINT_HAS_DEFAULT(h->HintDescriptor)) | |
100 | av_log(ctx, level, " (default %i)", (int)values[ctl]); | |
101 | } else { | |
102 | if (LADSPA_IS_HINT_INTEGER(h->HintDescriptor)) { | |
103 | av_log(ctx, level, "<int>"); | |
104 | ||
105 | if (LADSPA_IS_HINT_BOUNDED_BELOW(h->HintDescriptor)) | |
106 | av_log(ctx, level, ", min: %i", (int)h->LowerBound); | |
107 | ||
108 | if (LADSPA_IS_HINT_BOUNDED_ABOVE(h->HintDescriptor)) | |
109 | av_log(ctx, level, ", max: %i", (int)h->UpperBound); | |
110 | ||
111 | if (print) | |
112 | av_log(ctx, level, " (value %d)", (int)values[ctl]); | |
113 | else if (LADSPA_IS_HINT_HAS_DEFAULT(h->HintDescriptor)) | |
114 | av_log(ctx, level, " (default %d)", (int)values[ctl]); | |
115 | } else { | |
116 | av_log(ctx, level, "<float>"); | |
117 | ||
118 | if (LADSPA_IS_HINT_BOUNDED_BELOW(h->HintDescriptor)) | |
119 | av_log(ctx, level, ", min: %f", h->LowerBound); | |
120 | ||
121 | if (LADSPA_IS_HINT_BOUNDED_ABOVE(h->HintDescriptor)) | |
122 | av_log(ctx, level, ", max: %f", h->UpperBound); | |
123 | ||
124 | if (print) | |
125 | av_log(ctx, level, " (value %f)", values[ctl]); | |
126 | else if (LADSPA_IS_HINT_HAS_DEFAULT(h->HintDescriptor)) | |
127 | av_log(ctx, level, " (default %f)", values[ctl]); | |
128 | } | |
129 | ||
130 | if (LADSPA_IS_HINT_SAMPLE_RATE(h->HintDescriptor)) | |
131 | av_log(ctx, level, ", multiple of sample rate"); | |
132 | ||
133 | if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor)) | |
134 | av_log(ctx, level, ", logarithmic scale"); | |
135 | } | |
136 | ||
137 | av_log(ctx, level, "]\n"); | |
138 | } | |
139 | ||
140 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |
141 | { | |
142 | AVFilterContext *ctx = inlink->dst; | |
143 | LADSPAContext *s = ctx->priv; | |
144 | AVFrame *out; | |
145 | int i, h; | |
146 | ||
147 | if (!s->nb_outputs || | |
148 | (av_frame_is_writable(in) && s->nb_inputs == s->nb_outputs && | |
149 | !(s->desc->Properties & LADSPA_PROPERTY_INPLACE_BROKEN))) { | |
150 | out = in; | |
151 | } else { | |
152 | out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples); | |
153 | if (!out) { | |
154 | av_frame_free(&in); | |
155 | return AVERROR(ENOMEM); | |
156 | } | |
157 | av_frame_copy_props(out, in); | |
158 | } | |
159 | ||
160 | for (h = 0; h < s->nb_handles; h++) { | |
161 | for (i = 0; i < s->nb_inputs; i++) { | |
162 | s->desc->connect_port(s->handles[h], s->ipmap[i], | |
163 | (LADSPA_Data*)in->extended_data[i]); | |
164 | } | |
165 | ||
166 | for (i = 0; i < s->nb_outputs; i++) { | |
167 | s->desc->connect_port(s->handles[h], s->opmap[i], | |
168 | (LADSPA_Data*)out->extended_data[i]); | |
169 | } | |
170 | ||
171 | s->desc->run(s->handles[h], in->nb_samples); | |
172 | } | |
173 | ||
174 | for (i = 0; i < s->nb_outputcontrols; i++) | |
175 | print_ctl_info(ctx, AV_LOG_VERBOSE, s, i, s->ocmap, s->octlv, 1); | |
176 | ||
177 | if (out != in) | |
178 | av_frame_free(&in); | |
179 | ||
180 | return ff_filter_frame(ctx->outputs[0], out); | |
181 | } | |
182 | ||
183 | static int request_frame(AVFilterLink *outlink) | |
184 | { | |
185 | AVFilterContext *ctx = outlink->src; | |
186 | LADSPAContext *s = ctx->priv; | |
187 | AVFrame *out; | |
188 | int64_t t; | |
189 | int i; | |
190 | ||
191 | if (ctx->nb_inputs) | |
192 | return ff_request_frame(ctx->inputs[0]); | |
193 | ||
194 | t = av_rescale(s->pts, AV_TIME_BASE, s->sample_rate); | |
195 | if (s->duration >= 0 && t >= s->duration) | |
196 | return AVERROR_EOF; | |
197 | ||
198 | out = ff_get_audio_buffer(outlink, s->nb_samples); | |
199 | if (!out) | |
200 | return AVERROR(ENOMEM); | |
201 | ||
202 | for (i = 0; i < s->nb_outputs; i++) | |
203 | s->desc->connect_port(s->handles[0], s->opmap[i], | |
204 | (LADSPA_Data*)out->extended_data[i]); | |
205 | ||
206 | s->desc->run(s->handles[0], s->nb_samples); | |
207 | ||
208 | for (i = 0; i < s->nb_outputcontrols; i++) | |
209 | print_ctl_info(ctx, AV_LOG_INFO, s, i, s->ocmap, s->octlv, 1); | |
210 | ||
211 | out->sample_rate = s->sample_rate; | |
212 | out->pts = s->pts; | |
213 | s->pts += s->nb_samples; | |
214 | ||
215 | return ff_filter_frame(outlink, out); | |
216 | } | |
217 | ||
218 | static void set_default_ctl_value(LADSPAContext *s, int ctl, | |
219 | unsigned long *map, LADSPA_Data *values) | |
220 | { | |
221 | const LADSPA_PortRangeHint *h = s->desc->PortRangeHints + map[ctl]; | |
222 | const LADSPA_Data lower = h->LowerBound; | |
223 | const LADSPA_Data upper = h->UpperBound; | |
224 | ||
225 | if (LADSPA_IS_HINT_DEFAULT_MINIMUM(h->HintDescriptor)) { | |
226 | values[ctl] = lower; | |
227 | } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(h->HintDescriptor)) { | |
228 | values[ctl] = upper; | |
229 | } else if (LADSPA_IS_HINT_DEFAULT_0(h->HintDescriptor)) { | |
230 | values[ctl] = 0.0; | |
231 | } else if (LADSPA_IS_HINT_DEFAULT_1(h->HintDescriptor)) { | |
232 | values[ctl] = 1.0; | |
233 | } else if (LADSPA_IS_HINT_DEFAULT_100(h->HintDescriptor)) { | |
234 | values[ctl] = 100.0; | |
235 | } else if (LADSPA_IS_HINT_DEFAULT_440(h->HintDescriptor)) { | |
236 | values[ctl] = 440.0; | |
237 | } else if (LADSPA_IS_HINT_DEFAULT_LOW(h->HintDescriptor)) { | |
238 | if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor)) | |
239 | values[ctl] = exp(log(lower) * 0.75 + log(upper) * 0.25); | |
240 | else | |
241 | values[ctl] = lower * 0.75 + upper * 0.25; | |
242 | } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(h->HintDescriptor)) { | |
243 | if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor)) | |
244 | values[ctl] = exp(log(lower) * 0.5 + log(upper) * 0.5); | |
245 | else | |
246 | values[ctl] = lower * 0.5 + upper * 0.5; | |
247 | } else if (LADSPA_IS_HINT_DEFAULT_HIGH(h->HintDescriptor)) { | |
248 | if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor)) | |
249 | values[ctl] = exp(log(lower) * 0.25 + log(upper) * 0.75); | |
250 | else | |
251 | values[ctl] = lower * 0.25 + upper * 0.75; | |
252 | } | |
253 | } | |
254 | ||
255 | static int connect_ports(AVFilterContext *ctx, AVFilterLink *link) | |
256 | { | |
257 | LADSPAContext *s = ctx->priv; | |
258 | int i, j; | |
259 | ||
260 | s->nb_handles = s->nb_inputs == 1 && s->nb_outputs == 1 ? link->channels : 1; | |
261 | s->handles = av_calloc(s->nb_handles, sizeof(*s->handles)); | |
262 | if (!s->handles) | |
263 | return AVERROR(ENOMEM); | |
264 | ||
265 | for (i = 0; i < s->nb_handles; i++) { | |
266 | s->handles[i] = s->desc->instantiate(s->desc, link->sample_rate); | |
267 | if (!s->handles[i]) { | |
268 | av_log(ctx, AV_LOG_ERROR, "Could not instantiate plugin.\n"); | |
269 | return AVERROR_EXTERNAL; | |
270 | } | |
271 | ||
272 | // Connect the input control ports | |
273 | for (j = 0; j < s->nb_inputcontrols; j++) | |
274 | s->desc->connect_port(s->handles[i], s->icmap[j], s->ictlv + j); | |
275 | ||
276 | // Connect the output control ports | |
277 | for (j = 0; j < s->nb_outputcontrols; j++) | |
278 | s->desc->connect_port(s->handles[i], s->ocmap[j], &s->octlv[j]); | |
279 | ||
280 | if (s->desc->activate) | |
281 | s->desc->activate(s->handles[i]); | |
282 | } | |
283 | ||
284 | av_log(ctx, AV_LOG_DEBUG, "handles: %d\n", s->nb_handles); | |
285 | ||
286 | return 0; | |
287 | } | |
288 | ||
289 | static int config_input(AVFilterLink *inlink) | |
290 | { | |
291 | AVFilterContext *ctx = inlink->dst; | |
292 | ||
293 | return connect_ports(ctx, inlink); | |
294 | } | |
295 | ||
296 | static int config_output(AVFilterLink *outlink) | |
297 | { | |
298 | AVFilterContext *ctx = outlink->src; | |
299 | int ret; | |
300 | ||
301 | if (ctx->nb_inputs) { | |
302 | AVFilterLink *inlink = ctx->inputs[0]; | |
303 | ||
304 | outlink->format = inlink->format; | |
305 | outlink->sample_rate = inlink->sample_rate; | |
306 | ||
307 | ret = 0; | |
308 | } else { | |
309 | LADSPAContext *s = ctx->priv; | |
310 | ||
311 | outlink->sample_rate = s->sample_rate; | |
312 | outlink->time_base = (AVRational){1, s->sample_rate}; | |
313 | ||
314 | ret = connect_ports(ctx, outlink); | |
315 | } | |
316 | ||
317 | return ret; | |
318 | } | |
319 | ||
320 | static void count_ports(const LADSPA_Descriptor *desc, | |
321 | unsigned long *nb_inputs, unsigned long *nb_outputs) | |
322 | { | |
323 | LADSPA_PortDescriptor pd; | |
324 | int i; | |
325 | ||
326 | for (i = 0; i < desc->PortCount; i++) { | |
327 | pd = desc->PortDescriptors[i]; | |
328 | ||
329 | if (LADSPA_IS_PORT_AUDIO(pd)) { | |
330 | if (LADSPA_IS_PORT_INPUT(pd)) { | |
331 | (*nb_inputs)++; | |
332 | } else if (LADSPA_IS_PORT_OUTPUT(pd)) { | |
333 | (*nb_outputs)++; | |
334 | } | |
335 | } | |
336 | } | |
337 | } | |
338 | ||
339 | static void *try_load(const char *dir, const char *soname) | |
340 | { | |
341 | char *path = av_asprintf("%s/%s.so", dir, soname); | |
342 | void *ret = NULL; | |
343 | ||
344 | if (path) { | |
345 | ret = dlopen(path, RTLD_LOCAL|RTLD_NOW); | |
346 | av_free(path); | |
347 | } | |
348 | ||
349 | return ret; | |
350 | } | |
351 | ||
352 | static int set_control(AVFilterContext *ctx, unsigned long port, LADSPA_Data value) | |
353 | { | |
354 | LADSPAContext *s = ctx->priv; | |
355 | const char *label = s->desc->Label; | |
356 | LADSPA_PortRangeHint *h = (LADSPA_PortRangeHint *)s->desc->PortRangeHints + | |
357 | s->icmap[port]; | |
358 | ||
359 | if (port >= s->nb_inputcontrols) { | |
360 | av_log(ctx, AV_LOG_ERROR, "Control c%ld is out of range [0 - %lu].\n", | |
361 | port, s->nb_inputcontrols); | |
362 | return AVERROR(EINVAL); | |
363 | } | |
364 | ||
365 | if (LADSPA_IS_HINT_BOUNDED_BELOW(h->HintDescriptor) && | |
366 | value < h->LowerBound) { | |
367 | av_log(ctx, AV_LOG_ERROR, | |
368 | "%s: input control c%ld is below lower boundary of %0.4f.\n", | |
369 | label, port, h->LowerBound); | |
370 | return AVERROR(EINVAL); | |
371 | } | |
372 | ||
373 | if (LADSPA_IS_HINT_BOUNDED_ABOVE(h->HintDescriptor) && | |
374 | value > h->UpperBound) { | |
375 | av_log(ctx, AV_LOG_ERROR, | |
376 | "%s: input control c%ld is above upper boundary of %0.4f.\n", | |
377 | label, port, h->UpperBound); | |
378 | return AVERROR(EINVAL); | |
379 | } | |
380 | ||
381 | s->ictlv[port] = value; | |
382 | ||
383 | return 0; | |
384 | } | |
385 | ||
386 | static av_cold int init(AVFilterContext *ctx) | |
387 | { | |
388 | LADSPAContext *s = ctx->priv; | |
389 | LADSPA_Descriptor_Function descriptor_fn; | |
390 | const LADSPA_Descriptor *desc; | |
391 | LADSPA_PortDescriptor pd; | |
392 | AVFilterPad pad = { NULL }; | |
393 | char *p, *arg, *saveptr = NULL; | |
394 | unsigned long nb_ports; | |
395 | int i; | |
396 | ||
397 | if (!s->dl_name) { | |
398 | av_log(ctx, AV_LOG_ERROR, "No plugin name provided\n"); | |
399 | return AVERROR(EINVAL); | |
400 | } | |
401 | ||
402 | if (s->dl_name[0] == '/' || s->dl_name[0] == '.') { | |
403 | // argument is a path | |
404 | s->dl_handle = dlopen(s->dl_name, RTLD_LOCAL|RTLD_NOW); | |
405 | } else { | |
406 | // argument is a shared object name | |
407 | char *paths = av_strdup(getenv("LADSPA_PATH")); | |
408 | const char *separator = ":"; | |
409 | ||
410 | if (paths) { | |
411 | p = paths; | |
412 | while ((arg = av_strtok(p, separator, &saveptr)) && !s->dl_handle) { | |
413 | s->dl_handle = try_load(arg, s->dl_name); | |
414 | p = NULL; | |
415 | } | |
416 | } | |
417 | ||
418 | av_free(paths); | |
419 | if (!s->dl_handle && (paths = av_asprintf("%s/.ladspa/lib", getenv("HOME")))) { | |
420 | s->dl_handle = try_load(paths, s->dl_name); | |
421 | av_free(paths); | |
422 | } | |
423 | ||
424 | if (!s->dl_handle) | |
425 | s->dl_handle = try_load("/usr/local/lib/ladspa", s->dl_name); | |
426 | ||
427 | if (!s->dl_handle) | |
428 | s->dl_handle = try_load("/usr/lib/ladspa", s->dl_name); | |
429 | } | |
430 | if (!s->dl_handle) { | |
431 | av_log(ctx, AV_LOG_ERROR, "Failed to load '%s'\n", s->dl_name); | |
432 | return AVERROR(EINVAL); | |
433 | } | |
434 | ||
435 | descriptor_fn = dlsym(s->dl_handle, "ladspa_descriptor"); | |
436 | if (!descriptor_fn) { | |
437 | av_log(ctx, AV_LOG_ERROR, "Could not find ladspa_descriptor: %s\n", dlerror()); | |
438 | return AVERROR(EINVAL); | |
439 | } | |
440 | ||
441 | // Find the requested plugin, or list plugins | |
442 | if (!s->plugin) { | |
443 | av_log(ctx, AV_LOG_INFO, "The '%s' library contains the following plugins:\n", s->dl_name); | |
444 | av_log(ctx, AV_LOG_INFO, "I = Input Channels\n"); | |
445 | av_log(ctx, AV_LOG_INFO, "O = Output Channels\n"); | |
446 | av_log(ctx, AV_LOG_INFO, "I:O %-25s %s\n", "Plugin", "Description"); | |
447 | av_log(ctx, AV_LOG_INFO, "\n"); | |
448 | for (i = 0; desc = descriptor_fn(i); i++) { | |
449 | unsigned long inputs = 0, outputs = 0; | |
450 | ||
451 | count_ports(desc, &inputs, &outputs); | |
452 | av_log(ctx, AV_LOG_INFO, "%lu:%lu %-25s %s\n", inputs, outputs, desc->Label, | |
453 | (char *)av_x_if_null(desc->Name, "?")); | |
454 | av_log(ctx, AV_LOG_VERBOSE, "Maker: %s\n", | |
455 | (char *)av_x_if_null(desc->Maker, "?")); | |
456 | av_log(ctx, AV_LOG_VERBOSE, "Copyright: %s\n", | |
457 | (char *)av_x_if_null(desc->Copyright, "?")); | |
458 | } | |
459 | return AVERROR_EXIT; | |
460 | } else { | |
461 | for (i = 0;; i++) { | |
462 | desc = descriptor_fn(i); | |
463 | if (!desc) { | |
464 | av_log(ctx, AV_LOG_ERROR, "Could not find plugin: %s\n", s->plugin); | |
465 | return AVERROR(EINVAL); | |
466 | } | |
467 | ||
468 | if (desc->Label && !strcmp(desc->Label, s->plugin)) | |
469 | break; | |
470 | } | |
471 | } | |
472 | ||
473 | s->desc = desc; | |
474 | nb_ports = desc->PortCount; | |
475 | ||
476 | s->ipmap = av_calloc(nb_ports, sizeof(*s->ipmap)); | |
477 | s->opmap = av_calloc(nb_ports, sizeof(*s->opmap)); | |
478 | s->icmap = av_calloc(nb_ports, sizeof(*s->icmap)); | |
479 | s->ocmap = av_calloc(nb_ports, sizeof(*s->ocmap)); | |
480 | s->ictlv = av_calloc(nb_ports, sizeof(*s->ictlv)); | |
481 | s->octlv = av_calloc(nb_ports, sizeof(*s->octlv)); | |
482 | s->ctl_needs_value = av_calloc(nb_ports, sizeof(*s->ctl_needs_value)); | |
483 | if (!s->ipmap || !s->opmap || !s->icmap || | |
484 | !s->ocmap || !s->ictlv || !s->octlv || !s->ctl_needs_value) | |
485 | return AVERROR(ENOMEM); | |
486 | ||
487 | for (i = 0; i < nb_ports; i++) { | |
488 | pd = desc->PortDescriptors[i]; | |
489 | ||
490 | if (LADSPA_IS_PORT_AUDIO(pd)) { | |
491 | if (LADSPA_IS_PORT_INPUT(pd)) { | |
492 | s->ipmap[s->nb_inputs] = i; | |
493 | s->nb_inputs++; | |
494 | } else if (LADSPA_IS_PORT_OUTPUT(pd)) { | |
495 | s->opmap[s->nb_outputs] = i; | |
496 | s->nb_outputs++; | |
497 | } | |
498 | } else if (LADSPA_IS_PORT_CONTROL(pd)) { | |
499 | if (LADSPA_IS_PORT_INPUT(pd)) { | |
500 | s->icmap[s->nb_inputcontrols] = i; | |
501 | ||
502 | if (LADSPA_IS_HINT_HAS_DEFAULT(desc->PortRangeHints[i].HintDescriptor)) | |
503 | set_default_ctl_value(s, s->nb_inputcontrols, s->icmap, s->ictlv); | |
504 | else | |
505 | s->ctl_needs_value[s->nb_inputcontrols] = 1; | |
506 | ||
507 | s->nb_inputcontrols++; | |
508 | } else if (LADSPA_IS_PORT_OUTPUT(pd)) { | |
509 | s->ocmap[s->nb_outputcontrols] = i; | |
510 | s->nb_outputcontrols++; | |
511 | } | |
512 | } | |
513 | } | |
514 | ||
515 | // List Control Ports if "help" is specified | |
516 | if (s->options && !strcmp(s->options, "help")) { | |
517 | if (!s->nb_inputcontrols) { | |
518 | av_log(ctx, AV_LOG_INFO, | |
519 | "The '%s' plugin does not have any input controls.\n", | |
520 | desc->Label); | |
521 | } else { | |
522 | av_log(ctx, AV_LOG_INFO, | |
523 | "The '%s' plugin has the following input controls:\n", | |
524 | desc->Label); | |
525 | for (i = 0; i < s->nb_inputcontrols; i++) | |
526 | print_ctl_info(ctx, AV_LOG_INFO, s, i, s->icmap, s->ictlv, 0); | |
527 | } | |
528 | return AVERROR_EXIT; | |
529 | } | |
530 | ||
531 | // Parse control parameters | |
532 | p = s->options; | |
533 | while (s->options) { | |
534 | LADSPA_Data val; | |
535 | int ret; | |
536 | ||
537 | if (!(arg = av_strtok(p, "|", &saveptr))) | |
538 | break; | |
539 | p = NULL; | |
540 | ||
541 | if (sscanf(arg, "c%d=%f", &i, &val) != 2) { | |
542 | av_log(ctx, AV_LOG_ERROR, "Invalid syntax.\n"); | |
543 | return AVERROR(EINVAL); | |
544 | } | |
545 | ||
546 | if ((ret = set_control(ctx, i, val)) < 0) | |
547 | return ret; | |
548 | s->ctl_needs_value[i] = 0; | |
549 | } | |
550 | ||
551 | // Check if any controls are not set | |
552 | for (i = 0; i < s->nb_inputcontrols; i++) { | |
553 | if (s->ctl_needs_value[i]) { | |
554 | av_log(ctx, AV_LOG_ERROR, "Control c%d must be set.\n", i); | |
555 | print_ctl_info(ctx, AV_LOG_ERROR, s, i, s->icmap, s->ictlv, 0); | |
556 | return AVERROR(EINVAL); | |
557 | } | |
558 | } | |
559 | ||
560 | pad.type = AVMEDIA_TYPE_AUDIO; | |
561 | ||
562 | if (s->nb_inputs) { | |
563 | pad.name = av_asprintf("in0:%s%lu", desc->Label, s->nb_inputs); | |
564 | if (!pad.name) | |
565 | return AVERROR(ENOMEM); | |
566 | ||
567 | pad.filter_frame = filter_frame; | |
568 | pad.config_props = config_input; | |
569 | if (ff_insert_inpad(ctx, ctx->nb_inputs, &pad) < 0) { | |
570 | av_freep(&pad.name); | |
571 | return AVERROR(ENOMEM); | |
572 | } | |
573 | } | |
574 | ||
575 | av_log(ctx, AV_LOG_DEBUG, "ports: %lu\n", nb_ports); | |
576 | av_log(ctx, AV_LOG_DEBUG, "inputs: %lu outputs: %lu\n", | |
577 | s->nb_inputs, s->nb_outputs); | |
578 | av_log(ctx, AV_LOG_DEBUG, "input controls: %lu output controls: %lu\n", | |
579 | s->nb_inputcontrols, s->nb_outputcontrols); | |
580 | ||
581 | return 0; | |
582 | } | |
583 | ||
584 | static int query_formats(AVFilterContext *ctx) | |
585 | { | |
586 | LADSPAContext *s = ctx->priv; | |
587 | AVFilterFormats *formats; | |
588 | AVFilterChannelLayouts *layouts; | |
589 | static const enum AVSampleFormat sample_fmts[] = { | |
590 | AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; | |
591 | ||
592 | formats = ff_make_format_list(sample_fmts); | |
593 | if (!formats) | |
594 | return AVERROR(ENOMEM); | |
595 | ff_set_common_formats(ctx, formats); | |
596 | ||
597 | if (s->nb_inputs) { | |
598 | formats = ff_all_samplerates(); | |
599 | if (!formats) | |
600 | return AVERROR(ENOMEM); | |
601 | ||
602 | ff_set_common_samplerates(ctx, formats); | |
603 | } else { | |
604 | int sample_rates[] = { s->sample_rate, -1 }; | |
605 | ||
606 | ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates)); | |
607 | } | |
608 | ||
609 | if (s->nb_inputs == 1 && s->nb_outputs == 1) { | |
610 | // We will instantiate multiple LADSPA_Handle, one over each channel | |
611 | layouts = ff_all_channel_layouts(); | |
612 | if (!layouts) | |
613 | return AVERROR(ENOMEM); | |
614 | ||
615 | ff_set_common_channel_layouts(ctx, layouts); | |
616 | } else { | |
617 | AVFilterLink *outlink = ctx->outputs[0]; | |
618 | ||
619 | if (s->nb_inputs >= 1) { | |
620 | AVFilterLink *inlink = ctx->inputs[0]; | |
621 | int64_t inlayout = FF_COUNT2LAYOUT(s->nb_inputs); | |
622 | ||
623 | layouts = NULL; | |
624 | ff_add_channel_layout(&layouts, inlayout); | |
625 | ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts); | |
626 | ||
627 | if (!s->nb_outputs) | |
628 | ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); | |
629 | } | |
630 | ||
631 | if (s->nb_outputs >= 1) { | |
632 | int64_t outlayout = FF_COUNT2LAYOUT(s->nb_outputs); | |
633 | ||
634 | layouts = NULL; | |
635 | ff_add_channel_layout(&layouts, outlayout); | |
636 | ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); | |
637 | } | |
638 | } | |
639 | ||
640 | return 0; | |
641 | } | |
642 | ||
643 | static av_cold void uninit(AVFilterContext *ctx) | |
644 | { | |
645 | LADSPAContext *s = ctx->priv; | |
646 | int i; | |
647 | ||
648 | for (i = 0; i < s->nb_handles; i++) { | |
649 | if (s->desc->deactivate) | |
650 | s->desc->deactivate(s->handles[i]); | |
651 | if (s->desc->cleanup) | |
652 | s->desc->cleanup(s->handles[i]); | |
653 | } | |
654 | ||
655 | if (s->dl_handle) | |
656 | dlclose(s->dl_handle); | |
657 | ||
658 | av_freep(&s->ipmap); | |
659 | av_freep(&s->opmap); | |
660 | av_freep(&s->icmap); | |
661 | av_freep(&s->ocmap); | |
662 | av_freep(&s->ictlv); | |
663 | av_freep(&s->octlv); | |
664 | av_freep(&s->handles); | |
665 | av_freep(&s->ctl_needs_value); | |
666 | ||
667 | if (ctx->nb_inputs) | |
668 | av_freep(&ctx->input_pads[0].name); | |
669 | } | |
670 | ||
671 | static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, | |
672 | char *res, int res_len, int flags) | |
673 | { | |
674 | LADSPA_Data value; | |
675 | unsigned long port; | |
676 | ||
677 | if (sscanf(cmd, "c%ld", &port) + sscanf(args, "%f", &value) != 2) | |
678 | return AVERROR(EINVAL); | |
679 | ||
680 | return set_control(ctx, port, value); | |
681 | } | |
682 | ||
683 | static const AVFilterPad ladspa_outputs[] = { | |
684 | { | |
685 | .name = "default", | |
686 | .type = AVMEDIA_TYPE_AUDIO, | |
687 | .config_props = config_output, | |
688 | .request_frame = request_frame, | |
689 | }, | |
690 | { NULL } | |
691 | }; | |
692 | ||
693 | AVFilter ff_af_ladspa = { | |
694 | .name = "ladspa", | |
695 | .description = NULL_IF_CONFIG_SMALL("Apply LADSPA effect."), | |
696 | .priv_size = sizeof(LADSPAContext), | |
697 | .priv_class = &ladspa_class, | |
698 | .init = init, | |
699 | .uninit = uninit, | |
700 | .query_formats = query_formats, | |
701 | .process_command = process_command, | |
702 | .inputs = 0, | |
703 | .outputs = ladspa_outputs, | |
704 | .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, | |
705 | }; |