]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_blend.c
Merge commit 'b420a27e74750b60d2e064236afb10be06a38ace'
[ffmpeg] / libavfilter / vf_blend.c
index 9f003b29b65b0bff8b5b7384b0cb8de1dad52abb..054c0d55d099dfb69b2523c19922397c378177cb 100644 (file)
@@ -25,8 +25,8 @@
 #include "avfilter.h"
 #include "bufferqueue.h"
 #include "formats.h"
+#include "framesync.h"
 #include "internal.h"
-#include "dualinput.h"
 #include "video.h"
 #include "blend.h"
 
@@ -35,7 +35,7 @@
 
 typedef struct BlendContext {
     const AVClass *class;
-    FFDualInputContext dinput;
+    FFFrameSync fs;
     int hsub, vsub;             ///< chroma subsampling values
     int nb_planes;
     char *all_expr;
@@ -66,16 +66,19 @@ typedef struct ThreadData {
     { "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" },\
@@ -113,12 +116,10 @@ typedef struct ThreadData {
 
 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,    \
@@ -235,14 +236,15 @@ static void blend_## name##_16bit(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))
@@ -277,14 +279,15 @@ DEFINE_BLEND8(linearlight,av_clip_uint8((B < 128) ? B + 2 * A - 255 : B + 2 * (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))
@@ -402,13 +405,28 @@ static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf,
     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;
 }
 
@@ -436,7 +454,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     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++)
@@ -447,16 +465,17 @@ void ff_blend_init(FilterParams *param, int is_16bit)
 {
     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;
@@ -535,7 +554,7 @@ static int config_output(AVFilterLink *outlink)
     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++) {
@@ -562,32 +581,24 @@ static int config_output(AVFilterLink *outlink)
         }
     }
 
-    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 }
 };
@@ -597,7 +608,6 @@ static const AVFilterPad blend_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
-        .request_frame = request_frame,
     },
     { NULL }
 };
@@ -605,10 +615,12 @@ static const AVFilterPad blend_outputs[] = {
 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,