From patchwork Mon Mar 19 02:30:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dylan Fernando X-Patchwork-Id: 8034 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.1.70 with SMTP id c67csp2147035jad; Sun, 18 Mar 2018 19:36:52 -0700 (PDT) X-Google-Smtp-Source: AG47ELspmEDzTDl/0y8XpyctNn+cjYifmzoaTp/t0Q+p/E9OPlK8Td6mgRBmDG0GV45dxJlyFaf4 X-Received: by 10.28.149.197 with SMTP id x188mr6667661wmd.87.1521427012173; Sun, 18 Mar 2018 19:36:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521427012; cv=none; d=google.com; s=arc-20160816; b=NQkagD9vcXelBWCgVvYYRoGG0mGKRmWmI/vCMAxdLJ8RTFbC/cuKLbVCXoMNtyPU3Q qiAjUTF3pwkeOVe5apNDXz6FUMYGtJIhS5yBXQAhXeSkKdf7dhI8nH5rGAa3GTiGwCuw 1HzGaNAaTkvURmdOXhWqR0xnARxK+CAaDkFygnaAXc/t/B/BZaoaZ13G9ZRmXAQl8pPZ 8xm+yQOpsp3XXxmJqJKaHnMXNZXXQvY3SsTAM1dSx1qeLXldc7sd7rPs2nIJwBtP9Ws+ 7CJ6qY+4F005rXZIculCLthL02a2P9bteG4VcIu04+ZWIGzaLlx4PYtHpImy4FpIU+ld Ic7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=89Gibhfy1Kf4cXfacBWwU9HTvR1R0uK3iPaxQUgu+wI=; b=D+oNBfXMLU7Tcq7ZZY+4DfqTfdeKrTI0Rx0E5+G6zd/GqJYJYhXSbwdv/MVSwzxo3o qrLcmNSck6PH1epHEZLgXnLFsCkeWiRXvoMsyQus0eRVpoJqWDMYkJ1j4Xs96gg+Dk9J zfon92ukrCU1IsOrHt0JLmL1XswrZzw3x+8FUFzup8fyq/KcKUstOCpNjnVZYRZG0iiw V4Jt/ZogTo8fWSxb1oqD9C6d3Bl/XuyQVngGh6picQjsJEI1Od6q2VyBfE8amXYZTxKF xtV2QZdEWXJi48Nft3AMgXYWIWKnb+2oA1IGmFCRt6TLu/nAQNVoM/IzdDWg/tCEug/g /sGA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=TnG8btH1; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 129si4578782wmy.211.2018.03.18.19.36.51; Sun, 18 Mar 2018 19:36:52 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=TnG8btH1; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 19FF96806BC; Mon, 19 Mar 2018 04:36:37 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 706ED680280 for ; Mon, 19 Mar 2018 04:36:30 +0200 (EET) Received: by mail-pl0-f67.google.com with SMTP id u11-v6so5713716plq.1 for ; Sun, 18 Mar 2018 19:36:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Yb69xwEuIAQS1dMHvidceeFZysWng4dpWS6LkH/LwUc=; b=TnG8btH1AcBTcpm3n15b0kUrhvfZsI6zcZCGOlXkAKM617lYPI/oxRa4gAgo6vcdmg G92gGzJw6a6gzzQUesZwN6txjnyAGlq1YdQV4EA7tN/Kk3TiQJPMVxndIiCOiV0hU5kG 3zdvBEEvOnd5B7T1byNHNHK1lX2vrYeICisSjVcMMZUCYWZ/api1fJIeaVJ0qJpQtg86 OXicRsAGZh96N6rGEq4nb3ZfHLm3OHNokCQu6A5rSGtnUlzQfhvX6bVaM2WuZ7D3pSRa mUT8CjqqvOqTSvnBqkkS9qNZ15J5IAeo4rZTaAwbo8oV6qX3Y7Ex6pqgpzyJf4xmQ2e+ eTVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Yb69xwEuIAQS1dMHvidceeFZysWng4dpWS6LkH/LwUc=; b=RYKgWAKskcAeYOTRwHKL1kvirwd7pkCIGruBTgkl55cG8QYG2gwOKM1AqLUog1Ht5x 6d2T81BBNVlF6AKUnOHivi2PYXhxAF2guW+sH79EqfbwY+37tlO+ZNd88PNyJFmBusvP OOayqFJMvd2jrj2LTGG+vr2WvAInGzZDaeZgA7SXqwYoHo4+KsvkeLswKRqNM3rGSTqd SrbfLwkzTMoUsHBZyb9siOQ0ujzX1dApJquTCjvfyWo3pTzCudXi+aHhLWy4EQMoR7LE 1iB6fU+8GKFdCZtYIHSBdbrodhyuCkPNYeMjXaQ5eDrKK2CEE8clAb8wvSmtENnRcNug 6tlQ== X-Gm-Message-State: AElRT7E5fY8398xvGqyQLlGB7yQx7j4/tpzP8lVuQu6xLiiUBYmHMZYh +5jfgm2euoXOWKDXj22+rYQ6w+Cb X-Received: by 2002:a17:902:8212:: with SMTP id x18-v6mr709319pln.372.1521426637145; Sun, 18 Mar 2018 19:30:37 -0700 (PDT) Received: from dyn-118-138-38-51.its.monash.edu.au (dyn-118-138-38-51.its.monash.edu.au. [118.138.38.51]) by smtp.googlemail.com with ESMTPSA id j83sm27587625pfj.18.2018.03.18.19.30.34 (version=TLS1 cipher=AES128-SHA bits=128/128); Sun, 18 Mar 2018 19:30:36 -0700 (PDT) From: dylanf123@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Mon, 19 Mar 2018 13:30:23 +1100 Message-Id: <20180319023023.19036-1-dylanf123@gmail.com> X-Mailer: git-send-email 2.14.3 (Apple Git-98) In-Reply-To: References: Subject: [FFmpeg-devel] [PATCH] lavfi: Add OpenCL avgblur filter 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 Cc: drfer3 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: drfer3 Behaves like the existing avgblur filter, except working on OpenCL hardware frames. Takes exactly the same options. --- configure | 1 + libavfilter/Makefile | 2 + libavfilter/allfilters.c | 1 + libavfilter/opencl/avgblur.cl | 60 ++++++++ libavfilter/opencl_source.h | 1 + libavfilter/vf_avgblur_opencl.c | 328 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 393 insertions(+) create mode 100644 libavfilter/opencl/avgblur.cl create mode 100644 libavfilter/vf_avgblur_opencl.c diff --git a/configure b/configure index 0c5ed07a07..481d338caf 100755 --- a/configure +++ b/configure @@ -3202,6 +3202,7 @@ aresample_filter_deps="swresample" ass_filter_deps="libass" atempo_filter_deps="avcodec" atempo_filter_select="rdft" +avgblur_opencl_filter_deps="opencl" azmq_filter_deps="libzmq" blackframe_filter_deps="gpl" boxblur_filter_deps="gpl" diff --git a/libavfilter/Makefile b/libavfilter/Makefile index fc16512e2c..1043b41d80 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -139,6 +139,8 @@ OBJS-$(CONFIG_ALPHAMERGE_FILTER) += vf_alphamerge.o OBJS-$(CONFIG_ASS_FILTER) += vf_subtitles.o OBJS-$(CONFIG_ATADENOISE_FILTER) += vf_atadenoise.o OBJS-$(CONFIG_AVGBLUR_FILTER) += vf_avgblur.o +OBJS-$(CONFIG_AVGBLUR_OPENCL_FILTER) += vf_avgblur_opencl.o opencl.o \ + opencl/avgblur.o OBJS-$(CONFIG_BBOX_FILTER) += bbox.o vf_bbox.o OBJS-$(CONFIG_BENCH_FILTER) += f_bench.o OBJS-$(CONFIG_BITPLANENOISE_FILTER) += vf_bitplanenoise.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index cc423af738..3f67e321bf 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -149,6 +149,7 @@ static void register_all(void) REGISTER_FILTER(ASS, ass, vf); REGISTER_FILTER(ATADENOISE, atadenoise, vf); REGISTER_FILTER(AVGBLUR, avgblur, vf); + REGISTER_FILTER(AVGBLUR_OPENCL, avgblur_opencl, vf); REGISTER_FILTER(BBOX, bbox, vf); REGISTER_FILTER(BENCH, bench, vf); REGISTER_FILTER(BITPLANENOISE, bitplanenoise, vf); diff --git a/libavfilter/opencl/avgblur.cl b/libavfilter/opencl/avgblur.cl new file mode 100644 index 0000000000..6a8d70df93 --- /dev/null +++ b/libavfilter/opencl/avgblur.cl @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Dylan Fernando + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +__kernel void avgblur_horiz(__write_only image2d_t dst, + __read_only image2d_t src, + int rad) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + int2 size = (int2)(get_global_size(0), get_global_size(1)); + + int count = 0; + float4 acc = (float4)(0,0,0,0); + + for (int xx = max(0, loc.x - rad); xx < min(loc.x + rad + 1, size.x); xx++) { + count++; + acc += read_imagef(src, sampler, (int2)(xx, loc.y)); + } + + write_imagef(dst, loc, acc / count); +} + +__kernel void avgblur_vert(__write_only image2d_t dst, + __read_only image2d_t src, + int radv) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + int2 size = (int2)(get_global_size(0), get_global_size(1)); + + int count = 0; + float4 acc = (float4)(0,0,0,0); + + for (int yy = max(0, loc.y - radv); yy < min(loc.y + radv + 1, size.y); yy++) { + count++; + acc += read_imagef(src, sampler, (int2)(loc.x, yy)); + } + + write_imagef(dst, loc, acc / count); +} diff --git a/libavfilter/opencl_source.h b/libavfilter/opencl_source.h index 23cdfc6ac9..02bc1723b0 100644 --- a/libavfilter/opencl_source.h +++ b/libavfilter/opencl_source.h @@ -19,6 +19,7 @@ #ifndef AVFILTER_OPENCL_SOURCE_H #define AVFILTER_OPENCL_SOURCE_H +extern const char *ff_opencl_source_avgblur; extern const char *ff_opencl_source_overlay; extern const char *ff_opencl_source_unsharp; diff --git a/libavfilter/vf_avgblur_opencl.c b/libavfilter/vf_avgblur_opencl.c new file mode 100644 index 0000000000..a6baa28ac1 --- /dev/null +++ b/libavfilter/vf_avgblur_opencl.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2018 Dylan Fernando + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + + +typedef struct AverageBlurOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel_horiz; + cl_kernel kernel_vert; + cl_command_queue command_queue; + + int radius; + int radiusV; + int planes; + +} AverageBlurOpenCLContext; + + +static int avgblur_opencl_init(AVFilterContext *avctx) +{ + AverageBlurOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_avgblur, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel_horiz = clCreateKernel(ctx->ocf.program,"avgblur_horiz", &cle); + if (!ctx->kernel_horiz) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel_vert = clCreateKernel(ctx->ocf.program,"avgblur_vert", &cle); + if (!ctx->kernel_vert) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + if (ctx->radiusV <= 0) { + ctx->radiusV = ctx->radius; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel_horiz) + clReleaseKernel(ctx->kernel_horiz); + if (ctx->kernel_vert) + clReleaseKernel(ctx->kernel_vert); + return err; +} + +static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + AverageBlurOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + AVFrame *intermediate = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst, inter; + int err, p; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = avgblur_opencl_init(avctx); + if (err < 0) + goto fail; + + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + intermediate = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!intermediate) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem)output->data[p]; + inter = (cl_mem) intermediate->data[p]; + + if (!dst) + break; + + int radius_x = ctx->radius; + int radius_y = ctx->radiusV; + + if (!(ctx->planes & (1 << p))) { + radius_x = 0; + radius_y = 0; + } + + cle = clSetKernelArg(ctx->kernel_horiz, 0, sizeof(cl_mem), &inter); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel_horiz, 1, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel_horiz, 2, sizeof(cl_int), &radius_x); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "sizeX argument: %d.\n", cle); + goto fail; + } + + global_work[0] = output->width; + global_work[1] = output->height; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_horiz, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + cle = clSetKernelArg(ctx->kernel_vert, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel_vert, 1, sizeof(cl_mem), &inter); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel_vert, 2, sizeof(cl_int), &radius_y); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "sizeY argument: %d.\n", cle); + goto fail; + } + + global_work[0] = output->width; + global_work[1] = output->height; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_vert, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + av_frame_free(&intermediate); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + av_frame_free(&intermediate); + return err; +} + +static av_cold void avgblur_opencl_uninit(AVFilterContext *avctx) +{ + AverageBlurOpenCLContext *ctx = avctx->priv; + cl_int cle; + + + if (ctx->kernel_horiz) { + cle = clReleaseKernel(ctx->kernel_horiz); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->kernel_vert) { + cle = clReleaseKernel(ctx->kernel_vert); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(AverageBlurOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption avgblur_opencl_options[] = { + { "sizeX", "set horizontal size", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=1}, 1, 1024, FLAGS }, + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=0xF}, 0, 0xF, FLAGS }, + { "sizeY", "set vertical size", OFFSET(radiusV), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(avgblur_opencl); + +static const AVFilterPad avgblur_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &avgblur_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad avgblur_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_avgblur_opencl = { + .name = "avgblur_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply average blur filter"), + .priv_size = sizeof(AverageBlurOpenCLContext), + .priv_class = &avgblur_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &avgblur_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = avgblur_opencl_inputs, + .outputs = avgblur_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +};