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

Thomas Guillem thomas at gllm.fr
Mon Aug 17 09:52:51 CEST 2020



On Mon, Aug 17, 2020, at 08:52, Steve Lhomme wrote:
> 
> 
> On 2020-08-17 8:48, Steve Lhomme wrote:
> > On 2020-08-14 15:18, Thomas Guillem wrote:
> >> ---
> >>   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);
> > 
> > I'm not a big fan of this. I'd prefer timed data attached to the audio 
> > blocks (or in a separate ES). This would provide more or less accurate 
> > values with each audio block. It could be used in the vout to blend in 
> > the UI. Here if there's a delay between the decoder and the playback the 
> > display also has this delay.
> 
> Also I feel the visualization filters may be changed to something like 
> this. They could generate SPUs that can be integrated in the UI (with 
> many of them at once for example). The vu meter would then be a 
> visualization filter which would rely on some timed data.

No, we need the raw data, and not a widget/SPU. Each VLC ports need to use their native widget API to draw the widget representating the data.

The simplification we could do is : 
 - Change the visualization filter to be an extra spu filter
 - This new visualisation plugin will receive data from "audio meter" plugins and will do the actual drawing in a SPU.
 - The core decides if the SPU is blent of rendered in an extra vout.


> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list