[vlc-devel] [RFC PATCH 3/7] audio_filter: add ebur128 "audio meter" plugin

Rémi Denis-Courmont remi at remlab.net
Mon Aug 17 11:57:02 CEST 2020


Hi,

I reject any new code that invokes vlc_object_parent(). Breaks encapsulation.

Le 14 août 2020 15:18:03 GMT+02:00, Thomas Guillem <thomas at gllm.fr> a écrit :
>---
> configure.ac                      |   5 +
> modules/audio_filter/Makefile.am  |   9 +-
> modules/audio_filter/libebur128.c | 290 ++++++++++++++++++++++++++++++
> 3 files changed, 303 insertions(+), 1 deletion(-)
> create mode 100644 modules/audio_filter/libebur128.c
>
>diff --git a/configure.ac b/configure.ac
>index 149c7c926b4..862546e49f3 100644
>--- a/configure.ac
>+++ b/configure.ac
>@@ -3919,6 +3919,11 @@ dnl  soxr module
> dnl
>PKG_ENABLE_MODULES_VLC([SOXR], [], [soxr >= 0.1.2], [SoX Resampler
>library], [auto])
> 
>+dnl
>+dnl  libebur128 module
>+dnl
>+PKG_ENABLE_MODULES_VLC([EBUR128], [], [libebur128 >= 1.2.4], [EBU R
>128 standard for loudness normalisation], [auto])
>+
> dnl
> dnl  OS/2 KAI plugin
> dnl
>diff --git a/modules/audio_filter/Makefile.am
>b/modules/audio_filter/Makefile.am
>index 279be02040f..028b188bfe2 100644
>--- a/modules/audio_filter/Makefile.am
>+++ b/modules/audio_filter/Makefile.am
>@@ -125,14 +125,21 @@ libsoxr_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
>$(SOXR_CFLAGS)
> libsoxr_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(audio_filterdir)'
> libsoxr_plugin_la_LIBADD = $(SOXR_LIBS) $(LIBM)
> 
>+libebur128_plugin_la_SOURCES = audio_filter/libebur128.c
>+libebur128_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(EBUR128_CFLAGS)
>+libebur128_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath
>'$(audio_filterdir)'
>+libebur128_plugin_la_LIBADD = $(EBUR128_LIBS)
>+
> audio_filter_LTLIBRARIES += \
> 	$(LTLIBsamplerate) \
> 	$(LTLIBsoxr) \
>+	$(LTLIBebur128) \
> 	libugly_resampler_plugin.la
> EXTRA_LTLIBRARIES += \
> 	libbandlimited_resampler_plugin.la \
> 	libsamplerate_plugin.la \
>-	libsoxr_plugin.la
>+	libsoxr_plugin.la \
>+	libebur128_plugin.la
> 
> libspeex_resampler_plugin_la_SOURCES = audio_filter/resampler/speex.c
> libspeex_resampler_plugin_la_CFLAGS = $(AM_CFLAGS) $(SPEEXDSP_CFLAGS)
>diff --git a/modules/audio_filter/libebur128.c
>b/modules/audio_filter/libebur128.c
>new file mode 100644
>index 00000000000..bd5464dc6d1
>--- /dev/null
>+++ b/modules/audio_filter/libebur128.c
>@@ -0,0 +1,290 @@
>+/*****************************************************************************
>+ * libebur128.c : libebur128 filter
>+
>*****************************************************************************
>+ * Copyright © 2020 Videolabs
>+ *
>+ * 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_aout.h>
>+#include <vlc_filter.h>
>+#include <vlc_modules.h>
>+#include <vlc_plugin.h>
>+
>+#include <ebur128.h>
>+
>+#define UPDATE_INTERVAL VLC_TICK_FROM_MS(400)
>+
>+struct filter_sys
>+{
>+    ebur128_state *state;
>+    vlc_tick_t last_update;
>+    bool new_frames;
>+};
>+
>+static ebur128_state *
>+CreateEbuR128State(filter_t *filter)
>+{
>+    int mode = var_InheritBool(filter, "ebur128-fullmeter")
>+             ? EBUR128_MODE_TRUE_PEAK|EBUR128_MODE_LRA :
>EBUR128_MODE_M;
>+
>+    ebur128_state *state =
>+        ebur128_init(filter->fmt_in.audio.i_channels,
>filter->fmt_in.audio.i_rate, mode);
>+    if (state == NULL)
>+        return NULL;
>+
>+    /* TODO: improve */
>+    unsigned channels_set = 2;
>+    int error;
>+    if (filter->fmt_in.audio.i_physical_channels == AOUT_CHANS_5_1
>+     || filter->fmt_in.audio.i_physical_channels == AOUT_CHANS_7_1)
>+    {
>+        error = ebur128_set_channel(state, 2, EBUR128_LEFT_SURROUND);
>+        if (error != EBUR128_SUCCESS)
>+            goto error;
>+        ebur128_set_channel(state, 3, EBUR128_RIGHT_SURROUND);
>+        if (error != EBUR128_SUCCESS)
>+            goto error;
>+        ebur128_set_channel(state, 4, EBUR128_CENTER);
>+        if (error != EBUR128_SUCCESS)
>+            goto error;
>+
>+        channels_set += 3;
>+    }
>+
>+    for (unsigned i = channels_set; i <
>filter->fmt_in.audio.i_channels; ++i)
>+    {
>+        error = ebur128_set_channel(state, i, EBUR128_UNUSED);
>+        if (error != EBUR128_SUCCESS)
>+            goto error;
>+    }
>+
>+    return state;
>+error:
>+    ebur128_destroy(&state);
>+    return NULL;
>+}
>+
>+static int
>+SendLoudnessMeter(filter_t *filter)
>+{
>+    struct filter_sys *sys = filter->p_sys;
>+
>+    int error;
>+    struct vlc_audio_loudness_meter meter = { 0, 0, 0, 0, 0 };
>+
>+    error = ebur128_loudness_momentary(sys->state,
>&meter.loudness_momentary);
>+    if (error != EBUR128_SUCCESS)
>+        return error;
>+
>+    if ((sys->state->mode & EBUR128_MODE_S) == EBUR128_MODE_S)
>+    {
>+        error = ebur128_loudness_shortterm(sys->state,
>&meter.loudness_shortterm);
>+        if (error != EBUR128_SUCCESS)
>+            return error;
>+    }
>+    if ((sys->state->mode & EBUR128_MODE_I) == EBUR128_MODE_I)
>+    {
>+        error = ebur128_loudness_global(sys->state,
>&meter.loudness_integrated);
>+        if (error != EBUR128_SUCCESS)
>+            return error;
>+
>+    }
>+    if ((sys->state->mode & EBUR128_MODE_LRA) == EBUR128_MODE_LRA)
>+    {
>+        error = ebur128_loudness_range(sys->state,
>&meter.loudness_range);
>+        if (error != EBUR128_SUCCESS)
>+            return error;
>+    }
>+    if ((sys->state->mode & EBUR128_MODE_TRUE_PEAK) ==
>EBUR128_MODE_TRUE_PEAK)
>+    {
>+        for (unsigned i = 0; i < filter->fmt_in.audio.i_channels; ++i)
>+        {
>+            double truepeak;
>+            error = ebur128_true_peak(sys->state, 0, &truepeak);
>+            if (error != EBUR128_SUCCESS)
>+                return error;
>+            if (truepeak > meter.truepeak)
>+                meter.truepeak = truepeak;
>+        }
>+    }
>+
>+    var_SetAddress(vlc_object_parent(VLC_OBJECT(filter)),
>"loudness-meter", &meter);
>+
>+    return EBUR128_SUCCESS;
>+}
>+
>+static block_t *
>+Process(filter_t *filter, block_t *block)
>+{
>+    struct filter_sys *sys = filter->p_sys;
>+    int error;
>+    block_t *out = block;
>+
>+    if (unlikely(sys->state == NULL))
>+    {
>+        /* Can happen after a flush */
>+        sys->state = CreateEbuR128State(filter);
>+        if (sys->state == NULL)
>+            return out;
>+    }
>+
>+    switch (filter->fmt_in.i_codec)
>+    {
>+        case VLC_CODEC_U8:
>+        {
>+            /* Convert to S16N */
>+            block_t *block_s16 = block_Alloc(block->i_buffer * 2);
>+            if (unlikely(block_s16 == NULL))
>+                return out;
>+
>+            block_CopyProperties(block_s16, block);
>+            uint8_t *src = (uint8_t *)block->p_buffer;
>+            int16_t *dst = (int16_t *)block_s16->p_buffer;
>+            for (size_t i = block->i_buffer; i--;)
>+                *dst++ = ((*src++) << 8) - 0x8000;
>+
>+            block = block_s16;
>+        }
>+        /* Fallthrough */
>+        case VLC_CODEC_S16N:
>+            error = ebur128_add_frames_short(sys->state,
>+                                             (const short
>*)block->p_buffer,
>+                                             block->i_nb_samples);
>+            break;
>+        case VLC_CODEC_S32N:
>+            error = ebur128_add_frames_int(sys->state,
>+                                           (const int *)
>block->p_buffer,
>+                                           block->i_nb_samples);
>+            break;
>+        case VLC_CODEC_FL32:
>+            error = ebur128_add_frames_float(sys->state,
>+                                             (const float *)
>block->p_buffer,
>+                                             block->i_nb_samples);
>+            break;
>+        case VLC_CODEC_FL64:
>+            error = ebur128_add_frames_double(sys->state,
>+                                              (const double *)
>block->p_buffer,
>+                                              block->i_nb_samples);
>+            break;
>+        default: vlc_assert_unreachable();
>+    }
>+
>+    if (error != EBUR128_SUCCESS)
>+    {
>+        msg_Warn(filter, "ebur128_add_frames_*() failed: %d\n",
>error);
>+        return out;
>+    }
>+
>+    if (sys->last_update == VLC_TICK_INVALID)
>+        sys->last_update = out->i_pts;
>+
>+    if (out->i_pts + out->i_length - sys->last_update >=
>UPDATE_INTERVAL)
>+    {
>+        error = SendLoudnessMeter(filter);
>+        if (error == EBUR128_SUCCESS)
>+        {
>+            sys->last_update = out->i_pts + out->i_length;
>+            sys->new_frames = false;
>+        }
>+    }
>+    else
>+        sys->new_frames = true;
>+
>+    return out;
>+}
>+
>+static void
>+Flush(filter_t *filter)
>+{
>+    struct filter_sys *sys = filter->p_sys;
>+
>+    if (sys->state != NULL)
>+    {
>+        if (sys->new_frames)
>+        {
>+            SendLoudnessMeter(filter);
>+            sys->new_frames = false;
>+        }
>+        sys->last_update = VLC_TICK_INVALID;
>+
>+        ebur128_destroy(&sys->state);
>+    }
>+}
>+
>+static int Open(vlc_object_t *this)
>+{
>+    filter_t *filter = (filter_t *) this;
>+
>+    switch (filter->fmt_in.i_codec)
>+    {
>+        case VLC_CODEC_U8:
>+        case VLC_CODEC_S16N:
>+        case VLC_CODEC_S32N:
>+        case VLC_CODEC_FL32:
>+        case VLC_CODEC_FL64:
>+            break;
>+        default:
>+            return VLC_EGENERIC;
>+    }
>+
>+    if (var_Type(vlc_object_parent(this), "loudness-meter") !=
>VLC_VAR_ADDRESS)
>+        return VLC_EGENERIC;
>+
>+    struct filter_sys *sys = malloc(sizeof(*sys));
>+    if (sys == NULL)
>+        return VLC_ENOMEM;
>+
>+    sys->last_update = VLC_TICK_INVALID;
>+    sys->new_frames = false;
>+    sys->state = CreateEbuR128State(filter);
>+    if (sys->state == NULL)
>+    {
>+        free(sys);
>+        return VLC_EGENERIC;
>+    }
>+
>+    filter->p_sys = sys;
>+    filter->fmt_out.audio = filter->fmt_in.audio;
>+    filter->pf_audio_filter = Process;
>+    filter->pf_flush = Flush;
>+    return VLC_SUCCESS;
>+}
>+
>+static void
>+Close(vlc_object_t *this)
>+{
>+    filter_t *filter = (filter_t*) this;
>+    struct filter_sys *sys = filter->p_sys;
>+
>+    if (sys->state != NULL)
>+        ebur128_destroy(&sys->state);
>+    free(filter->p_sys);
>+}
>+
>+vlc_module_begin()
>+    set_shortname("EBU R 128")
>+    set_description("EBU R128 standard for loudness normalisation")
>+    set_category(CAT_AUDIO)
>+    set_subcategory(SUBCAT_AUDIO_AFILTER)
>+    add_bool("ebur128-fullmeter", false, NULL, NULL, false)
>+    set_capability("audio meter", 0)
>+    set_callbacks(Open, Close)
>+vlc_module_end()
>-- 
>2.28.0
>
>_______________________________________________
>vlc-devel mailing list
>To unsubscribe or modify your subscription options:
>https://mailman.videolan.org/listinfo/vlc-devel

-- 
Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200817/b850e10b/attachment.html>


More information about the vlc-devel mailing list