[vlc-devel] [PATCH] audio_filter: introduce libavresample based filter

Luca Barbato lu_zero at gentoo.org
Tue Jun 5 14:36:34 CEST 2012


It supports mid-stream frame, channel map and format changes.
---
 configure.ac                                |   26 +++
 modules/LIST                                |    1 +
 modules/audio_filter/Modules.am             |    1 +
 modules/audio_filter/resampler/avresample.c |  237 +++++++++++++++++++++++++++
 4 files changed, 265 insertions(+), 0 deletions(-)
 create mode 100644 modules/audio_filter/resampler/avresample.c

diff --git a/configure.ac b/configure.ac
index 15cdc6c..b373ec3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2479,6 +2479,32 @@ then
 fi
 
 dnl
+dnl  avresample sound resampling and conversion plugin
+dnl
+
+AC_ARG_ENABLE(avresample,
+  AS_HELP_STRING([--enable-avresample],[libavresample sound resampling and conversion plugin (default auto)]))
+if test "${enable_avresample}" != "no"
+then
+  PKG_CHECK_MODULES(SWRESAMPLE,[libavresample libavutil],
+    [
+      VLC_SAVE_FLAGS
+      CPPFLAGS="${CPPFLAGS} ${SWRESAMPLE_CFLAGS}"
+      CFLAGS="${CFLAGS} ${SWRESAMPLE_CFLAGS}"
+      AC_CHECK_HEADERS([libavresample/avresample.h libavutil/audioconvert.h])
+      VLC_ADD_PLUGIN([avresample])
+      VLC_ADD_LIBS([avresample],[$SWRESAMPLE_LIBS])
+      VLC_ADD_CFLAGS([avresample],[$SWRESAMPLE_CFLAGS])
+      AS_IF([test "${ac_cv_ld_bsymbolic}" != "no"], [
+        VLC_ADD_LIBS([avresample],[-Wl,-Bsymbolic])
+      ])
+      VLC_RESTORE_FLAGS
+    ],[
+      AC_MSG_WARN([${SWRESAMPLE_PKG_ERRORS}. avresample not found.])
+  ])
+fi
+
+dnl
 dnl  postproc plugin
 dnl
 
diff --git a/modules/LIST b/modules/LIST
index 85f93a4..9bec6bc 100644
--- a/modules/LIST
+++ b/modules/LIST
@@ -61,6 +61,7 @@ $Id$
  * avcodec: libavcodec audio/video decoder
  * avformat: libavformat demuxer
  * avi: AVI file stream demuxer
+ * avresample_resampler: libavresample resampler
  * ball: Augmented reality ball video filter module
  * bandlimited_resampler: Bandlimited interpolation audio resampler
  * blend: a picture filter that blends two pictures
diff --git a/modules/audio_filter/Modules.am b/modules/audio_filter/Modules.am
index 913c228..2696564 100644
--- a/modules/audio_filter/Modules.am
+++ b/modules/audio_filter/Modules.am
@@ -65,6 +65,7 @@ SOURCES_bandlimited_resampler = \
 	resampler/bandlimited.c resampler/bandlimited.h
 SOURCES_ugly_resampler = resampler/ugly.c
 SOURCES_samplerate = resampler/src.c
+SOURCES_avresample = resampler/avresample.c
 
 libvlc_LTLIBRARIES += \
 	libugly_resampler_plugin.la
diff --git a/modules/audio_filter/resampler/avresample.c b/modules/audio_filter/resampler/avresample.c
new file mode 100644
index 0000000..6bcd153
--- /dev/null
+++ b/modules/audio_filter/resampler/avresample.c
@@ -0,0 +1,237 @@
+/*****************************************************************************
+ * avresample.c : libavresample audio resampler
+ *****************************************************************************
+ * Copyright © 2012 Luca Barbato
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_aout.h>
+#include <vlc_filter.h>
+
+#include <libavutil/opt.h>
+#include <libavutil/error.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/audioconvert.h>
+#include <libavresample/avresample.h>
+
+static int Open (vlc_object_t *);
+static void Close (vlc_object_t *);
+
+/*
+ * Keep track of input parameters, they could change midstream
+ */
+
+struct avr_sys_t
+{
+    int16_t      in_channel_map;
+    unsigned int in_sample_rate;
+    vlc_fourcc_t in_sample_format;
+
+    AVAudioResampleContext *avr;
+};
+
+vlc_module_begin ()
+    set_description (N_("avresample resampler"))
+    set_shortname (N_("avresample resampler"))
+    set_category (CAT_AUDIO)
+    set_subcategory (SUBCAT_AUDIO_MISC)
+    set_capability ("audio filter", 10)
+    set_callbacks (Open, Close)
+    add_submodule ()
+    set_capability ("audio resampler", 10)
+    set_callbacks (Open, Close)
+vlc_module_end ()
+
+static block_t *Resample (filter_t *, block_t *);
+
+static enum AVSampleFormat GetAvutilAudioFormat (vlc_fourcc_t codec)
+{
+    switch(codec) {
+        case VLC_CODEC_U8  : return AV_SAMPLE_FMT_U8;
+        case VLC_CODEC_S32N: return AV_SAMPLE_FMT_S32;
+        case VLC_CODEC_FL32: return AV_SAMPLE_FMT_FLT;
+        case VLC_CODEC_FL64: return AV_SAMPLE_FMT_DBL;
+        case VLC_CODEC_S16N: return AV_SAMPLE_FMT_S16;
+    }
+    return AV_SAMPLE_FMT_NONE;
+}
+
+static int ConfigureResample(filter_t *f)
+{
+    int ret;
+    struct avr_sys_t *sys = (struct avr_sys_t *)f->p_sys;
+    AVAudioResampleContext *s = sys->avr;
+
+    int64_t out_channel_layout =
+        av_get_default_channel_layout (
+            aout_FormatNbChannels (&f->fmt_out.audio));
+    int64_t in_channel_layout =
+        av_get_default_channel_layout (
+            aout_FormatNbChannels (&f->fmt_in.audio));
+
+    enum AVSampleFormat out_sample_format =
+        GetAvutilAudioFormat (f->fmt_out.audio.i_format);
+
+    enum AVSampleFormat in_sample_format =
+        GetAvutilAudioFormat (f->fmt_in.audio.i_format);
+
+    if (in_sample_format == AV_SAMPLE_FMT_NONE)
+    {
+        msg_Err (f, "unsupported input format");
+        return VLC_EGENERIC;
+    }
+
+    if (out_sample_format == AV_SAMPLE_FMT_NONE)
+    {
+        msg_Err (f, "unsupported output format");
+        return VLC_EGENERIC;
+    }
+
+    av_opt_set_int (s, "in_channel_layout", in_channel_layout, 0);
+    av_opt_set_int (s, "in_sample_fmt",     in_sample_format, 0);
+    av_opt_set_int (s, "in_sample_rate",    f->fmt_in.audio.i_rate, 0);
+
+    av_opt_set_int (s, "out_channel_layout", out_channel_layout, 0);
+    av_opt_set_int (s, "out_sample_fmt",     out_sample_format, 0);
+    av_opt_set_int (s, "out_sample_rate",    f->fmt_out.audio.i_rate, 0);
+
+    if (av_get_bytes_per_sample (in_sample_format)  <= 2 &&
+        av_get_bytes_per_sample (out_sample_format) <= 2)
+        av_opt_set_int (s, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
+
+    if ((ret = avresample_open (s)))
+    {
+        char errbuf[128];
+        av_strerror (ret, errbuf, sizeof(errbuf));
+        msg_Err (f, "cannot initialise resampler: %s", errbuf);
+        return VLC_EGENERIC;
+    }
+
+    sys->in_sample_format = f->fmt_in.audio.i_format;
+    sys->in_sample_rate   = f->fmt_in.audio.i_rate;
+    sys->in_channel_map   = f->fmt_in.audio.i_physical_channels;
+
+    return VLC_SUCCESS;
+}
+
+static void Close (vlc_object_t *obj)
+{
+    filter_t *filter = (filter_t *)obj;
+    struct avr_sys_t *sys = (struct avr_sys_t *) filter->p_sys;
+    AVAudioResampleContext *s = sys->avr;
+
+    avresample_close (s);
+    avresample_free (&s);
+
+    free(sys);
+    filter->p_sys = NULL;
+}
+
+static int Open (vlc_object_t *obj)
+{
+    int ret;
+    filter_t *f = (filter_t *)obj;
+    struct avr_sys_t *s = f->p_sys = malloc (sizeof (struct avr_sys_t));
+
+    if (unlikely(s == NULL))
+    {
+        msg_Err (obj, "cannot create resampler context");
+        return VLC_EGENERIC;
+    }
+
+    s->avr = avresample_alloc_context();
+
+    if (unlikely (s->avr == NULL))
+    {
+        msg_Err (obj, "cannot create resampler context");
+        free (s);
+        return VLC_EGENERIC;
+    }
+
+    ret = ConfigureResample(f);
+
+    if (unlikely (ret != VLC_SUCCESS))
+    {
+        Close(obj);
+        return VLC_EGENERIC;
+    }
+
+    f->pf_audio_filter = Resample;
+    return VLC_SUCCESS;
+}
+
+static block_t *Resample (filter_t *f, block_t *in)
+{
+    int ret;
+    block_t *out = NULL;
+    struct avr_sys_t *sys = (struct avr_sys_t *) f->p_sys;
+    AVAudioResampleContext *s = sys->avr;
+    int out_size, out_linesize;
+    const size_t framesize = f->fmt_out.audio.i_bytes_per_frame;
+    int nb_samples = in->i_nb_samples;
+
+    if (unlikely (
+        sys->in_sample_rate   != f->fmt_in.audio.i_rate              ||
+        sys->in_sample_format != f->fmt_in.audio.i_format            ||
+        sys->in_channel_map   != f->fmt_in.audio.i_physical_channels))
+    {
+        avresample_close (s);
+
+        ret = ConfigureResample (f);
+
+        if (unlikely (ret != VLC_SUCCESS))
+            goto error;
+    }
+
+    out_size = av_samples_get_buffer_size (&out_linesize,
+                                           f->fmt_out.audio.i_physical_channels,
+                                           nb_samples,
+                                           GetAvutilAudioFormat (f->fmt_out.audio.i_format), 0);
+
+    out = block_Alloc (out_size);
+
+    if (unlikely(out == NULL))
+        goto error;
+
+    ret = avresample_convert (s, (void **)&out->p_buffer, out_linesize, nb_samples,
+                                 (void **)&in->p_buffer,  in->i_buffer, in->i_nb_samples);
+
+    if (ret < 0)
+    {
+        char errbuf[128];
+        av_strerror (ret, errbuf, sizeof(errbuf));
+        msg_Err (f, "cannot resample: %s", errbuf);
+        block_Release (out);
+        out = NULL;
+        goto error;
+    }
+
+    out->i_nb_samples = ret;
+    out->i_buffer     = ret * framesize;
+    out->i_pts        = in->i_pts;
+    out->i_length     = ret * CLOCK_FREQ / f->fmt_out.audio.i_rate;
+
+error:
+    block_Release (in);
+    return out;
+}
-- 
1.7.8.rc1




More information about the vlc-devel mailing list