From 0914e3a14ae6a8b61af72abd90f9caca5053b9c1 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 3 May 2022 17:34:25 +0200 Subject: [PATCH] avfilter/vf_maskfun: properly handle read-only frames --- libavfilter/vf_maskfun.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/libavfilter/vf_maskfun.c b/libavfilter/vf_maskfun.c index cafd9e33b3..253e5e40f7 100644 --- a/libavfilter/vf_maskfun.c +++ b/libavfilter/vf_maskfun.c @@ -41,7 +41,9 @@ typedef struct MaskFunContext { int max; uint64_t max_sum; + AVFrame *in; AVFrame *empty; + int (*getsum)(AVFilterContext *ctx, AVFrame *out); int (*maskfun)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } MaskFunContext; @@ -81,29 +83,42 @@ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NONE }; -static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; MaskFunContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out; - if (s->getsum(ctx, frame)) { + if (s->getsum(ctx, in)) { AVFrame *out = av_frame_clone(s->empty); if (!out) { - av_frame_free(&frame); + av_frame_free(&in); return AVERROR(ENOMEM); } - out->pts = frame->pts; - av_frame_free(&frame); + out->pts = in->pts; + av_frame_free(&in); return ff_filter_frame(outlink, out); } - ff_filter_execute(ctx, s->maskfun, frame, NULL, + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + av_frame_copy_props(out, in); + } + + s->in = in; + ff_filter_execute(ctx, s->maskfun, out, NULL, FFMIN(s->planeheight[1], ff_filter_get_nb_threads(ctx))); - return ff_filter_frame(outlink, frame); + if (out != in) + av_frame_free(&in); + return ff_filter_frame(outlink, out); } #define GETSUM(name, type, div) \ @@ -142,6 +157,7 @@ static int maskfun##name(AVFilterContext *ctx, void *arg, \ int jobnr, int nb_jobs) \ { \ MaskFunContext *s = ctx->priv; \ + AVFrame *in = s->in; \ AVFrame *out = arg; \ const int low = s->low; \ const int high = s->high; \ @@ -149,24 +165,30 @@ static int maskfun##name(AVFilterContext *ctx, void *arg, \ int p; \ \ for (p = 0; p < s->nb_planes; p++) { \ + const int src_linesize = in->linesize[p] / div; \ const int linesize = out->linesize[p] / div; \ const int w = s->planewidth[p]; \ const int h = s->planeheight[p]; \ const int slice_start = (h * jobnr) / nb_jobs; \ const int slice_end = (h * (jobnr+1)) / nb_jobs; \ - type *dst = (type *)out->data[p] + slice_start * linesize; \ + const type *src = (type *)in->data[p] + \ + slice_start * src_linesize; \ + type *dst = (type *)out->data[p] + \ + slice_start * linesize; \ \ if (!((1 << p) & s->planes)) \ continue; \ \ for (int y = slice_start; y < slice_end; y++) { \ for (int x = 0; x < w; x++) { \ + dst[x] = src[x]; \ if (dst[x] <= low) \ dst[x] = 0; \ else if (dst[x] > high) \ dst[x] = max; \ } \ \ + src += src_linesize; \ dst += linesize; \ } \ } \