#include "avfilter.h"
#include "bufferqueue.h"
#include "formats.h"
+#include "framesync.h"
#include "internal.h"
-#include "dualinput.h"
#include "video.h"
#include "blend.h"
typedef struct BlendContext {
const AVClass *class;
- FFDualInputContext dinput;
+ FFFrameSync fs;
int hsub, vsub; ///< chroma subsampling values
int nb_planes;
char *all_expr;
{ "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" },\
- { "addition128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION128}, 0, 0, FLAGS, "mode" },\
+ { "addition128","", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_GRAINMERGE}, 0, 0, FLAGS, "mode" },\
+ { "grainmerge", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_GRAINMERGE}, 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" },\
+ { "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_GRAINEXTRACT}, 0, 0, FLAGS, "mode" },\
+ { "grainextract", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_GRAINEXTRACT}, 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" },\
+ { "extremity", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXTREMITY}, 0, 0, FLAGS, "mode" },\
{ "freeze", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_FREEZE}, 0, 0, FLAGS, "mode" },\
{ "glow", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_GLOW}, 0, 0, FLAGS, "mode" },\
{ "hardlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT}, 0, 0, FLAGS, "mode" },\
static const AVOption blend_options[] = {
COMMON_OPTIONS,
- { "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
- { "repeatlast", "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
{ NULL }
};
-AVFILTER_DEFINE_CLASS(blend);
+FRAMESYNC_DEFINE_CLASS(blend, BlendContext, fs);
#define COPY(src) \
static void blend_copy ## src(const uint8_t *top, ptrdiff_t top_linesize, \
#define DODGE(a, b) (((a) == 255) ? (a) : FFMIN(255, (((b) << 8) / (255 - (a)))))
DEFINE_BLEND8(addition, FFMIN(255, A + B))
-DEFINE_BLEND8(addition128, av_clip_uint8(A + B - 128))
+DEFINE_BLEND8(grainmerge, av_clip_uint8(A + B - 128))
DEFINE_BLEND8(average, (A + B) / 2)
DEFINE_BLEND8(subtract, FFMAX(0, A - B))
DEFINE_BLEND8(multiply, MULTIPLY(1, A, B))
DEFINE_BLEND8(multiply128,av_clip_uint8((A - 128) * B / 32. + 128))
DEFINE_BLEND8(negation, 255 - FFABS(255 - A - B))
+DEFINE_BLEND8(extremity, FFABS(255 - A - B))
DEFINE_BLEND8(difference, FFABS(A - B))
-DEFINE_BLEND8(difference128, av_clip_uint8(128 + A - B))
+DEFINE_BLEND8(grainextract, av_clip_uint8(128 + A - B))
DEFINE_BLEND8(screen, SCREEN(1, A, B))
DEFINE_BLEND8(overlay, (A < 128) ? MULTIPLY(2, A, B) : SCREEN(2, A, B))
DEFINE_BLEND8(hardlight, (B < 128) ? MULTIPLY(2, B, A) : SCREEN(2, B, A))
#define DODGE(a, b) (((a) == 65535) ? (a) : FFMIN(65535, (((b) << 16) / (65535 - (a)))))
DEFINE_BLEND16(addition, FFMIN(65535, A + B))
-DEFINE_BLEND16(addition128, av_clip_uint16(A + B - 32768))
+DEFINE_BLEND16(grainmerge, av_clip_uint16(A + B - 32768))
DEFINE_BLEND16(average, (A + B) / 2)
DEFINE_BLEND16(subtract, FFMAX(0, A - B))
DEFINE_BLEND16(multiply, MULTIPLY(1, A, B))
DEFINE_BLEND16(multiply128, av_clip_uint16((A - 32768) * B / 8192. + 32768))
DEFINE_BLEND16(negation, 65535 - FFABS(65535 - A - B))
+DEFINE_BLEND16(extremity, FFABS(65535 - A - B))
DEFINE_BLEND16(difference, FFABS(A - B))
-DEFINE_BLEND16(difference128, av_clip_uint16(32768 + A - B))
+DEFINE_BLEND16(grainextract, av_clip_uint16(32768 + A - B))
DEFINE_BLEND16(screen, SCREEN(1, A, B))
DEFINE_BLEND16(overlay, (A < 32768) ? MULTIPLY(2, A, B) : SCREEN(2, A, B))
DEFINE_BLEND16(hardlight, (B < 32768) ? MULTIPLY(2, B, A) : SCREEN(2, B, A))
return dst_buf;
}
+static int blend_frame_for_dualinput(FFFrameSync *fs)
+{
+ AVFilterContext *ctx = fs->parent;
+ AVFrame *top_buf, *bottom_buf, *dst_buf;
+ int ret;
+
+ ret = ff_framesync_dualinput_get(fs, &top_buf, &bottom_buf);
+ if (ret < 0)
+ return ret;
+ if (!bottom_buf)
+ return ff_filter_frame(ctx->outputs[0], top_buf);
+ dst_buf = blend_frame(ctx, top_buf, bottom_buf);
+ return ff_filter_frame(ctx->outputs[0], dst_buf);
+}
+
static av_cold int init(AVFilterContext *ctx)
{
BlendContext *s = ctx->priv;
s->tblend = !strcmp(ctx->filter->name, "tblend");
- s->dinput.process = blend_frame;
+ s->fs.on_event = blend_frame_for_dualinput;
return 0;
}
BlendContext *s = ctx->priv;
int i;
- ff_dualinput_uninit(&s->dinput);
+ ff_framesync_uninit(&s->fs);
av_frame_free(&s->prev_frame);
for (i = 0; i < FF_ARRAY_ELEMS(s->params); i++)
{
switch (param->mode) {
case BLEND_ADDITION: param->blend = is_16bit ? blend_addition_16bit : blend_addition_8bit; break;
- case BLEND_ADDITION128: param->blend = is_16bit ? blend_addition128_16bit : blend_addition128_8bit; break;
+ case BLEND_GRAINMERGE: param->blend = is_16bit ? blend_grainmerge_16bit : blend_grainmerge_8bit; break;
case BLEND_AND: param->blend = is_16bit ? blend_and_16bit : blend_and_8bit; break;
case BLEND_AVERAGE: param->blend = is_16bit ? blend_average_16bit : blend_average_8bit; break;
case BLEND_BURN: param->blend = is_16bit ? blend_burn_16bit : blend_burn_8bit; break;
case BLEND_DARKEN: param->blend = is_16bit ? blend_darken_16bit : blend_darken_8bit; break;
case BLEND_DIFFERENCE: param->blend = is_16bit ? blend_difference_16bit : blend_difference_8bit; break;
- case BLEND_DIFFERENCE128: param->blend = is_16bit ? blend_difference128_16bit: blend_difference128_8bit; break;
+ case BLEND_GRAINEXTRACT: param->blend = is_16bit ? blend_grainextract_16bit: blend_grainextract_8bit; break;
case BLEND_DIVIDE: param->blend = is_16bit ? blend_divide_16bit : blend_divide_8bit; break;
case BLEND_DODGE: param->blend = is_16bit ? blend_dodge_16bit : blend_dodge_8bit; break;
case BLEND_EXCLUSION: param->blend = is_16bit ? blend_exclusion_16bit : blend_exclusion_8bit; break;
+ case BLEND_EXTREMITY: param->blend = is_16bit ? blend_extremity_16bit : blend_extremity_8bit; break;
case BLEND_FREEZE: param->blend = is_16bit ? blend_freeze_16bit : blend_freeze_8bit; break;
case BLEND_GLOW: param->blend = is_16bit ? blend_glow_16bit : blend_glow_8bit; break;
case BLEND_HARDLIGHT: param->blend = is_16bit ? blend_hardlight_16bit : blend_hardlight_8bit; break;
s->nb_planes = av_pix_fmt_count_planes(toplink->format);
if (!s->tblend)
- if ((ret = ff_dualinput_init(ctx, &s->dinput)) < 0)
+ if ((ret = ff_framesync_init_dualinput(&s->fs, ctx)) < 0)
return ret;
for (plane = 0; plane < FF_ARRAY_ELEMS(s->params); plane++) {
}
}
- return 0;
+ return s->tblend ? 0 : ff_framesync_configure(&s->fs);
}
#if CONFIG_BLEND_FILTER
-static int request_frame(AVFilterLink *outlink)
+static int activate(AVFilterContext *ctx)
{
- BlendContext *s = outlink->src->priv;
- return ff_dualinput_request_frame(&s->dinput, outlink);
-}
-
-static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
-{
- BlendContext *s = inlink->dst->priv;
- return ff_dualinput_filter_frame(&s->dinput, inlink, buf);
+ BlendContext *s = ctx->priv;
+ return ff_framesync_activate(&s->fs);
}
static const AVFilterPad blend_inputs[] = {
{
.name = "top",
.type = AVMEDIA_TYPE_VIDEO,
- .filter_frame = filter_frame,
},{
.name = "bottom",
.type = AVMEDIA_TYPE_VIDEO,
- .filter_frame = filter_frame,
},
{ NULL }
};
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_output,
- .request_frame = request_frame,
},
{ NULL }
};
AVFilter ff_vf_blend = {
.name = "blend",
.description = NULL_IF_CONFIG_SMALL("Blend two video frames into each other."),
+ .preinit = blend_framesync_preinit,
.init = init,
.uninit = uninit,
.priv_size = sizeof(BlendContext),
.query_formats = query_formats,
+ .activate = activate,
.inputs = blend_inputs,
.outputs = blend_outputs,
.priv_class = &blend_class,