Add support for changing expr on the fly.
Showing the changes to libavfilter (1 of 3 files). Show all
Unified · Split
| @@ -63,6 +63,7 @@ static const char *const var_names[] = { · 62 unmodified lines | ||
| 63 | 63 | "S", // Number of samples in the current frame |
| 64 | 64 | "SR", // Audio sample rate |
| 65 | 65 | "FR", ///< defined only for constant frame-rate video |
| 66 | + "T_CHANGE", ///< time of first frame after latest command was applied | |
| 66 | 67 | NULL |
| 67 | 68 | }; |
| 68 | 69 | |
| @@ -90,7 +91,8 @@ enum var_name { · 21 unmodified lines | ||
| 90 | 91 | VAR_S, |
| 91 | 92 | VAR_SR, |
| 92 | 93 | VAR_FR, |
| 93 | − VAR_VARS_NB | |
| 94 | + VAR_T_CHANGE, | |
| 95 | + VAR_VARS_NB, | |
| 94 | 96 | }; |
| 95 | 97 | |
| 96 | 98 | typedef struct SetPTSContext { |
| @@ -120,6 +122,7 @@ static av_cold int init(AVFilterContext *ctx) · 23 unmodified lines | ||
| 120 | 122 | setpts->var_values[VAR_PREV_OUTT] = NAN; |
| 121 | 123 | setpts->var_values[VAR_STARTPTS] = NAN; |
| 122 | 124 | setpts->var_values[VAR_STARTT] = NAN; |
| 125 | + setpts->var_values[VAR_T_CHANGE] = NAN; | |
| 123 | 126 | return 0; |
| 124 | 127 | } |
| 125 | 128 | |
| @@ -163,6 +166,9 @@ static double eval_pts(SetPTSContext *setpts, AVFilterLink *inlink, AVFrame *fra · 37 unmodified lines | ||
| 163 | 166 | setpts->var_values[VAR_STARTPTS] = TS2D(pts); |
| 164 | 167 | setpts->var_values[VAR_STARTT ] = TS2T(pts, inlink->time_base); |
| 165 | 168 | } |
| 169 | + if (isnan(setpts->var_values[VAR_T_CHANGE])) { | |
| 170 | + setpts->var_values[VAR_T_CHANGE] = TS2T(pts, inlink->time_base); | |
| 171 | + } | |
| 166 | 172 | setpts->var_values[VAR_PTS ] = TS2D(pts); |
| 167 | 173 | setpts->var_values[VAR_T ] = TS2T(pts, inlink->time_base); |
| 168 | 174 | #if FF_API_FRAME_PKT |
| @@ -269,14 +275,45 @@ static av_cold void uninit(AVFilterContext *ctx) · 100 unmodified lines | ||
| 269 | 275 | setpts->expr = NULL; |
| 270 | 276 | } |
| 271 | 277 | |
| 278 | +static int process_command(AVFilterContext *ctx, const char *cmd, const char *arg, | |
| 279 | + char *res, int res_len, int flags) | |
| 280 | +{ | |
| 281 | + SetPTSContext *setpts = ctx->priv; | |
| 282 | + AVExpr *new_expr; | |
| 283 | + int ret; | |
| 284 | + | |
| 285 | + ret = ff_filter_process_command(ctx, cmd, arg, res, res_len, flags); | |
| 286 | + | |
| 287 | + if (ret < 0) | |
| 288 | + return ret; | |
| 289 | + | |
| 290 | + if (!strcmp(cmd, "expr")) { | |
| 291 | + ret = av_expr_parse(&new_expr, arg, var_names, NULL, NULL, NULL, NULL, 0, ctx); | |
| 292 | + // Only free and replace previous expression if new one succeeds, | |
| 293 | + // otherwise defensively keep everything intact even if reporting an error. | |
| 294 | + if (ret < 0) { | |
| 295 | + av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", arg); | |
| 296 | + } else { | |
| 297 | + av_expr_free(setpts->expr); | |
| 298 | + setpts->expr = new_expr; | |
| 299 | + setpts->var_values[VAR_T_CHANGE] = NAN; | |
| 300 | + } | |
| 301 | + } else { | |
| 302 | + ret = AVERROR(EINVAL); | |
| 303 | + } | |
| 304 | + | |
| 305 | + return ret; | |
| 306 | +} | |
| 307 | + | |
| 272 | 308 | #define OFFSET(x) offsetof(SetPTSContext, x) |
| 273 | 309 | #define V AV_OPT_FLAG_VIDEO_PARAM |
| 274 | 310 | #define A AV_OPT_FLAG_AUDIO_PARAM |
| 311 | +#define R AV_OPT_FLAG_RUNTIME_PARAM | |
| 275 | 312 | #define F AV_OPT_FLAG_FILTERING_PARAM |
| 276 | 313 | |
| 277 | 314 | #if CONFIG_SETPTS_FILTER |
| 278 | 315 | static const AVOption setpts_options[] = { |
| 279 | − { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = V|F }, | |
| 316 | + { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = V|F|R }, | |
| 280 | 317 | { NULL } |
| 281 | 318 | }; |
| 282 | 319 | AVFILTER_DEFINE_CLASS(setpts); |
| @@ -297,12 +334,13 @@ static const AVFilterPad avfilter_vf_setpts_outputs[] = { · 14 unmodified lines | ||
| 297 | 334 | }; |
| 298 | 335 | |
| 299 | 336 | const AVFilter ff_vf_setpts = { |
| 300 | − .name = "setpts", | |
| 301 | − .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."), | |
| 302 | − .init = init, | |
| 303 | − .activate = activate, | |
| 304 | − .uninit = uninit, | |
| 305 | − .flags = AVFILTER_FLAG_METADATA_ONLY, | |
| 337 | + .name = "setpts", | |
| 338 | + .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."), | |
| 339 | + .init = init, | |
| 340 | + .activate = activate, | |
| 341 | + .uninit = uninit, | |
| 342 | + .process_command = process_command, | |
| 343 | + .flags = AVFILTER_FLAG_METADATA_ONLY, | |
| 306 | 344 | |
| 307 | 345 | .priv_size = sizeof(SetPTSContext), |
| 308 | 346 | .priv_class = &setpts_class, |
| @@ -315,7 +353,7 @@ const AVFilter ff_vf_setpts = { · 6 unmodified lines | ||
| 315 | 353 | #if CONFIG_ASETPTS_FILTER |
| 316 | 354 | |
| 317 | 355 | static const AVOption asetpts_options[] = { |
| 318 | − { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = A|F }, | |
| 356 | + { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = A|F|R }, | |
| 319 | 357 | { NULL } |
| 320 | 358 | }; |
| 321 | 359 | AVFILTER_DEFINE_CLASS(asetpts); |
| @@ -336,14 +374,15 @@ static const AVFilterPad asetpts_outputs[] = { · 14 unmodified lines | ||
| 336 | 374 | }; |
| 337 | 375 | |
| 338 | 376 | const AVFilter ff_af_asetpts = { |
| 339 | − .name = "asetpts", | |
| 340 | − .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."), | |
| 341 | − .init = init, | |
| 342 | − .activate = activate, | |
| 343 | − .uninit = uninit, | |
| 344 | − .priv_size = sizeof(SetPTSContext), | |
| 345 | − .priv_class = &asetpts_class, | |
| 346 | − .flags = AVFILTER_FLAG_METADATA_ONLY, | |
| 377 | + .name = "asetpts", | |
| 378 | + .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."), | |
| 379 | + .init = init, | |
| 380 | + .activate = activate, | |
| 381 | + .uninit = uninit, | |
| 382 | + .process_command = process_command, | |
| 383 | + .priv_size = sizeof(SetPTSContext), | |
| 384 | + .priv_class = &asetpts_class, | |
| 385 | + .flags = AVFILTER_FLAG_METADATA_ONLY, | |
| 347 | 386 | FILTER_INPUTS(asetpts_inputs), |
| 348 | 387 | FILTER_OUTPUTS(asetpts_outputs), |
| 349 | 388 | }; |