From patchwork Thu May 18 10:17:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 41710 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:ba91:b0:105:feb:71f2 with SMTP id fb17csp368852pzb; Thu, 18 May 2023 03:18:20 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6o9+B2+BH0BtAADbgOmnkg5tPsC6wq1LX2K8YGXY/Hq0F0H/DiqGfgNvSZ3MwSA/Qcj5L6 X-Received: by 2002:a17:906:7947:b0:94e:dd68:aba1 with SMTP id l7-20020a170906794700b0094edd68aba1mr41157159ejo.67.1684405099815; Thu, 18 May 2023 03:18:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684405099; cv=none; d=google.com; s=arc-20160816; b=SO/BBJkqc+VI3NDbVCCa2Pf+7cYbdfxXMnQJnDInSra5RCVnQYH7G6RnivWv+Rg9yC chkk4R0H5EK91mPERx2793lsr6M8WVobvDAkVMnrLOhljS9r6yKb6jjVs5EcnzOOPS0x u+VcoGIK++jMXQsK5ZNChuumo91a13Jz55vCz5C1+FLkOVBaPl2Eg2OBOfiK3fu0tbSa s3Eq8jlNn9Lf3h526RxMotmKb+odtbp+nVUR1in5fwBjWhkHkZEgFk8jUkjT/3Einz1Y 9HnuRl+XHvNPYDAOPlo8fDa/uUorNNekEii2l8iQMSE7E7DtoyqFQBHpKSnhqbjpy2Hd lE4g== 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=tgzDCioLlPyQ4CK3MQaEkIiJsLgw8LCp1gV67Q9uL0Y=; b=kmwkyyw5/rDBmiFtDm0IMknFvyHqBbFEjqrPdqOEpofb4wJhSl5EJZBltpoV8NgKug uQYiHQijdOqJhcJHnjipZ+tCn1CyxqCEdA0Tdb8/4w7vhsCR37jz8wABvxyxrhqBCKT6 EoU4wBjqOLBuQ8mfS0MWXw1z79R3uIBl3gMs0tl7zV1/Qhu8zdJgMzuQY9ehGHHhOxSZ UTQU1BKtuK2jCQLGHDFx00ajdCAkNT6vK2lC4F9Lkuw21m3Cd0jJfecmb+lEYQJefl/t Sj7OyeGfTd1C1kabv1qe4xr6y8URyPd9jZROE9XD/U4MZIXla2u4yajh099GeNMNVA82 6EvQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20221208 header.b=mOHBn4Ys; 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 bl24-20020a170906c25800b0094f7d249bf1si1135164ejb.484.2023.05.18.03.18.19; Thu, 18 May 2023 03:18:19 -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=mOHBn4Ys; 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 8F7CD68C156; Thu, 18 May 2023 13:18:16 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-vk1-f174.google.com (mail-vk1-f174.google.com [209.85.221.174]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8DE0D68C07A for ; Thu, 18 May 2023 13:18:09 +0300 (EEST) Received: by mail-vk1-f174.google.com with SMTP id 71dfb90a1353d-452f92680ecso608137e0c.1 for ; Thu, 18 May 2023 03:18:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1684405088; x=1686997088; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=F1gbmXkmbI9FVeZWevV8gk3epGP87zy1RAiF5JZBzMk=; b=mOHBn4Ys2689jUZm8KREhiUFg7nq8BrGxI+pPa7mpm7VZRMQDAUN3oSVay0fl3gfl0 ztl57lysuYIqlQpZKhsFrLTHO0Fw34qJWfXXOkByELQ06vmO/UIBjUUn0KZnFqP/t45x T1M96Xl8v7qhLFbz1u96TD3K3eUyCkvhgGclcY+EOLjViuCNiQuh5BOf3MvnXOATFbfT zNY3OD/pBVqpKEJKD14yPwyxVqeyxittLDadA0COmwVtWr0ndDIaYxb2oIAuUks0mlFD xHl2utB+UMPmhyRIDCGqeE9mY6H1FC9KODoUVxtPXw/5kF3exxF41lHa6v+sStWbix1W 7fKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684405088; x=1686997088; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=F1gbmXkmbI9FVeZWevV8gk3epGP87zy1RAiF5JZBzMk=; b=WKmYwsnSwmhzieRgu4yK+aENjuPF1IgwkOuKOYEnE3xDSebGmWnAi/ZjjUGOwNPhqV Xtcr9OeADUZwUVlI4XyCFlhRSjGempuhFLjNiVi9pCSZ++KxKpmntYdqOrFgqfhTtDga 8t0dTj4DGA6rHBzCWYtUXM2xz+8xCzNX1dzMwUeAxLME5hb46jWVrUl6qjAhjEtjgZGu 3K7eYnsh4UFOL+CvvXkYcJ0avt5ksFyy45AhYnVoLlctehehSkBPJsHWMZQ1ENfy3gYh oMPw6juK5sSN9EuktxUGoicDcsg55U7IunL+NVvzjlP8Gry1D3Kcg87i35x2wbi91a89 h+xw== X-Gm-Message-State: AC+VfDzJjKU11UrzCpIHoZXo6CHh14UW9ntYVdFCe9TVHyXMOeQXtR+P St5kczjNpveca+0WWI+FoKBIC832zcRIXOGo0LjmbZnu X-Received: by 2002:a1f:4391:0:b0:440:3ef7:35ba with SMTP id q139-20020a1f4391000000b004403ef735bamr390527vka.13.1684405088043; Thu, 18 May 2023 03:18:08 -0700 (PDT) MIME-Version: 1.0 From: Paul B Mahol Date: Thu, 18 May 2023 12:17:29 +0200 Message-ID: To: FFmpeg development discussions and patches X-Content-Filtered-By: Mailman/MimeDel 2.1.29 Subject: [FFmpeg-devel] [PATCH] avfilter/trim: switch to activate 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: nqGL3df13lKk To provide EOF pts and also signal EOF to its inputs when dropping all remaining frames. Attached. From 6aba088d4a994f90efec01308056684d52b04f5d Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 17 May 2023 00:46:29 +0200 Subject: [PATCH] avfilter/trim: switch to activate Signed-off-by: Paul B Mahol --- libavfilter/trim.c | 214 +++++++++++++++++++++++++++------------------ 1 file changed, 131 insertions(+), 83 deletions(-) diff --git a/libavfilter/trim.c b/libavfilter/trim.c index ee6e821cd2..6bb567879d 100644 --- a/libavfilter/trim.c +++ b/libavfilter/trim.c @@ -31,6 +31,7 @@ #include "audio.h" #include "avfilter.h" #include "internal.h" +#include "filters.h" typedef struct TrimContext { const AVClass *class; @@ -68,6 +69,8 @@ typedef struct TrimContext { int64_t next_pts; int eof; + + int (*filter_frame)(AVFilterLink *inlink, AVFrame *frame); } TrimContext; static av_cold int init(AVFilterContext *ctx) @@ -79,47 +82,6 @@ static av_cold int init(AVFilterContext *ctx) return 0; } -static int config_input(AVFilterLink *inlink) -{ - AVFilterContext *ctx = inlink->dst; - TrimContext *s = ctx->priv; - AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ? - inlink->time_base : (AVRational){ 1, inlink->sample_rate }; - - if (s->start_time != INT64_MAX) { - int64_t start_pts = av_rescale_q(s->start_time, AV_TIME_BASE_Q, tb); - if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts) - s->start_pts = start_pts; - } - if (s->end_time != INT64_MAX) { - int64_t end_pts = av_rescale_q(s->end_time, AV_TIME_BASE_Q, tb); - if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts) - s->end_pts = end_pts; - } - if (s->duration) - s->duration_tb = av_rescale_q(s->duration, AV_TIME_BASE_Q, tb); - - return 0; -} - -#define OFFSET(x) offsetof(TrimContext, x) -#define COMMON_OPTS \ - { "start", "Timestamp of the first frame that " \ - "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ - { "starti", "Timestamp of the first frame that " \ - "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ - { "end", "Timestamp of the first frame that " \ - "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ - { "endi", "Timestamp of the first frame that " \ - "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ - { "start_pts", "Timestamp of the first frame that should be " \ - " passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ - { "end_pts", "Timestamp of the first frame that should be " \ - "dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ - { "duration", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, \ - { "durationi", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, - - #if CONFIG_TRIM_FILTER static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) { @@ -161,7 +123,8 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) if (drop) { s->eof = 1; - ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); + ff_inlink_set_status(inlink, AVERROR_EOF); + ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, frame->pts); goto drop; } } @@ -171,49 +134,12 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) return ff_filter_frame(ctx->outputs[0], frame); drop: + if (!s->eof) + ff_filter_set_ready(ctx, 100); s->nb_frames++; av_frame_free(&frame); return 0; } - -#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM -static const AVOption trim_options[] = { - COMMON_OPTS - { "start_frame", "Number of the first frame that should be passed " - "to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, - { "end_frame", "Number of the first frame that should be dropped " - "again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS }, - { NULL } -}; -#undef FLAGS - -AVFILTER_DEFINE_CLASS(trim); - -static const AVFilterPad trim_inputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = trim_filter_frame, - .config_props = config_input, - }, -}; - -static const AVFilterPad trim_outputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - }, -}; - -const AVFilter ff_vf_trim = { - .name = "trim", - .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), - .init = init, - .priv_size = sizeof(TrimContext), - .priv_class = &trim_class, - FILTER_INPUTS(trim_inputs), - FILTER_OUTPUTS(trim_outputs), -}; #endif // CONFIG_TRIM_FILTER #if CONFIG_ATRIM_FILTER @@ -290,7 +216,8 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) if (drop) { s->eof = 1; - ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); + ff_inlink_set_status(inlink, AVERROR_EOF); + ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, frame->pts); goto drop; } } @@ -324,10 +251,131 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) return ff_filter_frame(ctx->outputs[0], frame); drop: + if (!s->eof) + ff_filter_set_ready(ctx, 100); s->nb_samples += frame->nb_samples; av_frame_free(&frame); return 0; } +#endif // CONFIG_ATRIM_FILTER + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + TrimContext *s = ctx->priv; + AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ? + inlink->time_base : (AVRational){ 1, inlink->sample_rate }; + +#if CONFIG_TRIM_FILTER + if (inlink->type == AVMEDIA_TYPE_VIDEO) + s->filter_frame = trim_filter_frame; +#endif +#if CONFIG_ATRIM_FILTER + if (inlink->type == AVMEDIA_TYPE_AUDIO) + s->filter_frame = atrim_filter_frame; +#endif + if (s->start_time != INT64_MAX) { + int64_t start_pts = av_rescale_q(s->start_time, AV_TIME_BASE_Q, tb); + if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts) + s->start_pts = start_pts; + } + if (s->end_time != INT64_MAX) { + int64_t end_pts = av_rescale_q(s->end_time, AV_TIME_BASE_Q, tb); + if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts) + s->end_pts = end_pts; + } + if (s->duration) + s->duration_tb = av_rescale_q(s->duration, AV_TIME_BASE_Q, tb); + + return 0; +} + +static int activate(AVFilterContext *ctx) +{ + TrimContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!s->eof && ff_inlink_queued_frames(inlink)) { + AVFrame *frame = NULL; + int ret; + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) + return s->filter_frame(inlink, frame); + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +#define OFFSET(x) offsetof(TrimContext, x) +#define COMMON_OPTS \ + { "start", "Timestamp of the first frame that " \ + "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ + { "starti", "Timestamp of the first frame that " \ + "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ + { "end", "Timestamp of the first frame that " \ + "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ + { "endi", "Timestamp of the first frame that " \ + "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \ + { "start_pts", "Timestamp of the first frame that should be " \ + " passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ + { "end_pts", "Timestamp of the first frame that should be " \ + "dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \ + { "duration", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, \ + { "durationi", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, + + +#if CONFIG_TRIM_FILTER + +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +static const AVOption trim_options[] = { + COMMON_OPTS + { "start_frame", "Number of the first frame that should be passed " + "to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, + { "end_frame", "Number of the first frame that should be dropped " + "again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS }, + { NULL } +}; +#undef FLAGS + +AVFILTER_DEFINE_CLASS(trim); + +static const AVFilterPad trim_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + }, +}; + +static const AVFilterPad trim_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, +}; + +const AVFilter ff_vf_trim = { + .name = "trim", + .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), + .init = init, + .activate = activate, + .priv_size = sizeof(TrimContext), + .priv_class = &trim_class, + FILTER_INPUTS(trim_inputs), + FILTER_OUTPUTS(trim_outputs), +}; +#endif // CONFIG_TRIM_FILTER + +#if CONFIG_ATRIM_FILTER #define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM static const AVOption atrim_options[] = { @@ -346,7 +394,6 @@ static const AVFilterPad atrim_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = atrim_filter_frame, .config_props = config_input, }, }; @@ -362,6 +409,7 @@ const AVFilter ff_af_atrim = { .name = "atrim", .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."), .init = init, + .activate = activate, .priv_size = sizeof(TrimContext), .priv_class = &atrim_class, .flags = AVFILTER_FLAG_METADATA_ONLY, -- 2.39.1