From 893d4068adb9d3d2c118186bdc5645056f0ef172 Mon Sep 17 00:00:00 2001
From: Muhammad Faiz
Date: Tue, 13 Oct 2015 12:06:37 +0700
Subject: [PATCH] avfilter/avf_showcqt: fix frame management
follow frame writability rule
reuse buffer
---
libavfilter/avf_showcqt.c | 61 +++
1 file changed, 51 insertions(+), 10 deletions(-)
diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c
index e939d8f..5d5fa6c 100644
--- a/libavfilter/avf_showcqt.c
+++ b/libavfilter/avf_showcqt.c
@@ -60,9 +60,12 @@ typedef struct {
int start, len;
} Coeffs;
+#define NB_OUTPICREF_MAX 16
+
typedef struct {
const AVClass *class;
-AVFrame *outpicref;
+AVFrame *outpicref[NB_OUTPICREF_MAX];
+int nb_outpicref;
FFTContext *fft_context;
FFTComplex *fft_data;
FFTComplex *fft_result;
@@ -123,7 +126,8 @@ static av_cold void uninit(AVFilterContext *ctx)
av_freep(&s->fft_result);
av_freep(&s->spectogram);
av_freep(&s->font_alpha);
-av_frame_free(&s->outpicref);
+for (k = 0; k < s->nb_outpicref; k++)
+av_frame_free(&s->outpicref[k]);
}
static int query_formats(AVFilterContext *ctx)
@@ -428,11 +432,12 @@ static int config_output(AVFilterLink *outlink)
s->remaining_fill = fft_len >> 1;
memset(s->fft_data, 0, fft_len * sizeof(*s->fft_data));
-s->outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-if (!s->outpicref)
+s->outpicref[0] = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+if (!s->outpicref[0])
return AVERROR(ENOMEM);
+s->nb_outpicref = 1;
-s->spectogram = av_calloc(spectogram_height, s->outpicref->linesize[0]);
+s->spectogram = av_calloc(spectogram_height, s->outpicref[0]->linesize[0]);
if (!s->spectogram)
return AVERROR(ENOMEM);
@@ -456,7 +461,7 @@ static int plot_cqt(AVFilterLink *inlink)
int fft_len = 1 << s->fft_bits;
FFTSample result[VIDEO_WIDTH][4];
int x, y, ret = 0;
-int linesize = s->outpicref->linesize[0];
+int linesize = s->outpicref[0]->linesize[0];
int video_scale = s->fullhd ? 2 : 1;
int video_width = (VIDEO_WIDTH/2) * video_scale;
int spectogram_height = (SPECTOGRAM_HEIGHT/2) * video_scale;
@@ -549,10 +554,46 @@ static int plot_cqt(AVFilterLink *inlink)
/* drawing */
if (!s->spectogram_count) {
-uint8_t *data = (uint8_t*) s->outpicref->data[0];
+AVFrame *outpic = NULL;
+uint8_t *data;
float rcp_result[VIDEO_WIDTH];
int total_length = linesize * spectogram_height;
int back_length = linesize * s->spectogram_index;
+int pic_idx;
+
+/* reuse buffer if it is available */
+/* faster, but not writable to next filters */
+/* become slower if next filters need writable frame */
+for (pic_idx = 0; pic_idx < s->nb_outpicref; pic_idx++) {
+if (av_frame_is_writable(s->outpicref[pic_idx])) {
+outpic = av_frame_clone(s->outpicref[pic_idx]);
+break;
+}
+}
+
+/* allocate buffer and make it reusable if it is possible */
+if (pic_idx == s->nb_outpicref) {
+if (s->nb_outpicref < NB_OUTPICREF_MAX) {
+s->nb_outpicref++;
+av_log(ctx, AV_LOG_DEBUG, "allocating reusable buffer
(nb_outpicref = %d) "
+ "at frame %"PRId64"\n", s->nb_outpicref,
s->frame_count);
+s->outpicref[pic_idx] = ff_get_video_buffer(outlink,
outlink->w, outlink->h);
+if (!s->outpicref[pic_idx])
+return AVERROR(ENOMEM);
+outpic = av_frame_clone(s->outpicref[pic_idx]);
+} else {
+av_log(ctx, AV_LOG_DEBUG, "allocating buffer at frame
%"PRId64"\n",
+ s->frame_count);
+outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+}
+}
+
+if (!outpic)
+return AVERROR(ENOMEM);
+data = outpic->data[0];
+/* linesize should be consistent accross different call to
ff_get_video_buffer */
+/* needed for drawing sonogram */
+av_assert0(outpic->linesize[0] == linesize);
for (x = 0; x < video_width; x++)
rcp_result[x] = 1.0f / (result[x][3]+0.0001f);
@@ -645,8 +686,8 @@ static int plot_cqt(AVFilterLink *inlink)
if (back_length)
memcpy(data, s->spectogram, back_length);
-s->outpicref->pts = s->frame_count;
-ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref));
+outpic->pts = s->frame_count;
+ret = ff_filter_frame(outlink, outpic);
s->frame_count++;
}
s->spectogram_count = (s->spectogram_count + 1) % s->count;
@@ -721,7 +762,7 @@ static int request_frame(AVFilterLink *outlink)
int ret;
ret = ff_request_frame(inlink);
-if (ret == AVERROR_EOF && s->outpicref)
+if (ret =