[vlc-devel] [RFC PATCH 3/7] audio_filter: add ebur128 "audio meter" plugin
Rémi Denis-Courmont
remi at remlab.net
Fri Aug 14 17:54:24 CEST 2020
Le perjantaina 14. elokuuta 2020, 16.18.03 EEST Thomas Guillem 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;
I can't follow where this gets freed.
--
Rémi Denis-Courmont
http://www.remlab.net/
More information about the vlc-devel
mailing list