1 /*****************************************************************************
2 * filters.c : audio output filters management
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_dialog.h>
36 #include <vlc_modules.h>
38 #include <vlc_filter.h>
39 #include <vlc_vout.h> /* for vout_Request */
40 #include <vlc_input.h>
43 #include "aout_internal.h"
45 static filter_t
*CreateFilter (vlc_object_t
*obj
, const char *type
,
46 const char *name
, filter_owner_sys_t
*owner
,
47 const audio_sample_format_t
*infmt
,
48 const audio_sample_format_t
*outfmt
,
49 config_chain_t
*cfg
, bool const_fmt
)
51 filter_t
*filter
= vlc_custom_create (obj
, sizeof (*filter
), type
);
52 if (unlikely(filter
== NULL
))
55 filter
->owner
.sys
= owner
;
57 filter
->fmt_in
.audio
= *infmt
;
58 filter
->fmt_in
.i_codec
= infmt
->i_format
;
59 filter
->fmt_out
.audio
= *outfmt
;
60 filter
->fmt_out
.i_codec
= outfmt
->i_format
;
63 /* Assure that infmt/oufmt are well prepared and that channels
64 * configurations are valid*/
65 if( infmt
->i_physical_channels
!= 0 )
66 assert( aout_FormatNbChannels( infmt
) == infmt
->i_channels
);
67 if( outfmt
->i_physical_channels
!= 0 )
68 assert( aout_FormatNbChannels( outfmt
) == outfmt
->i_channels
);
71 filter
->p_module
= module_need (filter
, type
, name
, false);
74 if (filter
->p_module
== NULL
|| const_fmt
)
76 /* If probing failed, formats shall not have been modified. */
77 assert (AOUT_FMTS_IDENTICAL(&filter
->fmt_in
.audio
, infmt
));
78 assert (AOUT_FMTS_IDENTICAL(&filter
->fmt_out
.audio
, outfmt
));
82 if (filter
->p_module
== NULL
)
84 vlc_object_release (filter
);
88 assert (filter
->pf_audio_filter
!= NULL
);
92 static filter_t
*FindConverter (vlc_object_t
*obj
,
93 const audio_sample_format_t
*infmt
,
94 const audio_sample_format_t
*outfmt
)
96 return CreateFilter (obj
, "audio converter", NULL
, NULL
, infmt
, outfmt
,
100 static filter_t
*FindResampler (vlc_object_t
*obj
,
101 const audio_sample_format_t
*infmt
,
102 const audio_sample_format_t
*outfmt
)
104 return CreateFilter (obj
, "audio resampler", "$audio-resampler", NULL
,
105 infmt
, outfmt
, NULL
, true);
109 * Destroys a chain of audio filters.
111 static void aout_FiltersPipelineDestroy(filter_t
*const *filters
, unsigned n
)
113 for( unsigned i
= 0; i
< n
; i
++ )
115 filter_t
*p_filter
= filters
[i
];
117 module_unneed( p_filter
, p_filter
->p_module
);
118 vlc_object_release( p_filter
);
122 static filter_t
*TryFormat (vlc_object_t
*obj
, vlc_fourcc_t codec
,
123 audio_sample_format_t
*restrict fmt
)
125 audio_sample_format_t output
= *fmt
;
127 assert (codec
!= fmt
->i_format
);
128 output
.i_format
= codec
;
129 aout_FormatPrepare (&output
);
131 filter_t
*filter
= FindConverter (obj
, fmt
, &output
);
138 * Allocates audio format conversion filters
139 * @param obj parent VLC object for new filters
140 * @param filters table of filters [IN/OUT]
141 * @param count pointer to the number of filters in the table [IN/OUT]
142 * @param max size of filters table [IN]
143 * @param infmt input audio format
144 * @param outfmt output audio format
145 * @return 0 on success, -1 on failure
147 static int aout_FiltersPipelineCreate(vlc_object_t
*obj
, filter_t
**filters
,
148 unsigned *count
, unsigned max
,
149 const audio_sample_format_t
*restrict infmt
,
150 const audio_sample_format_t
*restrict outfmt
,
153 aout_FormatsPrint (obj
, "conversion:", infmt
, outfmt
);
157 /* There is a lot of second guessing on what the conversion plugins can
158 * and cannot do. This seems hardly avoidable, the conversion problem need
159 * to be reduced somehow. */
160 audio_sample_format_t input
= *infmt
;
163 if (!AOUT_FMT_LINEAR(&input
))
165 msg_Err(obj
, "Can't convert non linear input");
170 if (infmt
->i_physical_channels
!= outfmt
->i_physical_channels
171 || infmt
->i_chan_mode
!= outfmt
->i_chan_mode
172 || infmt
->channel_type
!= outfmt
->channel_type
)
173 { /* Remixing currently requires FL32... TODO: S16N */
174 if (input
.i_format
!= VLC_CODEC_FL32
)
179 filter_t
*f
= TryFormat (obj
, VLC_CODEC_FL32
, &input
);
182 msg_Err (obj
, "cannot find %s for conversion pipeline",
183 "pre-mix converter");
193 audio_sample_format_t output
;
194 output
.i_format
= input
.i_format
;
195 output
.i_rate
= input
.i_rate
;
196 output
.i_physical_channels
= outfmt
->i_physical_channels
;
197 output
.channel_type
= outfmt
->channel_type
;
198 output
.i_chan_mode
= outfmt
->i_chan_mode
;
199 aout_FormatPrepare (&output
);
201 const char *filter_type
=
202 infmt
->channel_type
!= outfmt
->channel_type
?
203 "audio renderer" : "audio converter";
205 config_chain_t
*cfg
= NULL
;
207 config_ChainParseOptions(&cfg
, "{headphones=true}");
208 filter_t
*f
= CreateFilter (obj
, filter_type
, NULL
, NULL
,
209 &input
, &output
, cfg
, true);
211 config_ChainDestroy(cfg
);
215 msg_Err (obj
, "cannot find %s for conversion pipeline",
225 if (input
.i_rate
!= outfmt
->i_rate
)
226 { /* Resampling works with any linear format, but may be ugly. */
230 audio_sample_format_t output
= input
;
231 output
.i_rate
= outfmt
->i_rate
;
233 filter_t
*f
= FindConverter (obj
, &input
, &output
);
236 msg_Err (obj
, "cannot find %s for conversion pipeline",
246 if (input
.i_format
!= outfmt
->i_format
)
251 filter_t
*f
= TryFormat (obj
, outfmt
->i_format
, &input
);
254 msg_Err (obj
, "cannot find %s for conversion pipeline",
255 "post-mix converter");
261 msg_Dbg (obj
, "conversion pipeline complete");
266 msg_Err (obj
, "maximum of %u conversion filters reached", max
);
267 vlc_dialog_display_error (obj
, _("Audio filtering failed"),
268 _("The maximum number of filters (%u) was reached."), max
);
270 aout_FiltersPipelineDestroy (filters
, n
);
275 * Filters an audio buffer through a chain of filters.
277 static block_t
*aout_FiltersPipelinePlay(filter_t
*const *filters
,
278 unsigned count
, block_t
*block
)
280 /* TODO: use filter chain */
281 for (unsigned i
= 0; (i
< count
) && (block
!= NULL
); i
++)
283 filter_t
*filter
= filters
[i
];
285 /* Please note that p_block->i_nb_samples & i_buffer
286 * shall be set by the filter plug-in. */
287 block
= filter
->pf_audio_filter (filter
, block
);
294 * Drain the chain of filters.
296 static block_t
*aout_FiltersPipelineDrain(filter_t
*const *filters
,
299 block_t
*chain
= NULL
;
301 for (unsigned i
= 0; i
< count
; i
++)
303 filter_t
*filter
= filters
[i
];
305 block_t
*block
= filter_DrainAudio (filter
);
308 /* If there is a drained block, filter it through the following
309 * chain of filters */
311 block
= aout_FiltersPipelinePlay (&filters
[i
+ 1],
312 count
- i
- 1, block
);
314 block_ChainAppend (&chain
, block
);
319 return block_ChainGather(chain
);
325 * Flush the chain of filters.
327 static void aout_FiltersPipelineFlush(filter_t
*const *filters
,
330 for (unsigned i
= 0; i
< count
; i
++)
331 filter_Flush (filters
[i
]);
334 static void aout_FiltersPipelineChangeViewpoint(filter_t
*const *filters
,
336 const vlc_viewpoint_t
*vp
)
338 for (unsigned i
= 0; i
< count
; i
++)
339 filter_ChangeViewpoint (filters
[i
], vp
);
342 #define AOUT_MAX_FILTERS 10
346 filter_t
*rate_filter
; /**< The filter adjusting samples count
347 (either the scaletempo filter or a resampler) */
348 filter_t
*resampler
; /**< The resampler */
349 int resampling
; /**< Current resampling (Hz) */
351 unsigned count
; /**< Number of filters */
352 filter_t
*tab
[AOUT_MAX_FILTERS
]; /**< Configured user filters
353 (e.g. equalization) and their conversions */
356 /** Callback for visualization selection */
357 static int VisualizationCallback (vlc_object_t
*obj
, const char *var
,
358 vlc_value_t oldval
, vlc_value_t newval
,
361 const char *mode
= newval
.psz_string
;
365 /* FIXME: This ugly hack enforced by visual effect-list, as is the need for
366 * separate "visual" (external) and "audio-visual" (internal) variables...
367 * The visual plugin should have one submodule per effect instead. */
368 if (strcasecmp (mode
, "none") && strcasecmp (mode
, "goom")
369 && strcasecmp (mode
, "projectm") && strcasecmp (mode
, "vsxu")
370 && strcasecmp (mode
, "glspectrum"))
372 var_Create (obj
, "effect-list", VLC_VAR_STRING
);
373 var_SetString (obj
, "effect-list", mode
);
377 var_SetString (obj
, "audio-visual", mode
);
378 aout_InputRequestRestart ((audio_output_t
*)obj
);
379 (void) var
; (void) oldval
; (void) data
;
383 vout_thread_t
*aout_filter_RequestVout (filter_t
*filter
, vout_thread_t
*vout
,
384 const video_format_t
*fmt
)
386 /* NOTE: This only works from aout_filters_t.
387 * If you want to use visualization filters from another place, you will
388 * need to add a new pf_aout_request_vout callback or store a pointer
389 * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
390 const aout_request_vout_t
*req
= filter
->owner
.sys
;
391 char *visual
= var_InheritString (filter
->obj
.parent
, "audio-visual");
392 /* NOTE: Disable recycling to always close the filter vout because OpenGL
393 * visualizations do not use this function to ask for a context. */
394 bool recycle
= false;
397 return req
->pf_request_vout (req
->p_private
, vout
, fmt
, recycle
);
400 static int AppendFilter(vlc_object_t
*obj
, const char *type
, const char *name
,
401 aout_filters_t
*restrict filters
, const void *owner
,
402 audio_sample_format_t
*restrict infmt
,
403 const audio_sample_format_t
*restrict outfmt
,
406 const unsigned max
= sizeof (filters
->tab
) / sizeof (filters
->tab
[0]);
407 if (filters
->count
>= max
)
409 msg_Err (obj
, "maximum of %u filters reached", max
);
413 filter_t
*filter
= CreateFilter (obj
, type
, name
,
414 (void *)owner
, infmt
, outfmt
, cfg
, false);
417 msg_Err (obj
, "cannot add user %s \"%s\" (skipped)", type
, name
);
421 /* convert to the filter input format if necessary */
422 if (aout_FiltersPipelineCreate (obj
, filters
->tab
, &filters
->count
,
423 max
- 1, infmt
, &filter
->fmt_in
.audio
, false))
425 msg_Err (filter
, "cannot add user %s \"%s\" (skipped)", type
, name
);
426 module_unneed (filter
, filter
->p_module
);
427 vlc_object_release (filter
);
431 assert (filters
->count
< max
);
432 filters
->tab
[filters
->count
] = filter
;
434 *infmt
= filter
->fmt_out
.audio
;
438 static int AppendRemapFilter(vlc_object_t
*obj
, aout_filters_t
*restrict filters
,
439 audio_sample_format_t
*restrict infmt
,
440 const audio_sample_format_t
*restrict outfmt
,
441 const int *wg4_remap
)
446 /* The remap audio filter use a different order than wg4 */
447 static const uint8_t wg4_to_remap
[] = { 0, 2, 6, 7, 3, 5, 4, 1, 8 };
448 int remap
[AOUT_CHAN_MAX
];
450 for (int i
= 0; i
< AOUT_CHAN_MAX
; ++i
)
452 if (wg4_remap
[i
] != i
)
454 remap
[i
] = wg4_remap
[i
] >= 0 ? wg4_to_remap
[wg4_remap
[i
]] : -1;
460 int ret
= asprintf(&str
, "remap{channel-left=%d,channel-right=%d,"
461 "channel-middleleft=%d,channel-middleright=%d,"
462 "channel-rearleft=%d,channel-rearright=%d,"
463 "channel-rearcenter=%d,channel-center=%d,"
464 "channel-lfe=%d,normalize=false}",
465 remap
[0], remap
[1], remap
[2], remap
[3], remap
[4],
466 remap
[5], remap
[6], remap
[7], remap
[8]);
470 free(config_ChainCreate(&name
, &cfg
, str
));
471 if (name
!= NULL
&& cfg
!= NULL
)
472 ret
= AppendFilter(obj
, "audio filter", name
, filters
,
473 NULL
, infmt
, outfmt
, cfg
);
480 config_ChainDestroy(cfg
);
484 #undef aout_FiltersNew
486 * Sets a chain of audio filters up.
487 * \param obj parent object for the filters
488 * \param infmt chain input format [IN]
489 * \param outfmt chain output format [IN]
490 * \param request_vout visualization video output request callback
491 * \param cfg a valid aout_filters_cfg_t struct or NULL.
492 * \return a filters chain or NULL on failure
495 * *request_vout (if not NULL) must remain valid until aout_FiltersDelete().
498 * If request_vout is non NULL, obj is assumed to be an audio_output_t pointer.
500 aout_filters_t
*aout_FiltersNew (vlc_object_t
*obj
,
501 const audio_sample_format_t
*restrict infmt
,
502 const audio_sample_format_t
*restrict outfmt
,
503 const aout_request_vout_t
*request_vout
,
504 const aout_filters_cfg_t
*cfg
)
506 aout_filters_t
*filters
= malloc (sizeof (*filters
));
507 if (unlikely(filters
== NULL
))
510 filters
->rate_filter
= NULL
;
511 filters
->resampler
= NULL
;
512 filters
->resampling
= 0;
515 /* Prepare format structure */
516 aout_FormatPrint (obj
, "input", infmt
);
517 audio_sample_format_t input_format
= *infmt
;
518 audio_sample_format_t output_format
= *outfmt
;
520 /* Callbacks (before reading values and also before return statement) */
521 if (request_vout
!= NULL
)
522 var_AddCallback (obj
, "visual", VisualizationCallback
, NULL
);
524 if (!AOUT_FMT_LINEAR(outfmt
))
525 { /* Non-linear output: just convert formats, no filters/visu */
526 if (!AOUT_FMTS_IDENTICAL(infmt
, outfmt
))
528 aout_FormatsPrint (obj
, "pass-through:", infmt
, outfmt
);
529 filters
->tab
[0] = FindConverter(obj
, infmt
, outfmt
);
530 if (filters
->tab
[0] == NULL
)
532 msg_Err (obj
, "cannot setup pass-through");
539 if (aout_FormatNbChannels(outfmt
) == 0)
541 msg_Warn (obj
, "No ouput channel mask, cannot setup filters");
545 assert(output_format
.channel_type
== AUDIO_CHANNEL_TYPE_BITMAP
);
546 if (input_format
.channel_type
!= output_format
.channel_type
)
548 /* Do the channel type conversion before any filters since audio
549 * converters and filters handle only AUDIO_CHANNEL_TYPE_BITMAP */
551 /* convert to the output format (minus resampling) if necessary */
552 output_format
.i_rate
= input_format
.i_rate
;
553 if (aout_FiltersPipelineCreate (obj
, filters
->tab
, &filters
->count
,
554 AOUT_MAX_FILTERS
, &input_format
, &output_format
,
557 msg_Warn (obj
, "cannot setup audio renderer pipeline");
558 /* Fallback to bitmap without any conversions */
559 input_format
.channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
560 aout_FormatPrepare(&input_format
);
563 input_format
= output_format
;
566 if (aout_FormatNbChannels(&input_format
) == 0)
568 /* The input channel map is unknown, use the WAVE one and add a
569 * converter that will drop extra channels that are not handled by VLC
571 msg_Info(obj
, "unknown channel map, using the WAVE channel layout.");
573 assert(input_format
.i_channels
> 0);
574 audio_sample_format_t input_phys_format
= input_format
;
575 aout_SetWavePhysicalChannels(&input_phys_format
);
577 filter_t
*f
= FindConverter (obj
, &input_format
, &input_phys_format
);
580 msg_Err (obj
, "cannot find channel converter");
584 input_format
= input_phys_format
;
585 filters
->tab
[filters
->count
++] = f
;
588 assert(input_format
.channel_type
== AUDIO_CHANNEL_TYPE_BITMAP
);
590 /* parse user filter lists */
591 if (var_InheritBool (obj
, "audio-time-stretch"))
593 if (AppendFilter(obj
, "audio filter", "scaletempo",
594 filters
, NULL
, &input_format
, &output_format
, NULL
) == 0)
595 filters
->rate_filter
= filters
->tab
[filters
->count
- 1];
600 AppendRemapFilter(obj
, filters
, &input_format
, &output_format
,
603 if (input_format
.i_channels
> 2 && cfg
->headphones
)
604 AppendFilter(obj
, "audio filter", "binauralizer", filters
, NULL
,
605 &input_format
, &output_format
, NULL
);
608 /* Now add user filters */
609 char *str
= var_InheritString (obj
, "audio-filter");
612 char *p
= str
, *name
;
613 while ((name
= strsep (&p
, " :")) != NULL
)
615 AppendFilter(obj
, "audio filter", name
, filters
,
616 NULL
, &input_format
, &output_format
, NULL
);
621 if (request_vout
!= NULL
)
623 char *visual
= var_InheritString (obj
, "audio-visual");
624 if (visual
!= NULL
&& strcasecmp (visual
, "none"))
625 AppendFilter(obj
, "visualization", visual
, filters
,
626 request_vout
, &input_format
, &output_format
, NULL
);
630 /* convert to the output format (minus resampling) if necessary */
631 output_format
.i_rate
= input_format
.i_rate
;
632 if (aout_FiltersPipelineCreate (obj
, filters
->tab
, &filters
->count
,
633 AOUT_MAX_FILTERS
, &input_format
, &output_format
, false))
635 msg_Err (obj
, "cannot setup filtering pipeline");
638 input_format
= output_format
;
640 /* insert the resampler */
641 output_format
.i_rate
= outfmt
->i_rate
;
642 assert (AOUT_FMTS_IDENTICAL(&output_format
, outfmt
));
643 filters
->resampler
= FindResampler (obj
, &input_format
,
645 if (filters
->resampler
== NULL
&& input_format
.i_rate
!= outfmt
->i_rate
)
647 msg_Err (obj
, "cannot setup a resampler");
650 if (filters
->rate_filter
== NULL
)
651 filters
->rate_filter
= filters
->resampler
;
656 aout_FiltersPipelineDestroy (filters
->tab
, filters
->count
);
657 if (request_vout
!= NULL
)
658 var_DelCallback (obj
, "visual", VisualizationCallback
, NULL
);
663 #undef aout_FiltersDelete
665 * Destroys a chain of audio filters.
666 * \param obj object used with aout_FiltersNew()
667 * \param filters chain to be destroyed
669 * obj must be NULL iff request_vout was NULL in aout_FiltersNew()
670 * (this implies obj is an audio_output_t pointer if non NULL).
672 void aout_FiltersDelete (vlc_object_t
*obj
, aout_filters_t
*filters
)
674 if (filters
->resampler
!= NULL
)
675 aout_FiltersPipelineDestroy (&filters
->resampler
, 1);
676 aout_FiltersPipelineDestroy (filters
->tab
, filters
->count
);
678 var_DelCallback (obj
, "visual", VisualizationCallback
, NULL
);
682 bool aout_FiltersCanResample (aout_filters_t
*filters
)
684 return (filters
->resampler
!= NULL
);
687 bool aout_FiltersAdjustResampling (aout_filters_t
*filters
, int adjust
)
689 if (filters
->resampler
== NULL
)
693 filters
->resampling
+= adjust
;
695 filters
->resampling
= 0;
696 return filters
->resampling
!= 0;
699 block_t
*aout_FiltersPlay (aout_filters_t
*filters
, block_t
*block
, int rate
)
701 int nominal_rate
= 0;
703 if (rate
!= INPUT_RATE_DEFAULT
)
705 filter_t
*rate_filter
= filters
->rate_filter
;
707 if (rate_filter
== NULL
)
708 goto drop
; /* Without linear, non-nominal rate is impossible. */
710 /* Override input rate */
711 nominal_rate
= rate_filter
->fmt_in
.audio
.i_rate
;
712 rate_filter
->fmt_in
.audio
.i_rate
=
713 (nominal_rate
* INPUT_RATE_DEFAULT
) / rate
;
716 block
= aout_FiltersPipelinePlay (filters
->tab
, filters
->count
, block
);
717 if (filters
->resampler
!= NULL
)
718 { /* NOTE: the resampler needs to run even if resampling is 0.
719 * The decoder and output rates can still be different. */
720 filters
->resampler
->fmt_in
.audio
.i_rate
+= filters
->resampling
;
721 block
= aout_FiltersPipelinePlay (&filters
->resampler
, 1, block
);
722 filters
->resampler
->fmt_in
.audio
.i_rate
-= filters
->resampling
;
725 if (nominal_rate
!= 0)
726 { /* Restore input rate */
727 assert (filters
->rate_filter
!= NULL
);
728 filters
->rate_filter
->fmt_in
.audio
.i_rate
= nominal_rate
;
733 block_Release (block
);
737 block_t
*aout_FiltersDrain (aout_filters_t
*filters
)
739 /* Drain the filters pipeline */
740 block_t
*block
= aout_FiltersPipelineDrain (filters
->tab
, filters
->count
);
742 if (filters
->resampler
!= NULL
)
744 block_t
*chain
= NULL
;
746 filters
->resampler
->fmt_in
.audio
.i_rate
+= filters
->resampling
;
750 /* Resample the drained block from the filters pipeline */
751 block
= aout_FiltersPipelinePlay (&filters
->resampler
, 1, block
);
753 block_ChainAppend (&chain
, block
);
756 /* Drain the resampler filter */
757 block
= aout_FiltersPipelineDrain (&filters
->resampler
, 1);
759 block_ChainAppend (&chain
, block
);
761 filters
->resampler
->fmt_in
.audio
.i_rate
-= filters
->resampling
;
763 return chain
? block_ChainGather (chain
) : NULL
;
769 void aout_FiltersFlush (aout_filters_t
*filters
)
771 aout_FiltersPipelineFlush (filters
->tab
, filters
->count
);
773 if (filters
->resampler
!= NULL
)
774 aout_FiltersPipelineFlush (&filters
->resampler
, 1);
777 void aout_FiltersChangeViewpoint (aout_filters_t
*filters
,
778 const vlc_viewpoint_t
*vp
)
780 aout_FiltersPipelineChangeViewpoint (filters
->tab
, filters
->count
, vp
);