From patchwork Fri Jun 2 07:38:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Troffaes X-Patchwork-Id: 3789 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.10.2 with SMTP id 2csp76772vsk; Fri, 2 Jun 2017 00:47:06 -0700 (PDT) X-Received: by 10.28.196.73 with SMTP id u70mr1766387wmf.73.1496389626101; Fri, 02 Jun 2017 00:47:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496389626; cv=none; d=google.com; s=arc-20160816; b=XiArrDMAUsGsvGJ5jBSur8/ucMmDDBgc1qvdLsOdfp9OcUjJYhrxONMpVgZ/on18tU utE2Q/q0xvgU4qelq0MwzjIrHOKiHl0SgxZpGMQ32Gm/m7ncwxh/zYu76PoWc0Y1rDPQ wCPgPHBnsuU8C2eQ3QyrrpXmz9p8ANdIKvMExcVVJIzkY9Ma/GPzAU3zGzP9trwrwgK0 rbeuSBiT1t0qcmjbMNMuVTNhQSIDubwFh2y1BaMU8uHOEX81yDJrw24BzAjcws5NgbUJ S2nwxmzmtcu1Wam1QPzdyUTiWpuIv0EulhjlMgaBDWOiwORKuxo3ZbGBl6RslFv8r/e1 35Fg== 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=uQDPJfZ9HJgqQxSJVD3KVCs4t7FscndqMwqfRRuCXKg=; b=mC68w59hBtHA34Yy3aMZIkmHV9KVmpNnwCSREYw9lIDU3TRaJJAJ1YQ0tOVvwO4fgm 7CMUsixgwXu9h4fW3mWBtHX2IFrO8CQHQ7Mwx1lRd0K5ocFOnWH0+iC3JDXaSlegdBoV Tm2rQU/ke2TEITIb66guPnZuTj3pfAzpOtaIJAgE6t8EUpHwxGXgAzkpuZCFnxEmIrGR y+/iBxRt/Lqkj92vBJ6AEEc/gRXeAeYfZsIr10Li4pmffG5gwd4lWB9wcb3Y6AL8Ptcl itlk0a4xE89y20c7z1RNQVVPU/jIl+U7/F62GodNk35AGJ5kDdhAZJQEsVGuaNox62K1 eSMA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; 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 o5si1748033wma.167.2017.06.02.00.47.05; Fri, 02 Jun 2017 00:47:06 -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; 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 BC0AA689A86; Fri, 2 Jun 2017 10:46:57 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f46.google.com (mail-wm0-f46.google.com [74.125.82.46]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2574568981A for ; Fri, 2 Jun 2017 10:46:51 +0300 (EEST) Received: by mail-wm0-f46.google.com with SMTP id n195so16513594wmg.1 for ; Fri, 02 Jun 2017 00:46:56 -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=Q11def6q2DunJZbmW+4Q5YJ63pGf5KwGtDKHQsnr1wg=; b=Nx2oWJheareyOBQNmJq3rq4F1FS2DSVn8Zty/wja1ZhX92oKOmawXhb/vjOAHcnXBj RsKYWx1nyJXLgHDS5a7shcHVTd506AX2+Mz6Eujac7iSI/MsU+VAQrUOpUsjplZtwOJK JUv1/GfLkjse3vI2ryzjYiiC5e6Ua/8aP0dU0eTSOIZBhOkrBhneTKaH+/K9Ve5TnVhN 1GYkJSD1TrcnilrNg99MI+2X+WO+v+BmIgZzIa6LvArXMmgQq0yJfKYo8m7zc3yEmJ72 xD1nf+WAo+zfV4Au0kAfeX8no4eG9Nn/Zb4ZT/rbVQarjK5Q8oGSgc0e0LJXALG38Fnh Kl+g== 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=Q11def6q2DunJZbmW+4Q5YJ63pGf5KwGtDKHQsnr1wg=; b=rR183E987U/vHlUDi2kwto1DDPpAY3HwaEmj81kRcMBD9xsxzeFSMjOuhHk8LFRcx2 pnOSioqNSsC/PC6u1I/RpOnX8S0YKfZ/+xToXq3GImvrY1RobUTLzHec9WUWupYooT3V lTussz9M62Jt7bFXS+EhCqdmiYbgaYptD3JJHqKJnps5eKsCReMf5pK9bAd6SCaQF46e qC4EJNRwiPotqbxPrksLKKkDjxxOMXAdyGhAOlrGYKH35WD6w7RWW4/77XbIDMj3QtLo EYnkVciDUcpf2dr9/cXgDdh1g+KaoKTTeN5J9H31ztogOwdTbkZqbx0L7loDubNeQMKl dFgQ== X-Gm-Message-State: AODbwcDXW/6vmcQs3sI24HYkIFp0ylsfZQOUw0xlhtrD/+uRruX9mofc JpVEV4XZllI/a3bR X-Received: by 10.28.214.211 with SMTP id n202mr1767272wmg.105.1496389115375; Fri, 02 Jun 2017 00:38:35 -0700 (PDT) Received: from wilks.dur.ac.uk (wilks.dur.ac.uk. [129.234.21.182]) by smtp.gmail.com with ESMTPSA id w96sm21590244wrc.14.2017.06.02.00.38.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 02 Jun 2017 00:38:34 -0700 (PDT) From: "Matthias C. M. Troffaes" To: ffmpeg-devel@ffmpeg.org Date: Fri, 2 Jun 2017 08:38:20 +0100 Message-Id: <20170602073820.302853-2-matthias.troffaes@gmail.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170602073820.302853-1-matthias.troffaes@gmail.com> References: <20170602073820.302853-1-matthias.troffaes@gmail.com> Subject: [FFmpeg-devel] [PATCH] avfilter: add skipblend 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: "Matthias C. M. Troffaes" MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" --- Changelog | 1 + doc/filters.texi | 30 ++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/version.h | 2 +- libavfilter/vf_skipblend.c | 272 +++++++++++++++++++++++++++++++++ tests/fate/filter-video.mak | 12 ++ tests/ref/fate/filter-skipblend-anim-1 | 17 +++ tests/ref/fate/filter-skipblend-anim-2 | 17 +++ tests/ref/fate/filter-skipblend-gray-1 | 14 ++ tests/ref/fate/filter-skipblend-gray-2 | 13 ++ 11 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 libavfilter/vf_skipblend.c create mode 100644 tests/ref/fate/filter-skipblend-anim-1 create mode 100644 tests/ref/fate/filter-skipblend-anim-2 create mode 100644 tests/ref/fate/filter-skipblend-gray-1 create mode 100644 tests/ref/fate/filter-skipblend-gray-2 diff --git a/Changelog b/Changelog index 3533bdc..dc3c526 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ version : - remove the libnut muxer/demuxer wrappers - remove the libschroedinger encoder/decoder wrappers - surround audio filter +- skipblend video filter version 3.3: - CrystalHD decoder moved to new decode API diff --git a/doc/filters.texi b/doc/filters.texi index d4fbb5a..8f9db0f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -4724,6 +4724,7 @@ The threshold below which a pixel value is considered black; it defaults to @end table +@anchor{tblend} @section blend, tblend Blend two video frames into each other. @@ -4735,6 +4736,8 @@ stream, the first input is the "top" layer and second input is The @code{tblend} (time blend) filter takes two consecutive frames from one single stream, and outputs the result obtained by blending the new frame on top of the old frame. +See @ref{skipblend} for blending more than two frames at once +from the same stream. A description of the accepted options follows. @@ -8474,9 +8477,11 @@ This flag is enabled by default. @end table @end table +@anchor{framestep} @section framestep Select one frame every N-th frame. +See @ref{skipblend} for blending skipped frames. This filter accepts the following option: @table @option @@ -13128,6 +13133,31 @@ ffmpeg -i input1.mkv -i input2.mkv -filter_complex "[0:v][1:v] signature=nb_inpu @end itemize +@anchor{skipblend} +@section skipblend + +Skip frames whilst blending skipped frames, for a motion blur +effect. The number of frames that are blended (i.e. the exposure time, +in frames) can be controlled, allowing control over the strength of the +motion blur. +See @ref{framestep} for skipping frames without blending. +See @ref{tblend} for blending consecutive frames without skipping. + +This filter accepts the following options: +@table @option +@item step +Skip @code{step} frames each step. +Allowed values are positive integers between @code{1} and @code{65535}. +Default value is @code{1}. +@item blend +Blend the first @code{blend} frames on every step, +to produce a motion blur effect. +Allowed values are positive integers between @code{1} and @code{step}, +where @code{1} corresponds to no motion blur, and @code{step} +corresponds to maximal motion blur. +Default value is @code{step}. +@end table + @anchor{smartblur} @section smartblur diff --git a/libavfilter/Makefile b/libavfilter/Makefile index c88dfb3..6e01596 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -290,6 +290,7 @@ OBJS-$(CONFIG_SHUFFLEPLANES_FILTER) += vf_shuffleplanes.o OBJS-$(CONFIG_SIDEDATA_FILTER) += f_sidedata.o OBJS-$(CONFIG_SIGNALSTATS_FILTER) += vf_signalstats.o OBJS-$(CONFIG_SIGNATURE_FILTER) += vf_signature.o +OBJS-$(CONFIG_SKIPBLEND_FILTER) += vf_skipblend.o OBJS-$(CONFIG_SMARTBLUR_FILTER) += vf_smartblur.o OBJS-$(CONFIG_SOBEL_FILTER) += vf_convolution.o OBJS-$(CONFIG_SPLIT_FILTER) += split.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 534c340..605f2da 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -301,6 +301,7 @@ static void register_all(void) REGISTER_FILTER(SIDEDATA, sidedata, vf); REGISTER_FILTER(SIGNALSTATS, signalstats, vf); REGISTER_FILTER(SIGNATURE, signature, vf); + REGISTER_FILTER(SKIPBLEND, skipblend, vf); REGISTER_FILTER(SMARTBLUR, smartblur, vf); REGISTER_FILTER(SOBEL, sobel, vf); REGISTER_FILTER(SPLIT, split, vf); diff --git a/libavfilter/version.h b/libavfilter/version.h index 11cfe51..1fa3cf7 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFILTER_VERSION_MAJOR 6 -#define LIBAVFILTER_VERSION_MINOR 91 +#define LIBAVFILTER_VERSION_MINOR 92 #define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ diff --git a/libavfilter/vf_skipblend.c b/libavfilter/vf_skipblend.c new file mode 100644 index 0000000..2915b43 --- /dev/null +++ b/libavfilter/vf_skipblend.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2012 Stefano Sabatini + * Copyright (c) 2017 Matthias C. M. Troffaes + * + * 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 + */ + +/** + * @file skipblend filter, based on the framestep filter + */ + +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "internal.h" +#include "video.h" + +typedef struct NullContext { + const AVClass *class; + int64_t frame_step; ///< step size in frames + int64_t frame_blend; ///< how many frames to blend on each step + int nb_planes; ///< number of planes in the pixel format + int planewidth[4]; ///< width of each plane (after subsampling) + int planeheight[4]; ///< height of each plane (after subsampling) + uint32_t *data[4]; ///< buffer for blending input frames + + void (*blend_set)(AVFilterContext *ctx, AVFrame *in, int plane); + void (*blend_add)(AVFilterContext *ctx, AVFrame *in, int plane); + void (*blend_div)(AVFilterContext *ctx, AVFrame *in, int plane); +} SkipBlendContext; + +#define OFFSET(x) offsetof(SkipBlendContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +/* note: maximum value for blend must satisfy + blend * max_pixel_value <= max_buffer_value + where max_pixel_value is UINT16_MAX (support up to 16 bit formats) + and max_buffer_value is UINT32_MAX (internal blend buffer uses 32 bits) */ + +static const AVOption skipblend_options[] = { + { "step", "set frame step", OFFSET(frame_step), AV_OPT_TYPE_INT64, {.i64=1}, 1, UINT16_MAX, FLAGS}, + { "blend", "number of frames to blend per step", OFFSET(frame_blend), AV_OPT_TYPE_INT64, {.i64=UINT16_MAX}, 1, UINT16_MAX, FLAGS}, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(skipblend); + +#define DEFINE_BLEND(NAME, TYPE, DECL, EXPR) \ +static void blend_##NAME##_##TYPE(AVFilterContext *ctx, AVFrame *in, int plane)\ +{ \ + SkipBlendContext *s = ctx->priv; \ + DECL \ + const int height = s->planeheight[plane]; \ + const int width = s->planewidth[plane]; \ + const int stride = in->linesize[plane] / sizeof(TYPE); \ + TYPE *src = (TYPE *)in->data[plane]; \ + uint32_t *dst = s->data[plane]; \ + int y, x; \ + \ + for (y = 0; y < height; y++) { \ + for (x = 0; x < width; x++) { \ + EXPR; \ + } \ + src += stride; \ + } \ +} + +#define SET_DECL +#define SET_EXPR *dst++ = src[x] +#define ADD_DECL +#define ADD_EXPR *dst++ += src[x] +#define DIV_DECL const int frame_blend = s->frame_blend; +#define DIV_EXPR src[x] = *dst++ / frame_blend + +DEFINE_BLEND(set, uint8_t, SET_DECL, SET_EXPR) +DEFINE_BLEND(set, uint16_t, SET_DECL, SET_EXPR) +DEFINE_BLEND(add, uint8_t, ADD_DECL, ADD_EXPR) +DEFINE_BLEND(add, uint16_t, ADD_DECL, ADD_EXPR) +DEFINE_BLEND(div, uint8_t, DIV_DECL, DIV_EXPR) +DEFINE_BLEND(div, uint16_t, DIV_DECL, DIV_EXPR) + +#undef SET_DECL +#undef SET_EXPR +#undef ADD_DECL +#undef ADD_EXPR +#undef DIV_DECL +#undef DIV_EXPR +#undef DEFINE_BLEND + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + SkipBlendContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out = NULL; + int64_t frame_pos = inlink->frame_count_out % s->frame_step; + int direct = 0; + + /* update destination frame buffer; we need to do this even if filter is + disabled because buffer might be used for later frames when filter is + re-enabled */ + if (!frame_pos) { + /* copy first frame to destination frame buffer */ + for (int plane = 0; plane < s->nb_planes; plane++) + s->blend_set(ctx, in, plane); + } else if (frame_pos < s->frame_blend) { + /* add current frame to destination frame buffer */ + for (int plane = 0; plane < s->nb_planes; plane++) + s->blend_add(ctx, in, plane); + } + + /* write frame */ + if (ctx->is_disabled) { + /* filter is disabled, so pass input frame as is */ + return ff_filter_frame(outlink, in); + } else if ((frame_pos + 1) == s->frame_blend) { + /* filter is enabled, so write when all frames are blended */ + /* create a writable frame */ + if (av_frame_is_writable(in)) { + direct = 1; + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + /* finalize destination frame */ + for (int plane = 0; plane < s->nb_planes; plane++) + s->blend_div(ctx, out, plane); + /* free extra frame if created, and pass on output frame */ + if (!direct) + av_frame_free(&in); + return ff_filter_frame(outlink, out); + } else { + av_frame_free(&in); + return 0; + } +} + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NV12, AV_PIX_FMT_NV21, + AV_PIX_FMT_NONE + }; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +static int config_input_props(AVFilterLink *inlink) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + const AVFilterContext *ctx = inlink->dst; + SkipBlendContext *s = ctx->priv; + + s->planewidth[0] = s->planewidth[3] = inlink->w; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planeheight[0] = s->planeheight[3] = inlink->h; + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->nb_planes = av_pix_fmt_count_planes(inlink->format); + for (int plane = 0; plane < s->nb_planes; plane++) { + const int planesize = s->planewidth[plane] * s->planeheight[plane]; + s->data[plane] = av_mallocz_array(planesize, sizeof(uint32_t)); + if (!s->data[plane]) + return AVERROR(ENOMEM); + } + if (desc->comp[0].depth == 8) { + s->blend_set = blend_set_uint8_t; + s->blend_add = blend_add_uint8_t; + s->blend_div = blend_div_uint8_t; + } else if (desc->comp[0].depth == 16) { + s->blend_set = blend_set_uint16_t; + s->blend_add = blend_add_uint16_t; + s->blend_div = blend_div_uint16_t; + } else { + return AVERROR_BUG; + } + return 0; +} + +static int config_output_props(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + const SkipBlendContext *s = ctx->priv; + const AVFilterLink *inlink = ctx->inputs[0]; + + outlink->frame_rate = + av_div_q(inlink->frame_rate, (AVRational){s->frame_step, 1}); + + av_log(ctx, AV_LOG_VERBOSE, "step:%"PRId64" frame_rate:%d/%d(%f) -> frame_rate:%d/%d(%f)\n", + s->frame_step, + inlink->frame_rate.num, inlink->frame_rate.den, av_q2d(inlink->frame_rate), + outlink->frame_rate.num, outlink->frame_rate.den, av_q2d(outlink->frame_rate)); + + return 0; +} + +static av_cold int init(AVFilterContext *ctx) +{ + SkipBlendContext *s = ctx->priv; + s->frame_blend = FFMIN(s->frame_blend, s->frame_step); + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + SkipBlendContext *s = ctx->priv; + for (int plane = 0; plane < s->nb_planes; plane++) + av_freep(&s->data[plane]); +} + +static const AVFilterPad skipblend_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input_props, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad skipblend_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output_props, + }, + { NULL } +}; + +AVFilter ff_vf_skipblend = { + .name = "skipblend", + .description = NULL_IF_CONFIG_SMALL("Skip frames whilst blending skipped frames."), + .priv_size = sizeof(SkipBlendContext), + .priv_class = &skipblend_class, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = skipblend_inputs, + .outputs = skipblend_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, +}; diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak index 1ca29e8..f37b96c 100644 --- a/tests/fate/filter-video.mak +++ b/tests/fate/filter-video.mak @@ -320,6 +320,14 @@ FATE_FILTER_VSYNTH-$(CONFIG_SWAPRECT_FILTER) += $(FATE_SWAPRECT) FATE_FILTER_VSYNTH-$(CONFIG_TBLEND_FILTER) += fate-filter-tblend fate-filter-tblend: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf tblend=all_mode=difference128 +FATE_SKIPBLEND += fate-filter-skipblend-gray-1 +fate-filter-skipblend-gray-1: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf skipblend=step=6:blend=1 + +FATE_SKIPBLEND += fate-filter-skipblend-gray-2 +fate-filter-skipblend-gray-2: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf skipblend=step=6:blend=3 + +FATE_FILTER_VSYNTH-$(CONFIG_SKIPBLEND_FILTER) += $(FATE_SKIPBLEND) + FATE_FILTER_VSYNTH-$(CONFIG_TELECINE_FILTER) += fate-filter-telecine fate-filter-telecine: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf telecine @@ -384,6 +392,10 @@ fate-filter-fps-cfr: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/apple-animation-v fate-filter-fps-r: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -r 30 -vf fps -pix_fmt yuv420p fate-filter-fps: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -vf fps=30 -pix_fmt yuv420p +FATE_FILTER_SAMPLES-$(call ALLYES, SKIPBLEND_FILTER) += fate-filter-skipblend-anim-1 fate-filter-skipblend-anim-2 +fate-filter-skipblend-anim-1: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -vf skipblend=step=6:blend=1 +fate-filter-skipblend-anim-2: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -vf skipblend=step=6:blend=3 + FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER SPLIT_FILTER ALPHAEXTRACT_FILTER ALPHAMERGE_FILTER) += fate-filter-alphaextract_alphamerge_rgb fate-filter-alphaextract_alphamerge_rgb: tests/data/filtergraphs/alphamerge_alphaextract_rgb fate-filter-alphaextract_alphamerge_rgb: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/alphamerge_alphaextract_rgb diff --git a/tests/ref/fate/filter-skipblend-anim-1 b/tests/ref/fate/filter-skipblend-anim-1 new file mode 100644 index 0000000..0a6dd19 --- /dev/null +++ b/tests/ref/fate/filter-skipblend-anim-1 @@ -0,0 +1,17 @@ +#tb 0: 1001/4000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x180 +#sar 0: 1/1 +0, 0, 0, 1, 172800, 0x5adff92c +0, 1, 1, 1, 172800, 0x37b7f659 +0, 2, 2, 1, 172800, 0xb4a6f1d1 +0, 3, 3, 1, 172800, 0xd596f9c6 +0, 4, 4, 1, 172800, 0xff5a015b +0, 5, 5, 1, 172800, 0x65477f11 +0, 6, 6, 1, 172800, 0x41569400 +0, 7, 7, 1, 172800, 0xcff9ddf9 +0, 8, 8, 1, 172800, 0xd6daba1e +0, 9, 9, 1, 172800, 0xad83bda1 +0, 10, 10, 1, 172800, 0x1518bdb3 +0, 11, 11, 1, 172800, 0xfdd1c7ca diff --git a/tests/ref/fate/filter-skipblend-anim-2 b/tests/ref/fate/filter-skipblend-anim-2 new file mode 100644 index 0000000..3984f6d --- /dev/null +++ b/tests/ref/fate/filter-skipblend-anim-2 @@ -0,0 +1,17 @@ +#tb 0: 1001/4000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x180 +#sar 0: 1/1 +0, 0, 0, 1, 172800, 0xa99bf27e +0, 1, 1, 1, 172800, 0x6e2fdfe3 +0, 2, 2, 1, 172800, 0x96e7ea35 +0, 3, 3, 1, 172800, 0x832ff6cf +0, 4, 4, 1, 172800, 0x7a2dffb9 +0, 5, 5, 1, 172800, 0xa0a05854 +0, 6, 6, 1, 172800, 0x91d93f46 +0, 7, 7, 1, 172800, 0x3051d27b +0, 8, 8, 1, 172800, 0x0c13b87c +0, 9, 9, 1, 172800, 0xa80eba4c +0, 10, 10, 1, 172800, 0xd206ba19 +0, 11, 11, 1, 172800, 0x6608b61c diff --git a/tests/ref/fate/filter-skipblend-gray-1 b/tests/ref/fate/filter-skipblend-gray-1 new file mode 100644 index 0000000..dd209db --- /dev/null +++ b/tests/ref/fate/filter-skipblend-gray-1 @@ -0,0 +1,14 @@ +#tb 0: 6/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +0, 0, 0, 1, 152064, 0x05b789ef +0, 1, 1, 1, 152064, 0xe20f7c23 +0, 2, 2, 1, 152064, 0xc711ad61 +0, 3, 3, 1, 152064, 0xf25f6acc +0, 4, 4, 1, 152064, 0xce09f9d6 +0, 5, 5, 1, 152064, 0x0f9d6aca +0, 6, 6, 1, 152064, 0x4c9737ab +0, 7, 7, 1, 152064, 0x20cebfa9 +0, 8, 8, 1, 152064, 0xbb87b483 diff --git a/tests/ref/fate/filter-skipblend-gray-2 b/tests/ref/fate/filter-skipblend-gray-2 new file mode 100644 index 0000000..c2dfc9b --- /dev/null +++ b/tests/ref/fate/filter-skipblend-gray-2 @@ -0,0 +1,13 @@ +#tb 0: 6/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +0, 0, 0, 1, 152064, 0x999eb961 +0, 1, 1, 1, 152064, 0x0e947017 +0, 2, 2, 1, 152064, 0x2f338ae6 +0, 3, 3, 1, 152064, 0x4ead448b +0, 4, 4, 1, 152064, 0x6aef2c67 +0, 5, 5, 1, 152064, 0x809df637 +0, 6, 6, 1, 152064, 0x57b0bd89 +0, 7, 7, 1, 152064, 0x3649efd8