From patchwork Mon May 1 21:01:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Afanasyev X-Patchwork-Id: 41439 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:dca6:b0:f3:34fa:f187 with SMTP id ky38csp3481734pzb; Mon, 1 May 2023 14:00:36 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6dbkAy1gGEdHN7IyAkPTzWv47GkF/wwaL68mdyse+TQcHWFo66ZSAAEh14bEMDDhjW40nW X-Received: by 2002:a17:907:26ca:b0:94e:46ef:1361 with SMTP id bp10-20020a17090726ca00b0094e46ef1361mr13079610ejc.34.1682974835888; Mon, 01 May 2023 14:00:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1682974835; cv=none; d=google.com; s=arc-20160816; b=P5SpznsESmvWzF3ApEI/eWXjwJ4V3DphkRX7WeEr6jnuBpkvnCJC50xUCpEn8rc6xd PyiAfaQseKjuaZKU12kniFsca3zen3SbrkvllG98JQ2DB8fHE8KCD7A2F5r9eP4EN/0P 4tRVdnZjMvE9YdjJ+d4MrsfzhtAb5r4jo11S77Nn0zCMcPn1mwBMbi04cjH7rH8ukPxq e5oqsHzt5/VCmVafK5CTjsu8BDBYP7/vL9rWjxVdIfV4GfwOZiebEyLlCvX+HaEgKFEP +1fySmhrSTyR1cbFTfoC8pfie5ogH9jlF0yE2WKbce4lhcke94JGo314Gc6XXhknzmvP J7dw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to :message-id:date:from:mime-version:dkim-signature:delivered-to; bh=KnDnA9zqLRBenes580cW06vTfj2ZF1n7COlKhd6f05I=; b=HC1p9GVW9EuwFj/PtbUfMK5Gtb4AWTcdNM8ePbF3tBISW3eCzfVvAoReGR/4gl08Rc VXgIjSYgePWzFJNgpo40V+o9bkXFSGLzSV2LAXazMdbKQT7IjkBpDsZ0VwfKpb+/X3Bj 2ssPXBAwKQjCvN2+5LM/bm05/GhBPqOvHY4BQhPxsS4wor+XmOfzz6u+Vl1T4hV30tgF UUhRSz0F+8NAVyl2ZPeVHudPqPCyMNTVKe6gFQTnnV5PtOgnAG0h1n6RK4ZHlADE7XDU 07HvlhdOUKLIHEr41QoQwugsAn49Y7XrDfBW1w0hO1yqdCD+3q3DEthBp70ywu0k8OhZ a7bQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20221208 header.b=W0YP7+4p; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id ga24-20020a1709070c1800b0094f7a9b69dbsi26610037ejc.931.2023.05.01.14.00.34; Mon, 01 May 2023 14:00:35 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20221208 header.b=W0YP7+4p; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7C37468BEC4; Tue, 2 May 2023 00:00:30 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A4BF868BEC4 for ; Tue, 2 May 2023 00:00:23 +0300 (EEST) Received: by mail-ej1-f41.google.com with SMTP id a640c23a62f3a-94f3cd32799so604245966b.0 for ; Mon, 01 May 2023 14:00:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1682974822; x=1685566822; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=XqLPho8JHVWSncg+38JZkt8CGshfwalKk/adCoiU8RY=; b=W0YP7+4pWI4XWXOjj5wi4GxZUDu5WQByrEOvcB8Lmlgg8+py7jeMm4uPuiNm4Kv4i8 Y2LE14pucPibXlc93yk3dTDWu0UZzbEHZJ3vcjwwNGJkk3aEBzxu0XMgv+HWDZWnmVcv woLsPdSSUhc0zSrpNF4gEtAmc0tzWyiey9KcGZAKCLWlUWQJNImbSucqvzfm7n51Jee8 K1hTmog2ihs9AKWg+vuj2ca42cTocJ5WRfnraTMgy5Kqsi6Lf7BCy0ka/Br+fmMImJOg qjsakSTzKWgVRtaSXXwUBmv5ghOYpmDaVPiHY6PzNw+OTEwy3Cz3+FK5zNsrVChcECTf LQ8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1682974822; x=1685566822; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=XqLPho8JHVWSncg+38JZkt8CGshfwalKk/adCoiU8RY=; b=IY3pb/Kh7SE2GuofRderLh7W0QU6YEDTGoufnlnlN2R5fuCoS9+IV880t09qjjW6qX W0PPyvWe1qoIYpVWd9v13d4vAFyV6osxzWFs80msCxvGr2ZvKpIyZGFk+dZremRXXvt5 diGWQMlm1TfoFoXbRJ4tdEfSbmssPZnYOkFJiqBmmqOfvRK9FR+9Dp58EkeevTF7tYRo HwRMoELSGJynQhsdfVx92GbGYzoWUkWlG3qeyad+/m9wPAQ8Z0d5AETY1CZ9yP+8i6eh cPcD6dosdKQVZvrHf7218WVwPbRhV9i1wRUs4yWMSNcOWque80Id/+FAbVdsYZJrjCej ykvQ== X-Gm-Message-State: AC+VfDxbnX4n2U4bgeCYZZFoc2q1Jyn+S6HgFm7HCuvh5jR19yShrsI0 bh7FRG8OYrr8bm395s8ZT6Vvj6I7+jqBP7GpEFZxtwcW X-Received: by 2002:a17:906:eec8:b0:93e:fa12:aa1a with SMTP id wu8-20020a170906eec800b0093efa12aa1amr14308333ejb.1.1682974821951; Mon, 01 May 2023 14:00:21 -0700 (PDT) MIME-Version: 1.0 From: Oleg Afanasyev Date: Mon, 1 May 2023 22:01:05 +0100 Message-ID: To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH] avfilter/setpts: add command support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: Zc1qHyDML8yY 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 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 --- 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 --- 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..7b09ce7707 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,40 @@ 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; + 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); + } + 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 +329,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 +348,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 +369,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