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:
parent
9e21ba3dc3
commit
0939c33b54
@ -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.
|
Allowed range is 0.1 to 60 seconds.
|
||||||
|
|
||||||
@item response
|
@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.
|
By default it is disabled.
|
||||||
|
|
||||||
@item channel
|
@item channel
|
||||||
|
@ -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)
|
static void draw_response(AVFilterContext *ctx, AVFrame *out)
|
||||||
{
|
{
|
||||||
AudioFIRContext *s = ctx->priv;
|
AudioFIRContext *s = ctx->priv;
|
||||||
float *mag, *phase, min = FLT_MAX, max = FLT_MIN;
|
float *mag, *phase, *delay, min = FLT_MAX, max = FLT_MIN;
|
||||||
int prev_ymag = -1, prev_yphase = -1;
|
float min_delay = FLT_MAX, max_delay = FLT_MIN;
|
||||||
|
int prev_ymag = -1, prev_yphase = -1, prev_ydelay = -1;
|
||||||
char text[32];
|
char text[32];
|
||||||
int channel, i, x;
|
int channel, i, x;
|
||||||
|
|
||||||
@ -220,44 +221,56 @@ static void draw_response(AVFilterContext *ctx, AVFrame *out)
|
|||||||
|
|
||||||
phase = av_malloc_array(s->w, sizeof(*phase));
|
phase = av_malloc_array(s->w, sizeof(*phase));
|
||||||
mag = av_malloc_array(s->w, sizeof(*mag));
|
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;
|
goto end;
|
||||||
|
|
||||||
channel = av_clip(s->ir_channel, 0, s->in[1]->channels - 1);
|
channel = av_clip(s->ir_channel, 0, s->in[1]->channels - 1);
|
||||||
for (i = 0; i < s->w; i++) {
|
for (i = 0; i < s->w; i++) {
|
||||||
const float *src = (const float *)s->in[1]->extended_data[channel];
|
const float *src = (const float *)s->in[1]->extended_data[channel];
|
||||||
double w = i * M_PI / (s->w - 1);
|
double w = i * M_PI / (s->w - 1);
|
||||||
double real = 0.;
|
double div, real_num = 0., imag_num = 0., real = 0., imag = 0.;
|
||||||
double imag = 0.;
|
|
||||||
|
|
||||||
for (x = 0; x < s->nb_taps; x++) {
|
for (x = 0; x < s->nb_taps; x++) {
|
||||||
real += cos(-x * w) * src[x];
|
real += cos(-x * w) * src[x];
|
||||||
imag += sin(-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);
|
mag[i] = hypot(real, imag);
|
||||||
phase[i] = atan2(imag, real);
|
phase[i] = atan2(imag, real);
|
||||||
|
div = real * real + imag * imag;
|
||||||
|
delay[i] = (real_num * real + imag_num * imag) / div;
|
||||||
min = fminf(min, mag[i]);
|
min = fminf(min, mag[i]);
|
||||||
max = fmaxf(max, 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++) {
|
for (i = 0; i < s->w; i++) {
|
||||||
int ymag = mag[i] / max * (s->h - 1);
|
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);
|
int yphase = (0.5 * (1. + phase[i] / M_PI)) * (s->h - 1);
|
||||||
|
|
||||||
ymag = s->h - 1 - av_clip(ymag, 0, 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);
|
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)
|
if (prev_ymag < 0)
|
||||||
prev_ymag = ymag;
|
prev_ymag = ymag;
|
||||||
if (prev_yphase < 0)
|
if (prev_yphase < 0)
|
||||||
prev_yphase = yphase;
|
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, ymag, FFMAX(i - 1, 0), prev_ymag, 0xFFFF00FF);
|
||||||
draw_line(out, i, yphase, FFMAX(i - 1, 0), prev_yphase, 0xFF00FF00);
|
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_ymag = ymag;
|
||||||
prev_yphase = yphase;
|
prev_yphase = yphase;
|
||||||
|
prev_ydelay = ydelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->w > 400 && s->h > 100) {
|
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);
|
drawtext(out, 2, 12, "Min Magnitude:", 0xDDDDDDDD);
|
||||||
snprintf(text, sizeof(text), "%.2f", min);
|
snprintf(text, sizeof(text), "%.2f", min);
|
||||||
drawtext(out, 15 * 8 + 2, 12, text, 0xDDDDDDDD);
|
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:
|
end:
|
||||||
|
av_free(delay);
|
||||||
av_free(phase);
|
av_free(phase);
|
||||||
av_free(mag);
|
av_free(mag);
|
||||||
}
|
}
|
||||||
@ -337,7 +359,7 @@ static int convert_coeffs(AVFilterContext *ctx)
|
|||||||
|
|
||||||
switch (s->gtype) {
|
switch (s->gtype) {
|
||||||
case -1:
|
case -1:
|
||||||
/* nothinkg to do */
|
/* nothing to do */
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
|
for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
|
||||||
|
Loading…
Reference in New Issue
Block a user