... | ... |
@@ -4279,7 +4279,8 @@ Set when the expressions for @option{x}, @option{y}, and |
4279 | 4279 |
It accepts the following values: |
4280 | 4280 |
@table @samp |
4281 | 4281 |
@item init |
4282 |
-only evaluate expressions once during the filter initialization |
|
4282 |
+only evaluate expressions once during the filter initialization or |
|
4283 |
+when a command is processed |
|
4283 | 4284 |
|
4284 | 4285 |
@item frame |
4285 | 4286 |
evaluate expressions for each incoming frame |
... | ... |
@@ -4360,6 +4361,20 @@ the @var{movie} filter. |
4360 | 4360 |
You can chain together more overlays but you should test the |
4361 | 4361 |
efficiency of such approach. |
4362 | 4362 |
|
4363 |
+@subsection Commands |
|
4364 |
+ |
|
4365 |
+This filter supports the following command: |
|
4366 |
+@table @option |
|
4367 |
+@item x |
|
4368 |
+Set the @option{x} option expression. |
|
4369 |
+ |
|
4370 |
+@item y |
|
4371 |
+Set the @option{y} option expression. |
|
4372 |
+ |
|
4373 |
+@item enable |
|
4374 |
+Set the @option{enable} option expression. |
|
4375 |
+@end table |
|
4376 |
+ |
|
4363 | 4377 |
@subsection Examples |
4364 | 4378 |
|
4365 | 4379 |
@itemize |
... | ... |
@@ -30,7 +30,7 @@ |
30 | 30 |
|
31 | 31 |
#define LIBAVFILTER_VERSION_MAJOR 3 |
32 | 32 |
#define LIBAVFILTER_VERSION_MINOR 50 |
33 |
-#define LIBAVFILTER_VERSION_MICRO 102 |
|
33 |
+#define LIBAVFILTER_VERSION_MICRO 103 |
|
34 | 34 |
|
35 | 35 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
36 | 36 |
LIBAVFILTER_VERSION_MINOR, \ |
... | ... |
@@ -164,6 +164,74 @@ static av_cold void uninit(AVFilterContext *ctx) |
164 | 164 |
av_expr_free(over->enable_pexpr); over->enable_pexpr = NULL; |
165 | 165 |
} |
166 | 166 |
|
167 |
+static inline int normalize_xy(double d, int chroma_sub) |
|
168 |
+{ |
|
169 |
+ if (isnan(d)) |
|
170 |
+ return INT_MAX; |
|
171 |
+ return (int)d & ~((1 << chroma_sub) - 1); |
|
172 |
+} |
|
173 |
+ |
|
174 |
+enum EvalTarget { EVAL_XY, EVAL_ENABLE, EVAL_ALL }; |
|
175 |
+ |
|
176 |
+static void eval_expr(AVFilterContext *ctx, enum EvalTarget eval_tgt) |
|
177 |
+{ |
|
178 |
+ OverlayContext *over = ctx->priv; |
|
179 |
+ |
|
180 |
+ if (eval_tgt == EVAL_XY || eval_tgt == EVAL_ALL) { |
|
181 |
+ over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL); |
|
182 |
+ over->var_values[VAR_Y] = av_expr_eval(over->y_pexpr, over->var_values, NULL); |
|
183 |
+ over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL); |
|
184 |
+ over->x = normalize_xy(over->var_values[VAR_X], over->hsub); |
|
185 |
+ over->y = normalize_xy(over->var_values[VAR_Y], over->vsub); |
|
186 |
+ } |
|
187 |
+ if (eval_tgt == EVAL_ENABLE || eval_tgt == EVAL_ALL) { |
|
188 |
+ over->enable = av_expr_eval(over->enable_pexpr, over->var_values, NULL); |
|
189 |
+ } |
|
190 |
+} |
|
191 |
+ |
|
192 |
+static int set_expr(AVExpr **pexpr, const char *expr, void *log_ctx) |
|
193 |
+{ |
|
194 |
+ int ret; |
|
195 |
+ |
|
196 |
+ if (*pexpr) |
|
197 |
+ av_expr_free(*pexpr); |
|
198 |
+ *pexpr = NULL; |
|
199 |
+ ret = av_expr_parse(pexpr, expr, var_names, |
|
200 |
+ NULL, NULL, NULL, NULL, 0, log_ctx); |
|
201 |
+ if (ret < 0) |
|
202 |
+ av_log(log_ctx, AV_LOG_ERROR, |
|
203 |
+ "Error when evaluating the expression '%s'\n", expr); |
|
204 |
+ return ret; |
|
205 |
+} |
|
206 |
+ |
|
207 |
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, |
|
208 |
+ char *res, int res_len, int flags) |
|
209 |
+{ |
|
210 |
+ OverlayContext *over = ctx->priv; |
|
211 |
+ int ret; |
|
212 |
+ |
|
213 |
+ if (!strcmp(cmd, "x")) |
|
214 |
+ ret = set_expr(&over->x_pexpr, args, ctx); |
|
215 |
+ else if (!strcmp(cmd, "y")) |
|
216 |
+ ret = set_expr(&over->y_pexpr, args, ctx); |
|
217 |
+ else if (!strcmp(cmd, "enable")) |
|
218 |
+ ret = set_expr(&over->enable_pexpr, args, ctx); |
|
219 |
+ else |
|
220 |
+ ret = AVERROR(ENOSYS); |
|
221 |
+ |
|
222 |
+ if (ret < 0) |
|
223 |
+ return ret; |
|
224 |
+ |
|
225 |
+ if (over->eval_mode == EVAL_MODE_INIT) { |
|
226 |
+ eval_expr(ctx, EVAL_ALL); |
|
227 |
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d enable:%f\n", |
|
228 |
+ over->var_values[VAR_X], over->x, |
|
229 |
+ over->var_values[VAR_Y], over->y, |
|
230 |
+ over->enable); |
|
231 |
+ } |
|
232 |
+ return ret; |
|
233 |
+} |
|
234 |
+ |
|
167 | 235 |
static int query_formats(AVFilterContext *ctx) |
168 | 236 |
{ |
169 | 237 |
OverlayContext *over = ctx->priv; |
... | ... |
@@ -244,30 +312,10 @@ static int config_input_main(AVFilterLink *inlink) |
244 | 244 |
return 0; |
245 | 245 |
} |
246 | 246 |
|
247 |
-static inline int normalize_xy(double d, int chroma_sub) |
|
248 |
-{ |
|
249 |
- if (isnan(d)) |
|
250 |
- return INT_MAX; |
|
251 |
- return (int)d & ~((1 << chroma_sub) - 1); |
|
252 |
-} |
|
253 |
- |
|
254 |
-static void eval_expr(AVFilterContext *ctx) |
|
255 |
-{ |
|
256 |
- OverlayContext *over = ctx->priv; |
|
257 |
- |
|
258 |
- over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL); |
|
259 |
- over->var_values[VAR_Y] = av_expr_eval(over->y_pexpr, over->var_values, NULL); |
|
260 |
- over->var_values[VAR_X] = av_expr_eval(over->x_pexpr, over->var_values, NULL); |
|
261 |
- over->x = normalize_xy(over->var_values[VAR_X], over->hsub); |
|
262 |
- over->y = normalize_xy(over->var_values[VAR_Y], over->vsub); |
|
263 |
- over->enable = av_expr_eval(over->enable_pexpr, over->var_values, NULL); |
|
264 |
-} |
|
265 |
- |
|
266 | 247 |
static int config_input_overlay(AVFilterLink *inlink) |
267 | 248 |
{ |
268 | 249 |
AVFilterContext *ctx = inlink->dst; |
269 | 250 |
OverlayContext *over = inlink->dst->priv; |
270 |
- char *expr; |
|
271 | 251 |
int ret; |
272 | 252 |
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); |
273 | 253 |
|
... | ... |
@@ -287,25 +335,17 @@ static int config_input_overlay(AVFilterLink *inlink) |
287 | 287 |
over->var_values[VAR_T] = NAN; |
288 | 288 |
over->var_values[VAR_POS] = NAN; |
289 | 289 |
|
290 |
- expr = over->x_expr; |
|
291 |
- if ((ret = av_expr_parse(&over->x_pexpr, expr, var_names, |
|
292 |
- NULL, NULL, NULL, NULL, 0, ctx)) < 0) |
|
293 |
- goto fail; |
|
294 |
- expr = over->y_expr; |
|
295 |
- if ((ret = av_expr_parse(&over->y_pexpr, expr, var_names, |
|
296 |
- NULL, NULL, NULL, NULL, 0, ctx)) < 0) |
|
297 |
- goto fail; |
|
298 |
- expr = over->enable_expr; |
|
299 |
- if ((ret = av_expr_parse(&over->enable_pexpr, expr, var_names, |
|
300 |
- NULL, NULL, NULL, NULL, 0, ctx)) < 0) |
|
301 |
- goto fail; |
|
290 |
+ if ((ret = set_expr(&over->x_pexpr, over->x_expr, ctx)) < 0 || |
|
291 |
+ (ret = set_expr(&over->y_pexpr, over->y_expr, ctx)) < 0 || |
|
292 |
+ (ret = set_expr(&over->enable_pexpr, over->enable_expr, ctx)) < 0) |
|
293 |
+ return ret; |
|
302 | 294 |
|
303 | 295 |
over->overlay_is_packed_rgb = |
304 | 296 |
ff_fill_rgba_map(over->overlay_rgba_map, inlink->format) >= 0; |
305 | 297 |
over->overlay_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts); |
306 | 298 |
|
307 | 299 |
if (over->eval_mode == EVAL_MODE_INIT) { |
308 |
- eval_expr(ctx); |
|
300 |
+ eval_expr(ctx, EVAL_ALL); |
|
309 | 301 |
av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d enable:%f\n", |
310 | 302 |
over->var_values[VAR_X], over->x, |
311 | 303 |
over->var_values[VAR_Y], over->y, |
... | ... |
@@ -319,11 +359,6 @@ static int config_input_overlay(AVFilterLink *inlink) |
319 | 319 |
ctx->inputs[OVERLAY]->w, ctx->inputs[OVERLAY]->h, |
320 | 320 |
av_get_pix_fmt_name(ctx->inputs[OVERLAY]->format)); |
321 | 321 |
return 0; |
322 |
- |
|
323 |
-fail: |
|
324 |
- av_log(NULL, AV_LOG_ERROR, |
|
325 |
- "Error when parsing the expression '%s'\n", expr); |
|
326 |
- return ret; |
|
327 | 322 |
} |
328 | 323 |
|
329 | 324 |
static int config_output(AVFilterLink *outlink) |
... | ... |
@@ -581,7 +616,7 @@ static int try_filter_frame(AVFilterContext *ctx, AVFrame *mainpic) |
581 | 581 |
NAN : mainpic->pts * av_q2d(inlink->time_base); |
582 | 582 |
over->var_values[VAR_POS] = pos == -1 ? NAN : pos; |
583 | 583 |
|
584 |
- eval_expr(ctx); |
|
584 |
+ eval_expr(ctx, EVAL_ALL); |
|
585 | 585 |
av_log(ctx, AV_LOG_DEBUG, "n:%f t:%f pos:%f x:%f xi:%d y:%f yi:%d enable:%f\n", |
586 | 586 |
over->var_values[VAR_N], over->var_values[VAR_T], over->var_values[VAR_POS], |
587 | 587 |
over->var_values[VAR_X], over->x, |
... | ... |
@@ -725,6 +760,7 @@ AVFilter avfilter_vf_overlay = { |
725 | 725 |
.priv_size = sizeof(OverlayContext), |
726 | 726 |
|
727 | 727 |
.query_formats = query_formats, |
728 |
+ .process_command = process_command, |
|
728 | 729 |
|
729 | 730 |
.inputs = avfilter_vf_overlay_inputs, |
730 | 731 |
.outputs = avfilter_vf_overlay_outputs, |