diff --git a/doc/filters.texi b/doc/filters.texi index 605d92a952..79cabcfd6c 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -28432,6 +28432,9 @@ It accepts the following values: @item delay @end table Default is @code{magnitude}. + +@item channels +Set channels to use when processing audio. By default all are processed. @end table @section showspatial diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c index b2c7886985..5d13f71a2b 100644 --- a/libavfilter/avf_showfreqs.c +++ b/libavfilter/avf_showfreqs.c @@ -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);