From 0939c33b54dbb91328e73c5c0828b15398fef05e Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 20 Oct 2018 22:38:52 +0200 Subject: [PATCH] avfilter/af_afir: calculate group delay too --- doc/filters.texi | 2 +- libavfilter/af_afir.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 54b85c4bb9..a2dee4a39b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -1205,7 +1205,7 @@ Set max allowed Impulse Response filter duration in seconds. Default is 30 secon Allowed range is 0.1 to 60 seconds. @item response -Show IR frequency reponse, magnitude and phase in additional video stream. +Show IR frequency reponse, magnitude(magenta) and phase(green) and group delay(yellow) in additional video stream. By default it is disabled. @item channel diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index 244da3ab4c..346104a56e 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -211,8 +211,9 @@ static void draw_line(AVFrame *out, int x0, int y0, int x1, int y1, uint32_t col static void draw_response(AVFilterContext *ctx, AVFrame *out) { AudioFIRContext *s = ctx->priv; - float *mag, *phase, min = FLT_MAX, max = FLT_MIN; - int prev_ymag = -1, prev_yphase = -1; + float *mag, *phase, *delay, min = FLT_MAX, max = FLT_MIN; + float min_delay = FLT_MAX, max_delay = FLT_MIN; + int prev_ymag = -1, prev_yphase = -1, prev_ydelay = -1; char text[32]; int channel, i, x; @@ -220,44 +221,56 @@ static void draw_response(AVFilterContext *ctx, AVFrame *out) phase = av_malloc_array(s->w, sizeof(*phase)); mag = av_malloc_array(s->w, sizeof(*mag)); - if (!mag || !phase) + delay = av_malloc_array(s->w, sizeof(*delay)); + if (!mag || !phase || !delay) goto end; channel = av_clip(s->ir_channel, 0, s->in[1]->channels - 1); for (i = 0; i < s->w; i++) { const float *src = (const float *)s->in[1]->extended_data[channel]; double w = i * M_PI / (s->w - 1); - double real = 0.; - double imag = 0.; + double div, real_num = 0., imag_num = 0., real = 0., imag = 0.; for (x = 0; x < s->nb_taps; x++) { real += cos(-x * w) * src[x]; imag += sin(-x * w) * src[x]; + real_num += cos(-x * w) * src[x] * x; + imag_num += sin(-x * w) * src[x] * x; } mag[i] = hypot(real, imag); phase[i] = atan2(imag, real); + div = real * real + imag * imag; + delay[i] = (real_num * real + imag_num * imag) / div; min = fminf(min, mag[i]); max = fmaxf(max, mag[i]); + min_delay = fminf(min_delay, delay[i]); + max_delay = fmaxf(max_delay, delay[i]); } for (i = 0; i < s->w; i++) { int ymag = mag[i] / max * (s->h - 1); + int ydelay = (delay[i] - min_delay) / (max_delay - min_delay) * (s->h - 1); int yphase = (0.5 * (1. + phase[i] / M_PI)) * (s->h - 1); ymag = s->h - 1 - av_clip(ymag, 0, s->h - 1); yphase = s->h - 1 - av_clip(yphase, 0, s->h - 1); + ydelay = s->h - 1 - av_clip(ydelay, 0, s->h - 1); if (prev_ymag < 0) prev_ymag = ymag; if (prev_yphase < 0) prev_yphase = yphase; + if (prev_ydelay < 0) + prev_ydelay = ydelay; draw_line(out, i, ymag, FFMAX(i - 1, 0), prev_ymag, 0xFFFF00FF); draw_line(out, i, yphase, FFMAX(i - 1, 0), prev_yphase, 0xFF00FF00); + draw_line(out, i, ydelay, FFMAX(i - 1, 0), prev_ydelay, 0xFF00FFFF); prev_ymag = ymag; prev_yphase = yphase; + prev_ydelay = ydelay; } if (s->w > 400 && s->h > 100) { @@ -268,9 +281,18 @@ static void draw_response(AVFilterContext *ctx, AVFrame *out) drawtext(out, 2, 12, "Min Magnitude:", 0xDDDDDDDD); snprintf(text, sizeof(text), "%.2f", min); drawtext(out, 15 * 8 + 2, 12, text, 0xDDDDDDDD); + + drawtext(out, 2, 22, "Max Delay:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", max_delay); + drawtext(out, 11 * 8 + 2, 22, text, 0xDDDDDDDD); + + drawtext(out, 2, 32, "Min Delay:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", min_delay); + drawtext(out, 11 * 8 + 2, 32, text, 0xDDDDDDDD); } end: + av_free(delay); av_free(phase); av_free(mag); } @@ -337,7 +359,7 @@ static int convert_coeffs(AVFilterContext *ctx) switch (s->gtype) { case -1: - /* nothinkg to do */ + /* nothing to do */ break; case 0: for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {