1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

avfilter/af_afir: calculate group delay too

This commit is contained in:
Paul B Mahol 2018-10-20 22:38:52 +02:00
parent 9e21ba3dc3
commit 0939c33b54
2 changed files with 29 additions and 7 deletions

View File

@ -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

View File

@ -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++) {