From d8e8aa944aa633dbb1990c4d33654234aaf0d312 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 30 Apr 2022 15:33:13 +0200 Subject: [PATCH] avfilter/avf_showfreqs: add rate option Fix possible buffer overflow. --- doc/filters.texi | 3 ++ libavfilter/avf_showfreqs.c | 58 ++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 72628af9b2..478a75bd3a 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -28476,6 +28476,9 @@ Specify size of video. For the syntax of this option, check the @ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}. Default is @code{1024x512}. +@item rate, r +Set video rate. Default is @code{25}. + @item mode Set display mode. This set how each frequency bin will be represented. diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c index 5d13f71a2b..6dcff686b6 100644 --- a/libavfilter/avf_showfreqs.c +++ b/libavfilter/avf_showfreqs.c @@ -70,6 +70,9 @@ typedef struct ShowFreqsContext { int win_size; float scale; char *colors; + int64_t pts; + int64_t old_pts; + AVRational frame_rate; } ShowFreqsContext; #define OFFSET(x) offsetof(ShowFreqsContext, x) @@ -78,6 +81,8 @@ typedef struct ShowFreqsContext { static const AVOption showfreqs_options[] = { { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1024x512"}, 0, 0, FLAGS }, { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1024x512"}, 0, 0, FLAGS }, + { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS }, + { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS }, { "mode", "set display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=BAR}, 0, NB_MODES-1, FLAGS, "mode" }, { "line", "show lines", 0, AV_OPT_TYPE_CONST, {.i64=LINE}, 0, 0, FLAGS, "mode" }, { "bar", "show bars", 0, AV_OPT_TYPE_CONST, {.i64=BAR}, 0, 0, FLAGS, "mode" }, @@ -149,6 +154,7 @@ static int config_output(AVFilterLink *outlink) float overlap, scale; int i, ret; + s->old_pts = AV_NOPTS_VALUE; s->nb_freq = s->fft_size / 2; s->win_size = s->fft_size; av_tx_uninit(&s->fft); @@ -215,7 +221,7 @@ static int config_output(AVFilterLink *outlink) if (!s->window) return AVERROR(ENOMEM); - outlink->frame_rate = av_make_q(inlink->sample_rate, s->hop_size); + outlink->frame_rate = s->frame_rate; outlink->time_base = av_inv_q(outlink->frame_rate); outlink->sample_aspect_ratio = (AVRational){1,1}; outlink->w = s->w; @@ -328,13 +334,13 @@ static inline void plot_freq(ShowFreqsContext *s, int ch, switch (s->avg) { case 0: - y = s->avg_data[ch][f] = !outlink->frame_count_in ? y : FFMIN(avg, y); + y = s->avg_data[ch][f] = !outlink->frame_count_in ? y : FFMIN(0, y); break; case 1: break; default: - s->avg_data[ch][f] = avg + y * (y - avg) / (FFMIN(outlink->frame_count_in + 1, s->avg) * y); - y = s->avg_data[ch][f]; + s->avg_data[ch][f] = avg + y * (y - avg) / (FFMIN(outlink->frame_count_in + 1, s->avg) * (float)y); + y = av_clip(s->avg_data[ch][f], 0, outlink->h - 1); break; } @@ -379,13 +385,6 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) AVFrame *out; int ch, n; - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - if (!out) - return AVERROR(ENOMEM); - - for (n = 0; n < outlink->h; n++) - memset(out->data[0] + out->linesize[0] * n, 0, outlink->w * 4); - /* fill FFT input with the number of samples available */ for (ch = 0; ch < s->nb_channels; ch++) { const float *p = (float *)in->extended_data[ch]; @@ -407,16 +406,26 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) s->tx_fn(s->fft, s->fft_data[ch], s->fft_input[ch], sizeof(float)); } + s->pts = av_rescale_q(pts, inlink->time_base, outlink->time_base); + if (s->old_pts >= s->pts) + return 0; + s->old_pts = s->pts; + #define RE(x, ch) s->fft_data[ch][x].re #define IM(x, ch) s->fft_data[ch][x].im #define M(a, b) (sqrt((a) * (a) + (b) * (b))) #define P(a, b) (atan2((b), (a))) colors = av_strdup(s->colors); - if (!colors) { - av_frame_free(&out); + if (!colors) return AVERROR(ENOMEM); - } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + + for (n = 0; n < outlink->h; n++) + memset(out->data[0] + out->linesize[0] * n, 0, outlink->w * 4); for (ch = 0; ch < s->nb_channels; ch++) { uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff }; @@ -432,29 +441,21 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) switch (s->data_mode) { case MAGNITUDE: - a = av_clipd(M(RE(0, ch), 0) / s->scale, 0, 1); - plot_freq(s, ch, a, 0, fg, &prev_y, out, outlink); - - for (f = 1; f < s->nb_freq; f++) { + for (f = 0; f < s->nb_freq; f++) { a = av_clipd(M(RE(f, ch), IM(f, ch)) / s->scale, 0, 1); plot_freq(s, ch, a, f, fg, &prev_y, out, outlink); } break; case PHASE: - a = av_clipd((M_PI + P(RE(0, ch), 0)) / (2. * M_PI), 0, 1); - plot_freq(s, ch, a, 0, fg, &prev_y, out, outlink); - - for (f = 1; f < s->nb_freq; f++) { + for (f = 0; f < s->nb_freq; f++) { a = av_clipd((M_PI + P(RE(f, ch), IM(f, ch))) / (2. * M_PI), 0, 1); plot_freq(s, ch, a, f, fg, &prev_y, out, outlink); } break; case DELAY: - plot_freq(s, ch, 0, 0, fg, &prev_y, out, outlink); - - for (f = 1; f < s->nb_freq; f++) { + for (f = 0; f < s->nb_freq; f++) { a = av_clipd((M_PI - P(IM(f, ch) * RE(f-1, ch) - IM(f-1, ch) * RE(f, ch), RE(f, ch) * RE(f-1, ch) + IM(f, ch) * IM(f-1, ch))) / (2. * M_PI), 0, 1); @@ -465,7 +466,7 @@ static int plot_freqs(AVFilterLink *inlink, int64_t pts) } av_free(colors); - out->pts = av_rescale_q(pts, inlink->time_base, outlink->time_base); + out->pts = s->pts; out->sample_aspect_ratio = (AVRational){1,1}; return ff_filter_frame(outlink, out); } @@ -509,6 +510,11 @@ static int activate(AVFilterContext *ctx) if (ret < 0) return ret; + if (ff_inlink_queued_samples(inlink) >= s->hop_size) { + ff_filter_set_ready(ctx, 10); + return 0; + } + FF_FILTER_FORWARD_STATUS(inlink, outlink); FF_FILTER_FORWARD_WANTED(outlink, inlink);