f_ebur128.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Clément Bœsch
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 /**
22  * @file
23  * EBU R.128 implementation
24  * @see http://tech.ebu.ch/loudness
25  * @see https://www.youtube.com/watch?v=iuEtQqC-Sqo "EBU R128 Introduction - Florian Camerer"
26  * @todo True Peak
27  * @todo implement start/stop/reset through filter command injection
28  * @todo support other frequencies to avoid resampling
29  */
30 
31 #include <math.h>
32 
33 #include "libavutil/avassert.h"
34 #include "libavutil/avstring.h"
36 #include "libavutil/dict.h"
38 #include "libavutil/opt.h"
39 #include "libavutil/timestamp.h"
40 #include "audio.h"
41 #include "avfilter.h"
42 #include "formats.h"
43 #include "internal.h"
44 
45 #define MAX_CHANNELS 63
46 
47 /* pre-filter coefficients */
48 #define PRE_B0 1.53512485958697
49 #define PRE_B1 -2.69169618940638
50 #define PRE_B2 1.19839281085285
51 #define PRE_A1 -1.69065929318241
52 #define PRE_A2 0.73248077421585
53 
54 /* RLB-filter coefficients */
55 #define RLB_B0 1.0
56 #define RLB_B1 -2.0
57 #define RLB_B2 1.0
58 #define RLB_A1 -1.99004745483398
59 #define RLB_A2 0.99007225036621
60 
61 #define ABS_THRES -70 ///< silence gate: we discard anything below this absolute (LUFS) threshold
62 #define ABS_UP_THRES 10 ///< upper loud limit to consider (ABS_THRES being the minimum)
63 #define HIST_GRAIN 100 ///< defines histogram precision
64 #define HIST_SIZE ((ABS_UP_THRES - ABS_THRES) * HIST_GRAIN + 1)
65 
66 /**
67  * An histogram is an array of HIST_SIZE hist_entry storing all the energies
68  * recorded (with an accuracy of 1/HIST_GRAIN) of the loudnesses from ABS_THRES
69  * (at 0) to ABS_UP_THRES (at HIST_SIZE-1).
70  * This fixed-size system avoids the need of a list of energies growing
71  * infinitely over the time and is thus more scalable.
72  */
73 struct hist_entry {
74  int count; ///< how many times the corresponding value occurred
75  double energy; ///< E = 10^((L + 0.691) / 10)
76  double loudness; ///< L = -0.691 + 10 * log10(E)
77 };
78 
79 struct integrator {
80  double *cache[MAX_CHANNELS]; ///< window of filtered samples (N ms)
81  int cache_pos; ///< focus on the last added bin in the cache array
82  double sum[MAX_CHANNELS]; ///< sum of the last N ms filtered samples (cache content)
83  int filled; ///< 1 if the cache is completely filled, 0 otherwise
84  double rel_threshold; ///< relative threshold
85  double sum_kept_powers; ///< sum of the powers (weighted sums) above absolute threshold
86  int nb_kept_powers; ///< number of sum above absolute threshold
87  struct hist_entry *histogram; ///< histogram of the powers, used to compute LRA and I
88 };
89 
90 struct rect { int x, y, w, h; };
91 
92 typedef struct {
93  const AVClass *class; ///< AVClass context for log and options purpose
94 
95  /* video */
96  int do_video; ///< 1 if video output enabled, 0 otherwise
97  int w, h; ///< size of the video output
98  struct rect text; ///< rectangle for the LU legend on the left
99  struct rect graph; ///< rectangle for the main graph in the center
100  struct rect gauge; ///< rectangle for the gauge on the right
101  AVFrame *outpicref; ///< output picture reference, updated regularly
102  int meter; ///< select a EBU mode between +9 and +18
103  int scale_range; ///< the range of LU values according to the meter
104  int y_zero_lu; ///< the y value (pixel position) for 0 LU
105  int *y_line_ref; ///< y reference values for drawing the LU lines in the graph and the gauge
106 
107  /* audio */
108  int nb_channels; ///< number of channels in the input
109  double *ch_weighting; ///< channel weighting mapping
110  int sample_count; ///< sample count used for refresh frequency, reset at refresh
111 
112  /* Filter caches.
113  * The mult by 3 in the following is for X[i], X[i-1] and X[i-2] */
114  double x[MAX_CHANNELS * 3]; ///< 3 input samples cache for each channel
115  double y[MAX_CHANNELS * 3]; ///< 3 pre-filter samples cache for each channel
116  double z[MAX_CHANNELS * 3]; ///< 3 RLB-filter samples cache for each channel
117 
118 #define I400_BINS (48000 * 4 / 10)
119 #define I3000_BINS (48000 * 3)
120  struct integrator i400; ///< 400ms integrator, used for Momentary loudness (M), and Integrated loudness (I)
121  struct integrator i3000; ///< 3s integrator, used for Short term loudness (S), and Loudness Range (LRA)
122 
123  /* I and LRA specific */
124  double integrated_loudness; ///< integrated loudness in LUFS (I)
125  double loudness_range; ///< loudness range in LU (LRA)
126  double lra_low, lra_high; ///< low and high LRA values
127 
128  /* misc */
129  int loglevel; ///< log level for frame logging
130  int metadata; ///< whether or not to inject loudness results in frames
132 
133 #define OFFSET(x) offsetof(EBUR128Context, x)
134 #define A AV_OPT_FLAG_AUDIO_PARAM
135 #define V AV_OPT_FLAG_VIDEO_PARAM
136 #define F AV_OPT_FLAG_FILTERING_PARAM
137 static const AVOption ebur128_options[] = {
138  { "video", "set video output", OFFSET(do_video), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, V|F },
139  { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, V|F },
140  { "meter", "set scale meter (+9 to +18)", OFFSET(meter), AV_OPT_TYPE_INT, {.i64 = 9}, 9, 18, V|F },
141  { "framelog", "force frame logging level", OFFSET(loglevel), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, A|V|F, "level" },
142  { "info", "information logging level", 0, AV_OPT_TYPE_CONST, {.i64 = AV_LOG_INFO}, INT_MIN, INT_MAX, A|V|F, "level" },
143  { "verbose", "verbose logging level", 0, AV_OPT_TYPE_CONST, {.i64 = AV_LOG_VERBOSE}, INT_MIN, INT_MAX, A|V|F, "level" },
144  { "metadata", "inject metadata in the filtergraph", OFFSET(metadata), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, A|V|F },
145  { NULL },
146 };
147 
148 AVFILTER_DEFINE_CLASS(ebur128);
149 
150 static const uint8_t graph_colors[] = {
151  0xdd, 0x66, 0x66, // value above 0LU non reached
152  0x66, 0x66, 0xdd, // value below 0LU non reached
153  0x96, 0x33, 0x33, // value above 0LU reached
154  0x33, 0x33, 0x96, // value below 0LU reached
155  0xdd, 0x96, 0x96, // value above 0LU line non reached
156  0x96, 0x96, 0xdd, // value below 0LU line non reached
157  0xdd, 0x33, 0x33, // value above 0LU line reached
158  0x33, 0x33, 0xdd, // value below 0LU line reached
159 };
160 
161 static const uint8_t *get_graph_color(const EBUR128Context *ebur128, int v, int y)
162 {
163  const int below0 = y > ebur128->y_zero_lu;
164  const int reached = y >= v;
165  const int line = ebur128->y_line_ref[y] || y == ebur128->y_zero_lu;
166  const int colorid = 4*line + 2*reached + below0;
167  return graph_colors + 3*colorid;
168 }
169 
170 static inline int lu_to_y(const EBUR128Context *ebur128, double v)
171 {
172  v += 2 * ebur128->meter; // make it in range [0;...]
173  v = av_clipf(v, 0, ebur128->scale_range); // make sure it's in the graph scale
174  v = ebur128->scale_range - v; // invert value (y=0 is on top)
175  return v * ebur128->graph.h / ebur128->scale_range; // rescale from scale range to px height
176 }
177 
178 #define FONT8 0
179 #define FONT16 1
180 
181 static const uint8_t font_colors[] = {
182  0xdd, 0xdd, 0x00,
183  0x00, 0x96, 0x96,
184 };
185 
186 static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt, ...)
187 {
188  int i;
189  char buf[128] = {0};
190  const uint8_t *font;
191  int font_height;
192  va_list vl;
193 
194  if (ftid == FONT16) font = avpriv_vga16_font, font_height = 16;
195  else if (ftid == FONT8) font = avpriv_cga_font, font_height = 8;
196  else return;
197 
198  va_start(vl, fmt);
199  vsnprintf(buf, sizeof(buf), fmt, vl);
200  va_end(vl);
201 
202  for (i = 0; buf[i]; i++) {
203  int char_y, mask;
204  uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8)*3;
205 
206  for (char_y = 0; char_y < font_height; char_y++) {
207  for (mask = 0x80; mask; mask >>= 1) {
208  if (font[buf[i] * font_height + char_y] & mask)
209  memcpy(p, color, 3);
210  else
211  memcpy(p, "\x00\x00\x00", 3);
212  p += 3;
213  }
214  p += pic->linesize[0] - 8*3;
215  }
216  }
217 }
218 
219 static void drawline(AVFrame *pic, int x, int y, int len, int step)
220 {
221  int i;
222  uint8_t *p = pic->data[0] + y*pic->linesize[0] + x*3;
223 
224  for (i = 0; i < len; i++) {
225  memcpy(p, "\x00\xff\x00", 3);
226  p += step;
227  }
228 }
229 
230 static int config_video_output(AVFilterLink *outlink)
231 {
232  int i, x, y;
233  uint8_t *p;
234  AVFilterContext *ctx = outlink->src;
235  EBUR128Context *ebur128 = ctx->priv;
236  AVFrame *outpicref;
237 
238  /* check if there is enough space to represent everything decently */
239  if (ebur128->w < 640 || ebur128->h < 480) {
240  av_log(ctx, AV_LOG_ERROR, "Video size %dx%d is too small, "
241  "minimum size is 640x480\n", ebur128->w, ebur128->h);
242  return AVERROR(EINVAL);
243  }
244  outlink->w = ebur128->w;
245  outlink->h = ebur128->h;
246 
247 #define PAD 8
248 
249  /* configure text area position and size */
250  ebur128->text.x = PAD;
251  ebur128->text.y = 40;
252  ebur128->text.w = 3 * 8; // 3 characters
253  ebur128->text.h = ebur128->h - PAD - ebur128->text.y;
254 
255  /* configure gauge position and size */
256  ebur128->gauge.w = 20;
257  ebur128->gauge.h = ebur128->text.h;
258  ebur128->gauge.x = ebur128->w - PAD - ebur128->gauge.w;
259  ebur128->gauge.y = ebur128->text.y;
260 
261  /* configure graph position and size */
262  ebur128->graph.x = ebur128->text.x + ebur128->text.w + PAD;
263  ebur128->graph.y = ebur128->gauge.y;
264  ebur128->graph.w = ebur128->gauge.x - ebur128->graph.x - PAD;
265  ebur128->graph.h = ebur128->gauge.h;
266 
267  /* graph and gauge share the LU-to-pixel code */
268  av_assert0(ebur128->graph.h == ebur128->gauge.h);
269 
270  /* prepare the initial picref buffer */
271  av_frame_free(&ebur128->outpicref);
272  ebur128->outpicref = outpicref =
273  ff_get_video_buffer(outlink, outlink->w, outlink->h);
274  if (!outpicref)
275  return AVERROR(ENOMEM);
276  outlink->sample_aspect_ratio = (AVRational){1,1};
277 
278  /* init y references values (to draw LU lines) */
279  ebur128->y_line_ref = av_calloc(ebur128->graph.h + 1, sizeof(*ebur128->y_line_ref));
280  if (!ebur128->y_line_ref)
281  return AVERROR(ENOMEM);
282 
283  /* black background */
284  memset(outpicref->data[0], 0, ebur128->h * outpicref->linesize[0]);
285 
286  /* draw LU legends */
287  drawtext(outpicref, PAD, PAD+16, FONT8, font_colors+3, " LU");
288  for (i = ebur128->meter; i >= -ebur128->meter * 2; i--) {
289  y = lu_to_y(ebur128, i);
290  x = PAD + (i < 10 && i > -10) * 8;
291  ebur128->y_line_ref[y] = i;
292  y -= 4; // -4 to center vertically
293  drawtext(outpicref, x, y + ebur128->graph.y, FONT8, font_colors+3,
294  "%c%d", i < 0 ? '-' : i > 0 ? '+' : ' ', FFABS(i));
295  }
296 
297  /* draw graph */
298  ebur128->y_zero_lu = lu_to_y(ebur128, 0);
299  p = outpicref->data[0] + ebur128->graph.y * outpicref->linesize[0]
300  + ebur128->graph.x * 3;
301  for (y = 0; y < ebur128->graph.h; y++) {
302  const uint8_t *c = get_graph_color(ebur128, INT_MAX, y);
303 
304  for (x = 0; x < ebur128->graph.w; x++)
305  memcpy(p + x*3, c, 3);
306  p += outpicref->linesize[0];
307  }
308 
309  /* draw fancy rectangles around the graph and the gauge */
310 #define DRAW_RECT(r) do { \
311  drawline(outpicref, r.x, r.y - 1, r.w, 3); \
312  drawline(outpicref, r.x, r.y + r.h, r.w, 3); \
313  drawline(outpicref, r.x - 1, r.y, r.h, outpicref->linesize[0]); \
314  drawline(outpicref, r.x + r.w, r.y, r.h, outpicref->linesize[0]); \
315 } while (0)
316  DRAW_RECT(ebur128->graph);
317  DRAW_RECT(ebur128->gauge);
318 
319  outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
320 
321  return 0;
322 }
323 
324 static int config_audio_input(AVFilterLink *inlink)
325 {
326  AVFilterContext *ctx = inlink->dst;
327  EBUR128Context *ebur128 = ctx->priv;
328 
329  /* force 100ms framing in case of metadata injection: the frames must have
330  * a granularity of the window overlap to be accurately exploited */
331  if (ebur128->metadata)
332  inlink->min_samples =
333  inlink->max_samples =
334  inlink->partial_buf_size = inlink->sample_rate / 10;
335  return 0;
336 }
337 
338 static int config_audio_output(AVFilterLink *outlink)
339 {
340  int i;
341  int idx_bitposn = 0;
342  AVFilterContext *ctx = outlink->src;
343  EBUR128Context *ebur128 = ctx->priv;
345 
346 #define BACK_MASK (AV_CH_BACK_LEFT |AV_CH_BACK_CENTER |AV_CH_BACK_RIGHT| \
347  AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_BACK_RIGHT| \
348  AV_CH_SIDE_LEFT |AV_CH_SIDE_RIGHT| \
349  AV_CH_SURROUND_DIRECT_LEFT |AV_CH_SURROUND_DIRECT_RIGHT)
350 
351  ebur128->nb_channels = nb_channels;
352  ebur128->ch_weighting = av_calloc(nb_channels, sizeof(*ebur128->ch_weighting));
353  if (!ebur128->ch_weighting)
354  return AVERROR(ENOMEM);
355 
356  for (i = 0; i < nb_channels; i++) {
357 
358  /* find the next bit that is set starting from the right */
359  while ((outlink->channel_layout & 1ULL<<idx_bitposn) == 0 && idx_bitposn < 63)
360  idx_bitposn++;
361 
362  /* channel weighting */
363  if ((1ULL<<idx_bitposn & AV_CH_LOW_FREQUENCY) ||
364  (1ULL<<idx_bitposn & AV_CH_LOW_FREQUENCY_2)) {
365  ebur128->ch_weighting[i] = 0;
366  } else if (1ULL<<idx_bitposn & BACK_MASK) {
367  ebur128->ch_weighting[i] = 1.41;
368  } else {
369  ebur128->ch_weighting[i] = 1.0;
370  }
371 
372  idx_bitposn++;
373 
374  if (!ebur128->ch_weighting[i])
375  continue;
376 
377  /* bins buffer for the two integration window (400ms and 3s) */
378  ebur128->i400.cache[i] = av_calloc(I400_BINS, sizeof(*ebur128->i400.cache[0]));
379  ebur128->i3000.cache[i] = av_calloc(I3000_BINS, sizeof(*ebur128->i3000.cache[0]));
380  if (!ebur128->i400.cache[i] || !ebur128->i3000.cache[i])
381  return AVERROR(ENOMEM);
382  }
383 
384  outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
385 
386  return 0;
387 }
388 
389 #define ENERGY(loudness) (pow(10, ((loudness) + 0.691) / 10.))
390 #define LOUDNESS(energy) (-0.691 + 10 * log10(energy))
391 
392 static struct hist_entry *get_histogram(void)
393 {
394  int i;
395  struct hist_entry *h = av_calloc(HIST_SIZE, sizeof(*h));
396 
397  if (!h)
398  return NULL;
399  for (i = 0; i < HIST_SIZE; i++) {
400  h[i].loudness = i / (double)HIST_GRAIN + ABS_THRES;
401  h[i].energy = ENERGY(h[i].loudness);
402  }
403  return h;
404 }
405 
406 static av_cold int init(AVFilterContext *ctx)
407 {
408  EBUR128Context *ebur128 = ctx->priv;
409  AVFilterPad pad;
410 
411  if (ebur128->loglevel != AV_LOG_INFO &&
412  ebur128->loglevel != AV_LOG_VERBOSE) {
413  if (ebur128->do_video || ebur128->metadata)
414  ebur128->loglevel = AV_LOG_VERBOSE;
415  else
416  ebur128->loglevel = AV_LOG_INFO;
417  }
418 
419  // if meter is +9 scale, scale range is from -18 LU to +9 LU (or 3*9)
420  // if meter is +18 scale, scale range is from -36 LU to +18 LU (or 3*18)
421  ebur128->scale_range = 3 * ebur128->meter;
422 
423  ebur128->i400.histogram = get_histogram();
424  ebur128->i3000.histogram = get_histogram();
425  if (!ebur128->i400.histogram || !ebur128->i3000.histogram)
426  return AVERROR(ENOMEM);
427 
428  ebur128->integrated_loudness = ABS_THRES;
429  ebur128->loudness_range = 0;
430 
431  /* insert output pads */
432  if (ebur128->do_video) {
433  pad = (AVFilterPad){
434  .name = av_strdup("out0"),
435  .type = AVMEDIA_TYPE_VIDEO,
436  .config_props = config_video_output,
437  };
438  if (!pad.name)
439  return AVERROR(ENOMEM);
440  ff_insert_outpad(ctx, 0, &pad);
441  }
442  pad = (AVFilterPad){
443  .name = av_asprintf("out%d", ebur128->do_video),
444  .type = AVMEDIA_TYPE_AUDIO,
445  .config_props = config_audio_output,
446  };
447  if (!pad.name)
448  return AVERROR(ENOMEM);
449  ff_insert_outpad(ctx, ebur128->do_video, &pad);
450 
451  /* summary */
452  av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter);
453 
454  return 0;
455 }
456 
457 #define HIST_POS(power) (int)(((power) - ABS_THRES) * HIST_GRAIN)
458 
459 /* loudness and power should be set such as loudness = -0.691 +
460  * 10*log10(power), we just avoid doing that calculus two times */
461 static int gate_update(struct integrator *integ, double power,
462  double loudness, int gate_thres)
463 {
464  int ipower;
465  double relative_threshold;
466  int gate_hist_pos;
467 
468  /* update powers histograms by incrementing current power count */
469  ipower = av_clip(HIST_POS(loudness), 0, HIST_SIZE - 1);
470  integ->histogram[ipower].count++;
471 
472  /* compute relative threshold and get its position in the histogram */
473  integ->sum_kept_powers += power;
474  integ->nb_kept_powers++;
475  relative_threshold = integ->sum_kept_powers / integ->nb_kept_powers;
476  if (!relative_threshold)
477  relative_threshold = 1e-12;
478  integ->rel_threshold = LOUDNESS(relative_threshold) + gate_thres;
479  gate_hist_pos = av_clip(HIST_POS(integ->rel_threshold), 0, HIST_SIZE - 1);
480 
481  return gate_hist_pos;
482 }
483 
484 static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
485 {
486  int i, ch, idx_insample;
487  AVFilterContext *ctx = inlink->dst;
488  EBUR128Context *ebur128 = ctx->priv;
489  const int nb_channels = ebur128->nb_channels;
490  const int nb_samples = insamples->nb_samples;
491  const double *samples = (double *)insamples->data[0];
492  AVFrame *pic = ebur128->outpicref;
493 
494  for (idx_insample = 0; idx_insample < nb_samples; idx_insample++) {
495  const int bin_id_400 = ebur128->i400.cache_pos;
496  const int bin_id_3000 = ebur128->i3000.cache_pos;
497 
498 #define MOVE_TO_NEXT_CACHED_ENTRY(time) do { \
499  ebur128->i##time.cache_pos++; \
500  if (ebur128->i##time.cache_pos == I##time##_BINS) { \
501  ebur128->i##time.filled = 1; \
502  ebur128->i##time.cache_pos = 0; \
503  } \
504 } while (0)
505 
508 
509  for (ch = 0; ch < nb_channels; ch++) {
510  double bin;
511 
512  ebur128->x[ch * 3] = *samples++; // set X[i]
513 
514  if (!ebur128->ch_weighting[ch])
515  continue;
516 
517  /* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */
518 #define FILTER(Y, X, name) do { \
519  double *dst = ebur128->Y + ch*3; \
520  double *src = ebur128->X + ch*3; \
521  dst[2] = dst[1]; \
522  dst[1] = dst[0]; \
523  dst[0] = src[0]*name##_B0 + src[1]*name##_B1 + src[2]*name##_B2 \
524  - dst[1]*name##_A1 - dst[2]*name##_A2; \
525 } while (0)
526 
527  // TODO: merge both filters in one?
528  FILTER(y, x, PRE); // apply pre-filter
529  ebur128->x[ch * 3 + 2] = ebur128->x[ch * 3 + 1];
530  ebur128->x[ch * 3 + 1] = ebur128->x[ch * 3 ];
531  FILTER(z, y, RLB); // apply RLB-filter
532 
533  bin = ebur128->z[ch * 3] * ebur128->z[ch * 3];
534 
535  /* add the new value, and limit the sum to the cache size (400ms or 3s)
536  * by removing the oldest one */
537  ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400];
538  ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000];
539 
540  /* override old cache entry with the new value */
541  ebur128->i400.cache [ch][bin_id_400 ] = bin;
542  ebur128->i3000.cache[ch][bin_id_3000] = bin;
543  }
544 
545  /* For integrated loudness, gating blocks are 400ms long with 75%
546  * overlap (see BS.1770-2 p5), so a re-computation is needed each 100ms
547  * (4800 samples at 48kHz). */
548  if (++ebur128->sample_count == 4800) {
549  double loudness_400, loudness_3000;
550  double power_400 = 1e-12, power_3000 = 1e-12;
551  AVFilterLink *outlink = ctx->outputs[0];
552  const int64_t pts = insamples->pts +
553  av_rescale_q(idx_insample, (AVRational){ 1, inlink->sample_rate },
554  outlink->time_base);
555 
556  ebur128->sample_count = 0;
557 
558 #define COMPUTE_LOUDNESS(m, time) do { \
559  if (ebur128->i##time.filled) { \
560  /* weighting sum of the last <time> ms */ \
561  for (ch = 0; ch < nb_channels; ch++) \
562  power_##time += ebur128->ch_weighting[ch] * ebur128->i##time.sum[ch]; \
563  power_##time /= I##time##_BINS; \
564  } \
565  loudness_##time = LOUDNESS(power_##time); \
566 } while (0)
567 
568  COMPUTE_LOUDNESS(M, 400);
569  COMPUTE_LOUDNESS(S, 3000);
570 
571  /* Integrated loudness */
572 #define I_GATE_THRES -10 // initially defined to -8 LU in the first EBU standard
573 
574  if (loudness_400 >= ABS_THRES) {
575  double integrated_sum = 0;
576  int nb_integrated = 0;
577  int gate_hist_pos = gate_update(&ebur128->i400, power_400,
578  loudness_400, I_GATE_THRES);
579 
580  /* compute integrated loudness by summing the histogram values
581  * above the relative threshold */
582  for (i = gate_hist_pos; i < HIST_SIZE; i++) {
583  const int nb_v = ebur128->i400.histogram[i].count;
584  nb_integrated += nb_v;
585  integrated_sum += nb_v * ebur128->i400.histogram[i].energy;
586  }
587  if (nb_integrated)
588  ebur128->integrated_loudness = LOUDNESS(integrated_sum / nb_integrated);
589  }
590 
591  /* LRA */
592 #define LRA_GATE_THRES -20
593 #define LRA_LOWER_PRC 10
594 #define LRA_HIGHER_PRC 95
595 
596  /* XXX: example code in EBU 3342 is ">=" but formula in BS.1770
597  * specs is ">" */
598  if (loudness_3000 >= ABS_THRES) {
599  int nb_powers = 0;
600  int gate_hist_pos = gate_update(&ebur128->i3000, power_3000,
601  loudness_3000, LRA_GATE_THRES);
602 
603  for (i = gate_hist_pos; i < HIST_SIZE; i++)
604  nb_powers += ebur128->i3000.histogram[i].count;
605  if (nb_powers) {
606  int n, nb_pow;
607 
608  /* get lower loudness to consider */
609  n = 0;
610  nb_pow = LRA_LOWER_PRC * nb_powers / 100. + 0.5;
611  for (i = gate_hist_pos; i < HIST_SIZE; i++) {
612  n += ebur128->i3000.histogram[i].count;
613  if (n >= nb_pow) {
614  ebur128->lra_low = ebur128->i3000.histogram[i].loudness;
615  break;
616  }
617  }
618 
619  /* get higher loudness to consider */
620  n = nb_powers;
621  nb_pow = LRA_HIGHER_PRC * nb_powers / 100. + 0.5;
622  for (i = HIST_SIZE - 1; i >= 0; i--) {
623  n -= ebur128->i3000.histogram[i].count;
624  if (n < nb_pow) {
625  ebur128->lra_high = ebur128->i3000.histogram[i].loudness;
626  break;
627  }
628  }
629 
630  // XXX: show low & high on the graph?
631  ebur128->loudness_range = ebur128->lra_high - ebur128->lra_low;
632  }
633  }
634 
635 #define LOG_FMT "M:%6.1f S:%6.1f I:%6.1f LUFS LRA:%6.1f LU"
636 
637  /* push one video frame */
638  if (ebur128->do_video) {
639  int x, y, ret;
640  uint8_t *p;
641 
642  const int y_loudness_lu_graph = lu_to_y(ebur128, loudness_3000 + 23);
643  const int y_loudness_lu_gauge = lu_to_y(ebur128, loudness_400 + 23);
644 
645  /* draw the graph using the short-term loudness */
646  p = pic->data[0] + ebur128->graph.y*pic->linesize[0] + ebur128->graph.x*3;
647  for (y = 0; y < ebur128->graph.h; y++) {
648  const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_graph, y);
649 
650  memmove(p, p + 3, (ebur128->graph.w - 1) * 3);
651  memcpy(p + (ebur128->graph.w - 1) * 3, c, 3);
652  p += pic->linesize[0];
653  }
654 
655  /* draw the gauge using the momentary loudness */
656  p = pic->data[0] + ebur128->gauge.y*pic->linesize[0] + ebur128->gauge.x*3;
657  for (y = 0; y < ebur128->gauge.h; y++) {
658  const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_gauge, y);
659 
660  for (x = 0; x < ebur128->gauge.w; x++)
661  memcpy(p + x*3, c, 3);
662  p += pic->linesize[0];
663  }
664 
665  /* draw textual info */
666  drawtext(pic, PAD, PAD - PAD/2, FONT16, font_colors,
667  LOG_FMT " ", // padding to erase trailing characters
668  loudness_400, loudness_3000,
669  ebur128->integrated_loudness, ebur128->loudness_range);
670 
671  /* set pts and push frame */
672  pic->pts = pts;
673  ret = ff_filter_frame(outlink, av_frame_clone(pic));
674  if (ret < 0)
675  return ret;
676  }
677 
678  if (ebur128->metadata) { /* happens only once per filter_frame call */
679  char metabuf[128];
680 #define SET_META(name, var) do { \
681  snprintf(metabuf, sizeof(metabuf), "%.3f", var); \
682  av_dict_set(&insamples->metadata, "lavfi.r128." name, metabuf, 0); \
683 } while (0)
684  SET_META("M", loudness_400);
685  SET_META("S", loudness_3000);
686  SET_META("I", ebur128->integrated_loudness);
687  SET_META("LRA", ebur128->loudness_range);
688  SET_META("LRA.low", ebur128->lra_low);
689  SET_META("LRA.high", ebur128->lra_high);
690  }
691 
692  av_log(ctx, ebur128->loglevel, "t: %-10s " LOG_FMT "\n",
693  av_ts2timestr(pts, &outlink->time_base),
694  loudness_400, loudness_3000,
695  ebur128->integrated_loudness, ebur128->loudness_range);
696  }
697  }
698 
699  return ff_filter_frame(ctx->outputs[ebur128->do_video], insamples);
700 }
701 
703 {
704  EBUR128Context *ebur128 = ctx->priv;
707  AVFilterLink *inlink = ctx->inputs[0];
708  AVFilterLink *outlink = ctx->outputs[0];
709 
711  static const int input_srate[] = {48000, -1}; // ITU-R BS.1770 provides coeff only for 48kHz
712  static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
713 
714  /* set optional output video format */
715  if (ebur128->do_video) {
716  formats = ff_make_format_list(pix_fmts);
717  if (!formats)
718  return AVERROR(ENOMEM);
719  ff_formats_ref(formats, &outlink->in_formats);
720  outlink = ctx->outputs[1];
721  }
722 
723  /* set input and output audio formats
724  * Note: ff_set_common_* functions are not used because they affect all the
725  * links, and thus break the video format negociation */
726  formats = ff_make_format_list(sample_fmts);
727  if (!formats)
728  return AVERROR(ENOMEM);
729  ff_formats_ref(formats, &inlink->out_formats);
730  ff_formats_ref(formats, &outlink->in_formats);
731 
732  layouts = ff_all_channel_layouts();
733  if (!layouts)
734  return AVERROR(ENOMEM);
735  ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
736  ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
737 
738  formats = ff_make_format_list(input_srate);
739  if (!formats)
740  return AVERROR(ENOMEM);
741  ff_formats_ref(formats, &inlink->out_samplerates);
742  ff_formats_ref(formats, &outlink->in_samplerates);
743 
744  return 0;
745 }
746 
747 static av_cold void uninit(AVFilterContext *ctx)
748 {
749  int i;
750  EBUR128Context *ebur128 = ctx->priv;
751 
752  av_log(ctx, AV_LOG_INFO, "Summary:\n\n"
753  " Integrated loudness:\n"
754  " I: %5.1f LUFS\n"
755  " Threshold: %5.1f LUFS\n\n"
756  " Loudness range:\n"
757  " LRA: %5.1f LU\n"
758  " Threshold: %5.1f LUFS\n"
759  " LRA low: %5.1f LUFS\n"
760  " LRA high: %5.1f LUFS\n",
761  ebur128->integrated_loudness, ebur128->i400.rel_threshold,
762  ebur128->loudness_range, ebur128->i3000.rel_threshold,
763  ebur128->lra_low, ebur128->lra_high);
764 
765  av_freep(&ebur128->y_line_ref);
766  av_freep(&ebur128->ch_weighting);
767  av_freep(&ebur128->i400.histogram);
768  av_freep(&ebur128->i3000.histogram);
769  for (i = 0; i < ebur128->nb_channels; i++) {
770  av_freep(&ebur128->i400.cache[i]);
771  av_freep(&ebur128->i3000.cache[i]);
772  }
773  for (i = 0; i < ctx->nb_outputs; i++)
774  av_freep(&ctx->output_pads[i].name);
775  av_frame_free(&ebur128->outpicref);
776 }
777 
778 static const AVFilterPad ebur128_inputs[] = {
779  {
780  .name = "default",
781  .type = AVMEDIA_TYPE_AUDIO,
782  .get_audio_buffer = ff_null_get_audio_buffer,
783  .filter_frame = filter_frame,
784  .config_props = config_audio_input,
785  },
786  { NULL }
787 };
788 
790  .name = "ebur128",
791  .description = NULL_IF_CONFIG_SMALL("EBU R128 scanner."),
792  .priv_size = sizeof(EBUR128Context),
793  .init = init,
794  .uninit = uninit,
796  .inputs = ebur128_inputs,
797  .outputs = NULL,
798  .priv_class = &ebur128_class,
800 };
static struct hist_entry * get_histogram(void)
Definition: f_ebur128.c:392
float v
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
int scale_range
the range of LU values according to the meter
Definition: f_ebur128.c:103
static int query_formats(AVFilterContext *ctx)
Definition: f_ebur128.c:702
double lra_low
Definition: f_ebur128.c:126
AVOption.
Definition: opt.h:251
const char * fmt
Definition: avisynth_c.h:669
#define LRA_HIGHER_PRC
struct hist_entry * histogram
histogram of the powers, used to compute LRA and I
Definition: f_ebur128.c:87
static int config_video_output(AVFilterLink *outlink)
Definition: f_ebur128.c:230
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
int sample_count
sample count used for refresh frequency, reset at refresh
Definition: f_ebur128.c:110
#define I_GATE_THRES
external API header
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:70
int y_zero_lu
the y value (pixel position) for 0 LU
Definition: f_ebur128.c:104
static int config_audio_output(AVFilterLink *outlink)
Definition: f_ebur128.c:338
static int lu_to_y(const EBUR128Context *ebur128, double v)
Definition: f_ebur128.c:170
#define COMPUTE_LOUDNESS(m, time)
static av_cold int init(AVFilterContext *ctx)
Definition: f_ebur128.c:406
int cache_pos
focus on the last added bin in the cache array
Definition: f_ebur128.c:81
#define vsnprintf
Definition: snprintf.h:36
#define AV_CH_LOW_FREQUENCY_2
const uint8_t avpriv_vga16_font[4096]
int do_video
1 if video output enabled, 0 otherwise
Definition: f_ebur128.c:96
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:143
static const AVOption ebur128_options[]
Definition: f_ebur128.c:137
#define HIST_SIZE
Definition: f_ebur128.c:64
text(-8, 1,'a)')
int nb_channels
number of channels in the input
Definition: f_ebur128.c:108
output residual component w
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:308
#define F
Definition: f_ebur128.c:136
#define FONT16
Definition: f_ebur128.c:179
initialize output if(nPeaks >3)%at least 3 peaks in spectrum for trying to find f0 nf0peaks
AVFILTER_DEFINE_CLASS(ebur128)
int metadata
whether or not to inject loudness results in frames
Definition: f_ebur128.c:130
const char * name
Pad name.
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:532
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
#define HIST_GRAIN
defines histogram precision
Definition: f_ebur128.c:63
Public dictionary API.
AVFilterPad * output_pads
array of output pads
Definition: avfilter.h:538
#define M(a, b)
Definition: vp3dsp.c:43
uint8_t
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
#define av_cold
Definition: attributes.h:78
static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt,...)
Definition: f_ebur128.c:186
static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
Definition: f_ebur128.c:484
AVOptions.
double sum_kept_powers
sum of the powers (weighted sums) above absolute threshold
Definition: f_ebur128.c:85
timestamp utils, mostly useful for debugging/logging purposes
static void drawline(AVFrame *pic, int x, int y, int len, int step)
Definition: f_ebur128.c:219
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:77
double * cache[MAX_CHANNELS]
window of filtered samples (N ms)
Definition: f_ebur128.c:80
struct integrator i3000
3s integrator, used for Short term loudness (S), and Loudness Range (LRA)
Definition: f_ebur128.c:121
int y
Definition: f_ebur128.c:90
double integrated_loudness
integrated loudness in LUFS (I)
Definition: f_ebur128.c:124
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:159
static const uint8_t font_colors[]
Definition: f_ebur128.c:181
#define AV_CH_LOW_FREQUENCY
void ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:427
int meter
select a EBU mode between +9 and +18
Definition: f_ebur128.c:102
#define AVFILTER_FLAG_DYNAMIC_OUTPUTS
The number of the filter outputs is not determined just by AVFilter.outputs.
Definition: avfilter.h:430
An histogram is an array of HIST_SIZE hist_entry storing all the energies recorded (with an accuracy ...
Definition: f_ebur128.c:73
AVFrame * outpicref
output picture reference, updated regularly
Definition: f_ebur128.c:101
#define MAX_CHANNELS
Definition: f_ebur128.c:45
A filter pad used for either input or output.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:130
Discrete Time axis x
const uint8_t avpriv_cga_font[2048]
Definition: xga_font_data.c:29
int count
how many times the corresponding value occurred
Definition: f_ebur128.c:74
static const uint16_t mask[17]
Definition: lzw.c:37
#define S(s, c, i)
#define av_ts2timestr(ts, tb)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:72
unsigned nb_outputs
number of output pads
Definition: avfilter.h:543
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void * priv
private data for use by the filter
Definition: avfilter.h:545
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
Return the number of channels in the channel layout.
Definition: graph2dot.c:48
simple assert() macros that are a bit more flexible than ISO C assert().
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
#define MOVE_TO_NEXT_CACHED_ENTRY(time)
struct integrator i400
400ms integrator, used for Momentary loudness (M), and Integrated loudness (I)
Definition: f_ebur128.c:120
static av_cold void uninit(AVFilterContext *ctx)
Definition: f_ebur128.c:747
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:112
#define I3000_BINS
Definition: f_ebur128.c:119
#define AV_LOG_VERBOSE
Definition: log.h:157
struct AVRational AVRational
rational number numerator/denominator
int * y_line_ref
y reference values for drawing the LU lines in the graph and the gauge
Definition: f_ebur128.c:105
struct rect graph
rectangle for the main graph in the center
Definition: f_ebur128.c:99
audio channel layout utility functions
AVFilter avfilter_af_ebur128
Definition: f_ebur128.c:789
ret
Definition: avfilter.c:821
static void ff_insert_outpad(AVFilterContext *f, unsigned index, AVFilterPad *p)
Insert a new output pad for the filter.
double loudness
L = -0.691 + 10 * log10(E)
Definition: f_ebur128.c:76
#define LOG_FMT
double rel_threshold
relative threshold
Definition: f_ebur128.c:84
#define FFABS(a)
Definition: common.h:53
#define LRA_LOWER_PRC
double loudness_range
loudness range in LU (LRA)
Definition: f_ebur128.c:125
#define ENERGY(loudness)
Definition: f_ebur128.c:389
#define HIST_POS(power)
Definition: f_ebur128.c:457
#define OFFSET(x)
Definition: f_ebur128.c:133
AVFrame * ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples)
get_audio_buffer() handler for filters which simply pass audio along
Definition: audio.c:36
AVFilterChannelLayouts * ff_all_channel_layouts(void)
Construct an empty AVFilterChannelLayouts/AVFilterFormats struct – representing any channel layout (...
Definition: formats.c:402
A list of supported channel layouts.
Definition: formats.h:85
AVFrame * av_frame_clone(AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:317
NULL
Definition: eval.c:55
void ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:432
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:220
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
#define ABS_THRES
silence gate: we discard anything below this absolute (LUFS) threshold
Definition: f_ebur128.c:61
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
int x
Definition: f_ebur128.c:90
void * buf
Definition: avisynth_c.h:594
int nb_kept_powers
number of sum above absolute threshold
Definition: f_ebur128.c:86
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
Definition: f_ebur128.c:90
synthesis window for stochastic i
rational number numerator/denominator
Definition: rational.h:43
const char * name
filter name
Definition: avfilter.h:437
int h
Definition: f_ebur128.c:90
offset must point to two consecutive integers
Definition: opt.h:230
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
#define LOUDNESS(energy)
Definition: f_ebur128.c:390
void * av_calloc(size_t nmemb, size_t size)
Allocate a block of nmemb * size bytes with alignment suitable for all memory accesses (including vec...
Definition: mem.c:213
static int flags
Definition: cpu.c:23
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
struct rect text
rectangle for the LU legend on the left
Definition: f_ebur128.c:98
static const AVFilterPad ebur128_inputs[]
Definition: f_ebur128.c:778
int h
size of the video output
Definition: f_ebur128.c:97
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common formats
Definition: swscale.txt:33
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
static double c[64]
struct rect gauge
rectangle for the gauge on the right
Definition: f_ebur128.c:100
AVSampleFormat
Audio Sample Formats.
Definition: samplefmt.h:49
int w
Definition: f_ebur128.c:90
#define DRAW_RECT(r)
#define I400_BINS
Definition: f_ebur128.c:118
static int config_audio_input(AVFilterLink *inlink)
Definition: f_ebur128.c:324
#define A
Definition: f_ebur128.c:134
function y
Definition: D.m:1
struct AVFilterPad AVFilterPad
Definition: avfilter.h:65
#define FONT8
Definition: f_ebur128.c:178
static int gate_update(struct integrator *integ, double power, double loudness, int gate_thres)
Definition: f_ebur128.c:461
int loglevel
log level for frame logging
Definition: f_ebur128.c:129
double x[MAX_CHANNELS *3]
3 input samples cache for each channel
Definition: f_ebur128.c:114
#define V
Definition: f_ebur128.c:135
int len
#define FILTER(Y, X, name)
double lra_high
low and high LRA values
Definition: f_ebur128.c:126
A list of supported formats for one end of a filter link.
Definition: formats.h:64
#define PAD
An instance of a filter.
Definition: avfilter.h:524
#define LRA_GATE_THRES
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:700
#define AV_LOG_INFO
Definition: log.h:156
double sum[MAX_CHANNELS]
sum of the last N ms filtered samples (cache content)
Definition: f_ebur128.c:82
Filter the word “frame” indicates either a video frame or a group of audio samples
double z[MAX_CHANNELS *3]
3 RLB-filter samples cache for each channel
Definition: f_ebur128.c:116
#define SET_META(name, var)
double * ch_weighting
channel weighting mapping
Definition: f_ebur128.c:109
int nb_channels
internal API functions
AVPixelFormat
Pixel format.
Definition: pixfmt.h:66
Frame requests may need to loop in order to be fulfilled.
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:127
static const uint8_t graph_colors[]
Definition: f_ebur128.c:150
for(j=16;j >0;--j)
CGA/EGA/VGA ROM font data.
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about which is also called distortion Distortion can be quantified by almost any quality measurement one chooses the sum of squared differences is used but more complex methods that consider psychovisual effects can be used as well It makes no difference in this discussion First step
double energy
E = 10^((L + 0.691) / 10)
Definition: f_ebur128.c:75
#define BACK_MASK
int filled
1 if the cache is completely filled, 0 otherwise
Definition: f_ebur128.c:83
static const uint8_t * get_graph_color(const EBUR128Context *ebur128, int v, int y)
Definition: f_ebur128.c:161