Commit d4fd3f24 authored by Stefano Sabatini's avatar Stefano Sabatini

lavfi: add tblend filter

parent 05e74ac2
...@@ -8,6 +8,7 @@ version <next>: ...@@ -8,6 +8,7 @@ version <next>:
- RIFX format for *.wav files - RIFX format for *.wav files
- RTP/mpegts muxer - RTP/mpegts muxer
- non continuous cache protocol support - non continuous cache protocol support
- tblend filter
version 2.5: version 2.5:
......
...@@ -2634,13 +2634,17 @@ The threshold below which a pixel value is considered black; it defaults to ...@@ -2634,13 +2634,17 @@ The threshold below which a pixel value is considered black; it defaults to
@end table @end table
@section blend @section blend, tblend
Blend two video frames into each other. Blend two video frames into each other.
It takes two input streams and outputs one stream, the first input is the The @code{blend} filter takes two input streams and outputs one
"top" layer and second input is "bottom" layer. stream, the first input is the "top" layer and second input is
Output terminates when shortest input terminates. "bottom" layer. Output terminates when shortest input terminates.
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.
A description of the accepted options follows. A description of the accepted options follows.
...@@ -2730,11 +2734,13 @@ Value of pixel component at current location for second video frame (bottom laye ...@@ -2730,11 +2734,13 @@ Value of pixel component at current location for second video frame (bottom laye
@end table @end table
@item shortest @item shortest
Force termination when the shortest input terminates. Default is @code{0}. Force termination when the shortest input terminates. Default is
@code{0}. This option is only defined for the @code{blend} filter.
@item repeatlast @item repeatlast
Continue applying the last bottom frame after the end of the stream. A value of Continue applying the last bottom frame after the end of the stream. A value of
@code{0} disable the filter after the last frame of the bottom layer is reached. @code{0} disable the filter after the last frame of the bottom layer is reached.
Default is @code{1}. Default is @code{1}. This option is only defined for the @code{blend} filter.
@end table @end table
@subsection Examples @subsection Examples
...@@ -2769,6 +2775,12 @@ Apply uncover up-left effect: ...@@ -2769,6 +2775,12 @@ Apply uncover up-left effect:
@example @example
blend=all_expr='if(gte(T*SH*40+Y,H)*gte((T*40*SW+X)*W/H,W),A,B)' blend=all_expr='if(gte(T*SH*40+Y,H)*gte((T*40*SW+X)*W/H,W),A,B)'
@end example @end example
@item
Display differences between the current and the previous frame:
@example
tblend=all_mode=difference128
@end example
@end itemize @end itemize
@section boxblur @section boxblur
......
...@@ -188,6 +188,7 @@ OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o ...@@ -188,6 +188,7 @@ OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o
OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_subtitles.o OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_subtitles.o
OBJS-$(CONFIG_SUPER2XSAI_FILTER) += vf_super2xsai.o OBJS-$(CONFIG_SUPER2XSAI_FILTER) += vf_super2xsai.o
OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o
OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o
OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o
OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o
OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o
......
...@@ -203,6 +203,7 @@ void avfilter_register_all(void) ...@@ -203,6 +203,7 @@ void avfilter_register_all(void)
REGISTER_FILTER(SUBTITLES, subtitles, vf); REGISTER_FILTER(SUBTITLES, subtitles, vf);
REGISTER_FILTER(SUPER2XSAI, super2xsai, vf); REGISTER_FILTER(SUPER2XSAI, super2xsai, vf);
REGISTER_FILTER(SWAPUV, swapuv, vf); REGISTER_FILTER(SWAPUV, swapuv, vf);
REGISTER_FILTER(TBLEND, tblend, vf);
REGISTER_FILTER(TELECINE, telecine, vf); REGISTER_FILTER(TELECINE, telecine, vf);
REGISTER_FILTER(THUMBNAIL, thumbnail, vf); REGISTER_FILTER(THUMBNAIL, thumbnail, vf);
REGISTER_FILTER(TILE, tile, vf); REGISTER_FILTER(TILE, tile, vf);
......
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
#include "libavutil/version.h" #include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 5 #define LIBAVFILTER_VERSION_MAJOR 5
#define LIBAVFILTER_VERSION_MINOR 5 #define LIBAVFILTER_VERSION_MINOR 6
#define LIBAVFILTER_VERSION_MICRO 102 #define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \ LIBAVFILTER_VERSION_MINOR, \
......
...@@ -96,52 +96,57 @@ typedef struct { ...@@ -96,52 +96,57 @@ typedef struct {
double all_opacity; double all_opacity;
FilterParams params[4]; FilterParams params[4];
int tblend;
AVFrame *prev_frame; /* only used with tblend */
} BlendContext; } BlendContext;
#define COMMON_OPTIONS \
{ "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
{ "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
{ "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
{ "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
{ "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"},\
{ "addition", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION}, 0, 0, FLAGS, "mode" },\
{ "and", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND}, 0, 0, FLAGS, "mode" },\
{ "average", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE}, 0, 0, FLAGS, "mode" },\
{ "burn", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN}, 0, 0, FLAGS, "mode" },\
{ "darken", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN}, 0, 0, FLAGS, "mode" },\
{ "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" },\
{ "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" },\
{ "divide", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE}, 0, 0, FLAGS, "mode" },\
{ "dodge", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE}, 0, 0, FLAGS, "mode" },\
{ "exclusion", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION}, 0, 0, FLAGS, "mode" },\
{ "hardlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT}, 0, 0, FLAGS, "mode" },\
{ "lighten", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN}, 0, 0, FLAGS, "mode" },\
{ "multiply", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY}, 0, 0, FLAGS, "mode" },\
{ "negation", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION}, 0, 0, FLAGS, "mode" },\
{ "normal", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL}, 0, 0, FLAGS, "mode" },\
{ "or", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR}, 0, 0, FLAGS, "mode" },\
{ "overlay", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY}, 0, 0, FLAGS, "mode" },\
{ "phoenix", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX}, 0, 0, FLAGS, "mode" },\
{ "pinlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT}, 0, 0, FLAGS, "mode" },\
{ "reflect", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT}, 0, 0, FLAGS, "mode" },\
{ "screen", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN}, 0, 0, FLAGS, "mode" },\
{ "softlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT}, 0, 0, FLAGS, "mode" },\
{ "subtract", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT}, 0, 0, FLAGS, "mode" },\
{ "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" },\
{ "xor", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR}, 0, 0, FLAGS, "mode" },\
{ "c0_expr", "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
{ "c1_expr", "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
{ "c2_expr", "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
{ "c3_expr", "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
{ "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
{ "c0_opacity", "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
{ "c1_opacity", "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
{ "c2_opacity", "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
{ "c3_opacity", "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
{ "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}
#define OFFSET(x) offsetof(BlendContext, x) #define OFFSET(x) offsetof(BlendContext, x)
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
static const AVOption blend_options[] = { static const AVOption blend_options[] = {
{ "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"}, COMMON_OPTIONS,
{ "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
{ "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
{ "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
{ "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"},
{ "addition", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION}, 0, 0, FLAGS, "mode" },
{ "and", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND}, 0, 0, FLAGS, "mode" },
{ "average", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE}, 0, 0, FLAGS, "mode" },
{ "burn", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN}, 0, 0, FLAGS, "mode" },
{ "darken", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN}, 0, 0, FLAGS, "mode" },
{ "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" },
{ "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" },
{ "divide", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE}, 0, 0, FLAGS, "mode" },
{ "dodge", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE}, 0, 0, FLAGS, "mode" },
{ "exclusion", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION}, 0, 0, FLAGS, "mode" },
{ "hardlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT}, 0, 0, FLAGS, "mode" },
{ "lighten", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN}, 0, 0, FLAGS, "mode" },
{ "multiply", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY}, 0, 0, FLAGS, "mode" },
{ "negation", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION}, 0, 0, FLAGS, "mode" },
{ "normal", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL}, 0, 0, FLAGS, "mode" },
{ "or", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR}, 0, 0, FLAGS, "mode" },
{ "overlay", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY}, 0, 0, FLAGS, "mode" },
{ "phoenix", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX}, 0, 0, FLAGS, "mode" },
{ "pinlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT}, 0, 0, FLAGS, "mode" },
{ "reflect", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT}, 0, 0, FLAGS, "mode" },
{ "screen", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN}, 0, 0, FLAGS, "mode" },
{ "softlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT}, 0, 0, FLAGS, "mode" },
{ "subtract", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT}, 0, 0, FLAGS, "mode" },
{ "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" },
{ "xor", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR}, 0, 0, FLAGS, "mode" },
{ "c0_expr", "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "c1_expr", "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "c2_expr", "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "c3_expr", "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "c0_opacity", "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
{ "c1_opacity", "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
{ "c2_opacity", "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
{ "c3_opacity", "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
{ "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
{ "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS }, { "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
{ "repeatlast", "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS }, { "repeatlast", "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
{ NULL } { NULL }
...@@ -288,7 +293,8 @@ static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf, ...@@ -288,7 +293,8 @@ static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf,
ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads)); ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads));
} }
av_frame_free(&top_buf); if (!b->tblend)
av_frame_free(&top_buf);
return dst_buf; return dst_buf;
} }
...@@ -298,6 +304,8 @@ static av_cold int init(AVFilterContext *ctx) ...@@ -298,6 +304,8 @@ static av_cold int init(AVFilterContext *ctx)
BlendContext *b = ctx->priv; BlendContext *b = ctx->priv;
int ret, plane; int ret, plane;
b->tblend = !strcmp(ctx->filter->name, "tblend");
for (plane = 0; plane < FF_ARRAY_ELEMS(b->params); plane++) { for (plane = 0; plane < FF_ARRAY_ELEMS(b->params); plane++) {
FilterParams *param = &b->params[plane]; FilterParams *param = &b->params[plane];
...@@ -416,6 +424,8 @@ static av_cold void uninit(AVFilterContext *ctx) ...@@ -416,6 +424,8 @@ static av_cold void uninit(AVFilterContext *ctx)
int i; int i;
ff_dualinput_uninit(&b->dinput); ff_dualinput_uninit(&b->dinput);
av_freep(&b->prev_frame);
for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++) for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++)
av_expr_free(b->params[i].e); av_expr_free(b->params[i].e);
} }
...@@ -467,3 +477,71 @@ AVFilter ff_vf_blend = { ...@@ -467,3 +477,71 @@ AVFilter ff_vf_blend = {
.priv_class = &blend_class, .priv_class = &blend_class,
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
}; };
static int tblend_config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
AVFilterLink *inlink = ctx->inputs[0];
BlendContext *b = ctx->priv;
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
b->hsub = pix_desc->log2_chroma_w;
b->vsub = pix_desc->log2_chroma_h;
b->nb_planes = av_pix_fmt_count_planes(inlink->format);
outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
return 0;
}
static int tblend_filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
BlendContext *b = inlink->dst->priv;
AVFilterLink *outlink = inlink->dst->outputs[0];
if (b->prev_frame) {
AVFrame *out = blend_frame(inlink->dst, frame, b->prev_frame);
av_frame_free(&b->prev_frame);
b->prev_frame = frame;
return ff_filter_frame(outlink, out);
}
b->prev_frame = frame;
return 0;
}
static const AVOption tblend_options[] = {
COMMON_OPTIONS,
{ NULL }
};
AVFILTER_DEFINE_CLASS(tblend);
static const AVFilterPad tblend_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.filter_frame = tblend_filter_frame,
},
{ NULL }
};
static const AVFilterPad tblend_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = tblend_config_output,
},
{ NULL }
};
AVFilter ff_vf_tblend = {
.name = "tblend",
.description = NULL_IF_CONFIG_SMALL("Blend successive frames."),
.priv_size = sizeof(BlendContext),
.priv_class = &blend_class,
.query_formats = query_formats,
.init = init,
.uninit = uninit,
.inputs = tblend_inputs,
.outputs = tblend_outputs,
.flags = AVFILTER_FLAG_SLICE_THREADS,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment