From patchwork Sun Jul 30 17:36:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 4519 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.1.85 with SMTP id 82csp1558441vsb; Sun, 30 Jul 2017 10:36:42 -0700 (PDT) X-Received: by 10.223.169.2 with SMTP id u2mr9891650wrc.288.1501436202682; Sun, 30 Jul 2017 10:36:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1501436202; cv=none; d=google.com; s=arc-20160816; b=zQg/fJQ7qBy3diQZavZPR+7bodBRgyBOxCRSQ/7Vw76HcrY+Mo9+jdGZalTDVls9cE EjQ6KcbD0vM7gdN/eTrpbOq7ztV5oEeIONj76Fjj3VWolVqGEhHLDoFj3+53eEZFMGZE hkrpfmINOFAw873m0FMua0jgpqKEW9o7FnGYDevYQC8nnMXUg9DPXBamhjWkC5kbdhRA +i1GvXP5YEcL0BXVnL+KEhknEbTC0ppa3kp+TU+AhI+jodWP3FZWRQXGQ0sOS8RNHsOi 6wM9SInyt7cnC9asUxcGw3ibikHAfT4EPyXh26bofoscU/8M/s/ObfHt8GC7iApxx/i3 FVVw== 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: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=H0SpcMY8W23/bLwRnjwMSgx3hhIpKgvw9ZvNntBCOik=; b=S+OZreUpq9VqGFNtKeNoRBtKKpFrycYnUJXnELgYyfCu3n7QG9p2lDOzleQzFLbeGc RyYssGJfI4+eKYvyNppH+OdhSb0KF97RvVCNMiFWyy2sxCBKYINO4nJHfqhegEgdoyto 34nw3lmw/snHD0/3rkulS1ry8AMMVU0v3UQhePHpVLV3ORS9aWTcqOJANajXfJnHdRxz 6egfVFq52gy2wa377RBvnw+5Pr8lvNKKZUDUnRLQ62Dl+z7UhwWcqI6WkGPE3HVxgYIb HgSEbLPa1APx6DdxlsHsNHFDBrrvjlAca3v7jRs3iVntjhrJm/TtU4OkL1TUjZHQBQ4c Revg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=T+Hl+sXd; 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=NONE 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 n186si6434757wmn.214.2017.07.30.10.36.41; Sun, 30 Jul 2017 10:36:42 -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=T+Hl+sXd; 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=NONE 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 8BED868A0BC; Sun, 30 Jul 2017 20:36:36 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f51.google.com (mail-wm0-f51.google.com [74.125.82.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4401E68A083 for ; Sun, 30 Jul 2017 20:36:30 +0300 (EEST) Received: by mail-wm0-f51.google.com with SMTP id m85so152711134wma.1 for ; Sun, 30 Jul 2017 10:36:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=nn5WtynKpp9j10sH/U0M+gQgFX/dgl7qQFxojQNCWM8=; b=T+Hl+sXdM3cZtQOajHQVa96QOPFgT0TWh1OD23pTD3ydzbCeQFLRfpRqit0BGUJ9SF DQ2umrS85DsVwPoKc/rOFwrwUJTuPhzmukZiSI1sMs/CQRjWXp1OBxDHLkicDF88nrbY wle7h78br/b0PmVwkDya7aqvj0hM8qKkE9uz2zD0gYUUrWEzDuQJmxh3oQo81PJVp2np WmFpX2ycbhC7pwdVemEy6hENNSxFZbGRTXc+BE2yvRRo6tkjtwjbNQoWEX3VecVxpMix bFRFauR194OMIvOsVxq8TrD1HOjrBRcZtDns1gSeIcYffZ21tuQmr0J8cTIpAXEerlRz eqOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=nn5WtynKpp9j10sH/U0M+gQgFX/dgl7qQFxojQNCWM8=; b=N2J96PdxRF5vKiJkDLJcl6V7cMKTRWOKxEpL0UeBD8ULqdQI8dU+R07q8CcKvD7C+Y fwn4g7visawrRW61gbyrxwg0oGWNPxcsVLCK0VYiIFaDRrSzxjAi7bcTz7u3gUopRkZG eB2xEKL+olZkpuyOlVoKe5JRLBCwasfU3HwtgFLaHTTJEQHQ3VuNZhCeT1Vv7Oi0FRuX DcTLiZgpm0/zm88y+amlKyZSdtu0Vmu1o+tJpZAiON1Fn6JtPYXUo3DRozHn995NnB83 p+foRyWOgcRVJ0jqKXQbmgbBa2kg5x04VLqWva0WmFQado3h2LXjILyRZaTVJmsK6aRQ T02A== X-Gm-Message-State: AIVw1115ekXWE49392COvnGDseGqMXG3loxhti5VK4GqJnzOwnQgwSHR IiuDKGhpGWGrqmYB X-Received: by 10.28.184.87 with SMTP id i84mr9868551wmf.22.1501436191263; Sun, 30 Jul 2017 10:36:31 -0700 (PDT) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id 39sm33994059wrc.84.2017.07.30.10.36.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 30 Jul 2017 10:36:30 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Sun, 30 Jul 2017 19:36:19 +0200 Message-Id: <20170730173619.28287-1-onemda@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170729203405.24597-1-onemda@gmail.com> References: <20170729203405.24597-1-onemda@gmail.com> Subject: [FFmpeg-devel] [PATCH] avfilter: add floodfill 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- doc/filters.texi | 37 +++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_floodfill.c | 360 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 399 insertions(+) create mode 100644 libavfilter/vf_floodfill.c diff --git a/doc/filters.texi b/doc/filters.texi index 2324b96..a7e1d8a 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -8398,6 +8398,43 @@ ffmpeg -i file.ts -vf find_rect=newref.pgm,cover_rect=cover.jpg:mode=cover new.m @end example @end itemize +@section floodfill + +Flood area with values of same pixel components with another values. + +It accepts the following options: +@table @option +@item x +Set pixel x coordinate. + +@item y +Set pixel y coordinate. + +@item s0 +Set source #0 component value. + +@item s1 +Set source #1 component value. + +@item s2 +Set source #2 component value. + +@item s3 +Set source #3 component value. + +@item d0 +Set destination #0 component value. + +@item d1 +Set destination #1 component value. + +@item d2 +Set destination #2 component value. + +@item d3 +Set destination #3 component value. +@end table + @anchor{format} @section format diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 4d61d78..59ebe57 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -186,6 +186,7 @@ OBJS-$(CONFIG_FIELDHINT_FILTER) += vf_fieldhint.o OBJS-$(CONFIG_FIELDMATCH_FILTER) += vf_fieldmatch.o OBJS-$(CONFIG_FIELDORDER_FILTER) += vf_fieldorder.o OBJS-$(CONFIG_FIND_RECT_FILTER) += vf_find_rect.o lavfutils.o +OBJS-$(CONFIG_FLOODFILL_FILTER) += vf_floodfill.o OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o OBJS-$(CONFIG_FPS_FILTER) += vf_fps.o OBJS-$(CONFIG_FRAMEPACK_FILTER) += vf_framepack.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index b1c2d11..635c668 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -198,6 +198,7 @@ static void register_all(void) REGISTER_FILTER(FIELDMATCH, fieldmatch, vf); REGISTER_FILTER(FIELDORDER, fieldorder, vf); REGISTER_FILTER(FIND_RECT, find_rect, vf); + REGISTER_FILTER(FLOODFILL, floodfill, vf); REGISTER_FILTER(FORMAT, format, vf); REGISTER_FILTER(FPS, fps, vf); REGISTER_FILTER(FRAMEPACK, framepack, vf); diff --git a/libavfilter/vf_floodfill.c b/libavfilter/vf_floodfill.c new file mode 100644 index 0000000..fe4fdbb --- /dev/null +++ b/libavfilter/vf_floodfill.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * + * 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/opt.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct Points { + uint16_t x, y; +} Points; + +typedef struct FloodfillContext { + const AVClass *class; + + int x, y; + unsigned s0, s1, s2, s3; + unsigned d0, d1, d2, d3; + + int back, front; + Points *points; + + int (*is_same)(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3); + void (*set_pixel)(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3); +} FloodfillContext; + +static int is_inside(int x, int y, int w, int h) +{ + if (x >= 0 && x < w && y >= 0 && y < h) + return 1; + return 0; +} + +static int is_same4(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3) +{ + unsigned c0 = frame->data[0][y * frame->linesize[0] + x]; + unsigned c1 = frame->data[1][y * frame->linesize[1] + x]; + unsigned c2 = frame->data[2][y * frame->linesize[2] + x]; + unsigned c3 = frame->data[3][y * frame->linesize[3] + x]; + + if (s0 == c0 && s1 == c1 && s2 == c2 && s3 == c3) + return 1; + return 0; +} + +static int is_same4_16(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3) +{ + unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x); + unsigned c1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x); + unsigned c2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x); + unsigned c3 = AV_RN16(frame->data[3] + y * frame->linesize[3] + 2 * x); + + if (s0 == c0 && s1 == c1 && s2 == c2 && s3 == c3) + return 1; + return 0; +} + +static int is_same3(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3) +{ + unsigned c0 = frame->data[0][y * frame->linesize[0] + x]; + unsigned c1 = frame->data[1][y * frame->linesize[1] + x]; + unsigned c2 = frame->data[2][y * frame->linesize[2] + x]; + + if (s0 == c0 && s1 == c1 && s2 == c2) + return 1; + return 0; +} + +static int is_same3_16(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3) +{ + unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x); + unsigned c1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x); + unsigned c2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x); + + if (s0 == c0 && s1 == c1 && s2 == c2) + return 1; + return 0; +} + +static int is_same1(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3) +{ + unsigned c0 = frame->data[0][y * frame->linesize[0] + x]; + + if (s0 == c0) + return 1; + return 0; +} + +static int is_same1_16(AVFrame *frame, int x, int y, + unsigned s0, unsigned s1, unsigned s2, unsigned s3) +{ + unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x); + + if (s0 == c0) + return 1; + return 0; +} + +static void set_pixel1(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + frame->data[0][y * frame->linesize[0] + x] = d0; +} + +static void set_pixel1_16(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0); +} + +static void set_pixel3(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + frame->data[0][y * frame->linesize[0] + x] = d0; + frame->data[1][y * frame->linesize[1] + x] = d1; + frame->data[2][y * frame->linesize[2] + x] = d2; +} + +static void set_pixel3_16(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0); + AV_WN16(frame->data[1] + y * frame->linesize[1] + 2 * x, d1); + AV_WN16(frame->data[2] + y * frame->linesize[2] + 2 * x, d2); +} + +static void set_pixel4(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + frame->data[0][y * frame->linesize[0] + x] = d0; + frame->data[1][y * frame->linesize[1] + x] = d1; + frame->data[2][y * frame->linesize[2] + x] = d2; + frame->data[3][y * frame->linesize[3] + x] = d3; +} + +static void set_pixel4_16(AVFrame *frame, int x, int y, + unsigned d0, unsigned d1, unsigned d2, unsigned d3) +{ + AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0); + AV_WN16(frame->data[1] + y * frame->linesize[1] + 2 * x, d1); + AV_WN16(frame->data[2] + y * frame->linesize[2] + 2 * x, d2); + AV_WN16(frame->data[3] + y * frame->linesize[3] + 2 * x, d3); +} + +static int config_input(AVFilterLink *inlink) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + AVFilterContext *ctx = inlink->dst; + FloodfillContext *s = ctx->priv; + int nb_planes = av_pix_fmt_count_planes(inlink->format); + int depth; + + depth = desc->comp[0].depth; + if (depth == 8) { + switch (nb_planes) { + case 1: s->set_pixel = set_pixel1; + s->is_same = is_same1; break; + case 3: s->set_pixel = set_pixel3; + s->is_same = is_same3; break; + case 4: s->set_pixel = set_pixel4; + s->is_same = is_same4; break; + } + } else { + switch (nb_planes) { + case 1: s->set_pixel = set_pixel1_16; + s->is_same = is_same1_16; break; + case 3: s->set_pixel = set_pixel3_16; + s->is_same = is_same3_16; break; + case 4: s->set_pixel = set_pixel4_16; + s->is_same = is_same4_16; break; + } + } + + s->front = s->back = 0; + s->points = av_calloc(inlink->w * inlink->h, 4 * sizeof(Points)); + if (!s->points) + return AVERROR(ENOMEM); + + return 0; +} + +static int filter_frame(AVFilterLink *link, AVFrame *frame) +{ + AVFilterContext *ctx = link->dst; + FloodfillContext *s = ctx->priv; + const unsigned s0 = s->s0; + const unsigned s1 = s->s1; + const unsigned s2 = s->s2; + const unsigned s3 = s->s3; + const unsigned d0 = s->d0; + const unsigned d1 = s->d1; + const unsigned d2 = s->d2; + const unsigned d3 = s->d3; + const int w = frame->width; + const int h = frame->height; + int ret; + + if (ret = av_frame_make_writable(frame)) + return ret; + + if (is_inside(s->x, s->y, w, h)) { + if (s->is_same(frame, s->x, s->y, s0, s1, s2, s3)) { + s->points[s->front].x = s->x; + s->points[s->front].y = s->y; + s->front++; + } + + while (s->front > s->back) { + int x, y; + + s->front--; + x = s->points[s->front].x; + y = s->points[s->front].y; + + if (s->is_same(frame, x, y, s0, s1, s2, s3)) { + s->set_pixel(frame, x, y, d0, d1, d2, d3); + + if (is_inside(x + 1, y, w, h)) { + s->points[s->front] .x = x + 1; + s->points[s->front++].y = y; + } + + if (is_inside(x - 1, y, w, h)) { + s->points[s->front] .x = x - 1; + s->points[s->front++].y = y; + } + + if (is_inside(x, y + 1, w, h)) { + s->points[s->front] .x = x; + s->points[s->front++].y = y + 1; + } + + if (is_inside(x, y - 1, w, h)) { + s->points[s->front] .x = x; + s->points[s->front++].y = y - 1; + } + } + } + } + + return ff_filter_frame(ctx->outputs[0], frame); +} + +static av_cold int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_GRAY8, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVA444P, + AV_PIX_FMT_GBRP, + AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, + AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GBRAP, + AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV444P12, + AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats; + + formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + + return ff_set_common_formats(ctx, formats); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + FloodfillContext *s = ctx->priv; + + av_freep(&s->points); +} + +static const AVFilterPad floodfill_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad floodfill_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(FloodfillContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption floodfill_options[] = { + { "x", "set pixel x coordinate", OFFSET(x), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "y", "set pixel y coordinate", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "s0", "set source #0 component value", OFFSET(s0), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "s1", "set source #1 component value", OFFSET(s1), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "s2", "set source #2 component value", OFFSET(s2), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "s3", "set source #3 component value", OFFSET(s3), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "d0", "set destination #0 component value", OFFSET(d0), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "d1", "set destination #1 component value", OFFSET(d1), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "d2", "set destination #2 component value", OFFSET(d2), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "d3", "set destination #3 component value", OFFSET(d3), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(floodfill); + +AVFilter ff_vf_floodfill = { + .name = "floodfill", + .description = NULL_IF_CONFIG_SMALL("Fill area with same color with another color."), + .priv_size = sizeof(FloodfillContext), + .priv_class = &floodfill_class, + .query_formats = query_formats, + .uninit = uninit, + .inputs = floodfill_inputs, + .outputs = floodfill_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +};