| @@ -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 | }; |