]> git.sesse.net Git - vlc/commitdiff
aout: partly rewrite and move filters initialization code
authorRémi Denis-Courmont <remi@remlab.net>
Tue, 6 Nov 2012 19:27:47 +0000 (21:27 +0200)
committerRémi Denis-Courmont <remi@remlab.net>
Tue, 6 Nov 2012 19:27:47 +0000 (21:27 +0200)
 - simplify "audio-filter" parser and fix a tautology
 - keep a single pointer for the resampler instead of a table

src/audio_output/aout_internal.h
src/audio_output/dec.c
src/audio_output/filters.c
src/audio_output/input.c
src/audio_output/output.c

index 2685691f8c8154a0cbe0839bf580279400cc1d7b..caf6503b48c9a32fbbe58b7c755ba3079b4bc91c 100644 (file)
@@ -51,15 +51,6 @@ struct aout_input_t
 {
     unsigned            samplerate; /**< Input sample rate */
 
-    /* filters */
-    filter_t *              pp_filters[AOUT_MAX_FILTERS];
-    unsigned                i_nb_filters;
-
-    filter_t *              p_playback_rate_filter;
-
-    /* Resampler + converter to mixer */
-    filter_t *              pp_resamplers[5];
-    unsigned                i_nb_resamplers;
     int                     i_resampling_type;
     mtime_t                 i_resamp_start_date;
     int                     i_resamp_start_drift;
@@ -69,10 +60,6 @@ struct aout_input_t
 
     /* */
     int               i_buffer_lost;
-
-    /* */
-    bool                b_recycle_vout;
-    aout_request_vout_t request_vout;
 };
 
 typedef struct
@@ -87,12 +74,20 @@ typedef struct
         date_t date;
     } sync;
 
-    audio_sample_format_t mixer_format;
     audio_sample_format_t input_format;
+    audio_sample_format_t mixer_format;
 
-    /* Filters between mixer and output */
-    filter_t *filters[5];
-    unsigned  nb_filters;
+    filter_t *rate_filter; /**< The filter adjusting samples count
+        (either the scaletempo filter or a resampler) */
+    filter_t *resampler; /**< The resampler */
+    filter_t *filters[AOUT_MAX_FILTERS]; /**< Configured user filters
+        (e.g. equalization) and their conversions */
+    unsigned nb_filters;
+    unsigned nb_converters;
+    filter_t *converters[5]; /**< Converters to the output */
+
+    aout_request_vout_t request_vout;
+    bool recycle_vout;
 
     vlc_atomic_t restart;
 } aout_owner_t;
@@ -128,6 +123,10 @@ int aout_FiltersCreatePipeline( vlc_object_t *, filter_t **, unsigned *,
 void aout_FiltersDestroyPipeline( filter_t *const *, unsigned );
 void aout_FiltersPlay( filter_t *const *, unsigned, block_t ** );
 
+int aout_FiltersNew(audio_output_t *, const audio_sample_format_t *,
+                   const audio_sample_format_t *, const aout_request_vout_t *);
+void aout_FiltersDestroy(audio_output_t *);
+
 /* From mixer.c : */
 aout_volume_t *aout_volume_New(vlc_object_t *, const audio_replay_gain_t *);
 #define aout_volume_New(o, g) aout_volume_New(VLC_OBJECT(o), g)
index 8a886e8f8fba43a80c4c3b076c6e037f2645b7ac..124eb31a390fed87292130ec93bda978110a8b30 100644 (file)
@@ -138,7 +138,7 @@ static void aout_CheckRestart (audio_output_t *aout)
 
     assert (restart & AOUT_RESTART_INPUT);
 
-    const aout_request_vout_t request_vout = owner->input->request_vout;
+    const aout_request_vout_t request_vout = owner->request_vout;
 
     if (likely(owner->input != NULL))
         aout_InputDelete (aout, owner->input);
index bb75a89ef67f45b3b0162a18bce93d5a853d375a..cb7e2aef5d7396e50b25ddfa8c3fc2d574312a0c 100644 (file)
 # include "config.h"
 #endif
 
+#include <string.h>
 #include <assert.h>
 
 #include <vlc_common.h>
 #include <vlc_dialog.h>
 #include <vlc_modules.h>
-
 #include <vlc_aout.h>
 #include <vlc_filter.h>
-#include <vlc_cpu.h>
-#include "aout_internal.h"
+#include <vlc_vout.h>                  /* for vout_Request */
+
 #include <libvlc.h>
+#include "aout_internal.h"
 
 /*****************************************************************************
  * FindFilter: find an audio filter for a specific transformation
@@ -211,6 +212,12 @@ void aout_FiltersDestroyPipeline( filter_t *const *filters, unsigned n )
     }
 }
 
+static inline bool ChangeFiltersString (vlc_object_t *aout, const char *var,
+                                        const char *filter, bool add)
+{
+    return aout_ChangeFilterString (aout, aout, var, filter, add);
+}
+
 /**
  * Filters an audio buffer through a chain of filters.
  */
@@ -230,3 +237,302 @@ void aout_FiltersPlay( filter_t *const *pp_filters,
     }
     *pp_block = p_block;
 }
+
+/** Callback for visualization selection */
+static int VisualizationCallback (vlc_object_t *obj, char const *var,
+                                  vlc_value_t oldval, vlc_value_t newval,
+                                  void *data)
+{
+    audio_output_t *aout = (audio_output_t *)obj;
+    const char *mode = newval.psz_string;
+
+    if (!*mode)
+    {
+        ChangeFiltersString (obj, "audio-visual", "goom", false);
+        ChangeFiltersString (obj, "audio-visual", "visual", false);
+        ChangeFiltersString (obj, "audio-visual", "projectm", false);
+        ChangeFiltersString (obj, "audio-visual", "vsxu", false);
+    }
+    else if (!strcmp ("goom", mode))
+    {
+        ChangeFiltersString (obj, "audio-visual", "visual", false );
+        ChangeFiltersString (obj, "audio-visual", "goom", true );
+        ChangeFiltersString (obj, "audio-visual", "projectm", false );
+        ChangeFiltersString (obj, "audio-visual", "vsxu", false);
+    }
+    else if (!strcmp ("projectm", mode))
+    {
+        ChangeFiltersString (obj, "audio-visual", "visual", false);
+        ChangeFiltersString (obj, "audio-visual", "goom", false);
+        ChangeFiltersString (obj, "audio-visual", "projectm", true);
+        ChangeFiltersString (obj, "audio-visual", "vsxu", false);
+    }
+    else if (!strcmp ("vsxu", mode))
+    {
+        ChangeFiltersString (obj, "audio-visual", "visual", false);
+        ChangeFiltersString (obj, "audio-visual", "goom", false);
+        ChangeFiltersString (obj, "audio-visual", "projectm", false);
+        ChangeFiltersString (obj, "audio-visual", "vsxu", true);
+    }
+    else
+    {
+        var_Create (obj, "effect-list", VLC_VAR_STRING);
+        var_SetString (obj, "effect-list", mode);
+
+        ChangeFiltersString (obj, "audio-visual", "goom", false);
+        ChangeFiltersString (obj, "audio-visual", "visual", true);
+        ChangeFiltersString (obj, "audio-visual", "projectm", false);
+    }
+
+    aout_InputRequestRestart (aout);
+    (void) var; (void) oldval; (void) data;
+    return VLC_SUCCESS;
+}
+
+static int EqualizerCallback (vlc_object_t *obj, char const *var,
+                              vlc_value_t oldval, vlc_value_t newval,
+                              void *data)
+{
+    audio_output_t *aout = (audio_output_t *)obj;
+    char *mode = newval.psz_string;
+    bool ret;
+
+    if (!*mode)
+        ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
+    else
+    {
+        var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
+        var_SetString (obj, "equalizer-preset", mode);
+        ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
+    }
+
+    /* That sucks */
+    if (ret)
+        aout_InputRequestRestart (aout);
+    (void) var; (void) oldval; (void) data;
+    return VLC_SUCCESS;
+}
+
+static vout_thread_t *RequestVout (void *data, vout_thread_t *vout,
+                                   video_format_t *fmt, bool recycle)
+{
+    audio_output_t *aout = data;
+    vout_configuration_t cfg = {
+        .vout       = vout,
+        .input      = NULL,
+        .change_fmt = true,
+        .fmt        = fmt,
+        .dpb_size   = 1,
+    };
+
+    (void) recycle;
+    return vout_Request (aout, &cfg);
+}
+
+vout_thread_t *aout_filter_RequestVout (filter_t *filter, vout_thread_t *vout,
+                                        video_format_t *fmt)
+{
+    /* NOTE: This only works from audio output.
+     * If you want to use visualization filters from another place, you will
+     * need to add a new pf_aout_request_vout callback or store a pointer
+     * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
+    aout_owner_t *owner = aout_owner ((audio_output_t *)filter->p_parent);
+    aout_request_vout_t *req = &owner->request_vout;
+
+    return req->pf_request_vout (req->p_private, vout, fmt,
+                                 owner->recycle_vout);
+}
+
+static filter_t *CreateFilter (vlc_object_t *parent, const char *name,
+                               const audio_sample_format_t *restrict infmt,
+                               const audio_sample_format_t *restrict outfmt,
+                               bool visu)
+{
+    filter_t *filter = vlc_custom_create (parent, sizeof (*filter),
+                                          "audio filter");
+    if (unlikely(filter == NULL))
+        return NULL;
+
+    /*filter->p_owner = NOT NEEDED;*/
+    filter->fmt_in.i_codec = infmt->i_format;
+    filter->fmt_in.audio = *infmt;
+    filter->fmt_out.i_codec = outfmt->i_format;
+    filter->fmt_out.audio = *outfmt;
+
+    if (!visu)
+    {
+        filter->p_module = module_need (filter, "audio filter", name, true);
+        if (filter->p_module != NULL)
+            return filter;
+
+        /* If probing failed, formats shall not have been modified. */
+        assert (AOUT_FMTS_IDENTICAL(&filter->fmt_in.audio, infmt));
+        assert (AOUT_FMTS_IDENTICAL(&filter->fmt_out.audio, outfmt));
+    }
+
+    filter->p_module = module_need (filter, "visualization2", name, true);
+    if (filter->p_module != NULL)
+        return filter;
+
+    vlc_object_release (filter);
+    return NULL;
+}
+
+/**
+ * Sets up the audio filters.
+ */
+int aout_FiltersNew (audio_output_t *aout,
+                     const audio_sample_format_t *restrict infmt,
+                     const audio_sample_format_t *restrict outfmt,
+                     const aout_request_vout_t *request_vout)
+{
+    aout_owner_t *owner = aout_owner (aout);
+
+    /* Prepare format structure */
+    aout_FormatPrint (aout, "input", infmt);
+    audio_sample_format_t input_format = *infmt;
+    audio_sample_format_t output_format = *outfmt;
+
+    /* Now add user filters */
+    owner->nb_filters = 0;
+    owner->rate_filter = NULL;
+    owner->resampler = NULL;
+
+    if (!AOUT_FMT_LINEAR(outfmt))
+        return 0;
+
+    var_AddCallback (aout, "visual", VisualizationCallback, NULL);
+    var_AddCallback (aout, "equalizer", EqualizerCallback, NULL);
+
+    bool scaletempo = var_InheritBool (aout, "audio-time-stretch");
+    char *filters = var_InheritString (aout, "audio-filter");
+    char *visual = var_InheritString (aout, "audio-visual");
+
+    if (request_vout != NULL)
+        owner->request_vout = *request_vout;
+    else
+    {
+        owner->request_vout.pf_request_vout = RequestVout;
+        owner->request_vout.p_private = aout;
+    }
+    owner->recycle_vout = (visual != NULL) && *visual;
+
+    /* parse user filter lists */
+    const char *list[AOUT_MAX_FILTERS];
+    unsigned n = 0;
+
+    if (scaletempo)
+        list[n++] = "scaletempo";
+    if (filters != NULL)
+    {
+        char *p = filters, *name;
+        while ((name = strsep (&p, " :")) != NULL && n < AOUT_MAX_FILTERS)
+            list[n++] = name;
+    }
+    if (visual != NULL && n < AOUT_MAX_FILTERS)
+        list[n++] = visual;
+
+    for (unsigned i = 0; i < n; i++)
+    {
+        const char *name = list[i];
+
+        if (owner->nb_filters >= AOUT_MAX_FILTERS)
+        {
+            msg_Err (aout, "maximum of %u filters reached", AOUT_MAX_FILTERS);
+            msg_Err (aout, "cannot add user filter %s (skipped)", name);
+            break;
+        }
+
+        filter_t *filter = CreateFilter (VLC_OBJECT(aout), name,
+                                         &input_format, &output_format,
+                                         i == (n - (visual != NULL)));
+        if (filter == NULL)
+        {
+            msg_Err (aout, "cannot add user filter %s (skipped)", name);
+            continue;
+        }
+
+        /* convert to the filter input format if necessary */
+        if (aout_FiltersCreatePipeline (VLC_OBJECT(aout), owner->filters,
+                                        &owner->nb_filters,
+                                        AOUT_MAX_FILTERS - 1,
+                                        &input_format, &filter->fmt_in.audio))
+        {
+            msg_Err (aout, "cannot add user filter %s (skipped)", name);
+            module_unneed (filter, filter->p_module);
+            vlc_object_release (filter);
+            continue;
+        }
+
+        assert (owner->nb_filters < AOUT_MAX_FILTERS);
+        owner->filters[owner->nb_filters++] = filter;
+        input_format = filter->fmt_out.audio;
+
+        if (i == 0 && scaletempo) /* scaletempo */
+            owner->rate_filter = filter;
+    }
+    free (visual);
+    free (filters);
+
+    /* convert to the output format (minus resampling) if necessary */
+    output_format.i_rate = input_format.i_rate;
+    if (aout_FiltersCreatePipeline (VLC_OBJECT(aout), owner->filters,
+                                    &owner->nb_filters, AOUT_MAX_FILTERS,
+                                    &input_format, &output_format))
+    {
+        msg_Err (aout, "cannot setup filtering pipeline");
+        goto error;
+    }
+    input_format = output_format;
+
+    /* insert the resampler */
+    output_format.i_rate = outfmt->i_rate;
+    assert (AOUT_FMTS_IDENTICAL(&output_format, outfmt));
+
+    unsigned rate_bak = input_format.i_rate;
+    if (output_format.i_rate == input_format.i_rate)
+        /* For historical reasons, a different rate is required to probe
+         * resampling filters. */
+        input_format.i_rate++;
+    owner->resampler = FindFilter (VLC_OBJECT(aout), &input_format,
+                                   &output_format);
+    if (owner->resampler == NULL)
+    {
+        msg_Err (aout, "cannot setup a resampler");
+        goto error;
+    }
+    owner->resampler->fmt_in.audio.i_rate = rate_bak;
+    if (owner->rate_filter == NULL)
+        owner->rate_filter = owner->resampler;
+
+    return 0;
+
+error:
+    aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
+    var_DelCallback (aout, "equalizer", EqualizerCallback, NULL);
+    var_DelCallback (aout, "visual", VisualizationCallback, NULL);
+    return -1;
+}
+
+/**
+ * Destroys the audio filters.
+ */
+void aout_FiltersDestroy (audio_output_t *aout)
+{
+    aout_owner_t *owner = aout_owner (aout);
+
+    if (owner->resampler != NULL)
+        aout_FiltersDestroyPipeline (&owner->resampler, 1);
+    aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
+    var_DelCallback (aout, "equalizer", EqualizerCallback, NULL);
+    var_DelCallback (aout, "visual", VisualizationCallback, NULL);
+
+    /* XXX We need to update recycle_vout before calling
+     * aout_FiltersDestroyPipeline().
+     * FIXME There may be a race condition if audio-visual is updated between
+     * aout_FiltersDestroy() and the next aout_FiltersNew().
+     */
+    char *visual = var_InheritString (aout, "audio-visual");
+    owner->recycle_vout = (visual != NULL) && *visual;
+    free (visual);
+}
index 351edc63718310d36dc824f110fea1dbf8a2a50f..3056809bf612e5f4bd83c6f295df31cfd5bf150f 100644 (file)
 #endif
 
 #include <vlc_common.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
 #include <vlc_input.h>
-#include <vlc_vout.h>                  /* for vout_Request */
-#include <vlc_modules.h>
 #include <vlc_aout.h>
 #include <vlc_filter.h>
-#include <libvlc.h>
 
+#include <libvlc.h>
 #include "aout_internal.h"
 
 static void inputDrop( aout_input_t *, block_t * );
-static void inputResamplingStop( aout_input_t *p_input );
-
-static int VisualizationCallback( vlc_object_t *, char const *,
-                                  vlc_value_t, vlc_value_t, void * );
-static int EqualizerCallback( vlc_object_t *, char const *,
-                              vlc_value_t, vlc_value_t, void * );
-
-static vout_thread_t *RequestVout( void *,
-                                   vout_thread_t *, video_format_t *, bool );
+static void inputResamplingStop( audio_output_t *, aout_input_t * );
 
 /*****************************************************************************
  * aout_InputNew : allocate a new input and rework the filter pipeline
@@ -67,232 +52,18 @@ aout_input_t *aout_InputNew (audio_output_t * p_aout,
     if (unlikely(p_input == NULL))
         return NULL;
 
-    aout_FormatPrint( p_aout, "input", infmt );
     p_input->samplerate = infmt->i_rate;
 
-    p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
-
-    /* */
-    if( p_request_vout )
-    {
-        p_input->request_vout = *p_request_vout;
-    }
-    else
-    {
-        p_input->request_vout.pf_request_vout = RequestVout;
-        p_input->request_vout.p_private = p_aout;
-    }
-
-    /* Prepare format structure */
-    audio_sample_format_t chain_input_format = *infmt;
-    audio_sample_format_t chain_output_format = *outfmt;
-
-    chain_output_format.i_rate = infmt->i_rate;
-    aout_FormatPrepare( &chain_output_format );
-
-    /* Now add user filters */
-    var_AddCallback( p_aout, "visual", VisualizationCallback, p_input );
-    var_AddCallback( p_aout, "equalizer", EqualizerCallback, p_input );
-
-    char *psz_filters = var_GetString( p_aout, "audio-filter" );
-    char *psz_visual = var_GetString( p_aout, "audio-visual");
-    char *psz_scaletempo = var_InheritBool( p_aout, "audio-time-stretch" ) ? strdup( "scaletempo" ) : NULL;
-
-    p_input->b_recycle_vout = psz_visual && *psz_visual;
-
-    /* parse user filter lists */
-    char *const ppsz_array[] = { psz_scaletempo, psz_filters, psz_visual };
-    p_input->p_playback_rate_filter = NULL;
-
-    for (unsigned i_visual = 0;
-         i_visual < 3 && AOUT_FMT_LINEAR(&chain_output_format);
-         i_visual++)
+    if (aout_FiltersNew (p_aout, infmt, outfmt, p_request_vout))
     {
-        char *psz_next = NULL;
-        char *psz_parser = ppsz_array[i_visual];
-
-        if( psz_parser == NULL || !*psz_parser )
-            continue;
-
-        while( psz_parser && *psz_parser )
-        {
-            filter_t * p_filter = NULL;
-
-            if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
-            {
-                msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
-                break;
-            }
-
-            while( *psz_parser == ' ' && *psz_parser == ':' )
-            {
-                psz_parser++;
-            }
-            if( ( psz_next = strchr( psz_parser , ':'  ) ) )
-            {
-                *psz_next++ = '\0';
-            }
-            if( *psz_parser =='\0' )
-            {
-                break;
-            }
-
-            /* Create a VLC object */
-            p_filter = vlc_custom_create( p_aout, sizeof(*p_filter),
-                                          "audio filter" );
-            if( p_filter == NULL )
-            {
-                msg_Err( p_aout, "cannot add user filter %s (skipped)",
-                         psz_parser );
-                psz_parser = psz_next;
-                continue;
-            }
-            p_filter->p_owner = (filter_owner_sys_t *)p_input;
-
-            /* request format */
-            memcpy( &p_filter->fmt_in.audio, &chain_output_format,
-                    sizeof(audio_sample_format_t) );
-            p_filter->fmt_in.i_codec = chain_output_format.i_format;
-            memcpy( &p_filter->fmt_out.audio, &chain_output_format,
-                    sizeof(audio_sample_format_t) );
-            p_filter->fmt_out.i_codec = chain_output_format.i_format;
-
-            /* try to find the requested filter */
-            if( i_visual == 2 ) /* this can only be a visualization module */
-            {
-                p_filter->p_module = module_need( p_filter, "visualization2",
-                                                  psz_parser, true );
-            }
-            else /* this can be a audio filter module as well as a visualization module */
-            {
-                p_filter->p_module = module_need( p_filter, "audio filter",
-                                              psz_parser, true );
-
-                if ( p_filter->p_module == NULL )
-                {
-                    /* if the filter requested a special format, retry */
-                    if ( !( AOUT_FMTS_IDENTICAL( &p_filter->fmt_in.audio,
-                                                 &chain_input_format )
-                            && AOUT_FMTS_IDENTICAL( &p_filter->fmt_out.audio,
-                                                    &chain_output_format ) ) )
-                    {
-                        aout_FormatPrepare( &p_filter->fmt_in.audio );
-                        aout_FormatPrepare( &p_filter->fmt_out.audio );
-                        p_filter->p_module = module_need( p_filter,
-                                                          "audio filter",
-                                                          psz_parser, true );
-                    }
-                    /* try visual filters */
-                    else
-                    {
-                        memcpy( &p_filter->fmt_in.audio, &chain_output_format,
-                                sizeof(audio_sample_format_t) );
-                        memcpy( &p_filter->fmt_out.audio, &chain_output_format,
-                                sizeof(audio_sample_format_t) );
-                        p_filter->p_module = module_need( p_filter,
-                                                          "visualization2",
-                                                          psz_parser, true );
-                    }
-                }
-            }
-
-            /* failure */
-            if ( p_filter->p_module == NULL )
-            {
-                msg_Err( p_aout, "cannot add user filter %s (skipped)",
-                         psz_parser );
-
-                vlc_object_release( p_filter );
-
-                psz_parser = psz_next;
-                continue;
-            }
-
-            /* complete the filter chain if necessary */
-            if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
-                                             &p_input->i_nb_filters,
-                                             AOUT_MAX_FILTERS,
-                                             &chain_input_format,
-                                             &p_filter->fmt_in.audio ) < 0 )
-            {
-                msg_Err( p_aout, "cannot add user filter %s (skipped)",
-                         psz_parser );
-
-                module_unneed( p_filter, p_filter->p_module );
-                vlc_object_release( p_filter );
-
-                psz_parser = psz_next;
-                continue;
-            }
-
-            /* success */
-            p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
-            memcpy( &chain_input_format, &p_filter->fmt_out.audio,
-                    sizeof( audio_sample_format_t ) );
-
-            if( i_visual == 0 ) /* scaletempo */
-                p_input->p_playback_rate_filter = p_filter;
-
-            /* next filter if any */
-            psz_parser = psz_next;
-        }
-    }
-    free( psz_visual );
-    free( psz_filters );
-    free( psz_scaletempo );
-
-    /* complete the filter chain if necessary */
-    if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
-                                     &p_input->i_nb_filters, AOUT_MAX_FILTERS,
-                                     &chain_input_format,
-                                     &chain_output_format ) < 0 )
-    {
-        msg_Err (p_aout, "cannot setup filtering pipeline");
-        goto error;
+        free(p_input);
+        return NULL;
     }
 
-    /* Create resamplers. */
-    if (AOUT_FMT_LINEAR(outfmt))
-    {
-        chain_output_format.i_rate = (__MAX(p_input->samplerate,
-                                            outfmt->i_rate)
-                                 * (100 + AOUT_MAX_RESAMPLING)) / 100;
-        if ( chain_output_format.i_rate == outfmt->i_rate )
-        {
-            /* Just in case... */
-            chain_output_format.i_rate++;
-        }
-        if (aout_FiltersCreatePipeline (p_aout, p_input->pp_resamplers,
-                                        &p_input->i_nb_resamplers,
-                                        sizeof (p_input->pp_resamplers)
-                                          / sizeof (p_input->pp_resamplers[0]),
-                                        &chain_output_format, outfmt) < 0)
-        {
-            msg_Err (p_aout, "cannot setup a resampling pipeline");
-            goto error;
-        }
-
-        /* Setup the initial rate of the resampler */
-        p_input->pp_resamplers[0]->fmt_in.audio.i_rate = p_input->samplerate;
-    }
     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
-
-    if( ! p_input->p_playback_rate_filter && p_input->i_nb_resamplers > 0 )
-    {
-        p_input->p_playback_rate_filter = p_input->pp_resamplers[0];
-    }
-
-    /* Success */
     p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
     p_input->i_buffer_lost = 0;
     return p_input;
-
-error:
-    aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
-    aout_FiltersDestroyPipeline( p_input->pp_resamplers,
-                                 p_input->i_nb_resamplers );
-    free (p_input);
-    return NULL;
 }
 
 /*****************************************************************************
@@ -302,23 +73,8 @@ error:
  *****************************************************************************/
 int aout_InputDelete( audio_output_t * p_aout, aout_input_t * p_input )
 {
-    var_DelCallback (p_aout, "equalizer", EqualizerCallback, p_input);
-    var_DelCallback (p_aout, "visual", VisualizationCallback, p_input);
-
-    /* XXX We need to update b_recycle_vout before calling aout_FiltersDestroyPipeline.
-     * FIXME They can be a race condition if audio-visual is updated between
-     * aout_InputDelete and aout_InputNew.
-     */
-    char *psz_visual = var_GetString( p_aout, "audio-visual");
-    p_input->b_recycle_vout = psz_visual && *psz_visual;
-    free( psz_visual );
-
-    aout_FiltersDestroyPipeline( p_input->pp_filters, p_input->i_nb_filters );
-    p_input->i_nb_filters = 0;
-    aout_FiltersDestroyPipeline( p_input->pp_resamplers,
-                                 p_input->i_nb_resamplers );
-    p_input->i_nb_resamplers = 0;
-
+    aout_FiltersDestroy (p_aout);
+    (void) p_input;
     return 0;
 }
 
@@ -331,10 +87,11 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
                         block_t *p_buffer, int i_input_rate, date_t *date )
 {
     mtime_t start_date;
+    aout_owner_t *owner = aout_owner(p_aout);
 
     aout_assert_locked( p_aout );
 
-    if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
+    if( i_input_rate != INPUT_RATE_DEFAULT && owner->rate_filter == NULL )
     {
         inputDrop( p_input, p_buffer );
         return NULL;
@@ -343,7 +100,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
     /* Handle input rate change, but keep drift correction */
     if( i_input_rate != p_input->i_last_input_rate )
     {
-        unsigned int * const pi_rate = &p_input->p_playback_rate_filter->fmt_in.audio.i_rate;
+        unsigned int * const pi_rate = &owner->rate_filter->fmt_in.audio.i_rate;
 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
         const int i_delta = *pi_rate - F(p_input->samplerate,p_input->i_last_input_rate);
         *pi_rate = F(p_input->samplerate + i_delta, i_input_rate);
@@ -368,7 +125,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
         aout_OutputFlush( p_aout, false );
         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
             msg_Warn( p_aout, "timing screwed, stopping resampling" );
-        inputResamplingStop( p_input );
+        inputResamplingStop( p_aout, p_input );
         p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
         start_date = VLC_TS_INVALID;
     }
@@ -380,7 +137,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
         msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
                   now - p_buffer->i_pts );
         inputDrop( p_input, p_buffer );
-        inputResamplingStop( p_input );
+        inputResamplingStop( p_aout, p_input );
         return NULL;
     }
 
@@ -401,7 +158,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
         aout_OutputFlush( p_aout, false );
         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
             msg_Warn( p_aout, "timing screwed, stopping resampling" );
-        inputResamplingStop( p_input );
+        inputResamplingStop( p_aout, p_input );
         p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
         start_date = p_buffer->i_pts;
         date_Set (date, start_date);
@@ -417,7 +174,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
     }
 
     /* Run pre-filters. */
-    aout_FiltersPlay( p_input->pp_filters, p_input->i_nb_filters, &p_buffer );
+    aout_FiltersPlay( owner->filters, owner->nb_filters, &p_buffer );
     if( !p_buffer )
         return NULL;
 
@@ -425,7 +182,7 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
      * We first need to calculate the output rate of this resampler. */
     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
          ( drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY ) &&
-         p_input->i_nb_resamplers > 0 )
+         owner->resampler != NULL )
     {
         /* Can happen in several circumstances :
          * 1. A problem at the input (clock drift)
@@ -450,17 +207,17 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
          * it isn't too audible to the listener. */
 
         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
-            p_input->pp_resamplers[0]->fmt_in.audio.i_rate += 2; /* Hz */
+            owner->resampler->fmt_in.audio.i_rate += 2; /* Hz */
         else
-            p_input->pp_resamplers[0]->fmt_in.audio.i_rate -= 2; /* Hz */
+            owner->resampler->fmt_in.audio.i_rate -= 2; /* Hz */
 
         /* Check if everything is back to normal, in which case we can stop the
          * resampling */
         unsigned int i_nominal_rate =
-          (p_input->pp_resamplers[0] == p_input->p_playback_rate_filter)
+          (owner->resampler == owner->rate_filter)
           ? INPUT_RATE_DEFAULT * p_input->samplerate / i_input_rate
           : p_input->samplerate;
-        if( p_input->pp_resamplers[0]->fmt_in.audio.i_rate == i_nominal_rate )
+        if( owner->resampler->fmt_in.audio.i_rate == i_nominal_rate )
         {
             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
             msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
@@ -486,17 +243,14 @@ block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
             /* If the drift is increasing and not decreasing, than something
              * is bad. We'd better stop the resampling right now. */
             msg_Warn( p_aout, "timing screwed, stopping resampling" );
-            inputResamplingStop( p_input );
+            inputResamplingStop( p_aout, p_input );
             p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
         }
     }
 
     /* Actually run the resampler now. */
-    if ( p_input->i_nb_resamplers > 0 )
-    {
-        aout_FiltersPlay( p_input->pp_resamplers, p_input->i_nb_resamplers,
-                          &p_buffer );
-    }
+    if ( owner->resampler != NULL )
+        aout_FiltersPlay( &owner->resampler, 1, &p_buffer );
 
     if( !p_buffer )
         return NULL;
@@ -521,128 +275,16 @@ static void inputDrop( aout_input_t *p_input, block_t *p_buffer )
     p_input->i_buffer_lost++;
 }
 
-static void inputResamplingStop( aout_input_t *p_input )
+static void inputResamplingStop( audio_output_t *p_aout, aout_input_t *p_input )
 {
+    aout_owner_t *owner = aout_owner(p_aout);
+
     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
-    if( p_input->i_nb_resamplers != 0 )
+    if( owner->resampler != NULL )
     {
-        p_input->pp_resamplers[0]->fmt_in.audio.i_rate =
-            ( p_input->pp_resamplers[0] == p_input->p_playback_rate_filter )
+        owner->resampler->fmt_in.audio.i_rate =
+            ( owner->resampler == owner->rate_filter )
             ? INPUT_RATE_DEFAULT * p_input->samplerate / p_input->i_last_input_rate
             : p_input->samplerate;
     }
 }
-
-static vout_thread_t *RequestVout( void *p_private,
-                                   vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
-{
-    audio_output_t *p_aout = p_private;
-    VLC_UNUSED(b_recycle);
-    vout_configuration_t cfg = {
-        .vout       = p_vout,
-        .input      = NULL,
-        .change_fmt = true,
-        .fmt        = p_fmt,
-        .dpb_size   = 1,
-    };
-    return vout_Request( p_aout, &cfg );
-}
-
-vout_thread_t *aout_filter_RequestVout( filter_t *p_filter,
-                                        vout_thread_t *p_vout, video_format_t *p_fmt )
-{
-    aout_input_t *p_input = (aout_input_t *)p_filter->p_owner;
-    aout_request_vout_t *p_request = &p_input->request_vout;
-
-    /* XXX: this only works from audio input */
-    /* If you want to use visualization filters from another place, you will
-     * need to add a new pf_aout_request_vout callback or store a pointer
-     * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
-
-    return p_request->pf_request_vout( p_request->p_private,
-                                       p_vout, p_fmt, p_input->b_recycle_vout );
-}
-
-static inline bool ChangeFiltersString (vlc_object_t *aout, const char *var,
-                                        const char *filter, bool add)
-{
-    return aout_ChangeFilterString (aout, aout, var, filter, add);
-}
-
-static int VisualizationCallback (vlc_object_t *obj, char const *var,
-                                  vlc_value_t oldval, vlc_value_t newval,
-                                  void *data)
-{
-    const char *mode = newval.psz_string;
-    //aout_input_t *input = data;
-    (void) data;
-
-    if (!*mode)
-    {
-        ChangeFiltersString (obj, "audio-visual", "goom", false);
-        ChangeFiltersString (obj, "audio-visual", "visual", false);
-        ChangeFiltersString (obj, "audio-visual", "projectm", false);
-        ChangeFiltersString (obj, "audio-visual", "vsxu", false);
-    }
-    else if (!strcmp ("goom", mode))
-    {
-        ChangeFiltersString (obj, "audio-visual", "visual", false );
-        ChangeFiltersString (obj, "audio-visual", "goom", true );
-        ChangeFiltersString (obj, "audio-visual", "projectm", false );
-        ChangeFiltersString (obj, "audio-visual", "vsxu", false);
-    }
-    else if (!strcmp ("projectm", mode))
-    {
-        ChangeFiltersString (obj, "audio-visual", "visual", false);
-        ChangeFiltersString (obj, "audio-visual", "goom", false);
-        ChangeFiltersString (obj, "audio-visual", "projectm", true);
-        ChangeFiltersString (obj, "audio-visual", "vsxu", false);
-    }
-    else if (!strcmp ("vsxu", mode))
-    {
-        ChangeFiltersString (obj, "audio-visual", "visual", false);
-        ChangeFiltersString (obj, "audio-visual", "goom", false);
-        ChangeFiltersString (obj, "audio-visual", "projectm", false);
-        ChangeFiltersString (obj, "audio-visual", "vsxu", true);
-    }
-    else
-    {
-        var_Create (obj, "effect-list", VLC_VAR_STRING);
-        var_SetString (obj, "effect-list", mode);
-
-        ChangeFiltersString (obj, "audio-visual", "goom", false);
-        ChangeFiltersString (obj, "audio-visual", "visual", true);
-        ChangeFiltersString (obj, "audio-visual", "projectm", false);
-    }
-
-    /* That sucks FIXME: use "input" instead of cast */
-    aout_InputRequestRestart ((audio_output_t *)obj);
-
-    (void) var; (void) oldval;
-    return VLC_SUCCESS;
-}
-
-static int EqualizerCallback (vlc_object_t *obj, char const *cmd,
-                              vlc_value_t oldval, vlc_value_t newval,
-                              void *data)
-{
-    char *mode = newval.psz_string;
-    //aout_input_t *input = data;
-    bool ret;
-
-    (void) data;
-    (void) cmd; (void) oldval;
-    if (!*mode)
-        ret = ChangeFiltersString (obj, "audio-filter", "equalizer", false);
-    else
-    {
-        var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
-        var_SetString (obj, "equalizer-preset", mode);
-        ret = ChangeFiltersString (obj, "audio-filter", "equalizer", true);
-    }
-
-    /* That sucks */
-    if (ret)
-        aout_InputRequestRestart ((audio_output_t *)obj);
-    return VLC_SUCCESS;
-}
index 10db22ed454a6c0c256a6b568254a66689c969dd..c2019dafd1e24d8ce428d57054fc104a43a1328e 100644 (file)
@@ -403,11 +403,11 @@ int aout_OutputNew (audio_output_t *aout, const audio_sample_format_t *fmtp)
     aout_FormatPrepare (&owner->mixer_format);
     aout_FormatPrint (aout, "mixer", &owner->mixer_format);
 
-    /* Create filters. */
-    owner->nb_filters = 0;
-    if (aout_FiltersCreatePipeline (aout, owner->filters, &owner->nb_filters,
-                                    sizeof (owner->filters)
-                                                  / sizeof (owner->filters[0]),
+    /* Create converters. */
+    owner->nb_converters = 0;
+    if (aout_FiltersCreatePipeline (aout, owner->converters,
+                                    &owner->nb_converters,
+                    sizeof (owner->converters) / sizeof (owner->converters[0]),
                                     &owner->mixer_format, &fmt) < 0)
     {
         msg_Err (aout, "couldn't create audio output pipeline");
@@ -431,7 +431,7 @@ void aout_OutputDelete (audio_output_t *aout)
     var_DelCallback (aout, "stereo-mode", aout_ChannelsRestart, NULL);
     if (aout->stop != NULL)
         aout->stop (aout);
-    aout_FiltersDestroyPipeline (owner->filters, owner->nb_filters);
+    aout_FiltersDestroyPipeline (owner->converters, owner->nb_converters);
 }
 
 /**
@@ -446,7 +446,7 @@ void aout_OutputPlay (audio_output_t *aout, block_t *block)
 
     aout_assert_locked (aout);
 
-    aout_FiltersPlay (owner->filters, owner->nb_filters, &block);
+    aout_FiltersPlay (owner->converters, owner->nb_converters, &block);
     if (block == NULL)
         return;
     if (block->i_buffer == 0)