typedef struct {
const AVClass *class;
int x, y; ///< position of overlayed picture
- double enable; ///< tells if blending is enabled
+ int enable; ///< tells if blending is enabled
int allow_packed_rgb;
uint8_t frame_requested;
double var_values[VAR_VARS_NB];
char *x_expr, *y_expr;
- char *enable_expr;
- AVExpr *x_pexpr, *y_pexpr, *enable_pexpr;
+ AVExpr *x_pexpr, *y_pexpr;
} OverlayContext;
static av_cold int init(AVFilterContext *ctx)
ff_bufqueue_discard_all(&over->queue_over);
av_expr_free(over->x_pexpr); over->x_pexpr = NULL;
av_expr_free(over->y_pexpr); over->y_pexpr = NULL;
- av_expr_free(over->enable_pexpr); over->enable_pexpr = NULL;
}
static inline int normalize_xy(double d, int chroma_sub)
return (int)d & ~((1 << chroma_sub) - 1);
}
-enum EvalTarget { EVAL_XY, EVAL_ENABLE, EVAL_ALL };
-
-static void eval_expr(AVFilterContext *ctx, enum EvalTarget eval_tgt)
+static void eval_expr(AVFilterContext *ctx)
{
OverlayContext *over = ctx->priv;
- if (eval_tgt == EVAL_XY || eval_tgt == EVAL_ALL) {
+ /* TODO: reindent */
over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL);
over->var_values[VAR_Y] = av_expr_eval(over->y_pexpr, over->var_values, NULL);
over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL);
over->x = normalize_xy(over->var_values[VAR_X], over->hsub);
over->y = normalize_xy(over->var_values[VAR_Y], over->vsub);
- }
- if (eval_tgt == EVAL_ENABLE || eval_tgt == EVAL_ALL) {
- over->enable = av_expr_eval(over->enable_pexpr, over->var_values, NULL);
- }
}
static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx)
ret = set_expr(&over->x_pexpr, args, cmd, ctx);
else if (!strcmp(cmd, "y"))
ret = set_expr(&over->y_pexpr, args, cmd, ctx);
- else if (!strcmp(cmd, "enable"))
- ret = set_expr(&over->enable_pexpr, args, cmd, ctx);
else
ret = AVERROR(ENOSYS);
return ret;
if (over->eval_mode == EVAL_MODE_INIT) {
- eval_expr(ctx, EVAL_ALL);
- av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d enable:%f\n",
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d\n",
over->var_values[VAR_X], over->x,
- over->var_values[VAR_Y], over->y,
- over->enable);
+ over->var_values[VAR_Y], over->y);
}
return ret;
}
over->var_values[VAR_POS] = NAN;
if ((ret = set_expr(&over->x_pexpr, over->x_expr, "x", ctx)) < 0 ||
- (ret = set_expr(&over->y_pexpr, over->y_expr, "y", ctx)) < 0 ||
- (ret = set_expr(&over->enable_pexpr, over->enable_expr, "enable", ctx)) < 0)
+ (ret = set_expr(&over->y_pexpr, over->y_expr, "y", ctx)) < 0)
return ret;
over->overlay_is_packed_rgb =
over->overlay_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
if (over->eval_mode == EVAL_MODE_INIT) {
- eval_expr(ctx, EVAL_ALL);
- av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d enable:%f\n",
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d\n",
over->var_values[VAR_X], over->x,
- over->var_values[VAR_Y], over->y,
- over->enable);
+ over->var_values[VAR_Y], over->y);
}
av_log(ctx, AV_LOG_VERBOSE,
if (over->eval_mode == EVAL_MODE_FRAME) {
int64_t pos = av_frame_get_pkt_pos(mainpic);
+ over->var_values[VAR_N] = inlink->frame_count;
over->var_values[VAR_T] = mainpic->pts == AV_NOPTS_VALUE ?
NAN : mainpic->pts * av_q2d(inlink->time_base);
over->var_values[VAR_POS] = pos == -1 ? NAN : pos;
- eval_expr(ctx, EVAL_ALL);
- av_log(ctx, AV_LOG_DEBUG, "n:%f t:%f pos:%f x:%f xi:%d y:%f yi:%d enable:%f\n",
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_DEBUG, "n:%f t:%f pos:%f x:%f xi:%d y:%f yi:%d\n",
over->var_values[VAR_N], over->var_values[VAR_T], over->var_values[VAR_POS],
over->var_values[VAR_X], over->x,
- over->var_values[VAR_Y], over->y,
- over->enable);
+ over->var_values[VAR_Y], over->y);
}
if (over->enable)
blend_image(ctx, mainpic, over->overpicref, over->x, over->y);
- over->var_values[VAR_N] += 1.0;
}
ret = ff_filter_frame(ctx->outputs[0], mainpic);
av_assert1(ret != AVERROR(EAGAIN));
return ret == AVERROR(EAGAIN) ? 0 : ret;
}
+#define DEF_FILTER_FRAME(name, mode, enable_value) \
+static int filter_frame_##name##_##mode(AVFilterLink *inlink, AVFrame *frame) \
+{ \
+ AVFilterContext *ctx = inlink->dst; \
+ OverlayContext *over = ctx->priv; \
+ over->enable = enable_value; \
+ return filter_frame_##name(inlink, frame); \
+}
+
+DEF_FILTER_FRAME(main, enabled, 1);
+DEF_FILTER_FRAME(main, disabled, 0);
+DEF_FILTER_FRAME(over, enabled, 1);
+DEF_FILTER_FRAME(over, disabled, 0);
+
static int request_frame(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
static const AVOption overlay_options[] = {
{ "x", "set the x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "y", "set the y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
- { "enable", "set expression which enables overlay", OFFSET(enable_expr), AV_OPT_TYPE_STRING, {.str = "1"}, .flags = FLAGS },
{ "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_FRAME}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
{ "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
{ "frame", "eval expressions per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
.type = AVMEDIA_TYPE_VIDEO,
.get_video_buffer = ff_null_get_video_buffer,
.config_props = config_input_main,
- .filter_frame = filter_frame_main,
+ .filter_frame = filter_frame_main_enabled,
+ .passthrough_filter_frame = filter_frame_main_disabled,
.needs_writable = 1,
},
{
.name = "overlay",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_input_overlay,
- .filter_frame = filter_frame_over,
+ .filter_frame = filter_frame_over_enabled,
+ .passthrough_filter_frame = filter_frame_over_disabled,
},
{ NULL }
};
.inputs = avfilter_vf_overlay_inputs,
.outputs = avfilter_vf_overlay_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE,
};