00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00031 #include <math.h>
00032
00033 #include "libavutil/avassert.h"
00034 #include "libavutil/avstring.h"
00035 #include "libavutil/channel_layout.h"
00036 #include "libavutil/xga_font_data.h"
00037 #include "libavutil/opt.h"
00038 #include "libavutil/timestamp.h"
00039 #include "audio.h"
00040 #include "avfilter.h"
00041 #include "formats.h"
00042 #include "internal.h"
00043
00044 #define MAX_CHANNELS 63
00045
00046
00047 #define PRE_B0 1.53512485958697
00048 #define PRE_B1 -2.69169618940638
00049 #define PRE_B2 1.19839281085285
00050 #define PRE_A1 -1.69065929318241
00051 #define PRE_A2 0.73248077421585
00052
00053
00054 #define RLB_B0 1.0
00055 #define RLB_B1 -2.0
00056 #define RLB_B2 1.0
00057 #define RLB_A1 -1.99004745483398
00058 #define RLB_A2 0.99007225036621
00059
00060 #define ABS_THRES -70
00061 #define ABS_UP_THRES 10
00062 #define HIST_GRAIN 100
00063 #define HIST_SIZE ((ABS_UP_THRES - ABS_THRES) * HIST_GRAIN + 1)
00064
00072 struct hist_entry {
00073 int count;
00074 double energy;
00075 double loudness;
00076 };
00077
00078 struct integrator {
00079 double *cache[MAX_CHANNELS];
00080 int cache_pos;
00081 double sum[MAX_CHANNELS];
00082 int filled;
00083 double rel_threshold;
00084 double sum_kept_powers;
00085 int nb_kept_powers;
00086 struct hist_entry *histogram;
00087 };
00088
00089 struct rect { int x, y, w, h; };
00090
00091 typedef struct {
00092 const AVClass *class;
00093
00094
00095 int do_video;
00096 int w, h;
00097 struct rect text;
00098 struct rect graph;
00099 struct rect gauge;
00100 AVFilterBufferRef *outpicref;
00101 int meter;
00102 int scale_range;
00103 int y_zero_lu;
00104 int *y_line_ref;
00105
00106
00107 int nb_channels;
00108 double *ch_weighting;
00109 int sample_count;
00110
00111
00112
00113 double x[MAX_CHANNELS * 3];
00114 double y[MAX_CHANNELS * 3];
00115 double z[MAX_CHANNELS * 3];
00116
00117 #define I400_BINS (48000 * 4 / 10)
00118 #define I3000_BINS (48000 * 3)
00119 struct integrator i400;
00120 struct integrator i3000;
00121
00122
00123 double integrated_loudness;
00124 double loudness_range;
00125 double lra_low, lra_high;
00126 } EBUR128Context;
00127
00128 #define OFFSET(x) offsetof(EBUR128Context, x)
00129 #define A AV_OPT_FLAG_AUDIO_PARAM
00130 #define V AV_OPT_FLAG_VIDEO_PARAM
00131 #define F AV_OPT_FLAG_FILTERING_PARAM
00132 static const AVOption ebur128_options[] = {
00133 { "video", "set video output", OFFSET(do_video), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, V|F },
00134 { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, V|F },
00135 { "meter", "set scale meter (+9 to +18)", OFFSET(meter), AV_OPT_TYPE_INT, {.i64 = 9}, 9, 18, V|F },
00136 { NULL },
00137 };
00138
00139 AVFILTER_DEFINE_CLASS(ebur128);
00140
00141 static const uint8_t graph_colors[] = {
00142 0xdd, 0x66, 0x66,
00143 0x66, 0x66, 0xdd,
00144 0x96, 0x33, 0x33,
00145 0x33, 0x33, 0x96,
00146 0xdd, 0x96, 0x96,
00147 0x96, 0x96, 0xdd,
00148 0xdd, 0x33, 0x33,
00149 0x33, 0x33, 0xdd,
00150 };
00151
00152 static const uint8_t *get_graph_color(const EBUR128Context *ebur128, int v, int y)
00153 {
00154 const int below0 = y > ebur128->y_zero_lu;
00155 const int reached = y >= v;
00156 const int line = ebur128->y_line_ref[y] || y == ebur128->y_zero_lu;
00157 const int colorid = 4*line + 2*reached + below0;
00158 return graph_colors + 3*colorid;
00159 }
00160
00161 static inline int lu_to_y(const EBUR128Context *ebur128, double v)
00162 {
00163 v += 2 * ebur128->meter;
00164 v = av_clipf(v, 0, ebur128->scale_range);
00165 v = ebur128->scale_range - v;
00166 return v * ebur128->graph.h / ebur128->scale_range;
00167 }
00168
00169 #define FONT8 0
00170 #define FONT16 1
00171
00172 static const uint8_t font_colors[] = {
00173 0xdd, 0xdd, 0x00,
00174 0x00, 0x96, 0x96,
00175 };
00176
00177 static void drawtext(AVFilterBufferRef *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt, ...)
00178 {
00179 int i;
00180 char buf[128] = {0};
00181 const uint8_t *font;
00182 int font_height;
00183 va_list vl;
00184
00185 if (ftid == FONT16) font = avpriv_vga16_font, font_height = 16;
00186 else if (ftid == FONT8) font = avpriv_cga_font, font_height = 8;
00187 else return;
00188
00189 va_start(vl, fmt);
00190 vsnprintf(buf, sizeof(buf), fmt, vl);
00191 va_end(vl);
00192
00193 for (i = 0; buf[i]; i++) {
00194 int char_y, mask;
00195 uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8)*3;
00196
00197 for (char_y = 0; char_y < font_height; char_y++) {
00198 for (mask = 0x80; mask; mask >>= 1) {
00199 if (font[buf[i] * font_height + char_y] & mask)
00200 memcpy(p, color, 3);
00201 else
00202 memcpy(p, "\x00\x00\x00", 3);
00203 p += 3;
00204 }
00205 p += pic->linesize[0] - 8*3;
00206 }
00207 }
00208 }
00209
00210 static void drawline(AVFilterBufferRef *pic, int x, int y, int len, int step)
00211 {
00212 int i;
00213 uint8_t *p = pic->data[0] + y*pic->linesize[0] + x*3;
00214
00215 for (i = 0; i < len; i++) {
00216 memcpy(p, "\x00\xff\x00", 3);
00217 p += step;
00218 }
00219 }
00220
00221 static int config_video_output(AVFilterLink *outlink)
00222 {
00223 int i, x, y;
00224 uint8_t *p;
00225 AVFilterContext *ctx = outlink->src;
00226 EBUR128Context *ebur128 = ctx->priv;
00227 AVFilterBufferRef *outpicref;
00228
00229
00230 if (ebur128->w < 640 || ebur128->h < 480) {
00231 av_log(ctx, AV_LOG_ERROR, "Video size %dx%d is too small, "
00232 "minimum size is 640x480\n", ebur128->w, ebur128->h);
00233 return AVERROR(EINVAL);
00234 }
00235 outlink->w = ebur128->w;
00236 outlink->h = ebur128->h;
00237
00238 #define PAD 8
00239
00240
00241 ebur128->text.x = PAD;
00242 ebur128->text.y = 40;
00243 ebur128->text.w = 3 * 8;
00244 ebur128->text.h = ebur128->h - PAD - ebur128->text.y;
00245
00246
00247 ebur128->gauge.w = 20;
00248 ebur128->gauge.h = ebur128->text.h;
00249 ebur128->gauge.x = ebur128->w - PAD - ebur128->gauge.w;
00250 ebur128->gauge.y = ebur128->text.y;
00251
00252
00253 ebur128->graph.x = ebur128->text.x + ebur128->text.w + PAD;
00254 ebur128->graph.y = ebur128->gauge.y;
00255 ebur128->graph.w = ebur128->gauge.x - ebur128->graph.x - PAD;
00256 ebur128->graph.h = ebur128->gauge.h;
00257
00258
00259 av_assert0(ebur128->graph.h == ebur128->gauge.h);
00260
00261
00262 avfilter_unref_bufferp(&ebur128->outpicref);
00263 ebur128->outpicref = outpicref =
00264 ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_PRESERVE|AV_PERM_REUSE2,
00265 outlink->w, outlink->h);
00266 if (!outpicref)
00267 return AVERROR(ENOMEM);
00268 outlink->sample_aspect_ratio = (AVRational){1,1};
00269
00270
00271 ebur128->y_line_ref = av_calloc(ebur128->graph.h + 1, sizeof(*ebur128->y_line_ref));
00272 if (!ebur128->y_line_ref)
00273 return AVERROR(ENOMEM);
00274
00275
00276 memset(outpicref->data[0], 0, ebur128->h * outpicref->linesize[0]);
00277
00278
00279 drawtext(outpicref, PAD, PAD+16, FONT8, font_colors+3, " LU");
00280 for (i = ebur128->meter; i >= -ebur128->meter * 2; i--) {
00281 y = lu_to_y(ebur128, i);
00282 x = PAD + (i < 10 && i > -10) * 8;
00283 ebur128->y_line_ref[y] = i;
00284 y -= 4;
00285 drawtext(outpicref, x, y + ebur128->graph.y, FONT8, font_colors+3,
00286 "%c%d", i < 0 ? '-' : i > 0 ? '+' : ' ', FFABS(i));
00287 }
00288
00289
00290 ebur128->y_zero_lu = lu_to_y(ebur128, 0);
00291 p = outpicref->data[0] + ebur128->graph.y * outpicref->linesize[0]
00292 + ebur128->graph.x * 3;
00293 for (y = 0; y < ebur128->graph.h; y++) {
00294 const uint8_t *c = get_graph_color(ebur128, INT_MAX, y);
00295
00296 for (x = 0; x < ebur128->graph.w; x++)
00297 memcpy(p + x*3, c, 3);
00298 p += outpicref->linesize[0];
00299 }
00300
00301
00302 #define DRAW_RECT(r) do { \
00303 drawline(outpicref, r.x, r.y - 1, r.w, 3); \
00304 drawline(outpicref, r.x, r.y + r.h, r.w, 3); \
00305 drawline(outpicref, r.x - 1, r.y, r.h, outpicref->linesize[0]); \
00306 drawline(outpicref, r.x + r.w, r.y, r.h, outpicref->linesize[0]); \
00307 } while (0)
00308 DRAW_RECT(ebur128->graph);
00309 DRAW_RECT(ebur128->gauge);
00310
00311 return 0;
00312 }
00313
00314 static int config_audio_output(AVFilterLink *outlink)
00315 {
00316 int i;
00317 AVFilterContext *ctx = outlink->src;
00318 EBUR128Context *ebur128 = ctx->priv;
00319 const int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
00320
00321 #define BACK_MASK (AV_CH_BACK_LEFT |AV_CH_BACK_CENTER |AV_CH_BACK_RIGHT| \
00322 AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_BACK_RIGHT)
00323
00324 ebur128->nb_channels = nb_channels;
00325 ebur128->ch_weighting = av_calloc(nb_channels, sizeof(*ebur128->ch_weighting));
00326 if (!ebur128->ch_weighting)
00327 return AVERROR(ENOMEM);
00328
00329 for (i = 0; i < nb_channels; i++) {
00330
00331
00332 if ((outlink->channel_layout & 1ULL<<i) == AV_CH_LOW_FREQUENCY)
00333 continue;
00334 if (outlink->channel_layout & 1ULL<<i & BACK_MASK)
00335 ebur128->ch_weighting[i] = 1.41;
00336 else
00337 ebur128->ch_weighting[i] = 1.0;
00338
00339
00340 ebur128->i400.cache[i] = av_calloc(I400_BINS, sizeof(*ebur128->i400.cache[0]));
00341 ebur128->i3000.cache[i] = av_calloc(I3000_BINS, sizeof(*ebur128->i3000.cache[0]));
00342 if (!ebur128->i400.cache[i] || !ebur128->i3000.cache[i])
00343 return AVERROR(ENOMEM);
00344 }
00345
00346 return 0;
00347 }
00348
00349 #define ENERGY(loudness) (pow(10, ((loudness) + 0.691) / 10.))
00350 #define LOUDNESS(energy) (-0.691 + 10 * log10(energy))
00351
00352 static struct hist_entry *get_histogram(void)
00353 {
00354 int i;
00355 struct hist_entry *h = av_calloc(HIST_SIZE, sizeof(*h));
00356
00357 for (i = 0; i < HIST_SIZE; i++) {
00358 h[i].loudness = i / (double)HIST_GRAIN + ABS_THRES;
00359 h[i].energy = ENERGY(h[i].loudness);
00360 }
00361 return h;
00362 }
00363
00364 static av_cold int init(AVFilterContext *ctx, const char *args)
00365 {
00366 int ret;
00367 EBUR128Context *ebur128 = ctx->priv;
00368 AVFilterPad pad;
00369
00370 ebur128->class = &ebur128_class;
00371 av_opt_set_defaults(ebur128);
00372
00373 if ((ret = av_set_options_string(ebur128, args, "=", ":")) < 0)
00374 return ret;
00375
00376
00377
00378 ebur128->scale_range = 3 * ebur128->meter;
00379
00380 ebur128->i400.histogram = get_histogram();
00381 ebur128->i3000.histogram = get_histogram();
00382
00383 ebur128->integrated_loudness = ABS_THRES;
00384 ebur128->loudness_range = 0;
00385
00386
00387 if (ebur128->do_video) {
00388 pad = (AVFilterPad){
00389 .name = av_strdup("out0"),
00390 .type = AVMEDIA_TYPE_VIDEO,
00391 .config_props = config_video_output,
00392 };
00393 if (!pad.name)
00394 return AVERROR(ENOMEM);
00395 ff_insert_outpad(ctx, 0, &pad);
00396 }
00397 pad = (AVFilterPad){
00398 .name = av_asprintf("out%d", ebur128->do_video),
00399 .type = AVMEDIA_TYPE_AUDIO,
00400 .config_props = config_audio_output,
00401 };
00402 if (!pad.name)
00403 return AVERROR(ENOMEM);
00404 ff_insert_outpad(ctx, ebur128->do_video, &pad);
00405
00406
00407 av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter);
00408
00409 return 0;
00410 }
00411
00412 #define HIST_POS(power) (int)(((power) - ABS_THRES) * HIST_GRAIN)
00413
00414
00415
00416 static int gate_update(struct integrator *integ, double power,
00417 double loudness, int gate_thres)
00418 {
00419 int ipower;
00420 double relative_threshold;
00421 int gate_hist_pos;
00422
00423
00424 ipower = av_clip(HIST_POS(loudness), 0, HIST_SIZE - 1);
00425 integ->histogram[ipower].count++;
00426
00427
00428 integ->sum_kept_powers += power;
00429 integ->nb_kept_powers++;
00430 relative_threshold = integ->sum_kept_powers / integ->nb_kept_powers;
00431 if (!relative_threshold)
00432 relative_threshold = 1e-12;
00433 integ->rel_threshold = LOUDNESS(relative_threshold) + gate_thres;
00434 gate_hist_pos = av_clip(HIST_POS(integ->rel_threshold), 0, HIST_SIZE - 1);
00435
00436 return gate_hist_pos;
00437 }
00438
00439 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00440 {
00441 int i, ch;
00442 AVFilterContext *ctx = inlink->dst;
00443 EBUR128Context *ebur128 = ctx->priv;
00444 const int nb_channels = ebur128->nb_channels;
00445 const int nb_samples = insamples->audio->nb_samples;
00446 const double *samples = (double *)insamples->data[0];
00447 AVFilterBufferRef *pic = ebur128->outpicref;
00448
00449 for (i = 0; i < nb_samples; i++) {
00450 const int bin_id_400 = ebur128->i400.cache_pos;
00451 const int bin_id_3000 = ebur128->i3000.cache_pos;
00452
00453 #define MOVE_TO_NEXT_CACHED_ENTRY(time) do { \
00454 ebur128->i##time.cache_pos++; \
00455 if (ebur128->i##time.cache_pos == I##time##_BINS) { \
00456 ebur128->i##time.filled = 1; \
00457 ebur128->i##time.cache_pos = 0; \
00458 } \
00459 } while (0)
00460
00461 MOVE_TO_NEXT_CACHED_ENTRY(400);
00462 MOVE_TO_NEXT_CACHED_ENTRY(3000);
00463
00464 for (ch = 0; ch < nb_channels; ch++) {
00465 double bin;
00466
00467 if (!ebur128->ch_weighting[ch])
00468 continue;
00469
00470
00471 #define FILTER(Y, X, name) do { \
00472 double *dst = ebur128->Y + ch*3; \
00473 double *src = ebur128->X + ch*3; \
00474 dst[2] = dst[1]; \
00475 dst[1] = dst[0]; \
00476 dst[0] = src[0]*name##_B0 + src[1]*name##_B1 + src[2]*name##_B2 \
00477 - dst[1]*name##_A1 - dst[2]*name##_A2; \
00478 } while (0)
00479
00480 ebur128->x[ch * 3] = *samples++;
00481
00482
00483 FILTER(y, x, PRE);
00484 ebur128->x[ch * 3 + 2] = ebur128->x[ch * 3 + 1];
00485 ebur128->x[ch * 3 + 1] = ebur128->x[ch * 3 ];
00486 FILTER(z, y, RLB);
00487
00488 bin = ebur128->z[ch * 3] * ebur128->z[ch * 3];
00489
00490
00491
00492 ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400];
00493 ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000];
00494
00495
00496 ebur128->i400.cache [ch][bin_id_400 ] = bin;
00497 ebur128->i3000.cache[ch][bin_id_3000] = bin;
00498 }
00499
00500
00501
00502
00503 if (++ebur128->sample_count == 4800) {
00504 double loudness_400, loudness_3000;
00505 double power_400 = 1e-12, power_3000 = 1e-12;
00506 AVFilterLink *outlink = ctx->outputs[0];
00507 const int64_t pts = insamples->pts +
00508 av_rescale_q(i, (AVRational){ 1, inlink->sample_rate },
00509 outlink->time_base);
00510
00511 ebur128->sample_count = 0;
00512
00513 #define COMPUTE_LOUDNESS(m, time) do { \
00514 if (ebur128->i##time.filled) { \
00515 \
00516 for (ch = 0; ch < nb_channels; ch++) \
00517 power_##time += ebur128->ch_weighting[ch] * ebur128->i##time.sum[ch]; \
00518 power_##time /= I##time##_BINS; \
00519 } \
00520 loudness_##time = LOUDNESS(power_##time); \
00521 } while (0)
00522
00523 COMPUTE_LOUDNESS(M, 400);
00524 COMPUTE_LOUDNESS(S, 3000);
00525
00526
00527 #define I_GATE_THRES -10 // initially defined to -8 LU in the first EBU standard
00528
00529 if (loudness_400 >= ABS_THRES) {
00530 double integrated_sum = 0;
00531 int nb_integrated = 0;
00532 int gate_hist_pos = gate_update(&ebur128->i400, power_400,
00533 loudness_400, I_GATE_THRES);
00534
00535
00536
00537 for (i = gate_hist_pos; i < HIST_SIZE; i++) {
00538 const int nb_v = ebur128->i400.histogram[i].count;
00539 nb_integrated += nb_v;
00540 integrated_sum += nb_v * ebur128->i400.histogram[i].energy;
00541 }
00542 if (nb_integrated)
00543 ebur128->integrated_loudness = LOUDNESS(integrated_sum / nb_integrated);
00544 }
00545
00546
00547 #define LRA_GATE_THRES -20
00548 #define LRA_LOWER_PRC 10
00549 #define LRA_HIGHER_PRC 95
00550
00551
00552
00553 if (loudness_3000 >= ABS_THRES) {
00554 int nb_powers = 0;
00555 int gate_hist_pos = gate_update(&ebur128->i3000, power_3000,
00556 loudness_3000, LRA_GATE_THRES);
00557
00558 for (i = gate_hist_pos; i < HIST_SIZE; i++)
00559 nb_powers += ebur128->i3000.histogram[i].count;
00560 if (nb_powers) {
00561 int n, nb_pow;
00562
00563
00564 n = 0;
00565 nb_pow = LRA_LOWER_PRC * nb_powers / 100. + 0.5;
00566 for (i = gate_hist_pos; i < HIST_SIZE; i++) {
00567 n += ebur128->i3000.histogram[i].count;
00568 if (n >= nb_pow) {
00569 ebur128->lra_low = ebur128->i3000.histogram[i].loudness;
00570 break;
00571 }
00572 }
00573
00574
00575 n = nb_powers;
00576 nb_pow = LRA_HIGHER_PRC * nb_powers / 100. + 0.5;
00577 for (i = HIST_SIZE - 1; i >= 0; i--) {
00578 n -= ebur128->i3000.histogram[i].count;
00579 if (n < nb_pow) {
00580 ebur128->lra_high = ebur128->i3000.histogram[i].loudness;
00581 break;
00582 }
00583 }
00584
00585
00586 ebur128->loudness_range = ebur128->lra_high - ebur128->lra_low;
00587 }
00588 }
00589
00590 #define LOG_FMT "M:%6.1f S:%6.1f I:%6.1f LUFS LRA:%6.1f LU"
00591
00592
00593 if (ebur128->do_video) {
00594 int x, y, ret;
00595 uint8_t *p;
00596
00597 const int y_loudness_lu_graph = lu_to_y(ebur128, loudness_3000 + 23);
00598 const int y_loudness_lu_gauge = lu_to_y(ebur128, loudness_400 + 23);
00599
00600
00601 p = pic->data[0] + ebur128->graph.y*pic->linesize[0] + ebur128->graph.x*3;
00602 for (y = 0; y < ebur128->graph.h; y++) {
00603 const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_graph, y);
00604
00605 memmove(p, p + 3, (ebur128->graph.w - 1) * 3);
00606 memcpy(p + (ebur128->graph.w - 1) * 3, c, 3);
00607 p += pic->linesize[0];
00608 }
00609
00610
00611 p = pic->data[0] + ebur128->gauge.y*pic->linesize[0] + ebur128->gauge.x*3;
00612 for (y = 0; y < ebur128->gauge.h; y++) {
00613 const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_gauge, y);
00614
00615 for (x = 0; x < ebur128->gauge.w; x++)
00616 memcpy(p + x*3, c, 3);
00617 p += pic->linesize[0];
00618 }
00619
00620
00621 drawtext(pic, PAD, PAD - PAD/2, FONT16, font_colors,
00622 LOG_FMT " ",
00623 loudness_400, loudness_3000,
00624 ebur128->integrated_loudness, ebur128->loudness_range);
00625
00626
00627 pic->pts = pts;
00628 ret = ff_filter_frame(outlink, avfilter_ref_buffer(pic, ~AV_PERM_WRITE));
00629 if (ret < 0)
00630 return ret;
00631 }
00632
00633 av_log(ctx, ebur128->do_video ? AV_LOG_VERBOSE : AV_LOG_INFO,
00634 "t: %-10s " LOG_FMT "\n", av_ts2timestr(pts, &outlink->time_base),
00635 loudness_400, loudness_3000,
00636 ebur128->integrated_loudness, ebur128->loudness_range);
00637 }
00638 }
00639
00640 return ff_filter_frame(ctx->outputs[ebur128->do_video], insamples);
00641 }
00642
00643 static int query_formats(AVFilterContext *ctx)
00644 {
00645 EBUR128Context *ebur128 = ctx->priv;
00646 AVFilterFormats *formats;
00647 AVFilterChannelLayouts *layouts;
00648 AVFilterLink *inlink = ctx->inputs[0];
00649 AVFilterLink *outlink = ctx->outputs[0];
00650
00651 static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE };
00652 static const int input_srate[] = {48000, -1};
00653 static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
00654
00655
00656 formats = ff_make_format_list(sample_fmts);
00657 if (!formats)
00658 return AVERROR(ENOMEM);
00659 ff_formats_ref(formats, &inlink->out_formats);
00660
00661 layouts = ff_all_channel_layouts();
00662 if (!layouts)
00663 return AVERROR(ENOMEM);
00664 ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
00665
00666 formats = ff_make_format_list(input_srate);
00667 if (!formats)
00668 return AVERROR(ENOMEM);
00669 ff_formats_ref(formats, &inlink->out_samplerates);
00670
00671
00672 if (ebur128->do_video) {
00673 formats = ff_make_format_list(pix_fmts);
00674 if (!formats)
00675 return AVERROR(ENOMEM);
00676 ff_formats_ref(formats, &outlink->in_formats);
00677 outlink = ctx->outputs[1];
00678 }
00679
00680
00681 formats = ff_make_format_list(sample_fmts);
00682 if (!formats)
00683 return AVERROR(ENOMEM);
00684 ff_formats_ref(formats, &outlink->in_formats);
00685
00686 layouts = ff_all_channel_layouts();
00687 if (!layouts)
00688 return AVERROR(ENOMEM);
00689 ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
00690
00691 formats = ff_make_format_list(input_srate);
00692 if (!formats)
00693 return AVERROR(ENOMEM);
00694 ff_formats_ref(formats, &outlink->in_samplerates);
00695
00696 return 0;
00697 }
00698
00699 static av_cold void uninit(AVFilterContext *ctx)
00700 {
00701 int i;
00702 EBUR128Context *ebur128 = ctx->priv;
00703
00704 av_log(ctx, AV_LOG_INFO, "Summary:\n\n"
00705 " Integrated loudness:\n"
00706 " I: %5.1f LUFS\n"
00707 " Threshold: %5.1f LUFS\n\n"
00708 " Loudness range:\n"
00709 " LRA: %5.1f LU\n"
00710 " Threshold: %5.1f LUFS\n"
00711 " LRA low: %5.1f LUFS\n"
00712 " LRA high: %5.1f LUFS\n",
00713 ebur128->integrated_loudness, ebur128->i400.rel_threshold,
00714 ebur128->loudness_range, ebur128->i3000.rel_threshold,
00715 ebur128->lra_low, ebur128->lra_high);
00716
00717 av_freep(&ebur128->y_line_ref);
00718 av_freep(&ebur128->ch_weighting);
00719 av_freep(&ebur128->i400.histogram);
00720 av_freep(&ebur128->i3000.histogram);
00721 for (i = 0; i < ebur128->nb_channels; i++) {
00722 av_freep(&ebur128->i400.cache[i]);
00723 av_freep(&ebur128->i3000.cache[i]);
00724 }
00725 for (i = 0; i < ctx->nb_outputs; i++)
00726 av_freep(&ctx->output_pads[i].name);
00727 avfilter_unref_bufferp(&ebur128->outpicref);
00728 }
00729
00730 static const AVFilterPad ebur128_inputs[] = {
00731 {
00732 .name = "default",
00733 .type = AVMEDIA_TYPE_AUDIO,
00734 .get_audio_buffer = ff_null_get_audio_buffer,
00735 .filter_frame = filter_frame,
00736 },
00737 { NULL }
00738 };
00739
00740 AVFilter avfilter_af_ebur128 = {
00741 .name = "ebur128",
00742 .description = NULL_IF_CONFIG_SMALL("EBU R128 scanner."),
00743 .priv_size = sizeof(EBUR128Context),
00744 .init = init,
00745 .uninit = uninit,
00746 .query_formats = query_formats,
00747 .inputs = ebur128_inputs,
00748 .outputs = NULL,
00749 .priv_class = &ebur128_class,
00750 };