diff --git a/modules/audio_filter/Modules.am b/modules/audio_filter/Modules.am
index da4626c82e3adaad7f86663588b3648fbb9ee950..4963a39c1a872d1ecc5dcea3822e6838f89a9263 100644
--- a/modules/audio_filter/Modules.am
+++ b/modules/audio_filter/Modules.am
@@ -51,7 +51,9 @@ SOURCES_a52tofloat32 = converter/a52tofloat32.c
 SOURCES_dtstospdif = converter/dtstospdif.c
 SOURCES_dtstofloat32 = converter/dtstofloat32.c
 SOURCES_mpgatofixed32 = converter/mpgatofixed32.c
-SOURCES_audio_format = converter/format.c
+libaudio_format_plugin_la_SOURCES = converter/format.c
+libaudio_format_plugin_la_CFLAGS = $(AM_CFLAGS)
+libaudio_format_plugin_la_LIBADD = $(AM_LIBADD) $(LIBM)
 
 libvlc_LTLIBRARIES += \
 	liba52tospdif_plugin.la \
diff --git a/modules/audio_filter/converter/format.c b/modules/audio_filter/converter/format.c
index 372ce7bf535075d37eb3706feb3493fbf7854ece..db3faf68c25f5f43d35f773ab85870451bdad00b 100644
--- a/modules/audio_filter/converter/format.c
+++ b/modules/audio_filter/converter/format.c
@@ -31,6 +31,7 @@
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
+#include <math.h>
 #include <assert.h>
 
 #include <vlc_common.h>
@@ -43,35 +44,22 @@
  * Module descriptor
  *****************************************************************************/
 static int  Open(vlc_object_t *);
-static void Close(vlc_object_t *);
 
 vlc_module_begin()
     set_description(N_("Audio filter for PCM format conversion"))
     set_category(CAT_AUDIO)
     set_subcategory(SUBCAT_AUDIO_MISC)
     set_capability("audio converter", 1)
-    set_callbacks(Open, Close)
+    set_callbacks(Open, NULL)
 vlc_module_end()
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
 
-static block_t *Filter(filter_t *, block_t *);
+typedef block_t *(*cvt_t)(filter_t *, block_t *);
+static cvt_t FindConversion(vlc_fourcc_t src, vlc_fourcc_t dst);
 
-typedef block_t *(*cvt_direct_t)(filter_t *, block_t *);
-typedef void (*cvt_indirect_t)(block_t *, const block_t *);
-
-struct filter_sys_t {
-    cvt_direct_t   directs[2];
-    cvt_indirect_t indirects[2];
-    unsigned       indirects_ratio[2][2];
-};
-
-static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst);
-static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst);
-
-/* */
 static int Open(vlc_object_t *object)
 {
     filter_t     *filter = (filter_t *)object;
@@ -84,54 +72,9 @@ static int Open(vlc_object_t *object)
     if (src->i_codec == dst->i_codec)
         return VLC_EGENERIC;
 
-    cvt_direct_t direct = FindDirect(src->i_codec, dst->i_codec);
-    if (direct) {
-        filter->pf_audio_filter = direct;
-        filter->p_sys = NULL;
-        goto end;
-    }
-
-    /* */
-    filter_sys_t *sys = malloc(sizeof(*sys));
-    if (!sys)
-        return VLC_ENOMEM;
-
-    /* Find the cost minimal conversion */
-    for (unsigned mask = 0; mask <= 0x01; mask ++) {
-        memset(sys, 0, sizeof(*sys));
-
-        vlc_fourcc_t fsrc = src->i_codec;
-        vlc_fourcc_t fdst = dst->i_codec;
-
-        const bool has_middle = mask & 0x01;
-        for (int i = 0; fsrc != fdst && i < 1 + has_middle; i++) {
-            /* XXX Hardcoded middle format: native 16 bits */
-            vlc_fourcc_t ftarget = has_middle && i == 0 ? VLC_CODEC_S16N : fdst;
-            sys->directs[i] = FindDirect(fsrc, ftarget);
-            if (!sys->directs[i]) {
-                sys->indirects[i] = FindIndirect(fsrc, ftarget);
-                if (!sys->indirects[i])
-                    break;
-                sys->indirects_ratio[i][0] = aout_BitsPerSample(fsrc) / 8;
-                sys->indirects_ratio[i][1] = aout_BitsPerSample(ftarget) / 8;
-            }
-            fsrc = ftarget;
-        }
-        if (fsrc != fdst)
-            continue;
-
-        /* We have a full conversion */
-        filter->pf_audio_filter = Filter;
-        filter->p_sys = sys;
-        goto end;
-    }
-    free(sys);
-    return VLC_EGENERIC;
-
-end:
-    dst->audio = src->audio;
-    dst->audio.i_format = dst->i_codec;
-    aout_FormatPrepare(&dst->audio);
+    filter->pf_audio_filter = FindConversion(src->i_codec, dst->i_codec);
+    if (filter->pf_audio_filter == NULL)
+        return VLC_EGENERIC;
 
     msg_Dbg(filter, "%4.4s->%4.4s, bits per sample: %i->%i",
             (char *)&src->i_codec, (char *)&dst->i_codec,
@@ -139,68 +82,167 @@ end:
     return VLC_SUCCESS;
 }
 
-/* */
-static void Close(vlc_object_t *object)
+
+/*** from U8 ***/
+static block_t *U8toS16(filter_t *filter, block_t *bsrc)
 {
-    filter_t *filter = (filter_t *)object;
-    free(filter->p_sys);
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    uint8_t *src = (uint8_t *)bsrc->p_buffer;
+    int16_t *dst = (int16_t *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer; i--;)
+        *dst++ = ((*src++) - 128) << 8;
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
 }
 
-/* */
-static block_t *Filter(filter_t *filter, block_t *block)
+static block_t *U8toFl32(filter_t *filter, block_t *bsrc)
 {
-    filter_sys_t *sys = filter->p_sys;
-
-    for (int i = 0; i < 2; i++) {
-        if (sys->directs[i]) {
-            block = sys->directs[i](filter, block);
-        } else if (sys->indirects[i]) {
-            int dst_size = sys->indirects_ratio[i][1] *
-                           (block->i_buffer / sys->indirects_ratio[i][0]);
-            block_t *out = filter_NewAudioBuffer(filter, dst_size);
-            if (!out) {
-                block_Release(block);
-                return NULL;
-            }
-            out->i_nb_samples = block->i_nb_samples;
-            out->i_dts        = block->i_dts;
-            out->i_pts        = block->i_pts;
-            out->i_length     = block->i_length;
-
-            sys->indirects[i](out, block);
-
-            block_Release(block);
-            block = out;
-        }
-    }
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 4);
+    if (unlikely(bdst == NULL))
+        goto out;
 
-    return block;
+    uint8_t *src = (uint8_t *)bsrc->p_buffer;
+    float   *dst = (float *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer; i--;)
+        *dst++ = ((float)((*src++) - 128)) / 128.f;
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
 }
 
-/* */
+static block_t *U8toS32(filter_t *filter, block_t *bsrc)
+{
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 4);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    uint8_t *src = (uint8_t *)bsrc->p_buffer;
+    int32_t *dst = (int32_t *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer; i--;)
+        *dst++ = ((*src++) - 128) << 24;
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
+}
+
+static block_t *U8toFl64(filter_t *filter, block_t *bsrc)
+{
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 8);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    uint8_t *src = (uint8_t *)bsrc->p_buffer;
+    double  *dst = (double *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer; i--;)
+        *dst++ = ((double)((*src++) - 128)) / 128.;
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
+}
+
+
+/*** from S16N ***/
 static block_t *S16toU8(filter_t *filter, block_t *b)
 {
     VLC_UNUSED(filter);
     int16_t *src = (int16_t *)b->p_buffer;
     uint8_t *dst = (uint8_t *)src;
-    for (int i = b->i_buffer / 2; i--;)
+    for (size_t i = b->i_buffer / 2; i--;)
         *dst++ = ((*src++) + 32768) >> 8;
 
     b->i_buffer /= 2;
     return b;
 }
 
-static block_t *S32toS16(filter_t *filter, block_t *b)
+static block_t *S16toFl32(filter_t *filter, block_t *bsrc)
 {
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    int16_t *src = (int16_t *)bsrc->p_buffer;
+    float   *dst = (float *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer / 2; i--;)
+#if 0
+        /* Slow version */
+        *dst++ = (float)*src++ / 32768.f;
+#else
+    {   /* This is Walken's trick based on IEEE float format. On my PIII
+         * this takes 16 seconds to perform one billion conversions, instead
+         * of 19 seconds for the above division. */
+        union { float f; int32_t i; } u;
+        u.i = *src++ + 0x43c00000;
+        *dst++ = u.f - 384.0;
+    }
+#endif
+out:
+    block_Release(bsrc);
     VLC_UNUSED(filter);
-    int32_t *src = (int32_t *)b->p_buffer;
-    int16_t *dst = (int16_t *)src;
-    for (int i = b->i_buffer / 4; i--;)
-        *dst++ = (*src++) >> 16;
+    return bdst;
+}
 
-    b->i_buffer /= 2;
+static block_t *S16toS32(filter_t *filter, block_t *bsrc)
+{
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    int16_t *src = (int16_t *)bsrc->p_buffer;
+    int32_t *dst = (int32_t *)bdst->p_buffer;
+    for (int i = bsrc->i_buffer / 2; i--;)
+        *dst++ = *src++ << 16;
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
+}
+
+static block_t *S16toFl64(filter_t *filter, block_t *bsrc)
+{
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 4);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    int16_t *src = (int16_t *)bsrc->p_buffer;
+    float   *dst = (float *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer / 2; i--;)
+        *dst++ = (double)*src++ / 32768.;
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
+}
+
+
+/*** from FL32 ***/
+static block_t *Fl32toU8(filter_t *filter, block_t *b)
+{
+    float   *src = (float *)b->p_buffer;
+    uint8_t *dst = (uint8_t *)src;
+    for (size_t i = b->i_buffer / 4; i--;)
+    {
+        float s = *(src++) * 128.f;
+        if (s >= 127.f)
+            *(dst++) = 255;
+        else
+        if (s <= -128.f)
+            *(dst++) = 0;
+        else
+            *(dst++) = lroundf(s) + 128;
+    }
+    b->i_buffer /= 4;
+    VLC_UNUSED(filter);
     return b;
 }
+
 static block_t *Fl32toS16(filter_t *filter, block_t *b)
 {
     VLC_UNUSED(filter);
@@ -211,10 +253,10 @@ static block_t *Fl32toS16(filter_t *filter, block_t *b)
         /* Slow version. */
         if (*src >= 1.0) *dst = 32767;
         else if (*src < -1.0) *dst = -32768;
-        else *dst = *src * 32768.0;
+        else *dst = lroundf(*src * 32768.f);
         src++; dst++;
 #else
-        /* This is walken's trick based on IEEE float format. */
+        /* This is Walken's trick based on IEEE float format. */
         union { float f; int32_t i; } u;
         u.f = *src++ + 384.0;
         if (u.i > 0x43c07fff)
@@ -225,104 +267,205 @@ static block_t *Fl32toS16(filter_t *filter, block_t *b)
             *dst++ = u.i - 0x43c00000;
 #endif
     }
-
     b->i_buffer /= 2;
     return b;
 }
-static block_t *Fl64toS16(filter_t *filter, block_t *b)
+
+static block_t *Fl32toS32(filter_t *filter, block_t *b)
 {
-    VLC_UNUSED(filter);
-    double  *src = (double *)b->p_buffer;
-    int16_t *dst = (int16_t *)src;
-    for (int i = b->i_buffer / 8; i--;) {
-        const double v = *src++;
-        /* Slow version. */
-        if (v >= 1.0)
-            *dst++ = 32767;
-        else if (v < -1.0)
-            *dst++ = -32768;
+    float   *src = (float *)b->p_buffer;
+    int32_t *dst = (int32_t *)src;
+    for (size_t i = b->i_buffer / 4; i--;)
+    {
+        float s = *(src++) * 2147483648.f;
+        if (s >= 2147483647.f)
+            *(dst++) = 2147483647;
+        else
+        if (s <= -2147483648.f)
+            *(dst++) = -2147483648;
         else
-            *dst++ = v * 32768.0;
+            *(dst++) = lroundf(s);
     }
+    VLC_UNUSED(filter);
+    return b;
+}
+
+static block_t *Fl32toFl64(filter_t *filter, block_t *bsrc)
+{
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    float  *src = (float *)bsrc->p_buffer;
+    double *dst = (double *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer / 4; i--;)
+        *(dst++) = *(src++);
+out:
+    block_Release(bsrc);
+    VLC_UNUSED(filter);
+    return bdst;
+}
+
+
+/*** from S32N ***/
+static block_t *S32toU8(filter_t *filter, block_t *b)
+{
+    VLC_UNUSED(filter);
+    int32_t *src = (int32_t *)b->p_buffer;
+    uint8_t *dst = (uint8_t *)src;
+    for (size_t i = b->i_buffer / 4; i--;)
+        *dst++ = ((*src++) >> 24) + 128;
 
     b->i_buffer /= 4;
     return b;
 }
+
+static block_t *S32toS16(filter_t *filter, block_t *b)
+{
+    VLC_UNUSED(filter);
+    int32_t *src = (int32_t *)b->p_buffer;
+    int16_t *dst = (int16_t *)src;
+    for (size_t i = b->i_buffer / 4; i--;)
+        *dst++ = (*src++) >> 16;
+
+    b->i_buffer /= 2;
+    return b;
+}
+
 static block_t *S32toFl32(filter_t *filter, block_t *b)
 {
     VLC_UNUSED(filter);
     int32_t *src = (int32_t*)b->p_buffer;
     float   *dst = (float *)src;
     for (int i = b->i_buffer / 4; i--;)
-        *dst++ = (float)(*src++) / 2147483648.0;
+        *dst++ = (float)(*src++) / 2147483648.f;
     return b;
 }
 
-/* */
-static void U8toS16(block_t *bdst, const block_t *bsrc)
+static block_t *S32toFl64(filter_t *filter, block_t *bsrc)
 {
-    uint8_t *src = (uint8_t *)bsrc->p_buffer;
-    int16_t *dst = (int16_t *)bdst->p_buffer;
-    for (int i = bsrc->i_buffer; i--;)
-        *dst++ = ((*src++) - 128) << 8;
+    block_t *bdst = block_Alloc(bsrc->i_buffer * 2);
+    if (unlikely(bdst == NULL))
+        goto out;
+
+    int32_t *src = (int32_t*)bsrc->p_buffer;
+    double  *dst = (double *)bdst->p_buffer;
+    for (size_t i = bsrc->i_buffer / 4; i--;)
+        *dst++ = (double)(*src++) / 2147483648.;
+out:
+    VLC_UNUSED(filter);
+    block_Release(bsrc);
+    return bdst;
 }
 
-static void S16toS32(block_t *bdst, const block_t *bsrc)
+
+/*** from FL64 ***/
+static block_t *Fl64toU8(filter_t *filter, block_t *b)
 {
-    int16_t *src = (int16_t *)bsrc->p_buffer;
-    int32_t *dst = (int32_t *)bdst->p_buffer;
-    for (int i = bsrc->i_buffer / 2; i--;)
-        *dst++ = *src++ << 16;
+    double  *src = (double *)b->p_buffer;
+    uint8_t *dst = (uint8_t *)src;
+    for (size_t i = b->i_buffer / 8; i--;)
+    {
+        float s = *(src++) * 128.f;
+        if (s >= 127.)
+            *(dst++) = 255;
+        else
+        if (s <= -128.)
+            *(dst++) = 0;
+        else
+            *(dst++) = lround(s) + 128;
+    }
+    b->i_buffer /= 8;
+    VLC_UNUSED(filter);
+    return b;
 }
-static void S16toFl32(block_t *bdst, const block_t *bsrc)
+
+static block_t *Fl64toS16(filter_t *filter, block_t *b)
 {
-    int16_t *src = (int16_t *)bsrc->p_buffer;
-    float *dst = (float *)bdst->p_buffer;
-    for (int i = bsrc->i_buffer / 2; i--;) {
-#if 0
-        /* Slow version */
-        *dst++ = (float)*src++ / 32768.0;
-#else
-        /* This is walken's trick based on IEEE float format. On my PIII
-         * this takes 16 seconds to perform one billion conversions, instead
-         * of 19 seconds for the above division. */
-        union { float f; int32_t i; } u;
-        u.i = *src++ + 0x43c00000;
-        *dst++ = u.f - 384.0;
-#endif
+    VLC_UNUSED(filter);
+    double  *src = (double *)b->p_buffer;
+    int16_t *dst = (int16_t *)src;
+    for (size_t i = b->i_buffer / 8; i--;) {
+        const double v = *src++ * 32768.;
+        /* Slow version. */
+        if (v >= 32767.)
+            *dst++ = 32767;
+        else if (v < -32768.)
+            *dst++ = -32768;
+        else
+            *dst++ = lround(v);
     }
+    b->i_buffer /= 4;
+    return b;
+}
+
+static block_t *Fl64toFl32(filter_t *filter, block_t *b)
+{
+    double *src = (double *)b->p_buffer;
+    float  *dst = (float *)src;
+    for (size_t i = b->i_buffer / 8; i--;)
+        *(dst++) = *(src++);
+
+    VLC_UNUSED(filter);
+    return b;
 }
 
+static block_t *Fl64toS32(filter_t *filter, block_t *b)
+{
+    double  *src = (double *)b->p_buffer;
+    int32_t *dst = (int32_t *)src;
+    for (size_t i = b->i_buffer / 8; i--;)
+    {
+        float s = *(src++) * 2147483648.;
+        if (s >= 2147483647.)
+            *(dst++) = 2147483647;
+        else
+        if (s <= -2147483648.)
+            *(dst++) = -2147483648;
+        else
+            *(dst++) = lround(s);
+    }
+    VLC_UNUSED(filter);
+    return b;
+}
+
+
+/* */
 /* */
 static const struct {
     vlc_fourcc_t src;
     vlc_fourcc_t dst;
-    cvt_direct_t convert;
+    cvt_t convert;
 } cvt_directs[] = {
-    { VLC_CODEC_FL64, VLC_CODEC_S16N,   Fl64toS16 },
-    { VLC_CODEC_S32N, VLC_CODEC_FL32,   S32toFl32 },
+    { VLC_CODEC_U8,   VLC_CODEC_S16N, U8toS16    },
+    { VLC_CODEC_U8,   VLC_CODEC_FL32, U8toFl32   },
+    { VLC_CODEC_U8,   VLC_CODEC_S32N, U8toS32    },
+    { VLC_CODEC_U8,   VLC_CODEC_FL64, U8toFl64   },
+
+    { VLC_CODEC_S16N, VLC_CODEC_U8,   S16toU8    },
+    { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32  },
+    { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32   },
+    { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl64  },
+
+    { VLC_CODEC_FL32, VLC_CODEC_U8,   Fl32toU8   },
+    { VLC_CODEC_FL32, VLC_CODEC_S16N, Fl32toS16  },
+    { VLC_CODEC_FL32, VLC_CODEC_S32N, Fl32toS32  },
+    { VLC_CODEC_FL32, VLC_CODEC_FL64, Fl32toFl64 },
+
+    { VLC_CODEC_S32N, VLC_CODEC_U8,   S32toU8    },
+    { VLC_CODEC_S32N, VLC_CODEC_S16N, S32toS16   },
+    { VLC_CODEC_S32N, VLC_CODEC_FL32, S32toFl32  },
+    { VLC_CODEC_S32N, VLC_CODEC_FL64, S32toFl64  },
+
+    { VLC_CODEC_FL64, VLC_CODEC_U8,   Fl64toU8   },
+    { VLC_CODEC_FL64, VLC_CODEC_S16N, Fl64toS16  },
+    { VLC_CODEC_FL64, VLC_CODEC_FL32, Fl64toFl32 },
+    { VLC_CODEC_FL64, VLC_CODEC_S32N, Fl64toS32  },
 
-    { VLC_CODEC_S32N, VLC_CODEC_S16N,   S32toS16 },
-    { VLC_CODEC_FL32, VLC_CODEC_S16N,   Fl32toS16 },
-
-    { VLC_CODEC_S16N, VLC_CODEC_U8,     S16toU8 },
-
-    { 0, 0, NULL }
-};
-
-static const struct {
-    vlc_fourcc_t   src;
-    vlc_fourcc_t   dst;
-    cvt_indirect_t convert;
-} cvt_indirects[] = {
-    { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32 },
-    { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32 },
-
-    { VLC_CODEC_U8,   VLC_CODEC_S16N, U8toS16 },
     { 0, 0, NULL }
 };
 
-static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst)
+static cvt_t FindConversion(vlc_fourcc_t src, vlc_fourcc_t dst)
 {
     for (int i = 0; cvt_directs[i].convert; i++) {
         if (cvt_directs[i].src == src &&
@@ -331,13 +474,3 @@ static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst)
     }
     return NULL;
 }
-static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst)
-{
-    for (int i = 0; cvt_indirects[i].convert; i++) {
-        if (cvt_indirects[i].src == src &&
-            cvt_indirects[i].dst == dst)
-            return cvt_indirects[i].convert;
-    }
-    return NULL;
-}
-