diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index f5e8561713..30238e0c3f 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -38,6 +38,7 @@
 #include "audio.h"
 #include "video.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "window_func.h"
 
@@ -79,11 +80,13 @@ typedef struct ShowSpectrumContext {
     double win_scale;
     float overlap;
     float gain;
+    int consumed;
     int hop_size;
     float *combine_buffer;      ///< color combining buffer (3 * h items)
     float **color_buffer;       ///< color buffer (3 * h * ch items)
     AVAudioFifo *fifo;
     int64_t pts;
+    int eof;
     int single_pic;
     int legend;
     int start_x, start_y;
@@ -956,67 +959,51 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
         ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref));
         if (ret < 0)
             return ret;
+        return 0;
     }
 
-    return s->win_size;
+    return 1;
 }
 
 #if CONFIG_SHOWSPECTRUM_FILTER
 
-static int request_frame(AVFilterLink *outlink)
+static int activate(AVFilterContext *ctx)
 {
-    ShowSpectrumContext *s = outlink->src->priv;
-    AVFilterLink *inlink = outlink->src->inputs[0];
-    unsigned i;
+    AVFilterLink *inlink = ctx->inputs[0];
+    AVFilterLink *outlink = ctx->outputs[0];
+    ShowSpectrumContext *s = ctx->priv;
     int ret;
 
-    ret = ff_request_frame(inlink);
-    if (ret == AVERROR_EOF && s->sliding == FULLFRAME && s->xpos > 0 &&
-        s->outpicref) {
-        if (s->orientation == VERTICAL) {
-            for (i = 0; i < outlink->h; i++) {
-                memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos,   0, outlink->w - s->xpos);
-                memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos);
-                memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos);
-            }
-        } else {
-            for (i = s->xpos; i < outlink->h; i++) {
-                memset(s->outpicref->data[0] + i * s->outpicref->linesize[0],   0, outlink->w);
-                memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w);
-                memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w);
-            }
-        }
-        ret = ff_filter_frame(outlink, s->outpicref);
-        s->outpicref = NULL;
-    }
-
-    return ret;
-}
+    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
-{
-    AVFilterContext *ctx = inlink->dst;
-    ShowSpectrumContext *s = ctx->priv;
-    AVFrame *fin = NULL;
-    int ret = 0, consumed = 0;
+    if (av_audio_fifo_size(s->fifo) < s->win_size) {
+        AVFrame *frame = NULL;
 
-    if (s->pts == AV_NOPTS_VALUE)
-        s->pts = insamples->pts - av_audio_fifo_size(s->fifo);
+        ret = ff_inlink_consume_samples(inlink, s->win_size, s->win_size, &frame);
+        if (ret < 0)
+            return ret;
+        if (ret > 0) {
+            s->pts = frame->pts - av_audio_fifo_size(s->fifo);
+            s->consumed = 0;
 
-    av_audio_fifo_write(s->fifo, (void **)insamples->extended_data, insamples->nb_samples);
-    av_frame_free(&insamples);
-    while (av_audio_fifo_size(s->fifo) >= s->win_size) {
-        fin = ff_get_audio_buffer(inlink, s->win_size);
-        if (!fin) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
+            av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples);
+            av_frame_free(&frame);
         }
+    }
 
-        fin->pts = s->pts + consumed;
-        consumed += s->hop_size;
-        ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, s->win_size);
-        if (ret < 0)
-            goto fail;
+    if (s->outpicref && av_audio_fifo_size(s->fifo) >= s->win_size) {
+        AVFrame *fin = ff_get_audio_buffer(inlink, s->win_size);
+        if (!fin)
+            return AVERROR(ENOMEM);
+
+        fin->pts = s->pts + s->consumed;
+        s->consumed += s->hop_size;
+        ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data,
+                                 FFMIN(s->win_size, av_audio_fifo_size(s->fifo)));
+        if (ret < 0) {
+            av_frame_free(&fin);
+            return ret;
+        }
 
         av_assert0(fin->nb_samples == s->win_size);
 
@@ -1031,21 +1018,45 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
         ret = plot_spectrum_column(inlink, fin);
         av_frame_free(&fin);
         av_audio_fifo_drain(s->fifo, s->hop_size);
-        if (ret < 0)
-            goto fail;
+        if (ret <= 0)
+            return ret;
     }
 
-fail:
-    s->pts = AV_NOPTS_VALUE;
-    av_frame_free(&fin);
-    return ret;
+    if (ff_outlink_get_status(inlink) == AVERROR_EOF &&
+        s->sliding == FULLFRAME &&
+        s->xpos > 0 && s->outpicref) {
+        int64_t pts;
+
+        if (s->orientation == VERTICAL) {
+            for (int i = 0; i < outlink->h; i++) {
+                memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos,   0, outlink->w - s->xpos);
+                memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos);
+                memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos);
+            }
+        } else {
+            for (int i = s->xpos; i < outlink->h; i++) {
+                memset(s->outpicref->data[0] + i * s->outpicref->linesize[0],   0, outlink->w);
+                memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w);
+                memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w);
+            }
+        }
+        pts = s->outpicref->pts;
+        ret = ff_filter_frame(outlink, s->outpicref);
+        s->outpicref = NULL;
+        ff_outlink_set_status(outlink, AVERROR_EOF, pts);
+        return 0;
+    }
+
+    FF_FILTER_FORWARD_STATUS(inlink, outlink);
+    FF_FILTER_FORWARD_WANTED(outlink, inlink);
+
+    return FFERROR_NOT_READY;
 }
 
 static const AVFilterPad showspectrum_inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
-        .filter_frame = filter_frame,
     },
     { NULL }
 };
@@ -1055,7 +1066,6 @@ static const AVFilterPad showspectrum_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
-        .request_frame = request_frame,
     },
     { NULL }
 };
@@ -1068,6 +1078,7 @@ AVFilter ff_avf_showspectrum = {
     .priv_size     = sizeof(ShowSpectrumContext),
     .inputs        = showspectrum_inputs,
     .outputs       = showspectrum_outputs,
+    .activate      = activate,
     .priv_class    = &showspectrum_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
