[FFmpeg-devel] [PATCH 2/3] lavfi/loudnorm: add an internal libebur128 library

Marton Balint cus at passwd.hu
Sun Oct 16 22:32:03 EEST 2016


Also contains the following changes to the library:
- add ff_ prefix to functions
- remove cplusplus defines.
- add FF_ prefix to contants and some structs
- remove true peak calculation feature, since it uses its own resampler, and
  af_audnorm does not need it.
- remove version info and some fprintf(stderr) functions
- convert to use av_malloc
- always use histogram mode for LRA calculation, otherwise LRA data is slowly
  consuming memory making af_loudnorm unfit for 24/7 operation. It also uses a
  BSD style linked list implementation which is probably not available on all
  platforms. So let's just remove the classic mode which not uses histogram.
- add ff_thread_once for calculating static histogram tables
- convert some functions to void which cannot fail
- remove intrinsics and some unused headers
- add support for planar audio

Signed-off-by: Marton Balint <cus at passwd.hu>
---
 configure                 |   5 -
 libavfilter/Makefile      |   2 +-
 libavfilter/af_loudnorm.c |  60 ++--
 libavfilter/ebur128.c     | 850 ++++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/ebur128.h     | 359 ++++++++++++++++++++
 5 files changed, 1240 insertions(+), 36 deletions(-)
 create mode 100644 libavfilter/ebur128.c
 create mode 100644 libavfilter/ebur128.h

diff --git a/configure b/configure
index 96f575f..24d1906 100755
--- a/configure
+++ b/configure
@@ -223,8 +223,6 @@ External library support:
   --enable-libcdio         enable audio CD grabbing with libcdio [no]
   --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394
                            and libraw1394 [no]
-  --enable-libebur128      enable libebur128 for EBU R128 measurement,
-                           needed for loudnorm filter [no]
   --enable-libfdk-aac      enable AAC de/encoding via libfdk-aac [no]
   --enable-libflite        enable flite (voice synthesis) support via libflite [no]
   --enable-libfontconfig   enable libfontconfig, useful for drawtext filter [no]
@@ -1486,7 +1484,6 @@ EXTERNAL_LIBRARY_LIST="
     libcdio
     libcelt
     libdc1394
-    libebur128
     libfdk_aac
     libflite
     libfontconfig
@@ -3045,7 +3042,6 @@ hqdn3d_filter_deps="gpl"
 interlace_filter_deps="gpl"
 kerndeint_filter_deps="gpl"
 ladspa_filter_deps="ladspa dlopen"
-loudnorm_filter_deps="libebur128"
 mcdeint_filter_deps="avcodec gpl"
 movie_filter_deps="avcodec avformat"
 mpdecimate_filter_deps="gpl"
@@ -5684,7 +5680,6 @@ enabled libcelt           && require libcelt celt/celt.h celt_decode -lcelt0 &&
                              { check_lib celt/celt.h celt_decoder_create_custom -lcelt0 ||
                                die "ERROR: libcelt must be installed and version must be >= 0.11.0."; }
 enabled libcaca           && require_pkg_config caca caca.h caca_create_canvas
-enabled libebur128        && require ebur128 ebur128.h ebur128_relative_threshold -lebur128
 enabled libfdk_aac        && { use_pkg_config fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen ||
                                { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac &&
                                  warn "using libfdk without pkg-config"; } }
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 7ed4696..cdddb1b 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -93,7 +93,7 @@ OBJS-$(CONFIG_HDCD_FILTER)                   += af_hdcd.o
 OBJS-$(CONFIG_HIGHPASS_FILTER)               += af_biquads.o
 OBJS-$(CONFIG_JOIN_FILTER)                   += af_join.o
 OBJS-$(CONFIG_LADSPA_FILTER)                 += af_ladspa.o
-OBJS-$(CONFIG_LOUDNORM_FILTER)               += af_loudnorm.o
+OBJS-$(CONFIG_LOUDNORM_FILTER)               += af_loudnorm.o ebur128.o
 OBJS-$(CONFIG_LOWPASS_FILTER)                += af_biquads.o
 OBJS-$(CONFIG_PAN_FILTER)                    += af_pan.o
 OBJS-$(CONFIG_REPLAYGAIN_FILTER)             += af_replaygain.o
diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c
index 604697e..e470f03 100644
--- a/libavfilter/af_loudnorm.c
+++ b/libavfilter/af_loudnorm.c
@@ -24,7 +24,7 @@
 #include "avfilter.h"
 #include "internal.h"
 #include "audio.h"
-#include <ebur128.h>
+#include "ebur128.h"
 
 enum FrameType {
     FIRST_FRAME,
@@ -91,8 +91,8 @@ typedef struct LoudNormContext {
     int prev_nb_samples;
     int channels;
 
-    ebur128_state *r128_in;
-    ebur128_state *r128_out;
+    FFEBUR128State *r128_in;
+    FFEBUR128State *r128_out;
 } LoudNormContext;
 
 #define OFFSET(x) offsetof(LoudNormContext, x)
@@ -437,15 +437,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     buf = s->buf;
     limiter_buf = s->limiter_buf;
 
-    ebur128_add_frames_double(s->r128_in, src, in->nb_samples);
+    ff_ebur128_add_il_frames_double(s->r128_in, src, in->nb_samples);
 
     if (s->frame_type == FIRST_FRAME && in->nb_samples < frame_size(inlink->sample_rate, 3000)) {
         double offset, offset_tp, true_peak;
 
-        ebur128_loudness_global(s->r128_in, &global);
+        ff_ebur128_loudness_global(s->r128_in, &global);
         for (c = 0; c < inlink->channels; c++) {
             double tmp;
-            ebur128_sample_peak(s->r128_in, c, &tmp);
+            ff_ebur128_sample_peak(s->r128_in, c, &tmp);
             if (c == 0 || tmp > true_peak)
                 true_peak = tmp;
         }
@@ -467,7 +467,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             s->buf_index += inlink->channels;
         }
 
-        ebur128_loudness_shortterm(s->r128_in, &shortterm);
+        ff_ebur128_loudness_shortterm(s->r128_in, &shortterm);
 
         if (shortterm < s->measured_thresh) {
             s->above_threshold = 0;
@@ -497,7 +497,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
         subframe_length = frame_size(inlink->sample_rate, 100);
         true_peak_limiter(s, dst, subframe_length, inlink->channels);
-        ebur128_add_frames_double(s->r128_out, dst, subframe_length);
+        ff_ebur128_add_il_frames_double(s->r128_out, dst, subframe_length);
 
         s->pts +=
         out->nb_samples =
@@ -536,12 +536,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         s->limiter_buf_index = s->limiter_buf_index + subframe_length < s->limiter_buf_size ? s->limiter_buf_index + subframe_length : s->limiter_buf_index + subframe_length - s->limiter_buf_size;
 
         true_peak_limiter(s, dst, in->nb_samples, inlink->channels);
-        ebur128_add_frames_double(s->r128_out, dst, in->nb_samples);
+        ff_ebur128_add_il_frames_double(s->r128_out, dst, in->nb_samples);
 
-        ebur128_loudness_range(s->r128_in, &lra);
-        ebur128_loudness_global(s->r128_in, &global);
-        ebur128_loudness_shortterm(s->r128_in, &shortterm);
-        ebur128_relative_threshold(s->r128_in, &relative_threshold);
+        ff_ebur128_loudness_range(s->r128_in, &lra);
+        ff_ebur128_loudness_global(s->r128_in, &global);
+        ff_ebur128_loudness_shortterm(s->r128_in, &shortterm);
+        ff_ebur128_relative_threshold(s->r128_in, &relative_threshold);
 
         if (s->above_threshold == 0) {
             double shortterm_out;
@@ -549,7 +549,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             if (shortterm > s->measured_thresh)
                 s->prev_delta *= 1.0058;
 
-            ebur128_loudness_shortterm(s->r128_out, &shortterm_out);
+            ff_ebur128_loudness_shortterm(s->r128_out, &shortterm_out);
             if (shortterm_out >= s->target_i)
                 s->above_threshold = 1;
         }
@@ -611,7 +611,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         }
 
         dst = (double *)out->data[0];
-        ebur128_add_frames_double(s->r128_out, dst, in->nb_samples);
+        ff_ebur128_add_il_frames_double(s->r128_out, dst, in->nb_samples);
         break;
 
     case LINEAR_MODE:
@@ -624,7 +624,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         }
 
         dst = (double *)out->data[0];
-        ebur128_add_frames_double(s->r128_out, dst, in->nb_samples);
+        ff_ebur128_add_il_frames_double(s->r128_out, dst, in->nb_samples);
         s->pts += in->nb_samples;
         break;
     }
@@ -725,17 +725,17 @@ static int config_input(AVFilterLink *inlink)
     AVFilterContext *ctx = inlink->dst;
     LoudNormContext *s = ctx->priv;
 
-    s->r128_in = ebur128_init(inlink->channels, inlink->sample_rate, EBUR128_MODE_I | EBUR128_MODE_S | EBUR128_MODE_LRA | EBUR128_MODE_SAMPLE_PEAK);
+    s->r128_in = ff_ebur128_init(inlink->channels, inlink->sample_rate, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK);
     if (!s->r128_in)
         return AVERROR(ENOMEM);
 
-    s->r128_out = ebur128_init(inlink->channels, inlink->sample_rate, EBUR128_MODE_I | EBUR128_MODE_S | EBUR128_MODE_LRA | EBUR128_MODE_SAMPLE_PEAK);
+    s->r128_out = ff_ebur128_init(inlink->channels, inlink->sample_rate, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK);
     if (!s->r128_out)
         return AVERROR(ENOMEM);
 
     if (inlink->channels == 1 && s->dual_mono) {
-        ebur128_set_channel(s->r128_in,  0, EBUR128_DUAL_MONO);
-        ebur128_set_channel(s->r128_out, 0, EBUR128_DUAL_MONO);
+        ff_ebur128_set_channel(s->r128_in,  0, FF_EBUR128_DUAL_MONO);
+        ff_ebur128_set_channel(s->r128_out, 0, FF_EBUR128_DUAL_MONO);
     }
 
     s->buf_size = frame_size(inlink->sample_rate, 3000) * inlink->channels;
@@ -799,22 +799,22 @@ static av_cold void uninit(AVFilterContext *ctx)
     if (!s->r128_in || !s->r128_out)
         goto end;
 
-    ebur128_loudness_range(s->r128_in, &lra_in);
-    ebur128_loudness_global(s->r128_in, &i_in);
-    ebur128_relative_threshold(s->r128_in, &thresh_in);
+    ff_ebur128_loudness_range(s->r128_in, &lra_in);
+    ff_ebur128_loudness_global(s->r128_in, &i_in);
+    ff_ebur128_relative_threshold(s->r128_in, &thresh_in);
     for (c = 0; c < s->channels; c++) {
         double tmp;
-        ebur128_sample_peak(s->r128_in, c, &tmp);
+        ff_ebur128_sample_peak(s->r128_in, c, &tmp);
         if ((c == 0) || (tmp > tp_in))
             tp_in = tmp;
     }
 
-    ebur128_loudness_range(s->r128_out, &lra_out);
-    ebur128_loudness_global(s->r128_out, &i_out);
-    ebur128_relative_threshold(s->r128_out, &thresh_out);
+    ff_ebur128_loudness_range(s->r128_out, &lra_out);
+    ff_ebur128_loudness_global(s->r128_out, &i_out);
+    ff_ebur128_relative_threshold(s->r128_out, &thresh_out);
     for (c = 0; c < s->channels; c++) {
         double tmp;
-        ebur128_sample_peak(s->r128_out, c, &tmp);
+        ff_ebur128_sample_peak(s->r128_out, c, &tmp);
         if ((c == 0) || (tmp > tp_out))
             tp_out = tmp;
     }
@@ -881,9 +881,9 @@ static av_cold void uninit(AVFilterContext *ctx)
 
 end:
     if (s->r128_in)
-        ebur128_destroy(&s->r128_in);
+        ff_ebur128_destroy(&s->r128_in);
     if (s->r128_out)
-        ebur128_destroy(&s->r128_out);
+        ff_ebur128_destroy(&s->r128_out);
     av_freep(&s->limiter_buf);
     av_freep(&s->prev_smp);
     av_freep(&s->buf);
diff --git a/libavfilter/ebur128.c b/libavfilter/ebur128.c
new file mode 100644
index 0000000..318da2f
--- /dev/null
+++ b/libavfilter/ebur128.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2011 Jan Kokemüller
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This file is based on libebur128 which is available at
+ * https://github.com/jiixyj/libebur128/
+ *
+ * Libebur128 has the following copyright:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+*/
+
+#include "ebur128.h"
+
+#include <float.h>
+#include <limits.h>
+#include <math.h> /* You may have to define _USE_MATH_DEFINES if you use MSVC */
+
+#include "libavutil/mem.h"
+#include "libavutil/thread.h"
+
+#define CHECK_ERROR(condition, errorcode, goto_point)                          \
+  if ((condition)) {                                                           \
+    errcode = (errorcode);                                                     \
+    goto goto_point;                                                           \
+  }
+
+#define ALMOST_ZERO 0.000001
+
+struct FFEBUR128StateInternal {
+  /** Filtered audio data (used as ring buffer). */
+  double* audio_data;
+  /** Size of audio_data array. */
+  size_t audio_data_frames;
+  /** Current index for audio_data. */
+  size_t audio_data_index;
+  /** How many frames are needed for a gating block. Will correspond to 400ms
+   *  of audio at initialization, and 100ms after the first block (75% overlap
+   *  as specified in the 2011 revision of BS1770). */
+  unsigned long needed_frames;
+  /** The channel map. Has as many elements as there are channels. */
+  int* channel_map;
+  /** How many samples fit in 100ms (rounded). */
+  unsigned long samples_in_100ms;
+  /** BS.1770 filter coefficients (nominator). */
+  double b[5];
+  /** BS.1770 filter coefficients (denominator). */
+  double a[5];
+  /** BS.1770 filter state. */
+  double v[5][5];
+  /** Histograms, used to calculate LRA. */
+  unsigned long *block_energy_histogram;
+  unsigned long *short_term_block_energy_histogram;
+  /** Keeps track of when a new short term block is needed. */
+  size_t short_term_frame_counter;
+  /** Maximum sample peak, one per channel */
+  double* sample_peak;
+  /** The maximum window duration in ms. */
+  unsigned long window;
+  /** Data pointer array for interleaved data */
+  void  **data_ptrs;
+};
+
+static double relative_gate = -10.0;
+
+static AVOnce histogram_init = AV_ONCE_INIT;
+static double relative_gate_factor;
+static double minus_twenty_decibels;
+static double histogram_energies[1000];
+static double histogram_energy_boundaries[1001];
+
+static void ebur128_init_filter(FFEBUR128State* st) {
+  int i, j;
+
+  double f0 = 1681.974450955533;
+  double G  =    3.999843853973347;
+  double Q  =    0.7071752369554196;
+
+  double K  = tan(M_PI * f0 / (double) st->samplerate);
+  double Vh = pow(10.0, G / 20.0);
+  double Vb = pow(Vh, 0.4996667741545416);
+
+  double pb[3] = {0.0,  0.0, 0.0};
+  double pa[3] = {1.0,  0.0, 0.0};
+  double rb[3] = {1.0, -2.0, 1.0};
+  double ra[3] = {1.0,  0.0, 0.0};
+
+  double a0 =      1.0 + K / Q + K * K      ;
+  pb[0] =     (Vh + Vb * K / Q + K * K) / a0;
+  pb[1] =           2.0 * (K * K -  Vh) / a0;
+  pb[2] =     (Vh - Vb * K / Q + K * K) / a0;
+  pa[1] =           2.0 * (K * K - 1.0) / a0;
+  pa[2] =         (1.0 - K / Q + K * K) / a0;
+
+  f0 = 38.13547087602444;
+  Q  =  0.5003270373238773;
+  K  = tan(M_PI * f0 / (double) st->samplerate);
+
+  ra[1] =   2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K);
+  ra[2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K);
+
+  st->d->b[0] = pb[0] * rb[0];
+  st->d->b[1] = pb[0] * rb[1] + pb[1] * rb[0];
+  st->d->b[2] = pb[0] * rb[2] + pb[1] * rb[1] + pb[2] * rb[0];
+  st->d->b[3] = pb[1] * rb[2] + pb[2] * rb[1];
+  st->d->b[4] = pb[2] * rb[2];
+
+  st->d->a[0] = pa[0] * ra[0];
+  st->d->a[1] = pa[0] * ra[1] + pa[1] * ra[0];
+  st->d->a[2] = pa[0] * ra[2] + pa[1] * ra[1] + pa[2] * ra[0];
+  st->d->a[3] = pa[1] * ra[2] + pa[2] * ra[1];
+  st->d->a[4] = pa[2] * ra[2];
+
+  for (i = 0; i < 5; ++i) {
+    for (j = 0; j < 5; ++j) {
+      st->d->v[i][j] = 0.0;
+    }
+  }
+}
+
+static int ebur128_init_channel_map(FFEBUR128State* st) {
+  size_t i;
+  st->d->channel_map = (int*) av_malloc_array(st->channels, sizeof(int));
+  if (!st->d->channel_map) return FF_EBUR128_ERROR_NOMEM;
+  if (st->channels == 4) {
+    st->d->channel_map[0] = FF_EBUR128_LEFT;
+    st->d->channel_map[1] = FF_EBUR128_RIGHT;
+    st->d->channel_map[2] = FF_EBUR128_LEFT_SURROUND;
+    st->d->channel_map[3] = FF_EBUR128_RIGHT_SURROUND;
+  } else if (st->channels == 5) {
+    st->d->channel_map[0] = FF_EBUR128_LEFT;
+    st->d->channel_map[1] = FF_EBUR128_RIGHT;
+    st->d->channel_map[2] = FF_EBUR128_CENTER;
+    st->d->channel_map[3] = FF_EBUR128_LEFT_SURROUND;
+    st->d->channel_map[4] = FF_EBUR128_RIGHT_SURROUND;
+  } else {
+    for (i = 0; i < st->channels; ++i) {
+      switch (i) {
+        case 0:  st->d->channel_map[i] = FF_EBUR128_LEFT;           break;
+        case 1:  st->d->channel_map[i] = FF_EBUR128_RIGHT;          break;
+        case 2:  st->d->channel_map[i] = FF_EBUR128_CENTER;         break;
+        case 3:  st->d->channel_map[i] = FF_EBUR128_UNUSED;         break;
+        case 4:  st->d->channel_map[i] = FF_EBUR128_LEFT_SURROUND;  break;
+        case 5:  st->d->channel_map[i] = FF_EBUR128_RIGHT_SURROUND; break;
+        default: st->d->channel_map[i] = FF_EBUR128_UNUSED;         break;
+      }
+    }
+  }
+  return FF_EBUR128_SUCCESS;
+}
+
+static inline void init_histogram(void)
+{
+  int i;
+  /* initialize static constants */
+  relative_gate_factor = pow(10.0, relative_gate / 10.0);
+  minus_twenty_decibels = pow(10.0, -20.0 / 10.0);
+  histogram_energy_boundaries[0] = pow(10.0, (-70.0 + 0.691) / 10.0);
+  for (i = 0; i < 1000; ++i) {
+    histogram_energies[i] = pow(10.0, ((double) i / 10.0 - 69.95 + 0.691) / 10.0);
+  }
+  for (i = 1; i < 1001; ++i) {
+    histogram_energy_boundaries[i] = pow(10.0, ((double) i / 10.0 - 70.0 + 0.691) / 10.0);
+  }
+}
+
+FFEBUR128State* ff_ebur128_init(unsigned int channels,
+                               unsigned long samplerate,
+                               int mode) {
+  int errcode;
+  FFEBUR128State* st;
+  unsigned int i;
+  size_t j;
+
+  st = (FFEBUR128State*) av_malloc(sizeof(FFEBUR128State));
+  CHECK_ERROR(!st, 0, exit)
+  st->d = (struct FFEBUR128StateInternal*)
+          av_malloc(sizeof(struct FFEBUR128StateInternal));
+  CHECK_ERROR(!st->d, 0, free_state)
+  st->channels = channels;
+  errcode = ebur128_init_channel_map(st);
+  CHECK_ERROR(errcode, 0, free_internal)
+
+  st->d->sample_peak = (double*) av_malloc_array(channels, sizeof(double));
+  CHECK_ERROR(!st->d->sample_peak, 0, free_channel_map)
+  for (i = 0; i < channels; ++i) {
+    st->d->sample_peak[i] = 0.0;
+  }
+
+  st->samplerate = samplerate;
+  st->d->samples_in_100ms = (st->samplerate + 5) / 10;
+  st->mode = mode;
+  if ((mode & FF_EBUR128_MODE_S) == FF_EBUR128_MODE_S) {
+    st->d->window = 3000;
+  } else if ((mode & FF_EBUR128_MODE_M) == FF_EBUR128_MODE_M) {
+    st->d->window = 400;
+  } else {
+    goto free_sample_peak;
+  }
+  st->d->audio_data_frames = st->samplerate * st->d->window / 1000;
+  if (st->d->audio_data_frames % st->d->samples_in_100ms) {
+    /* round up to multiple of samples_in_100ms */
+    st->d->audio_data_frames = st->d->audio_data_frames
+                             + st->d->samples_in_100ms
+                             - (st->d->audio_data_frames % st->d->samples_in_100ms);
+  }
+  st->d->audio_data = (double*) av_malloc_array(st->d->audio_data_frames,
+                                                st->channels * sizeof(double));
+  CHECK_ERROR(!st->d->audio_data, 0, free_sample_peak)
+  for (j = 0; j < st->d->audio_data_frames * st->channels; ++j) {
+    st->d->audio_data[i] = 0.0;
+  }
+
+  ebur128_init_filter(st);
+
+  st->d->block_energy_histogram = av_malloc(1000 * sizeof(unsigned long));
+  CHECK_ERROR(!st->d->block_energy_histogram, 0, free_audio_data)
+  for (i = 0; i < 1000; ++i) {
+    st->d->block_energy_histogram[i] = 0;
+  }
+  st->d->short_term_block_energy_histogram = av_malloc(1000 * sizeof(unsigned long));
+  CHECK_ERROR(!st->d->short_term_block_energy_histogram, 0, free_block_energy_histogram)
+  for (i = 0; i < 1000; ++i) {
+    st->d->short_term_block_energy_histogram[i] = 0;
+  }
+  st->d->short_term_frame_counter = 0;
+
+  /* the first block needs 400ms of audio data */
+  st->d->needed_frames = st->d->samples_in_100ms * 4;
+  /* start at the beginning of the buffer */
+  st->d->audio_data_index = 0;
+
+  if (ff_thread_once(&histogram_init, &init_histogram) != 0)
+      goto free_short_term_block_energy_histogram;
+
+  st->d->data_ptrs = av_malloc_array(channels, sizeof(void*));
+  CHECK_ERROR(!st->d->data_ptrs, 0, free_short_term_block_energy_histogram);
+
+  return st;
+
+free_short_term_block_energy_histogram:
+  av_free(st->d->short_term_block_energy_histogram);
+free_block_energy_histogram:
+  av_free(st->d->block_energy_histogram);
+free_audio_data:
+  av_free(st->d->audio_data);
+free_sample_peak:
+  av_free(st->d->sample_peak);
+free_channel_map:
+  av_free(st->d->channel_map);
+free_internal:
+  av_free(st->d);
+free_state:
+  av_free(st);
+exit:
+  return NULL;
+}
+
+void ff_ebur128_destroy(FFEBUR128State** st) {
+  av_free((*st)->d->block_energy_histogram);
+  av_free((*st)->d->short_term_block_energy_histogram);
+  av_free((*st)->d->audio_data);
+  av_free((*st)->d->channel_map);
+  av_free((*st)->d->sample_peak);
+  av_free((*st)->d->data_ptrs);
+  av_free((*st)->d);
+  av_free(*st);
+  *st = NULL;
+}
+
+#define EBUR128_FILTER(type, min_scale, max_scale)                             \
+static void ebur128_filter_##type(FFEBUR128State* st, const type** srcs,       \
+                                  size_t src_index, size_t frames,             \
+                                  int stride) {                                \
+  static double scaling_factor = -((double) min_scale) > (double) max_scale ?  \
+                                 -((double) min_scale) : (double) max_scale;   \
+  double* audio_data = st->d->audio_data + st->d->audio_data_index;            \
+  size_t i, c;                                                                 \
+                                                                               \
+  if ((st->mode & FF_EBUR128_MODE_SAMPLE_PEAK) == FF_EBUR128_MODE_SAMPLE_PEAK) {     \
+    for (c = 0; c < st->channels; ++c) {                                       \
+      double max = 0.0;                                                        \
+      for (i = 0; i < frames; ++i) {                                           \
+        type v = srcs[c][src_index + i * stride];                              \
+        if (v > max) {                                                         \
+          max =        v;                                                      \
+        } else if (-v > max) {                                                 \
+          max = -1.0 * v;                                                      \
+        }                                                                      \
+      }                                                                        \
+      max /= scaling_factor;                                                   \
+      if (max > st->d->sample_peak[c]) st->d->sample_peak[c] = max;            \
+    }                                                                          \
+  }                                                                            \
+  for (c = 0; c < st->channels; ++c) {                                         \
+    int ci = st->d->channel_map[c] - 1;                                        \
+    if (ci < 0) continue;                                                      \
+    else if (ci == FF_EBUR128_DUAL_MONO - 1) ci = 0; /*dual mono */               \
+    for (i = 0; i < frames; ++i) {                                             \
+      st->d->v[ci][0] = (double) (srcs[c][src_index + i * stride] / scaling_factor) \
+                   - st->d->a[1] * st->d->v[ci][1]                             \
+                   - st->d->a[2] * st->d->v[ci][2]                             \
+                   - st->d->a[3] * st->d->v[ci][3]                             \
+                   - st->d->a[4] * st->d->v[ci][4];                            \
+      audio_data[i * st->channels + c] =                                       \
+                     st->d->b[0] * st->d->v[ci][0]                             \
+                   + st->d->b[1] * st->d->v[ci][1]                             \
+                   + st->d->b[2] * st->d->v[ci][2]                             \
+                   + st->d->b[3] * st->d->v[ci][3]                             \
+                   + st->d->b[4] * st->d->v[ci][4];                            \
+      st->d->v[ci][4] = st->d->v[ci][3];                                       \
+      st->d->v[ci][3] = st->d->v[ci][2];                                       \
+      st->d->v[ci][2] = st->d->v[ci][1];                                       \
+      st->d->v[ci][1] = st->d->v[ci][0];                                       \
+    }                                                                          \
+    st->d->v[ci][4] = fabs(st->d->v[ci][4]) < DBL_MIN ? 0.0 : st->d->v[ci][4]; \
+    st->d->v[ci][3] = fabs(st->d->v[ci][3]) < DBL_MIN ? 0.0 : st->d->v[ci][3]; \
+    st->d->v[ci][2] = fabs(st->d->v[ci][2]) < DBL_MIN ? 0.0 : st->d->v[ci][2]; \
+    st->d->v[ci][1] = fabs(st->d->v[ci][1]) < DBL_MIN ? 0.0 : st->d->v[ci][1]; \
+  }                                                                            \
+}
+EBUR128_FILTER(short, SHRT_MIN, SHRT_MAX)
+EBUR128_FILTER(int, INT_MIN, INT_MAX)
+EBUR128_FILTER(float, -1.0f, 1.0f)
+EBUR128_FILTER(double, -1.0, 1.0)
+
+static double ebur128_energy_to_loudness(double energy) {
+  return 10 * (log(energy) / log(10.0)) - 0.691;
+}
+
+static size_t find_histogram_index(double energy) {
+  size_t index_min = 0;
+  size_t index_max = 1000;
+  size_t index_mid;
+
+  do {
+    index_mid = (index_min + index_max) / 2;
+    if (energy >= histogram_energy_boundaries[index_mid]) {
+      index_min = index_mid;
+    } else {
+      index_max = index_mid;
+    }
+  } while (index_max - index_min != 1);
+
+  return index_min;
+}
+
+static void ebur128_calc_gating_block(FFEBUR128State* st, size_t frames_per_block,
+                                     double* optional_output) {
+  size_t i, c;
+  double sum = 0.0;
+  double channel_sum;
+  for (c = 0; c < st->channels; ++c) {
+    if (st->d->channel_map[c] == FF_EBUR128_UNUSED) continue;
+    channel_sum = 0.0;
+    if (st->d->audio_data_index < frames_per_block * st->channels) {
+      for (i = 0; i < st->d->audio_data_index / st->channels; ++i) {
+        channel_sum += st->d->audio_data[i * st->channels + c] *
+                       st->d->audio_data[i * st->channels + c];
+      }
+      for (i = st->d->audio_data_frames -
+              (frames_per_block -
+               st->d->audio_data_index / st->channels);
+           i < st->d->audio_data_frames; ++i) {
+        channel_sum += st->d->audio_data[i * st->channels + c] *
+                       st->d->audio_data[i * st->channels + c];
+      }
+    } else {
+      for (i = st->d->audio_data_index / st->channels - frames_per_block;
+           i < st->d->audio_data_index / st->channels;
+           ++i) {
+        channel_sum += st->d->audio_data[i * st->channels + c] *
+                       st->d->audio_data[i * st->channels + c];
+      }
+    }
+    if (st->d->channel_map[c] == FF_EBUR128_Mp110 ||
+        st->d->channel_map[c] == FF_EBUR128_Mm110 ||
+        st->d->channel_map[c] == FF_EBUR128_Mp060 ||
+        st->d->channel_map[c] == FF_EBUR128_Mm060 ||
+        st->d->channel_map[c] == FF_EBUR128_Mp090 ||
+        st->d->channel_map[c] == FF_EBUR128_Mm090) {
+      channel_sum *= 1.41;
+    } else if (st->d->channel_map[c] == FF_EBUR128_DUAL_MONO) {
+      channel_sum *= 2.0;
+    }
+    sum += channel_sum;
+  }
+  sum /= (double) frames_per_block;
+  if (optional_output) {
+    *optional_output = sum;
+  } else if (sum >= histogram_energy_boundaries[0]) {
+    ++st->d->block_energy_histogram[find_histogram_index(sum)];
+  }
+}
+
+int ff_ebur128_set_channel(FFEBUR128State* st,
+                           unsigned int channel_number,
+                           int value) {
+  if (channel_number >= st->channels) {
+    return 1;
+  }
+  if (value == FF_EBUR128_DUAL_MONO &&
+      (st->channels != 1 || channel_number != 0)) {
+    return 1;
+  }
+  st->d->channel_map[channel_number] = value;
+  return 0;
+}
+
+int ff_ebur128_change_parameters(FFEBUR128State* st,
+                                 unsigned int channels,
+                                 unsigned long samplerate) {
+  int errcode = FF_EBUR128_SUCCESS;
+  size_t j;
+
+  if (channels == st->channels &&
+      samplerate == st->samplerate) {
+    return FF_EBUR128_ERROR_NO_CHANGE;
+  }
+  av_free(st->d->audio_data);
+  st->d->audio_data = NULL;
+
+  if (channels != st->channels) {
+    unsigned int i;
+
+    av_free(st->d->channel_map); st->d->channel_map = NULL;
+    av_free(st->d->sample_peak); st->d->sample_peak = NULL;
+    st->channels = channels;
+
+    errcode = ebur128_init_channel_map(st);
+    CHECK_ERROR(errcode, FF_EBUR128_ERROR_NOMEM, exit)
+
+    st->d->sample_peak = (double*) av_malloc_array(channels, sizeof(double));
+    CHECK_ERROR(!st->d->sample_peak, FF_EBUR128_ERROR_NOMEM, exit)
+    for (i = 0; i < channels; ++i) {
+      st->d->sample_peak[i] = 0.0;
+    }
+  }
+  if (samplerate != st->samplerate) {
+    st->samplerate = samplerate;
+    st->d->samples_in_100ms = (st->samplerate + 5) / 10;
+    ebur128_init_filter(st);
+  }
+  st->d->audio_data_frames = st->samplerate * st->d->window / 1000;
+  if (st->d->audio_data_frames % st->d->samples_in_100ms) {
+    /* round up to multiple of samples_in_100ms */
+    st->d->audio_data_frames = st->d->audio_data_frames
+                             + st->d->samples_in_100ms
+                             - (st->d->audio_data_frames % st->d->samples_in_100ms);
+  }
+  st->d->audio_data = (double*) av_malloc_array(st->d->audio_data_frames,
+                                                st->channels * sizeof(double));
+  CHECK_ERROR(!st->d->audio_data, FF_EBUR128_ERROR_NOMEM, exit)
+  for (j = 0; j < st->d->audio_data_frames * st->channels; ++j) {
+    st->d->audio_data[j] = 0.0;
+  }
+
+  /* the first block needs 400ms of audio data */
+  st->d->needed_frames = st->d->samples_in_100ms * 4;
+  /* start at the beginning of the buffer */
+  st->d->audio_data_index = 0;
+  /* reset short term frame counter */
+  st->d->short_term_frame_counter = 0;
+
+exit:
+  return errcode;
+}
+
+int ff_ebur128_set_max_window(FFEBUR128State* st, unsigned long window)
+{
+  int errcode = FF_EBUR128_SUCCESS;
+  size_t j;
+
+  if ((st->mode & FF_EBUR128_MODE_S) == FF_EBUR128_MODE_S && window < 3000) {
+    window = 3000;
+  } else if ((st->mode & FF_EBUR128_MODE_M) == FF_EBUR128_MODE_M && window < 400) {
+    window = 400;
+  }
+  if (window == st->d->window) {
+    return FF_EBUR128_ERROR_NO_CHANGE;
+  }
+
+  st->d->window = window;
+  av_free(st->d->audio_data);
+  st->d->audio_data = NULL;
+  st->d->audio_data_frames = st->samplerate * st->d->window / 1000;
+  if (st->d->audio_data_frames % st->d->samples_in_100ms) {
+    /* round up to multiple of samples_in_100ms */
+    st->d->audio_data_frames = st->d->audio_data_frames
+                             + st->d->samples_in_100ms
+                             - (st->d->audio_data_frames % st->d->samples_in_100ms);
+  }
+  st->d->audio_data = (double*) av_malloc_array(st->d->audio_data_frames,
+                                                st->channels * sizeof(double));
+  CHECK_ERROR(!st->d->audio_data, FF_EBUR128_ERROR_NOMEM, exit)
+  for (j = 0; j < st->d->audio_data_frames * st->channels; ++j) {
+    st->d->audio_data[j] = 0.0;
+  }
+
+  /* the first block needs 400ms of audio data */
+  st->d->needed_frames = st->d->samples_in_100ms * 4;
+  /* start at the beginning of the buffer */
+  st->d->audio_data_index = 0;
+  /* reset short term frame counter */
+  st->d->short_term_frame_counter = 0;
+
+exit:
+  return errcode;
+}
+
+
+static int ebur128_energy_shortterm(FFEBUR128State* st, double* out);
+#define FF_EBUR128_ADD_FRAMES(type)                                               \
+void ff_ebur128_add_frames_##type(FFEBUR128State* st, const type** srcs,       \
+                                 size_t frames, int stride) {                  \
+  size_t src_index = 0;                                                        \
+  while (frames > 0) {                                                         \
+    if (frames >= st->d->needed_frames) {                                      \
+      ebur128_filter_##type(st, srcs, src_index, st->d->needed_frames, stride);\
+      src_index += st->d->needed_frames * stride;                              \
+      frames -= st->d->needed_frames;                                          \
+      st->d->audio_data_index += st->d->needed_frames * st->channels;          \
+      /* calculate the new gating block */                                     \
+      if ((st->mode & FF_EBUR128_MODE_I) == FF_EBUR128_MODE_I) {                     \
+        ebur128_calc_gating_block(st, st->d->samples_in_100ms * 4, NULL);      \
+      }                                                                        \
+      if ((st->mode & FF_EBUR128_MODE_LRA) == FF_EBUR128_MODE_LRA) {                 \
+        st->d->short_term_frame_counter += st->d->needed_frames;               \
+        if (st->d->short_term_frame_counter == st->d->samples_in_100ms * 30) { \
+          double st_energy;                                                    \
+          ebur128_energy_shortterm(st, &st_energy);                            \
+          if (st_energy >= histogram_energy_boundaries[0]) {                   \
+            ++st->d->short_term_block_energy_histogram[                        \
+                                            find_histogram_index(st_energy)];  \
+          }                                                                    \
+          st->d->short_term_frame_counter = st->d->samples_in_100ms * 20;      \
+        }                                                                      \
+      }                                                                        \
+      /* 100ms are needed for all blocks besides the first one */              \
+      st->d->needed_frames = st->d->samples_in_100ms;                          \
+      /* reset audio_data_index when buffer full */                            \
+      if (st->d->audio_data_index == st->d->audio_data_frames * st->channels) {\
+        st->d->audio_data_index = 0;                                           \
+      }                                                                        \
+    } else {                                                                   \
+      ebur128_filter_##type(st, srcs, src_index, frames, stride);              \
+      st->d->audio_data_index += frames * st->channels;                        \
+      if ((st->mode & FF_EBUR128_MODE_LRA) == FF_EBUR128_MODE_LRA) {                 \
+        st->d->short_term_frame_counter += frames;                             \
+      }                                                                        \
+      st->d->needed_frames -= frames;                                          \
+      frames = 0;                                                              \
+    }                                                                          \
+  }                                                                            \
+}
+FF_EBUR128_ADD_FRAMES(short)
+FF_EBUR128_ADD_FRAMES(int)
+FF_EBUR128_ADD_FRAMES(float)
+FF_EBUR128_ADD_FRAMES(double)
+
+#define FF_EBUR128_ADD_IL_FRAMES(type)                                         \
+void ff_ebur128_add_il_frames_##type(FFEBUR128State* st, const type* src,       \
+                                    size_t frames) {                           \
+  int i;                                                                       \
+  const type **buf = (const type**)st->d->data_ptrs;                           \
+  for (i = 0; i < st->channels; i++)                                           \
+    buf[i] = src + i;                                                          \
+  ff_ebur128_add_frames_##type(st, buf, frames, st->channels);                 \
+}
+FF_EBUR128_ADD_IL_FRAMES(short)
+FF_EBUR128_ADD_IL_FRAMES(int)
+FF_EBUR128_ADD_IL_FRAMES(float)
+FF_EBUR128_ADD_IL_FRAMES(double)
+
+static int ebur128_calc_relative_threshold(FFEBUR128State* st,
+                                           size_t* above_thresh_counter,
+                                           double* relative_threshold) {
+  size_t i;
+  *relative_threshold = 0.0;
+  *above_thresh_counter = 0;
+
+  for (i = 0; i < 1000; ++i) {
+    *relative_threshold += st->d->block_energy_histogram[i] *
+                          histogram_energies[i];
+    *above_thresh_counter += st->d->block_energy_histogram[i];
+  }
+
+  if (*above_thresh_counter != 0) {
+    *relative_threshold /= (double) *above_thresh_counter;
+    *relative_threshold *= relative_gate_factor;
+  }
+
+  return FF_EBUR128_SUCCESS;
+}
+
+static int ebur128_gated_loudness(FFEBUR128State** sts, size_t size,
+                                  double* out) {
+  double gated_loudness = 0.0;
+  double relative_threshold;
+  size_t above_thresh_counter;
+  size_t i, j, start_index;
+
+  for (i = 0; i < size; i++) {
+    if (sts[i] && (sts[i]->mode & FF_EBUR128_MODE_I) != FF_EBUR128_MODE_I) {
+      return FF_EBUR128_ERROR_INVALID_MODE;
+    }
+  }
+
+  for (i = 0; i < size; i++) {
+    if (!sts[i]) continue;
+    ebur128_calc_relative_threshold(sts[i], &above_thresh_counter, &relative_threshold);
+  }
+  if (!above_thresh_counter) {
+    *out = -HUGE_VAL;
+    return FF_EBUR128_SUCCESS;
+  }
+
+  above_thresh_counter = 0;
+  if (relative_threshold < histogram_energy_boundaries[0]) {
+    start_index = 0;
+  } else {
+    start_index = find_histogram_index(relative_threshold);
+    if (relative_threshold > histogram_energies[start_index]) {
+      ++start_index;
+    }
+  }
+  for (i = 0; i < size; i++) {
+    if (!sts[i]) continue;
+    for (j = start_index; j < 1000; ++j) {
+      gated_loudness += sts[i]->d->block_energy_histogram[j] *
+                        histogram_energies[j];
+      above_thresh_counter += sts[i]->d->block_energy_histogram[j];
+    }
+  }
+  if (!above_thresh_counter) {
+    *out = -HUGE_VAL;
+    return FF_EBUR128_SUCCESS;
+  }
+  gated_loudness /= (double) above_thresh_counter;
+  *out = ebur128_energy_to_loudness(gated_loudness);
+  return FF_EBUR128_SUCCESS;
+}
+
+int ff_ebur128_relative_threshold(FFEBUR128State* st, double* out) {
+  double relative_threshold;
+  size_t above_thresh_counter;
+
+  if (st && (st->mode & FF_EBUR128_MODE_I) != FF_EBUR128_MODE_I)
+    return FF_EBUR128_ERROR_INVALID_MODE;
+
+  ebur128_calc_relative_threshold(st, &above_thresh_counter, &relative_threshold);
+
+  if (!above_thresh_counter) {
+      *out = -70.0;
+      return FF_EBUR128_SUCCESS;
+  }
+
+  *out = ebur128_energy_to_loudness(relative_threshold);
+  return FF_EBUR128_SUCCESS;
+}
+
+int ff_ebur128_loudness_global(FFEBUR128State* st, double* out) {
+  return ebur128_gated_loudness(&st, 1, out);
+}
+
+int ff_ebur128_loudness_global_multiple(FFEBUR128State** sts, size_t size,
+                                     double* out) {
+  return ebur128_gated_loudness(sts, size, out);
+}
+
+static int ebur128_energy_in_interval(FFEBUR128State* st,
+                                      size_t interval_frames,
+                                      double* out) {
+  if (interval_frames > st->d->audio_data_frames) {
+    return FF_EBUR128_ERROR_INVALID_MODE;
+  }
+  ebur128_calc_gating_block(st, interval_frames, out);
+  return FF_EBUR128_SUCCESS;
+}
+
+static int ebur128_energy_shortterm(FFEBUR128State* st, double* out) {
+  return ebur128_energy_in_interval(st, st->d->samples_in_100ms * 30, out);
+}
+
+int ff_ebur128_loudness_momentary(FFEBUR128State* st, double* out) {
+  double energy;
+  int error = ebur128_energy_in_interval(st, st->d->samples_in_100ms * 4,
+                                         &energy);
+  if (error) {
+    return error;
+  } else if (energy <= 0.0) {
+    *out = -HUGE_VAL;
+    return FF_EBUR128_SUCCESS;
+  }
+  *out = ebur128_energy_to_loudness(energy);
+  return FF_EBUR128_SUCCESS;
+}
+
+int ff_ebur128_loudness_shortterm(FFEBUR128State* st, double* out) {
+  double energy;
+  int error = ebur128_energy_shortterm(st, &energy);
+  if (error) {
+    return error;
+  } else if (energy <= 0.0) {
+    *out = -HUGE_VAL;
+    return FF_EBUR128_SUCCESS;
+  }
+  *out = ebur128_energy_to_loudness(energy);
+  return FF_EBUR128_SUCCESS;
+}
+
+int ff_ebur128_loudness_window(FFEBUR128State* st,
+                            unsigned long window,
+                            double* out) {
+  double energy;
+  size_t interval_frames = st->samplerate * window / 1000;
+  int error = ebur128_energy_in_interval(st, interval_frames, &energy);
+  if (error) {
+    return error;
+  } else if (energy <= 0.0) {
+    *out = -HUGE_VAL;
+    return FF_EBUR128_SUCCESS;
+  }
+  *out = ebur128_energy_to_loudness(energy);
+  return FF_EBUR128_SUCCESS;
+}
+
+/* EBU - TECH 3342 */
+int ff_ebur128_loudness_range_multiple(FFEBUR128State** sts, size_t size,
+                                       double* out) {
+  size_t i, j;
+  size_t stl_size;
+  double stl_power, stl_integrated;
+  /* High and low percentile energy */
+  double h_en, l_en;
+
+  for (i = 0; i < size; ++i) {
+    if (sts[i]) {
+      if ((sts[i]->mode & FF_EBUR128_MODE_LRA) != FF_EBUR128_MODE_LRA) {
+        return FF_EBUR128_ERROR_INVALID_MODE;
+      }
+    }
+  }
+
+  {
+    unsigned long hist[1000] = { 0 };
+    size_t percentile_low, percentile_high;
+    size_t index;
+
+    stl_size = 0;
+    stl_power = 0.0;
+    for (i = 0; i < size; ++i) {
+      if (!sts[i]) continue;
+      for (j = 0; j < 1000; ++j) {
+        hist[j]   += sts[i]->d->short_term_block_energy_histogram[j];
+        stl_size  += sts[i]->d->short_term_block_energy_histogram[j];
+        stl_power += sts[i]->d->short_term_block_energy_histogram[j]
+                     * histogram_energies[j];
+      }
+    }
+    if (!stl_size) {
+      *out = 0.0;
+      return FF_EBUR128_SUCCESS;
+    }
+
+    stl_power /= stl_size;
+    stl_integrated = minus_twenty_decibels * stl_power;
+
+    if (stl_integrated < histogram_energy_boundaries[0]) {
+      index = 0;
+    } else {
+      index = find_histogram_index(stl_integrated);
+      if (stl_integrated > histogram_energies[index]) {
+        ++index;
+      }
+    }
+    stl_size = 0;
+    for (j = index; j < 1000; ++j) {
+      stl_size += hist[j];
+    }
+    if (!stl_size) {
+      *out = 0.0;
+      return FF_EBUR128_SUCCESS;
+    }
+
+    percentile_low  = (size_t) ((stl_size - 1) * 0.1 + 0.5);
+    percentile_high = (size_t) ((stl_size - 1) * 0.95 + 0.5);
+
+    stl_size = 0;
+    j = index;
+    while (stl_size <= percentile_low) {
+      stl_size += hist[j++];
+    }
+    l_en = histogram_energies[j - 1];
+    while (stl_size <= percentile_high) {
+      stl_size += hist[j++];
+    }
+    h_en = histogram_energies[j - 1];
+    *out = ebur128_energy_to_loudness(h_en) - ebur128_energy_to_loudness(l_en);
+    return FF_EBUR128_SUCCESS;
+  }
+}
+
+int ff_ebur128_loudness_range(FFEBUR128State* st, double* out) {
+  return ff_ebur128_loudness_range_multiple(&st, 1, out);
+}
+
+int ff_ebur128_sample_peak(FFEBUR128State* st,
+                        unsigned int channel_number,
+                        double* out) {
+  if ((st->mode & FF_EBUR128_MODE_SAMPLE_PEAK) != FF_EBUR128_MODE_SAMPLE_PEAK) {
+    return FF_EBUR128_ERROR_INVALID_MODE;
+  } else if (channel_number >= st->channels) {
+    return FF_EBUR128_ERROR_INVALID_CHANNEL_INDEX;
+  }
+  *out = st->d->sample_peak[channel_number];
+  return FF_EBUR128_SUCCESS;
+}
+
diff --git a/libavfilter/ebur128.h b/libavfilter/ebur128.h
new file mode 100644
index 0000000..8541e05
--- /dev/null
+++ b/libavfilter/ebur128.h
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2011 Jan Kokemüller
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This file is based on libebur128 which is available at
+ * https://github.com/jiixyj/libebur128/
+ *
+*/
+
+#ifndef AVFILTER_EBUR128_H
+#define AVFILTER_EBUR128_H
+
+/** \file ebur128.h
+ *  \brief libebur128 - a library for loudness measurement according to
+ *         the EBU R128 standard.
+ */
+
+#include <stddef.h>       /* for size_t */
+
+/** \enum channel
+ *  Use these values when setting the channel map with ebur128_set_channel().
+ *  See definitions in ITU R-REC-BS 1770-4
+ */
+enum channel {
+  FF_EBUR128_UNUSED = 0,     /**< unused channel (for example LFE channel) */
+  FF_EBUR128_LEFT,
+  FF_EBUR128_Mp030 = 1,      /**< itu M+030 */
+  FF_EBUR128_RIGHT,
+  FF_EBUR128_Mm030 = 2,      /**< itu M-030 */
+  FF_EBUR128_CENTER,
+  FF_EBUR128_Mp000 = 3,      /**< itu M+000 */
+  FF_EBUR128_LEFT_SURROUND,
+  FF_EBUR128_Mp110 = 4,      /**< itu M+110 */
+  FF_EBUR128_RIGHT_SURROUND,
+  FF_EBUR128_Mm110 = 5,      /**< itu M-110 */
+  FF_EBUR128_DUAL_MONO,      /**< a channel that is counted twice */
+  FF_EBUR128_MpSC,           /**< itu M+SC */
+  FF_EBUR128_MmSC,           /**< itu M-SC */
+  FF_EBUR128_Mp060,          /**< itu M+060 */
+  FF_EBUR128_Mm060,          /**< itu M-060 */
+  FF_EBUR128_Mp090,          /**< itu M+090 */
+  FF_EBUR128_Mm090,          /**< itu M-090 */
+  FF_EBUR128_Mp135,          /**< itu M+135 */
+  FF_EBUR128_Mm135,          /**< itu M-135 */
+  FF_EBUR128_Mp180,          /**< itu M+180 */
+  FF_EBUR128_Up000,          /**< itu U+000 */
+  FF_EBUR128_Up030,          /**< itu U+030 */
+  FF_EBUR128_Um030,          /**< itu U-030 */
+  FF_EBUR128_Up045,          /**< itu U+045 */
+  FF_EBUR128_Um045,          /**< itu U-030 */
+  FF_EBUR128_Up090,          /**< itu U+090 */
+  FF_EBUR128_Um090,          /**< itu U-090 */
+  FF_EBUR128_Up110,          /**< itu U+110 */
+  FF_EBUR128_Um110,          /**< itu U-110 */
+  FF_EBUR128_Up135,          /**< itu U+135 */
+  FF_EBUR128_Um135,          /**< itu U-135 */
+  FF_EBUR128_Up180,          /**< itu U+180 */
+  FF_EBUR128_Tp000,          /**< itu T+000 */
+  FF_EBUR128_Bp000,          /**< itu B+000 */
+  FF_EBUR128_Bp045,          /**< itu B+045 */
+  FF_EBUR128_Bm045           /**< itu B-045 */
+};
+
+/** \enum error
+ *  Error return values.
+ */
+enum error {
+  FF_EBUR128_SUCCESS = 0,
+  FF_EBUR128_ERROR_NOMEM,
+  FF_EBUR128_ERROR_INVALID_MODE,
+  FF_EBUR128_ERROR_INVALID_CHANNEL_INDEX,
+  FF_EBUR128_ERROR_NO_CHANGE
+};
+
+/** \enum mode
+ *  Use these values in ebur128_init (or'ed). Try to use the lowest possible
+ *  modes that suit your needs, as performance will be better.
+ */
+enum mode {
+  /** can call ebur128_loudness_momentary */
+  FF_EBUR128_MODE_M           = (1 << 0),
+  /** can call ebur128_loudness_shortterm */
+  FF_EBUR128_MODE_S           = (1 << 1) | FF_EBUR128_MODE_M,
+  /** can call ebur128_loudness_global_* and ebur128_relative_threshold */
+  FF_EBUR128_MODE_I           = (1 << 2) | FF_EBUR128_MODE_M,
+  /** can call ebur128_loudness_range */
+  FF_EBUR128_MODE_LRA         = (1 << 3) | FF_EBUR128_MODE_S,
+  /** can call ebur128_sample_peak */
+  FF_EBUR128_MODE_SAMPLE_PEAK = (1 << 4) | FF_EBUR128_MODE_M,
+};
+
+/** forward declaration of FFEBUR128StateInternal */
+struct FFEBUR128StateInternal;
+
+/** \brief Contains information about the state of a loudness measurement.
+ *
+ *  You should not need to modify this struct directly.
+ */
+typedef struct {
+  int mode;                           /**< The current mode. */
+  unsigned int channels;              /**< The number of channels. */
+  unsigned long samplerate;           /**< The sample rate. */
+  struct FFEBUR128StateInternal* d;   /**< Internal state. */
+} FFEBUR128State;
+
+/** \brief Initialize library state.
+ *
+ *  @param channels the number of channels.
+ *  @param samplerate the sample rate.
+ *  @param mode see the mode enum for possible values.
+ *  @return an initialized library state.
+ */
+FFEBUR128State* ff_ebur128_init(unsigned int channels,
+                               unsigned long samplerate,
+                               int mode);
+
+/** \brief Destroy library state.
+ *
+ *  @param st pointer to a library state.
+ */
+void ff_ebur128_destroy(FFEBUR128State** st);
+
+/** \brief Set channel type.
+ *
+ *  The default is:
+ *  - 0 -> FF_EBUR128_LEFT
+ *  - 1 -> FF_EBUR128_RIGHT
+ *  - 2 -> FF_EBUR128_CENTER
+ *  - 3 -> FF_EBUR128_UNUSED
+ *  - 4 -> FF_EBUR128_LEFT_SURROUND
+ *  - 5 -> FF_EBUR128_RIGHT_SURROUND
+ *
+ *  @param st library state.
+ *  @param channel_number zero based channel index.
+ *  @param value channel type from the "channel" enum.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_CHANNEL_INDEX if invalid channel index.
+ */
+int ff_ebur128_set_channel(FFEBUR128State* st,
+                           unsigned int channel_number,
+                           int value);
+
+/** \brief Change library parameters.
+ *
+ *  Note that the channel map will be reset when setting a different number of
+ *  channels. The current unfinished block will be lost.
+ *
+ *  @param st library state.
+ *  @param channels new number of channels.
+ *  @param samplerate new sample rate.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_NOMEM on memory allocation error. The state will be
+ *      invalid and must be destroyed.
+ *    - FF_EBUR128_ERROR_NO_CHANGE if channels and sample rate were not changed.
+ */
+int ff_ebur128_change_parameters(FFEBUR128State* st,
+                                 unsigned int channels,
+                                 unsigned long samplerate);
+
+/** \brief Set the maximum window duration.
+ *
+ *  Set the maximum duration that will be used for ebur128_window_loudness().
+ *  Note that this destroys the current content of the audio buffer.
+ *
+ *  @param st library state.
+ *  @param window duration of the window in ms.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_NOMEM on memory allocation error. The state will be
+ *      invalid and must be destroyed.
+ *    - FF_EBUR128_ERROR_NO_CHANGE if window duration not changed.
+ */
+int ff_ebur128_set_max_window(FFEBUR128State* st, unsigned long window);
+
+/** \brief Add frames to be processed.
+ *
+ *  @param st library state.
+ *  @param src array of source frames. Channels must be interleaved.
+ *  @param frames number of frames. Not number of samples!
+ */
+void ff_ebur128_add_il_frames_short(FFEBUR128State* st,
+                             const short* src,
+                             size_t frames);
+/** \brief See \ref ebur128_add_frames_short */
+void ff_ebur128_add_il_frames_int(FFEBUR128State* st,
+                             const int* src,
+                             size_t frames);
+/** \brief See \ref ebur128_add_frames_short */
+void ff_ebur128_add_il_frames_float(FFEBUR128State* st,
+                             const float* src,
+                             size_t frames);
+/** \brief See \ref ebur128_add_frames_short */
+void ff_ebur128_add_il_frames_double(FFEBUR128State* st,
+                             const double* src,
+                             size_t frames);
+
+/** \brief Add frames to be processed.
+ *
+ *  @param st library state.
+ *  @param srcs array of source frame channel data pointers
+ *  @param frames number of frames. Not number of samples!
+ *  @param stride number of samples to skip to for the next sample of the same channel
+ */
+void ff_ebur128_add_frames_short(FFEBUR128State* st,
+                             const short** srcs,
+                             size_t frames,
+                             int stride);
+/** \brief See \ref ebur128_add_frames_short */
+void ff_ebur128_add_frames_int(FFEBUR128State* st,
+                             const int** srcs,
+                             size_t frames,
+                             int stride);
+/** \brief See \ref ebur128_add_frames_short */
+void ff_ebur128_add_frames_float(FFEBUR128State* st,
+                             const float** srcs,
+                             size_t frames,
+                             int stride);
+/** \brief See \ref ebur128_add_frames_short */
+void ff_ebur128_add_frames_double(FFEBUR128State* st,
+                             const double** srcs,
+                             size_t frames,
+                             int stride);
+
+/** \brief Get global integrated loudness in LUFS.
+ *
+ *  @param st library state.
+ *  @param out integrated loudness in LUFS. -HUGE_VAL if result is negative
+ *             infinity.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_I" has not been set.
+ */
+int ff_ebur128_loudness_global(FFEBUR128State* st, double* out);
+/** \brief Get global integrated loudness in LUFS across multiple instances.
+ *
+ *  @param sts array of library states.
+ *  @param size length of sts
+ *  @param out integrated loudness in LUFS. -HUGE_VAL if result is negative
+ *             infinity.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_I" has not been set.
+ */
+int ff_ebur128_loudness_global_multiple(FFEBUR128State** sts,
+                                        size_t size,
+                                        double* out);
+
+/** \brief Get momentary loudness (last 400ms) in LUFS.
+ *
+ *  @param st library state.
+ *  @param out momentary loudness in LUFS. -HUGE_VAL if result is negative
+ *             infinity.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ */
+int ff_ebur128_loudness_momentary(FFEBUR128State* st, double* out);
+/** \brief Get short-term loudness (last 3s) in LUFS.
+ *
+ *  @param st library state.
+ *  @param out short-term loudness in LUFS. -HUGE_VAL if result is negative
+ *             infinity.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_S" has not been set.
+ */
+int ff_ebur128_loudness_shortterm(FFEBUR128State* st, double* out);
+
+/** \brief Get loudness of the specified window in LUFS.
+ *
+ *  window must not be larger than the current window set in st.
+ *  The current window can be changed by calling ebur128_set_max_window().
+ *
+ *  @param st library state.
+ *  @param window window in ms to calculate loudness.
+ *  @param out loudness in LUFS. -HUGE_VAL if result is negative infinity.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if window larger than current window in st.
+ */
+int ff_ebur128_loudness_window(FFEBUR128State* st,
+                               unsigned long window,
+                               double* out);
+
+/** \brief Get loudness range (LRA) of programme in LU.
+ *
+ *  Calculates loudness range according to EBU 3342.
+ *
+ *  @param st library state.
+ *  @param out loudness range (LRA) in LU. Will not be changed in case of
+ *             error. FF_EBUR128_ERROR_NOMEM or FF_EBUR128_ERROR_INVALID_MODE will be
+ *             returned in this case.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_NOMEM in case of memory allocation error.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_LRA" has not been set.
+ */
+int ff_ebur128_loudness_range(FFEBUR128State* st, double* out);
+/** \brief Get loudness range (LRA) in LU across multiple instances.
+ *
+ *  Calculates loudness range according to EBU 3342.
+ *
+ *  @param sts array of library states.
+ *  @param size length of sts
+ *  @param out loudness range (LRA) in LU. Will not be changed in case of
+ *             error. FF_EBUR128_ERROR_NOMEM or FF_EBUR128_ERROR_INVALID_MODE will be
+ *             returned in this case.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_NOMEM in case of memory allocation error.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_LRA" has not been set.
+ */
+int ff_ebur128_loudness_range_multiple(FFEBUR128State** sts,
+                                       size_t size,
+                                       double* out);
+
+/** \brief Get maximum sample peak of selected channel in float format.
+ *
+ *  @param st library state
+ *  @param channel_number channel to analyse
+ *  @param out maximum sample peak in float format (1.0 is 0 dBFS)
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_SAMPLE_PEAK" has not
+ *      been set.
+ *    - FF_EBUR128_ERROR_INVALID_CHANNEL_INDEX if invalid channel index.
+ */
+int ff_ebur128_sample_peak(FFEBUR128State* st,
+                           unsigned int channel_number,
+                           double* out);
+
+/** \brief Get relative threshold in LUFS.
+ *
+ *  @param st library state
+ *  @param out relative threshold in LUFS.
+ *  @return
+ *    - FF_EBUR128_SUCCESS on success.
+ *    - FF_EBUR128_ERROR_INVALID_MODE if mode "FF_EBUR128_MODE_I" has not
+ *      been set.
+ */
+int ff_ebur128_relative_threshold(FFEBUR128State* st, double* out);
+
+#endif  /* AVFILTER_EBUR128_H */
-- 
2.6.6



More information about the ffmpeg-devel mailing list