lavfi/overlay: support timeline through the new system.

This commit is contained in:
Clément Bœsch 2013-04-15 17:47:34 +02:00
parent 38853169ce
commit 15d2f26998
2 changed files with 37 additions and 42 deletions

View File

@ -4765,14 +4765,8 @@ on the main video. Default value is "0" for both expressions. In case
the expression is invalid, it is set to a huge value (meaning that the
overlay will not be displayed within the output visible area).
@item enable
Set the expression which enables the overlay. If the evaluation is
different from 0, the overlay is displayed on top of the input
frame. By default it is "1".
@item eval
Set when the expressions for @option{x}, @option{y}, and
@option{enable} are evaluated.
Set when the expressions for @option{x}, and @option{y} are evaluated.
It accepts the following values:
@table @samp
@ -4818,8 +4812,8 @@ main input until the end of the stream. A value of 0 disables this
behavior, which is enabled by default.
@end table
The @option{x}, @option{y}, and @option{enable} expressions can
contain the following parameters.
The @option{x}, and @option{y} expressions can contain the following
parameters.
@table @option
@item main_w, W
@ -4870,8 +4864,7 @@ This filter supports the following commands:
@table @option
@item x
@item y
@item enable
Modify the x/y and enable overlay of the overlay input.
Modify the x and y of the overlay input.
The command accepts the same syntax of the corresponding option.
If the specified expression is not valid, it is kept at its current

View File

@ -88,7 +88,7 @@ enum var_name {
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;
@ -114,8 +114,7 @@ typedef struct {
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)
@ -139,7 +138,6 @@ static av_cold void uninit(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)
@ -149,22 +147,16 @@ 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)
@ -198,8 +190,6 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
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);
@ -207,11 +197,10 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
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;
}
@ -320,8 +309,7 @@ static int config_input_overlay(AVFilterLink *inlink)
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 =
@ -329,11 +317,10 @@ static int config_input_overlay(AVFilterLink *inlink)
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,
@ -605,12 +592,11 @@ static int try_filter_frame(AVFilterContext *ctx, AVFrame *mainpic)
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);
@ -678,6 +664,20 @@ static int filter_frame_over(AVFilterLink *inlink, AVFrame *inpicref)
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;
@ -714,7 +714,6 @@ static int request_frame(AVFilterLink *outlink)
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" },
@ -736,14 +735,16 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = {
.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 }
};
@ -773,4 +774,5 @@ AVFilter avfilter_vf_overlay = {
.inputs = avfilter_vf_overlay_inputs,
.outputs = avfilter_vf_overlay_outputs,
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE,
};