|
|
|
@ -51,6 +51,9 @@ typedef struct ShowFreqsContext { |
|
|
|
|
int ascale, fscale; |
|
|
|
|
int avg; |
|
|
|
|
int win_func; |
|
|
|
|
char *ch_layout_str; |
|
|
|
|
uint8_t *bypass; |
|
|
|
|
AVChannelLayout ch_layout; |
|
|
|
|
AVTXContext *fft; |
|
|
|
|
av_tx_fn tx_fn; |
|
|
|
|
AVComplexFloat **fft_input; |
|
|
|
@ -62,6 +65,7 @@ typedef struct ShowFreqsContext { |
|
|
|
|
float minamp; |
|
|
|
|
int hop_size; |
|
|
|
|
int nb_channels; |
|
|
|
|
int nb_draw_channels; |
|
|
|
|
int nb_freq; |
|
|
|
|
int win_size; |
|
|
|
|
float scale; |
|
|
|
@ -100,6 +104,7 @@ static const AVOption showfreqs_options[] = { |
|
|
|
|
{ "magnitude", "show magnitude", 0, AV_OPT_TYPE_CONST, {.i64=MAGNITUDE}, 0, 0, FLAGS, "data" }, |
|
|
|
|
{ "phase", "show phase", 0, AV_OPT_TYPE_CONST, {.i64=PHASE}, 0, 0, FLAGS, "data" }, |
|
|
|
|
{ "delay", "show group delay",0, AV_OPT_TYPE_CONST, {.i64=DELAY}, 0, 0, FLAGS, "data" }, |
|
|
|
|
{ "channels", "set channels to draw", OFFSET(ch_layout_str), AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS }, |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -162,11 +167,15 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
av_freep(&s->fft_data[i]); |
|
|
|
|
av_freep(&s->avg_data[i]); |
|
|
|
|
} |
|
|
|
|
av_freep(&s->bypass); |
|
|
|
|
av_freep(&s->fft_input); |
|
|
|
|
av_freep(&s->fft_data); |
|
|
|
|
av_freep(&s->avg_data); |
|
|
|
|
s->nb_channels = inlink->ch_layout.nb_channels; |
|
|
|
|
|
|
|
|
|
s->bypass = av_calloc(s->nb_channels, sizeof(*s->bypass)); |
|
|
|
|
if (!s->bypass) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
s->fft_input = av_calloc(s->nb_channels, sizeof(*s->fft_input)); |
|
|
|
|
if (!s->fft_input) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
@ -212,6 +221,26 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
outlink->w = s->w; |
|
|
|
|
outlink->h = s->h; |
|
|
|
|
|
|
|
|
|
ret = av_channel_layout_copy(&s->ch_layout, &inlink->ch_layout); |
|
|
|
|
if (ret < 0) |
|
|
|
|
return ret; |
|
|
|
|
s->nb_draw_channels = s->nb_channels; |
|
|
|
|
|
|
|
|
|
if (strcmp(s->ch_layout_str, "all")) { |
|
|
|
|
int nb_draw_channels = 0; |
|
|
|
|
av_channel_layout_from_string(&s->ch_layout, |
|
|
|
|
s->ch_layout_str); |
|
|
|
|
|
|
|
|
|
for (int ch = 0; ch < s->nb_channels; ch++) { |
|
|
|
|
const enum AVChannel channel = av_channel_layout_channel_from_index(&inlink->ch_layout, ch); |
|
|
|
|
|
|
|
|
|
s->bypass[ch] = av_channel_layout_index_from_channel(&s->ch_layout, channel) < 0; |
|
|
|
|
nb_draw_channels += s->bypass[ch] == 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->nb_draw_channels = nb_draw_channels; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -288,8 +317,8 @@ static inline void plot_freq(ShowFreqsContext *s, int ch, |
|
|
|
|
y = a * outlink->h - 1; |
|
|
|
|
break; |
|
|
|
|
case SEPARATE: |
|
|
|
|
end = (outlink->h / s->nb_channels) * (ch + 1); |
|
|
|
|
y = (outlink->h / s->nb_channels) * ch + a * (outlink->h / s->nb_channels) - 1; |
|
|
|
|
end = (outlink->h / s->nb_draw_channels) * (ch + 1); |
|
|
|
|
y = (outlink->h / s->nb_draw_channels) * ch + a * (outlink->h / s->nb_draw_channels) - 1; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
av_assert0(0); |
|
|
|
@ -361,6 +390,9 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) |
|
|
|
|
for (ch = 0; ch < s->nb_channels; ch++) { |
|
|
|
|
const float *p = (float *)in->extended_data[ch]; |
|
|
|
|
|
|
|
|
|
if (s->bypass[ch]) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
for (n = 0; n < win_size; n++) { |
|
|
|
|
s->fft_input[ch][n].re = p[n] * s->window_func_lut[n]; |
|
|
|
|
s->fft_input[ch][n].im = 0; |
|
|
|
@ -369,6 +401,9 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) |
|
|
|
|
|
|
|
|
|
/* run FFT on each samples set */ |
|
|
|
|
for (ch = 0; ch < s->nb_channels; ch++) { |
|
|
|
|
if (s->bypass[ch]) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
s->tx_fn(s->fft, s->fft_data[ch], s->fft_input[ch], sizeof(float)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -392,6 +427,9 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) |
|
|
|
|
if (color) |
|
|
|
|
av_parse_color(fg, color, -1, ctx); |
|
|
|
|
|
|
|
|
|
if (s->bypass[ch]) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
switch (s->data_mode) { |
|
|
|
|
case MAGNITUDE: |
|
|
|
|
a = av_clipd(M(RE(0, ch), 0) / s->scale, 0, 1); |
|
|
|
@ -482,6 +520,7 @@ static av_cold void uninit(AVFilterContext *ctx) |
|
|
|
|
ShowFreqsContext *s = ctx->priv; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
av_channel_layout_uninit(&s->ch_layout); |
|
|
|
|
av_tx_uninit(&s->fft); |
|
|
|
|
for (i = 0; i < s->nb_channels; i++) { |
|
|
|
|
if (s->fft_input) |
|
|
|
@ -491,6 +530,7 @@ static av_cold void uninit(AVFilterContext *ctx) |
|
|
|
|
if (s->avg_data) |
|
|
|
|
av_freep(&s->avg_data[i]); |
|
|
|
|
} |
|
|
|
|
av_freep(&s->bypass); |
|
|
|
|
av_freep(&s->fft_input); |
|
|
|
|
av_freep(&s->fft_data); |
|
|
|
|
av_freep(&s->avg_data); |
|
|
|
|