On Sun, 7 May 2023 at 23:47, Stefano Sabatini <stefa...@gmail.com> wrote: > > On date Monday 2023-05-01 22:01:05 +0100, Oleg Afanasyev wrote: > > I'm using setpts to generate timelapses with slowdowns in the middle. > > Using setpts filter requires complicated expr to handle intervals. This > > patch allows commands to change expr and also adds a constant that > > provides time of last command applications to allow specifying gradual > > changes using difference between time and cmd time. > > > > ---------------------- > > with best regards > > Oleg Afanasyev > > > From a714a0957a57c1d392feca0ba675ba5ac7c875ee Mon Sep 17 00:00:00 2001 > > From: Oleg <oafanas...@gmail.com> > > Date: Sat, 29 Apr 2023 19:56:46 +0100 > > Subject: [PATCH] avfilter/setpts: add command support > > > > Add support for changing expr on the fly. > > > > Signed-off-by: Oleg <oafanas...@gmail.com> > > --- > > doc/filters.texi | 7 +++++ > > libavfilter/setpts.c | 68 +++++++++++++++++++++++++++++++++----------- > > 2 files changed, 58 insertions(+), 17 deletions(-) > > > > diff --git a/doc/filters.texi b/doc/filters.texi > > index 50e1682144..fbdb1f8ecf 100644 > > diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c > > index 5bcc0c2dcf..7b09ce7707 100644 > > --- a/libavfilter/setpts.c > > +++ b/libavfilter/setpts.c > [...] > > +static int process_command(AVFilterContext *ctx, const char *cmd, const > > char *arg, > > + char *res, int res_len, int flags) > > +{ > > + SetPTSContext *setpts = ctx->priv; > > + int ret; > > + > > + ret = ff_filter_process_command(ctx, cmd, arg, res, res_len, flags); > > + > > + if (ret < 0) > > + return ret; > > + > > > + if (!strcmp(cmd, "expr")) { > > + av_expr_free(setpts->expr); > > + ret = av_expr_parse(&setpts->expr, arg, var_names, NULL, NULL, > > NULL, NULL, 0, ctx); > > + if (ret < 0) { > > + av_log(ctx, AV_LOG_ERROR, "Error while parsing expression > > '%s'\n", arg); > > + } > > what happens in case setpts->expr is freed and this fails? > > probably it should keep a reference to expr and remove it only in case > the new expression was successfully parsed
Fixed! Didn't realize that encoding continues even if command fails, so it was crashing with the previous expression still in place. > > [...] > > Looks good to me otherwise. > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
From a50bf9e58a0f90d63aba3c84de40f31dc22ebfce Mon Sep 17 00:00:00 2001 From: Oleg <oafanas...@gmail.com> Date: Sat, 29 Apr 2023 19:56:46 +0100 Subject: [PATCH] avfilter/setpts: add command support Add support for changing expr on the fly. Signed-off-by: Oleg <oafanas...@gmail.com> --- doc/filters.texi | 7 +++++ libavfilter/setpts.c | 73 +++++++++++++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 50e1682144..fbdb1f8ecf 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -29384,6 +29384,9 @@ The wallclock (RTC) time at the start of the movie in microseconds. @item TB The timebase of the input timestamps. +@item T_CHANGE +Time of the first frame after command was applied or time of the first frame if no commands. + @end table @subsection Examples @@ -29439,6 +29442,10 @@ asetpts=N/SR/TB @end itemize +@subsection Commands + +Both filters support all above options as @ref{commands}. + @section setrange Force color range for the output video frame. diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c index 5bcc0c2dcf..c805a60ee4 100644 --- a/libavfilter/setpts.c +++ b/libavfilter/setpts.c @@ -63,6 +63,7 @@ static const char *const var_names[] = { "S", // Number of samples in the current frame "SR", // Audio sample rate "FR", ///< defined only for constant frame-rate video + "T_CHANGE", ///< time of first frame after latest command was applied NULL }; @@ -90,7 +91,8 @@ enum var_name { VAR_S, VAR_SR, VAR_FR, - VAR_VARS_NB + VAR_T_CHANGE, + VAR_VARS_NB, }; typedef struct SetPTSContext { @@ -120,6 +122,7 @@ static av_cold int init(AVFilterContext *ctx) setpts->var_values[VAR_PREV_OUTT] = NAN; setpts->var_values[VAR_STARTPTS] = NAN; setpts->var_values[VAR_STARTT] = NAN; + setpts->var_values[VAR_T_CHANGE] = NAN; return 0; } @@ -163,6 +166,9 @@ static double eval_pts(SetPTSContext *setpts, AVFilterLink *inlink, AVFrame *fra setpts->var_values[VAR_STARTPTS] = TS2D(pts); setpts->var_values[VAR_STARTT ] = TS2T(pts, inlink->time_base); } + if (isnan(setpts->var_values[VAR_T_CHANGE])) { + setpts->var_values[VAR_T_CHANGE] = TS2T(pts, inlink->time_base); + } setpts->var_values[VAR_PTS ] = TS2D(pts); setpts->var_values[VAR_T ] = TS2T(pts, inlink->time_base); #if FF_API_FRAME_PKT @@ -269,14 +275,45 @@ static av_cold void uninit(AVFilterContext *ctx) setpts->expr = NULL; } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *arg, + char *res, int res_len, int flags) +{ + SetPTSContext *setpts = ctx->priv; + AVExpr *new_expr; + int ret; + + ret = ff_filter_process_command(ctx, cmd, arg, res, res_len, flags); + + if (ret < 0) + return ret; + + if (!strcmp(cmd, "expr")) { + ret = av_expr_parse(&new_expr, arg, var_names, NULL, NULL, NULL, NULL, 0, ctx); + // Only free and replace previous expression if new one succeeds, + // otherwise defensively keep everything intact even if reporting an error. + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", arg); + } else { + av_expr_free(setpts->expr); + setpts->expr = new_expr; + setpts->var_values[VAR_T_CHANGE] = NAN; + } + } else { + ret = AVERROR(EINVAL); + } + + return ret; +} + #define OFFSET(x) offsetof(SetPTSContext, x) #define V AV_OPT_FLAG_VIDEO_PARAM #define A AV_OPT_FLAG_AUDIO_PARAM +#define R AV_OPT_FLAG_RUNTIME_PARAM #define F AV_OPT_FLAG_FILTERING_PARAM #if CONFIG_SETPTS_FILTER static const AVOption setpts_options[] = { - { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = V|F }, + { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = V|F|R }, { NULL } }; AVFILTER_DEFINE_CLASS(setpts); @@ -297,12 +334,13 @@ static const AVFilterPad avfilter_vf_setpts_outputs[] = { }; const AVFilter ff_vf_setpts = { - .name = "setpts", - .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."), - .init = init, - .activate = activate, - .uninit = uninit, - .flags = AVFILTER_FLAG_METADATA_ONLY, + .name = "setpts", + .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."), + .init = init, + .activate = activate, + .uninit = uninit, + .process_command = process_command, + .flags = AVFILTER_FLAG_METADATA_ONLY, .priv_size = sizeof(SetPTSContext), .priv_class = &setpts_class, @@ -315,7 +353,7 @@ const AVFilter ff_vf_setpts = { #if CONFIG_ASETPTS_FILTER static const AVOption asetpts_options[] = { - { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = A|F }, + { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = A|F|R }, { NULL } }; AVFILTER_DEFINE_CLASS(asetpts); @@ -336,14 +374,15 @@ static const AVFilterPad asetpts_outputs[] = { }; const AVFilter ff_af_asetpts = { - .name = "asetpts", - .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."), - .init = init, - .activate = activate, - .uninit = uninit, - .priv_size = sizeof(SetPTSContext), - .priv_class = &asetpts_class, - .flags = AVFILTER_FLAG_METADATA_ONLY, + .name = "asetpts", + .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."), + .init = init, + .activate = activate, + .uninit = uninit, + .process_command = process_command, + .priv_size = sizeof(SetPTSContext), + .priv_class = &asetpts_class, + .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(asetpts_inputs), FILTER_OUTPUTS(asetpts_outputs), }; -- 2.40.0
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".