]> git.sesse.net Git - vlc/blob - src/audio_output/filters.c
aout: inline one function and simplify
[vlc] / src / audio_output / filters.c
1 /*****************************************************************************
2  * filters.c : audio output filters management
3  *****************************************************************************
4  * Copyright (C) 2002-2007 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <string.h>
32 #include <assert.h>
33
34 #include <vlc_common.h>
35 #include <vlc_dialog.h>
36 #include <vlc_modules.h>
37 #include <vlc_aout.h>
38 #include <vlc_filter.h>
39 #include <vlc_vout.h>                  /* for vout_Request */
40 #include <vlc_input.h>
41
42 #include <libvlc.h>
43 #include "aout_internal.h"
44
45 static filter_t *FindFilter (vlc_object_t *obj, const char *type,
46                              const char *name,
47                              const audio_sample_format_t *infmt,
48                              const audio_sample_format_t *outfmt)
49 {
50     filter_t *filter = vlc_custom_create (obj, sizeof (*filter), type);
51     if (unlikely(filter == NULL))
52         return NULL;
53
54     filter->fmt_in.audio = *infmt;
55     filter->fmt_in.i_codec = infmt->i_format;
56     filter->fmt_out.audio = *outfmt;
57     filter->fmt_out.i_codec = outfmt->i_format;
58     filter->p_module = module_need (filter, type, name, false);
59     if (filter->p_module == NULL)
60     {
61         vlc_object_release (filter);
62         filter = NULL;
63     }
64     else
65         assert (filter->pf_audio_filter != NULL);
66     return filter;
67 }
68
69 static filter_t *FindConverter (vlc_object_t *obj,
70                                 const audio_sample_format_t *infmt,
71                                 const audio_sample_format_t *outfmt)
72 {
73     return FindFilter (obj, "audio converter", NULL, infmt, outfmt);
74 }
75
76 static filter_t *FindResampler (vlc_object_t *obj,
77                                 const audio_sample_format_t *infmt,
78                                 const audio_sample_format_t *outfmt)
79 {
80     return FindFilter (obj, "audio resampler", "$audio-resampler",
81                        infmt, outfmt);
82 }
83
84 /**
85  * Destroys a chain of audio filters.
86  */
87 static void aout_FiltersPipelineDestroy(filter_t *const *filters, unsigned n)
88 {
89     for( unsigned i = 0; i < n; i++ )
90     {
91         filter_t *p_filter = filters[i];
92
93         module_unneed( p_filter, p_filter->p_module );
94         vlc_object_release( p_filter );
95     }
96 }
97
98 static filter_t *TryFormat (vlc_object_t *obj, vlc_fourcc_t codec,
99                             audio_sample_format_t *restrict fmt)
100 {
101     audio_sample_format_t output = *fmt;
102
103     assert (codec != fmt->i_format);
104     output.i_format = codec;
105     aout_FormatPrepare (&output);
106
107     filter_t *filter = FindConverter (obj, fmt, &output);
108     if (filter != NULL)
109         *fmt = output;
110     return filter;
111 }
112
113 /**
114  * Allocates audio format conversion filters
115  * @param obj parent VLC object for new filters
116  * @param filters table of filters [IN/OUT]
117  * @param count pointer to the number of filters in the table [IN/OUT]
118  * @param max size of filters table [IN]
119  * @param infmt input audio format
120  * @param outfmt output audio format
121  * @return 0 on success, -1 on failure
122  */
123 static int aout_FiltersPipelineCreate(vlc_object_t *obj, filter_t **filters,
124                                       unsigned *count, unsigned max,
125                                  const audio_sample_format_t *restrict infmt,
126                                  const audio_sample_format_t *restrict outfmt)
127 {
128     aout_FormatsPrint (obj, "conversion:", infmt, outfmt);
129     max -= *count;
130     filters += *count;
131
132     /* There is a lot of second guessing on what the conversion plugins can
133      * and cannot do. This seems hardly avoidable, the conversion problem need
134      * to be reduced somehow. */
135     audio_sample_format_t input = *infmt;
136     unsigned n = 0;
137
138     /* Encapsulate or decode non-linear formats */
139     if (!AOUT_FMT_LINEAR(infmt) && infmt->i_format != outfmt->i_format)
140     {
141         if (n == max)
142             goto overflow;
143
144         filter_t *f = TryFormat (obj, VLC_CODEC_S32N, &input);
145         if (f == NULL)
146             f = TryFormat (obj, VLC_CODEC_FL32, &input);
147         if (f == NULL)
148         {
149             msg_Err (obj, "cannot find %s for conversion pipeline",
150                      "decoder");
151             goto error;
152         }
153
154         filters[n++] = f;
155     }
156     assert (AOUT_FMT_LINEAR(&input));
157
158     /* Remix channels */
159     if (infmt->i_physical_channels != outfmt->i_physical_channels
160      || infmt->i_original_channels != outfmt->i_original_channels)
161     {   /* Remixing currently requires FL32... TODO: S16N */
162         if (input.i_format != VLC_CODEC_FL32)
163         {
164             if (n == max)
165                 goto overflow;
166
167             filter_t *f = TryFormat (obj, VLC_CODEC_FL32, &input);
168             if (f == NULL)
169             {
170                 msg_Err (obj, "cannot find %s for conversion pipeline",
171                          "pre-mix converter");
172                 goto error;
173             }
174
175             filters[n++] = f;
176         }
177
178         if (n == max)
179             goto overflow;
180
181         audio_sample_format_t output;
182         output.i_format = input.i_format;
183         output.i_rate = input.i_rate;
184         output.i_physical_channels = outfmt->i_physical_channels;
185         output.i_original_channels = outfmt->i_original_channels;
186         aout_FormatPrepare (&output);
187
188         filter_t *f = FindConverter (obj, &input, &output);
189         if (f == NULL)
190         {
191             msg_Err (obj, "cannot find %s for conversion pipeline",
192                      "remixer");
193             goto error;
194         }
195
196         input = output;
197         filters[n++] = f;
198     }
199
200     /* Resample */
201     if (input.i_rate != outfmt->i_rate)
202     {   /* Resampling works with any linear format, but may be ugly. */
203         if (n == max)
204             goto overflow;
205
206         audio_sample_format_t output = input;
207         output.i_rate = outfmt->i_rate;
208
209         filter_t *f = FindConverter (obj, &input, &output);
210         if (f == NULL)
211         {
212             msg_Err (obj, "cannot find %s for conversion pipeline",
213                      "resampler");
214             goto error;
215         }
216
217         input = output;
218         filters[n++] = f;
219     }
220
221     /* Format */
222     if (input.i_format != outfmt->i_format)
223     {
224         if (max == 0)
225             goto overflow;
226
227         filter_t *f = TryFormat (obj, outfmt->i_format, &input);
228         if (f == NULL)
229         {
230             msg_Err (obj, "cannot find %s for conversion pipeline",
231                      "post-mix converter");
232             goto error;
233         }
234         filters[n++] = f;
235     }
236
237     msg_Dbg (obj, "conversion pipeline complete");
238     *count += n;
239     return 0;
240
241 overflow:
242     msg_Err (obj, "maximum of %u conversion filters reached", max);
243     dialog_Fatal (obj, _("Audio filtering failed"),
244                   _("The maximum number of filters (%u) was reached."), max);
245 error:
246     aout_FiltersPipelineDestroy (filters, n);
247     return -1;
248 }
249
250 #define aout_FiltersPipelineCreate(obj,f,n,m,i,o) \
251         aout_FiltersPipelineCreate(VLC_OBJECT(obj),f,n,m,i,o)
252
253 /**
254  * Filters an audio buffer through a chain of filters.
255  */
256 static block_t *aout_FiltersPipelinePlay(filter_t *const *filters,
257                                          unsigned count, block_t *block)
258 {
259     /* TODO: use filter chain */
260     for (unsigned i = 0; (i < count) && (block != NULL); i++)
261     {
262         filter_t *filter = filters[i];
263
264         /* Please note that p_block->i_nb_samples & i_buffer
265          * shall be set by the filter plug-in. */
266         block = filter->pf_audio_filter (filter, block);
267     }
268     return block;
269 }
270
271 /** Callback for visualization selection */
272 static int VisualizationCallback (vlc_object_t *obj, const char *var,
273                                   vlc_value_t oldval, vlc_value_t newval,
274                                   void *data)
275 {
276     const char *mode = newval.psz_string;
277
278     if (!*mode)
279         mode = "none";
280     /* FIXME: This ugly hack enforced by visual effect-list, as is the need for
281      * separate "visual" (external) and "audio-visual" (internal) variables...
282      * The visual plugin should have one submodule per effect instead. */
283     if (strcasecmp (mode, "none") && strcasecmp (mode, "goom")
284      && strcasecmp (mode, "projectm") && strcasecmp (mode, "vsxu"))
285     {
286         var_Create (obj, "effect-list", VLC_VAR_STRING);
287         var_SetString (obj, "effect-list", mode);
288         mode = "visual";
289     }
290
291     var_SetString (obj, "audio-visual", mode);
292     aout_InputRequestRestart ((audio_output_t *)obj);
293     (void) var; (void) oldval; (void) data;
294     return VLC_SUCCESS;
295 }
296
297 static int EqualizerCallback (vlc_object_t *obj, const char *var,
298                               vlc_value_t oldval, vlc_value_t newval,
299                               void *data)
300 {
301     const char *val = newval.psz_string;
302
303     if (*val)
304     {
305         var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
306         var_SetString (obj, "equalizer-preset", val);
307     }
308
309     if (aout_ChangeFilterString (obj, obj, "audio-filter", "equalizer", *val))
310         aout_InputRequestRestart ((audio_output_t *)obj); /* <- That sucks! */
311
312     (void) var; (void) oldval; (void) data;
313     return VLC_SUCCESS;
314 }
315
316 static vout_thread_t *RequestVout (void *data, vout_thread_t *vout,
317                                    video_format_t *fmt, bool recycle)
318 {
319     audio_output_t *aout = data;
320     vout_configuration_t cfg = {
321         .vout       = vout,
322         .input      = NULL,
323         .change_fmt = true,
324         .fmt        = fmt,
325         .dpb_size   = 1,
326     };
327
328     (void) recycle;
329     return vout_Request (aout, &cfg);
330 }
331
332 vout_thread_t *aout_filter_RequestVout (filter_t *filter, vout_thread_t *vout,
333                                         video_format_t *fmt)
334 {
335     /* NOTE: This only works from audio output.
336      * If you want to use visualization filters from another place, you will
337      * need to add a new pf_aout_request_vout callback or store a pointer
338      * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
339     aout_owner_t *owner = aout_owner ((audio_output_t *)filter->p_parent);
340     aout_request_vout_t *req = &owner->request_vout;
341
342     return req->pf_request_vout (req->p_private, vout, fmt,
343                                  owner->recycle_vout);
344 }
345
346 static filter_t *CreateFilter (vlc_object_t *parent, const char *name,
347                                const audio_sample_format_t *restrict infmt,
348                                const audio_sample_format_t *restrict outfmt,
349                                bool visu)
350 {
351     filter_t *filter = vlc_custom_create (parent, sizeof (*filter),
352                                           "audio filter");
353     if (unlikely(filter == NULL))
354         return NULL;
355
356     /*filter->p_owner = NOT NEEDED;*/
357     filter->fmt_in.i_codec = infmt->i_format;
358     filter->fmt_in.audio = *infmt;
359     filter->fmt_out.i_codec = outfmt->i_format;
360     filter->fmt_out.audio = *outfmt;
361
362     if (!visu)
363     {
364         filter->p_module = module_need (filter, "audio filter", name, true);
365         if (filter->p_module != NULL)
366             return filter;
367
368         /* If probing failed, formats shall not have been modified. */
369         assert (AOUT_FMTS_IDENTICAL(&filter->fmt_in.audio, infmt));
370         assert (AOUT_FMTS_IDENTICAL(&filter->fmt_out.audio, outfmt));
371     }
372
373     filter->p_module = module_need (filter, "visualization2", name, true);
374     if (filter->p_module != NULL)
375         return filter;
376
377     vlc_object_release (filter);
378     return NULL;
379 }
380
381 /**
382  * Sets up the audio filters.
383  */
384 int aout_FiltersNew (audio_output_t *aout,
385                      const audio_sample_format_t *restrict infmt,
386                      const audio_sample_format_t *restrict outfmt,
387                      const aout_request_vout_t *request_vout)
388 {
389     aout_owner_t *owner = aout_owner (aout);
390
391     /* Prepare format structure */
392     aout_FormatPrint (aout, "input", infmt);
393     audio_sample_format_t input_format = *infmt;
394     audio_sample_format_t output_format = *outfmt;
395
396     /* Now add user filters */
397     owner->nb_filters = 0;
398     owner->rate_filter = NULL;
399     owner->resampler = NULL;
400
401     var_AddCallback (aout, "visual", VisualizationCallback, NULL);
402     var_AddCallback (aout, "equalizer", EqualizerCallback, NULL);
403
404     if (!AOUT_FMT_LINEAR(outfmt))
405     {   /* Non-linear output: just convert formats, no filters/visu */
406         if (!AOUT_FMTS_IDENTICAL(infmt, outfmt))
407         {
408             aout_FormatsPrint (aout, "pass-through:", infmt, outfmt);
409             owner->filters[0] = FindConverter(VLC_OBJECT(aout), infmt, outfmt);
410             if (owner->filters[0] == NULL)
411             {
412                 msg_Err (aout, "cannot setup pass-through");
413                 goto error;
414             }
415             owner->nb_filters++;
416         }
417         return 0;
418     }
419
420     const char *scaletempo =
421         var_InheritBool (aout, "audio-time-stretch") ? "scaletempo" : NULL;
422     char *filters = var_InheritString (aout, "audio-filter");
423     char *visual = var_InheritString (aout, "audio-visual");
424     if (visual != NULL && !strcasecmp (visual, "none"))
425     {
426         free (visual);
427         visual = NULL;
428     }
429
430     if (request_vout != NULL)
431         owner->request_vout = *request_vout;
432     else
433     {
434         owner->request_vout.pf_request_vout = RequestVout;
435         owner->request_vout.p_private = aout;
436     }
437     owner->recycle_vout = visual != NULL;
438
439     /* parse user filter lists */
440     const char *list[AOUT_MAX_FILTERS];
441     unsigned n = 0;
442
443     if (scaletempo != NULL)
444         list[n++] = scaletempo;
445     if (filters != NULL)
446     {
447         char *p = filters, *name;
448         while ((name = strsep (&p, " :")) != NULL && n < AOUT_MAX_FILTERS)
449             list[n++] = name;
450     }
451     if (visual != NULL && n < AOUT_MAX_FILTERS)
452         list[n++] = visual;
453
454     for (unsigned i = 0; i < n; i++)
455     {
456         const char *name = list[i];
457
458         if (owner->nb_filters >= AOUT_MAX_FILTERS)
459         {
460             msg_Err (aout, "maximum of %u filters reached", AOUT_MAX_FILTERS);
461             msg_Err (aout, "cannot add user filter %s (skipped)", name);
462             break;
463         }
464
465         filter_t *filter = CreateFilter (VLC_OBJECT(aout), name,
466                                          &input_format, &output_format,
467                                          name == visual);
468         if (filter == NULL)
469         {
470             msg_Err (aout, "cannot add user filter %s (skipped)", name);
471             continue;
472         }
473
474         /* convert to the filter input format if necessary */
475         if (aout_FiltersPipelineCreate (aout, owner->filters,
476                                         &owner->nb_filters,
477                                         AOUT_MAX_FILTERS - 1,
478                                         &input_format, &filter->fmt_in.audio))
479         {
480             msg_Err (aout, "cannot add user filter %s (skipped)", name);
481             module_unneed (filter, filter->p_module);
482             vlc_object_release (filter);
483             continue;
484         }
485
486         assert (owner->nb_filters < AOUT_MAX_FILTERS);
487         owner->filters[owner->nb_filters++] = filter;
488         input_format = filter->fmt_out.audio;
489
490         if (name == scaletempo)
491             owner->rate_filter = filter;
492     }
493     free (visual);
494     free (filters);
495
496     /* convert to the output format (minus resampling) if necessary */
497     output_format.i_rate = input_format.i_rate;
498     if (aout_FiltersPipelineCreate (aout, owner->filters, &owner->nb_filters,
499                                     AOUT_MAX_FILTERS,
500                                     &input_format, &output_format))
501     {
502         msg_Err (aout, "cannot setup filtering pipeline");
503         goto error;
504     }
505     input_format = output_format;
506
507     /* insert the resampler */
508     output_format.i_rate = outfmt->i_rate;
509     assert (AOUT_FMTS_IDENTICAL(&output_format, outfmt));
510     owner->resampler = FindResampler (VLC_OBJECT(aout), &input_format,
511                                       &output_format);
512     if (owner->resampler == NULL && input_format.i_rate != outfmt->i_rate)
513     {
514         msg_Err (aout, "cannot setup a resampler");
515         goto error;
516     }
517     if (owner->rate_filter == NULL)
518         owner->rate_filter = owner->resampler;
519     owner->resampling = 0;
520
521     return 0;
522
523 error:
524     aout_FiltersPipelineDestroy (owner->filters, owner->nb_filters);
525     var_DelCallback (aout, "equalizer", EqualizerCallback, NULL);
526     var_DelCallback (aout, "visual", VisualizationCallback, NULL);
527     return -1;
528 }
529
530 /**
531  * Destroys the audio filters.
532  */
533 void aout_FiltersDelete (audio_output_t *aout)
534 {
535     aout_owner_t *owner = aout_owner (aout);
536
537     if (owner->resampler != NULL)
538         aout_FiltersPipelineDestroy (&owner->resampler, 1);
539     aout_FiltersPipelineDestroy (owner->filters, owner->nb_filters);
540     var_DelCallback (aout, "equalizer", EqualizerCallback, NULL);
541     var_DelCallback (aout, "visual", VisualizationCallback, NULL);
542
543     /* XXX We need to update recycle_vout before calling
544      * aout_FiltersPipelineDestroy().
545      * FIXME There may be a race condition if audio-visual is updated between
546      * aout_FiltersDestroy() and the next aout_FiltersNew().
547      */
548     char *visual = var_InheritString (aout, "audio-visual");
549     owner->recycle_vout = (visual != NULL) && *visual;
550     free (visual);
551 }
552
553 bool aout_FiltersAdjustResampling (audio_output_t *aout, int adjust)
554 {
555     aout_owner_t *owner = aout_owner (aout);
556
557     if (owner->resampler == NULL)
558         return false;
559
560     if (adjust)
561         owner->resampling += adjust;
562     else
563         owner->resampling = 0;
564     return owner->resampling != 0;
565 }
566
567 block_t *aout_FiltersPlay (audio_output_t *aout, block_t *block, int rate)
568 {
569     aout_owner_t *owner = aout_owner (aout);
570     int nominal_rate = 0;
571
572     if (rate != INPUT_RATE_DEFAULT)
573     {
574         filter_t *rate_filter = owner->rate_filter;
575
576         if (rate_filter == NULL)
577             goto drop; /* Without linear, non-nominal rate is impossible. */
578
579         /* Override input rate */
580         nominal_rate = rate_filter->fmt_in.audio.i_rate;
581         rate_filter->fmt_in.audio.i_rate =
582             (nominal_rate * INPUT_RATE_DEFAULT) / rate;
583     }
584
585     block = aout_FiltersPipelinePlay (owner->filters, owner->nb_filters,
586                                       block);
587     if (owner->resampler != NULL)
588     {   /* NOTE: the resampler needs to run even if resampling is 0.
589          * The decoder and output rates can still be different. */
590         owner->resampler->fmt_in.audio.i_rate += owner->resampling;
591         block = aout_FiltersPipelinePlay (&owner->resampler, 1, block);
592         owner->resampler->fmt_in.audio.i_rate -= owner->resampling;
593     }
594
595     if (nominal_rate != 0)
596     {   /* Restore input rate */
597         assert (owner->rate_filter != NULL);
598         owner->rate_filter->fmt_in.audio.i_rate = nominal_rate;
599     }
600     return block;
601
602 drop:
603     block_Release (block);
604     return NULL;
605 }