From patchwork Fri Dec 6 16:18:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Niedermayer X-Patchwork-Id: 16638 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 3494544B05E for ; Fri, 6 Dec 2019 18:21:23 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 212AA68B641; Fri, 6 Dec 2019 18:21:23 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from vie01a-dmta-pe06-2.mx.upcmail.net (vie01a-dmta-pe06-2.mx.upcmail.net [84.116.36.15]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A033A68B53B for ; Fri, 6 Dec 2019 18:21:16 +0200 (EET) Received: from [172.31.216.235] (helo=vie01a-pemc-psmtp-pe12.mail.upcmail.net) by vie01a-dmta-pe06.mx.upcmail.net with esmtp (Exim 4.92) (envelope-from ) id 1idGM0-00008I-AM for ffmpeg-devel@ffmpeg.org; Fri, 06 Dec 2019 17:21:16 +0100 Received: from localhost ([213.47.68.29]) by vie01a-pemc-psmtp-pe12.mail.upcmail.net with ESMTP id dGL2i6C4MwlysdGL2ihf8O; Fri, 06 Dec 2019 17:20:16 +0100 X-Env-Mailfrom: michael@niedermayer.cc X-Env-Rcptto: ffmpeg-devel@ffmpeg.org X-SourceIP: 213.47.68.29 X-CNFS-Analysis: v=2.3 cv=E5OzWpVl c=1 sm=1 tr=0 a=2hcxjKEKjp0CzLx6oWAm4g==:117 a=2hcxjKEKjp0CzLx6oWAm4g==:17 a=jpOVt7BSZ2e4Z31A5e1TngXxSK0=:19 a=MKtGQD3n3ToA:10 a=1oJP67jkp3AA:10 a=GEAsPZ9sns4A:10 a=ZZnuYtJkoWoA:10 a=ECICkYSP2SC5FMUmBisA:9 a=EnKHOcWXjp-yh-DL:21 a=z7eoU1XVjFbmMgqa:21 a=pHzHmUro8NiASowvMSCR:22 a=Ew2E2A-JSTLzCXPT_086:22 From: Michael Niedermayer To: FFmpeg development discussions and patches Date: Fri, 6 Dec 2019 17:18:18 +0100 Message-Id: <20191206161818.25008-3-michael@niedermayer.cc> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191206161818.25008-1-michael@niedermayer.cc> References: <20191206161818.25008-1-michael@niedermayer.cc> MIME-Version: 1.0 X-CMAE-Envelope: MS4wfDFu0t1lfZ+pJfSPPVyikrFYIK+ugJzUmKx1E/Q6RcheaYI5P86aWhCd+Bnisw1VzPiVb0DPk1wFeI3j5TBUVBh5nlhHq1v1IejPYKGT8mOrlmjM8vVV Huz/l1hG4C3IyTsNurfzIOeEeOZmMq/FA1CT6HLB9B+ndPcz/OhaPpxz Subject: [FFmpeg-devel] [PATCH 3/3] avfilter/vf_geq: Add support for reading sample sums and means of rectangles X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This allows integrating box blur style filters in geq. Without this computing the mean of an area in geq would have been excessivly slow Signed-off-by: Michael Niedermayer --- libavfilter/vf_geq.c | 107 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c index c965204a1c..f722f422c5 100644 --- a/libavfilter/vf_geq.c +++ b/libavfilter/vf_geq.c @@ -57,6 +57,9 @@ typedef struct GEQContext { int interpolation; int is_rgb; int bps; + + double *pixel_sums[NB_PLANES]; + int needs_sum[NB_PLANES]; } GEQContext; enum { Y = 0, U, V, A, G, B, R }; @@ -135,6 +138,76 @@ static inline double getpix(void *priv, double x, double y, int plane) } } +static int calculate_sums(GEQContext *geq, int plane, int w, int h) +{ + int xi, yi; + AVFrame *picref = geq->picref; + const uint8_t *src = picref->data[plane]; + int linesize = picref->linesize[plane]; + + if (!geq->pixel_sums[plane]) + geq->pixel_sums[plane] = av_malloc_array(w, h * sizeof (*geq->pixel_sums[plane])); + if (!geq->pixel_sums[plane]) + return AVERROR(ENOMEM); + if (geq->bps > 8) + linesize /= 2; + for (yi = 0; yi < h; yi ++) { + if (geq->bps > 8) { + const uint16_t *src16 = (const uint16_t*)src; + double linesum = 0; + + for (xi = 0; xi < w; xi ++) { + linesum += src16[xi + yi * linesize]; + geq->pixel_sums[plane][xi + yi * w] = linesum; + } + } else { + double linesum = 0; + + for (xi = 0; xi < w; xi ++) { + linesum += src[xi + yi * linesize]; + geq->pixel_sums[plane][xi + yi * w] = linesum; + } + } + if (yi) + for (xi = 0; xi < w; xi ++) { + geq->pixel_sums[plane][xi + yi * w] += geq->pixel_sums[plane][xi + yi * w - w]; + } + } + return 0; +} + +static inline double getpix_integrate_internal(GEQContext *geq, int x, int y, int plane, int w, int h) +{ + if (x > w - 1) { + double boundary = getpix_integrate_internal(geq, w - 1, y, plane, w, h); + return 2*boundary - getpix_integrate_internal(geq, 2*(w - 1) - x, y, plane, w, h); + } else if (y > h - 1) { + double boundary = getpix_integrate_internal(geq, x, h - 1, plane, w, h); + return 2*boundary - getpix_integrate_internal(geq, x, 2*(h - 1) - y, plane, w, h); + } else if (x < 0) { + if (x == -1) return 0; + return - getpix_integrate_internal(geq, -x-2, y, plane, w, h); + } else if (y < 0) { + if (y == -1) return 0; + return - getpix_integrate_internal(geq, x, -y-2, plane, w, h); + } + + return geq->pixel_sums[plane][x + y * w]; +} + +static inline double getpix_integrate(void *priv, double x, double y, int plane) { + GEQContext *geq = priv; + AVFrame *picref = geq->picref; + const uint8_t *src = picref->data[plane]; + const int w = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(picref->width, geq->hsub) : picref->width; + const int h = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(picref->height, geq->vsub) : picref->height; + + if (!src) + return 0; + + return getpix_integrate_internal(geq, lrint(av_clipd(x, -w, 2*w)), lrint(av_clipd(y, -h, 2*h)), plane, w, h); +} + //TODO: cubic interpolate //TODO: keep the last few frames static double lum(void *priv, double x, double y) { return getpix(priv, x, y, 0); } @@ -142,6 +215,11 @@ static double cb(void *priv, double x, double y) { return getpix(priv, x, y, 1) static double cr(void *priv, double x, double y) { return getpix(priv, x, y, 2); } static double alpha(void *priv, double x, double y) { return getpix(priv, x, y, 3); } +static double lumsum(void *priv, double x, double y) { return getpix_integrate(priv, x, y, 0); } +static double cbsum(void *priv, double x, double y) { return getpix_integrate(priv, x, y, 1); } +static double crsub(void *priv, double x, double y) { return getpix_integrate(priv, x, y, 2); } +static double alphasum(void *priv, double x, double y) { return getpix_integrate(priv, x, y, 3); } + static av_cold int geq_init(AVFilterContext *ctx) { GEQContext *geq = ctx->priv; @@ -191,16 +269,32 @@ static av_cold int geq_init(AVFilterContext *ctx) } for (plane = 0; plane < NB_PLANES; plane++) { - static double (*p[])(void *, double, double) = { lum, cb, cr, alpha }; - static const char *const func2_yuv_names[] = { "lum", "cb", "cr", "alpha", "p", NULL }; - static const char *const func2_rgb_names[] = { "g", "b", "r", "alpha", "p", NULL }; + static double (*p[])(void *, double, double) = { + lum , cb , cr , alpha , + lumsum, cbsum, crsub, alphasum, + }; + static const char *const func2_yuv_names[] = { + "lum" , "cb" , "cr" , "alpha" , "p", + "lumsum", "cbsum", "crsum", "alphasum", "psum", + NULL }; + static const char *const func2_rgb_names[] = { + "g" , "b" , "r" , "alpha" , "p", + "gsum", "bsum", "rsum", "alphasum", "psum", + NULL }; const char *const *func2_names = geq->is_rgb ? func2_rgb_names : func2_yuv_names; - double (*func2[])(void *, double, double) = { lum, cb, cr, alpha, p[plane], NULL }; + double (*func2[])(void *, double, double) = { + lum , cb , cr , alpha , p[plane], + lumsum, cbsum, crsub, alphasum, p[plane + 4], + NULL }; + int counter[10] = {0}; ret = av_expr_parse(&geq->e[plane], geq->expr_str[plane < 3 && geq->is_rgb ? plane+4 : plane], var_names, NULL, NULL, func2_names, func2, 0, ctx); if (ret < 0) break; + + av_expr_count_func(geq->e[plane], counter, FF_ARRAY_ELEMS(counter), 2); + geq->needs_sum[plane] = counter[5] + counter[6] + counter[7] + counter[8] + counter[9]; } end: @@ -357,6 +451,9 @@ static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in) td.plane = plane; td.linesize = linesize; + if (geq->needs_sum[plane]) + calculate_sums(geq, plane, width, height); + ctx->internal->execute(ctx, slice_geq_filter, &td, NULL, FFMIN(height, nb_threads)); } @@ -371,6 +468,8 @@ static av_cold void geq_uninit(AVFilterContext *ctx) for (i = 0; i < FF_ARRAY_ELEMS(geq->e); i++) av_expr_free(geq->e[i]); + for (i = 0; i < NB_PLANES; i++) + av_freep(&geq->pixel_sums); } static const AVFilterPad geq_inputs[] = {