Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames
@ 2025-06-16 22:43 Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status Marton Balint
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

No functional change.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 fftools/ffmpeg_filter.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index e0c40ffe00..a0dc4c745e 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -2672,7 +2672,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
         ret = avfilter_graph_request_oldest(fgt->graph);
         if (ret == AVERROR(EAGAIN)) {
             fgt->next_in = choose_input(fg, fgt);
-            break;
+            return 0;
         } else if (ret < 0) {
             if (ret == AVERROR_EOF)
                 av_log(fg, AV_LOG_VERBOSE, "Filtergraph returned EOF, finishing\n");
@@ -2702,7 +2702,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
         did_step = 1;
     }
 
-    return (fgp->nb_outputs_done == fg->nb_outputs) ? AVERROR_EOF : 0;
+    return AVERROR_EOF;
 }
 
 static void sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational tb)
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status
  2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
@ 2025-06-16 22:43 ` Marton Balint
  2025-06-18 11:39   ` Nicolas George
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 3/7] avfilter/f_select: port to activate Marton Balint
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavfilter/split.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavfilter/split.c b/libavfilter/split.c
index bf004358d8..0557f54cce 100644
--- a/libavfilter/split.c
+++ b/libavfilter/split.c
@@ -98,6 +98,7 @@ static int activate(AVFilterContext *ctx)
         av_frame_free(&in);
         if (ret < 0)
             return ret;
+        return 0;
     }
 
     if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [FFmpeg-devel] [PATCH 3/7] avfilter/f_select: port to activate
  2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status Marton Balint
@ 2025-06-16 22:43 ` Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback Marton Balint
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

Multi-input or multi-output filters should always use activate now.

Fixes ticket #10959.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavfilter/f_select.c | 54 +++++++++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 19 deletions(-)

diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index aa374c6ad0..38fe56623b 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -179,8 +179,6 @@ static const AVOption filt_name##_options[] = {                     \
     { NULL }                                                            \
 }
 
-static int request_frame(AVFilterLink *outlink);
-
 static av_cold int init(AVFilterContext *ctx)
 {
     SelectContext *select = ctx->priv;
@@ -201,7 +199,6 @@ static av_cold int init(AVFilterContext *ctx)
         if (!pad.name)
             return AVERROR(ENOMEM);
         pad.type = ctx->filter->inputs[0].type;
-        pad.request_frame = request_frame;
         if ((ret = ff_append_outpad_free_name(ctx, &pad)) < 0)
             return ret;
     }
@@ -349,7 +346,7 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
     if (isnan(select->var_values[VAR_START_T]))
         select->var_values[VAR_START_T] = TS2D(frame->pts) * av_q2d(inlink->time_base);
 
-    select->var_values[VAR_N  ] = inl->frame_count_out;
+    select->var_values[VAR_N  ] = inl->frame_count_out - 1;
     select->var_values[VAR_PTS] = TS2D(frame->pts);
     select->var_values[VAR_T  ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
     select->var_values[VAR_KEY] = !!(frame->flags & AV_FRAME_FLAG_KEY);
@@ -428,24 +425,44 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
     select->var_values[VAR_PREV_T]   = select->var_values[VAR_T];
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+static int activate(AVFilterContext *ctx)
 {
-    AVFilterContext *ctx = inlink->dst;
     SelectContext *select = ctx->priv;
+    AVFilterLink *inlink = ctx->inputs[0];
+    AVFrame *in;
+    int nb_eofs = 0;
+    int ret;
 
-    select_frame(ctx, frame);
-    if (select->select)
-        return ff_filter_frame(ctx->outputs[select->select_out], frame);
+    for (int i = 0; i < ctx->nb_outputs; i++)
+        nb_eofs += ff_outlink_get_status(ctx->outputs[i]) == AVERROR_EOF;
 
-    av_frame_free(&frame);
-    return 0;
-}
+    if (nb_eofs == ctx->nb_outputs) {
+        ff_inlink_set_status(inlink, AVERROR_EOF);
+        return 0;
+    }
 
-static int request_frame(AVFilterLink *outlink)
-{
-    AVFilterLink *inlink = outlink->src->inputs[0];
-    int ret = ff_request_frame(inlink);
-    return ret;
+    while ((ret = ff_inlink_consume_frame(inlink, &in))) {
+        if (ret < 0)
+            return ret;
+        select_frame(ctx, in);
+        if (select->select)
+            return ff_filter_frame(ctx->outputs[select->select_out], in);
+        av_frame_free(&in);
+    };
+
+    FF_FILTER_FORWARD_STATUS_ALL(inlink, ctx);
+
+    for (int i = 0; i < ctx->nb_outputs; i++) {
+        if (ff_outlink_get_status(ctx->outputs[i]))
+            continue;
+
+        if (ff_outlink_frame_wanted(ctx->outputs[i])) {
+            ff_inlink_request_frame(inlink);
+            return 0;
+        }
+    }
+
+    return FFERROR_NOT_READY;
 }
 
 static av_cold void uninit(AVFilterContext *ctx)
@@ -486,7 +503,6 @@ static const AVFilterPad avfilter_af_aselect_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
-        .filter_frame = filter_frame,
     },
 };
 
@@ -542,7 +558,6 @@ static const AVFilterPad avfilter_vf_select_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
-        .filter_frame = filter_frame,
     },
 };
 
@@ -553,6 +568,7 @@ const FFFilter ff_vf_select = {
     .p.flags       = AVFILTER_FLAG_DYNAMIC_OUTPUTS | AVFILTER_FLAG_METADATA_ONLY,
     .init          = select_init,
     .uninit        = uninit,
+    .activate      = activate,
     .priv_size     = sizeof(SelectContext),
     FILTER_INPUTS(avfilter_vf_select_inputs),
     FILTER_QUERY_FUNC2(query_formats),
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback
  2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 3/7] avfilter/f_select: port to activate Marton Balint
@ 2025-06-16 22:43 ` Marton Balint
  2025-06-16 22:56   ` Andreas Rheinhardt
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 5/7] avfilter/af_aresample: merge request_frame into activate function Marton Balint
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

Sinks without an activate callback (nullsink, anullsink) could cause
AVERROR(EAGAIN)-s in avfilter_graph_request_oldest() even when all the filter
graphs inputs were in EOF state.

Fixes ticket #11624.
Fixes ticket #10988.
Fixes ticket #10990.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavfilter/avfiltergraph.c | 38 ++++++++++++++++++-------------------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 2d6036df74..6f9f46f1ea 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1423,12 +1423,26 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, FilterLinkInternal *li)
     heap_bubble_down(graphi, li, li->age_index);
 }
 
+static int process_legacy_sink_output(FilterLinkInternal *oldesti)
+{
+    AVFilterLink *oldest = &oldesti->l.pub;
+    int ret;
+
+    do {
+        if (oldesti->frame_wanted_out)
+            ret = ff_filter_graph_run_once(oldest->dst->graph);
+        else
+            ret = ff_request_frame(oldest);
+    } while (ret >= 0);
+
+    return ret;
+}
+
 int avfilter_graph_request_oldest(AVFilterGraph *graph)
 {
     FFFilterGraph *graphi = fffiltergraph(graph);
     FilterLinkInternal *oldesti = graphi->sink_links[0];
     AVFilterLink *oldest = &oldesti->l.pub;
-    int64_t frame_count;
     int r;
 
     while (graphi->sink_links_count) {
@@ -1437,13 +1451,11 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
         if (fffilter(oldest->dst->filter)->activate) {
             r = av_buffersink_get_frame_flags(oldest->dst, NULL,
                                               AV_BUFFERSINK_FLAG_PEEK);
-            if (r != AVERROR_EOF)
-                return r;
         } else {
-            r = ff_request_frame(oldest);
+            r = process_legacy_sink_output(oldesti);
         }
         if (r != AVERROR_EOF)
-            break;
+            return r;
         av_log(oldest->dst, AV_LOG_DEBUG, "EOF on sink link %s:%s.\n",
                oldest->dst->name,
                oldest->dstpad->name);
@@ -1453,21 +1465,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
                              oldesti->age_index);
         oldesti->age_index = -1;
     }
-    if (!graphi->sink_links_count)
-        return AVERROR_EOF;
-    av_assert1(!fffilter(oldest->dst->filter)->activate);
-    av_assert1(oldesti->age_index >= 0);
-    frame_count = oldesti->l.frame_count_out;
-    while (frame_count == oldesti->l.frame_count_out) {
-        r = ff_filter_graph_run_once(graph);
-        if (r == AVERROR(EAGAIN) &&
-            !oldesti->frame_wanted_out && !oldesti->frame_blocked_in &&
-            !oldesti->status_in)
-            (void)ff_request_frame(oldest);
-        else if (r < 0)
-            return r;
-    }
-    return 0;
+    return AVERROR_EOF;
 }
 
 int ff_filter_graph_run_once(AVFilterGraph *graph)
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [FFmpeg-devel] [PATCH 5/7] avfilter/af_aresample: merge request_frame into activate function
  2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
                   ` (2 preceding siblings ...)
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback Marton Balint
@ 2025-06-16 22:43 ` Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 6/7] avfilter/af_aresample: make aresample return FFERROR_NOT_READY when no progress can be made Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 7/7] avfilter/af_aresample: rework activate logic to follow the advised flow more strictly Marton Balint
  5 siblings, 0 replies; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

No functional change.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavfilter/af_aresample.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 58e09906e0..703fb7c92d 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -302,14 +302,26 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref
     return 0;
 }
 
-static int request_frame(AVFilterLink *outlink)
+static int activate(AVFilterContext *ctx)
 {
-    AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
+    AVFilterLink *outlink = ctx->outputs[0];
     AResampleContext *aresample = ctx->priv;
     int ret = 0, status;
     int64_t pts;
 
+    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
+
+    if (!aresample->eof && ff_inlink_queued_frames(inlink)) {
+        AVFrame *frame = NULL;
+
+        ret = ff_inlink_consume_frame(inlink, &frame);
+        if (ret < 0)
+            return ret;
+        if (ret > 0)
+            return filter_frame(inlink, frame);
+    }
+
     // First try to get data from the internal buffers
     if (aresample->more_data) {
         AVFrame *outsamplesref;
@@ -346,28 +358,6 @@ static int request_frame(AVFilterLink *outlink)
     return 0;
 }
 
-static int activate(AVFilterContext *ctx)
-{
-    AResampleContext *aresample = ctx->priv;
-    AVFilterLink *inlink = ctx->inputs[0];
-    AVFilterLink *outlink = ctx->outputs[0];
-
-    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
-
-    if (!aresample->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 filter_frame(inlink, frame);
-    }
-
-    return request_frame(outlink);
-}
-
 static const AVClass *resample_child_class_iterate(void **iter)
 {
     const AVClass *c = *iter ? NULL : swr_get_class();
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [FFmpeg-devel] [PATCH 6/7] avfilter/af_aresample: make aresample return FFERROR_NOT_READY when no progress can be made
  2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
                   ` (3 preceding siblings ...)
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 5/7] avfilter/af_aresample: merge request_frame into activate function Marton Balint
@ 2025-06-16 22:43 ` Marton Balint
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 7/7] avfilter/af_aresample: rework activate logic to follow the advised flow more strictly Marton Balint
  5 siblings, 0 replies; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

FF_FILTER_FORWARD_WANTED() already sets the ready status as needed.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavfilter/af_aresample.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 703fb7c92d..4b3a732bb9 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -354,8 +354,7 @@ static int activate(AVFilterContext *ctx)
         return ff_filter_frame(outlink, outsamplesref);
     }
 
-    ff_filter_set_ready(ctx, 100);
-    return 0;
+    return FFERROR_NOT_READY;
 }
 
 static const AVClass *resample_child_class_iterate(void **iter)
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [FFmpeg-devel] [PATCH 7/7] avfilter/af_aresample: rework activate logic to follow the advised flow more strictly
  2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
                   ` (4 preceding siblings ...)
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 6/7] avfilter/af_aresample: make aresample return FFERROR_NOT_READY when no progress can be made Marton Balint
@ 2025-06-16 22:43 ` Marton Balint
  5 siblings, 0 replies; 12+ messages in thread
From: Marton Balint @ 2025-06-16 22:43 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marton Balint

This should prevent the possibility of audio data accumulating.

The commit also cleans up and simplifies the code a bit so all frame producers
(filter_frame(), flush_frame()) functions follow similar logic as
ff_inlink_consume_frame() for the return code.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 libavfilter/af_aresample.c | 74 ++++++++++++++++++--------------------
 1 file changed, 34 insertions(+), 40 deletions(-)

diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 4b3a732bb9..ea9927e7cf 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -43,7 +43,6 @@ typedef struct AResampleContext {
     struct SwrContext *swr;
     int64_t next_pts;
     int more_data;
-    int eof;
 } AResampleContext;
 
 static av_cold int preinit(AVFilterContext *ctx)
@@ -209,7 +208,7 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref, AVFrame **outsamplesref_ret)
 {
     AVFilterContext *ctx = inlink->dst;
     AResampleContext *aresample = ctx->priv;
@@ -220,23 +219,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
     AVFrame *outsamplesref;
     int ret;
 
+    *outsamplesref_ret = NULL;
     delay = swr_get_delay(aresample->swr, outlink->sample_rate);
     if (delay > 0)
         n_out += FFMIN(delay, FFMAX(4096, n_out));
 
     outsamplesref = ff_get_audio_buffer(outlink, n_out);
-
-    if(!outsamplesref) {
-        av_frame_free(&insamplesref);
+    if (!outsamplesref)
         return AVERROR(ENOMEM);
-    }
 
     av_frame_copy_props(outsamplesref, insamplesref);
     outsamplesref->format                = outlink->format;
     ret = av_channel_layout_copy(&outsamplesref->ch_layout, &outlink->ch_layout);
     if (ret < 0) {
         av_frame_free(&outsamplesref);
-        av_frame_free(&insamplesref);
         return ret;
     }
     outsamplesref->sample_rate           = outlink->sample_rate;
@@ -257,8 +253,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
                                  (void *)insamplesref->extended_data, n_in);
     if (n_out <= 0) {
         av_frame_free(&outsamplesref);
-        av_frame_free(&insamplesref);
-        ff_inlink_request_frame(inlink);
         return 0;
     }
 
@@ -266,9 +260,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
 
     outsamplesref->nb_samples  = n_out;
 
-    ret = ff_filter_frame(outlink, outsamplesref);
-    av_frame_free(&insamplesref);
-    return ret;
+    *outsamplesref_ret = outsamplesref;
+    return 1;
 }
 
 static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret)
@@ -291,7 +284,7 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref
     n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0);
     if (n_out <= 0) {
         av_frame_free(&outsamplesref);
-        return (n_out == 0) ? AVERROR_EOF : n_out;
+        return n_out;
     }
 
     outsamplesref->sample_rate = outlink->sample_rate;
@@ -299,7 +292,7 @@ static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref
 
     outsamplesref->pts = pts;
 
-    return 0;
+    return 1;
 }
 
 static int activate(AVFilterContext *ctx)
@@ -307,53 +300,54 @@ static int activate(AVFilterContext *ctx)
     AVFilterLink *inlink = ctx->inputs[0];
     AVFilterLink *outlink = ctx->outputs[0];
     AResampleContext *aresample = ctx->priv;
+    AVFrame *frame;
     int ret = 0, status;
     int64_t pts;
 
     FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
 
-    if (!aresample->eof && ff_inlink_queued_frames(inlink)) {
-        AVFrame *frame = NULL;
+    // First try to get data from the internal buffers
+    if (aresample->more_data) {
+        AVFrame *outsamplesref;
 
-        ret = ff_inlink_consume_frame(inlink, &frame);
+        ret = flush_frame(outlink, 0, &outsamplesref);
         if (ret < 0)
             return ret;
         if (ret > 0)
-            return filter_frame(inlink, frame);
+            return ff_filter_frame(outlink, outsamplesref);
     }
+    aresample->more_data = 0;
 
-    // First try to get data from the internal buffers
-    if (aresample->more_data) {
+    // Then consume frames from inlink
+    while ((ret = ff_inlink_consume_frame(inlink, &frame))) {
         AVFrame *outsamplesref;
+        if (ret < 0)
+            return ret;
 
-        if (flush_frame(outlink, 0, &outsamplesref) >= 0) {
+        ret = filter_frame(inlink, frame, &outsamplesref);
+        av_frame_free(&frame);
+        if (ret < 0)
+            return ret;
+        if (ret > 0)
             return ff_filter_frame(outlink, outsamplesref);
-        }
     }
-    aresample->more_data = 0;
-
-    if (!aresample->eof && ff_inlink_acknowledge_status(inlink, &status, &pts))
-        aresample->eof = 1;
-
-    // Second request more data from the input
-    if (!aresample->eof)
-        FF_FILTER_FORWARD_WANTED(outlink, inlink);
 
-    // Third if we hit the end flush
-    if (aresample->eof) {
+    // If we hit the end flush
+    if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
         AVFrame *outsamplesref;
 
-        if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0) {
-            if (ret == AVERROR_EOF) {
-                ff_outlink_set_status(outlink, AVERROR_EOF, aresample->next_pts);
-                return 0;
-            }
+        ret = flush_frame(outlink, 1, &outsamplesref);
+        if (ret < 0)
             return ret;
-        }
-
-        return ff_filter_frame(outlink, outsamplesref);
+        if (ret > 0)
+            return ff_filter_frame(outlink, outsamplesref);
+        ff_outlink_set_status(outlink, status, aresample->next_pts);
+        return 0;
     }
 
+    // If not, request more data from the input
+    FF_FILTER_FORWARD_WANTED(outlink, inlink);
+
     return FFERROR_NOT_READY;
 }
 
-- 
2.43.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback Marton Balint
@ 2025-06-16 22:56   ` Andreas Rheinhardt
  2025-06-16 23:02     ` Marton Balint
  0 siblings, 1 reply; 12+ messages in thread
From: Andreas Rheinhardt @ 2025-06-16 22:56 UTC (permalink / raw)
  To: ffmpeg-devel

Marton Balint:
> Sinks without an activate callback (nullsink, anullsink) could cause
> AVERROR(EAGAIN)-s in avfilter_graph_request_oldest() even when all the filter
> graphs inputs were in EOF state.
> 
> Fixes ticket #11624.
> Fixes ticket #10988.
> Fixes ticket #10990.
> 
> Signed-off-by: Marton Balint <cus@passwd.hu>
> ---
>  libavfilter/avfiltergraph.c | 38 ++++++++++++++++++-------------------
>  1 file changed, 18 insertions(+), 20 deletions(-)
> 
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index 2d6036df74..6f9f46f1ea 100644
> --- a/libavfilter/avfiltergraph.c
> +++ b/libavfilter/avfiltergraph.c
> @@ -1423,12 +1423,26 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, FilterLinkInternal *li)
>      heap_bubble_down(graphi, li, li->age_index);
>  }
>  
> +static int process_legacy_sink_output(FilterLinkInternal *oldesti)

Why is considered legacy (instead of being just a different API)?

> +{
> +    AVFilterLink *oldest = &oldesti->l.pub;
> +    int ret;
> +
> +    do {
> +        if (oldesti->frame_wanted_out)
> +            ret = ff_filter_graph_run_once(oldest->dst->graph);
> +        else
> +            ret = ff_request_frame(oldest);
> +    } while (ret >= 0);
> +
> +    return ret;
> +}
> +
>  int avfilter_graph_request_oldest(AVFilterGraph *graph)
>  {
>      FFFilterGraph *graphi = fffiltergraph(graph);
>      FilterLinkInternal *oldesti = graphi->sink_links[0];
>      AVFilterLink *oldest = &oldesti->l.pub;
> -    int64_t frame_count;
>      int r;
>  
>      while (graphi->sink_links_count) {
> @@ -1437,13 +1451,11 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
>          if (fffilter(oldest->dst->filter)->activate) {
>              r = av_buffersink_get_frame_flags(oldest->dst, NULL,
>                                                AV_BUFFERSINK_FLAG_PEEK);
> -            if (r != AVERROR_EOF)
> -                return r;
>          } else {
> -            r = ff_request_frame(oldest);
> +            r = process_legacy_sink_output(oldesti);
>          }
>          if (r != AVERROR_EOF)
> -            break;
> +            return r;
>          av_log(oldest->dst, AV_LOG_DEBUG, "EOF on sink link %s:%s.\n",
>                 oldest->dst->name,
>                 oldest->dstpad->name);
> @@ -1453,21 +1465,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
>                               oldesti->age_index);
>          oldesti->age_index = -1;
>      }
> -    if (!graphi->sink_links_count)
> -        return AVERROR_EOF;
> -    av_assert1(!fffilter(oldest->dst->filter)->activate);
> -    av_assert1(oldesti->age_index >= 0);
> -    frame_count = oldesti->l.frame_count_out;
> -    while (frame_count == oldesti->l.frame_count_out) {
> -        r = ff_filter_graph_run_once(graph);
> -        if (r == AVERROR(EAGAIN) &&
> -            !oldesti->frame_wanted_out && !oldesti->frame_blocked_in &&
> -            !oldesti->status_in)
> -            (void)ff_request_frame(oldest);
> -        else if (r < 0)
> -            return r;
> -    }
> -    return 0;
> +    return AVERROR_EOF;
>  }
>  
>  int ff_filter_graph_run_once(AVFilterGraph *graph)

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback
  2025-06-16 22:56   ` Andreas Rheinhardt
@ 2025-06-16 23:02     ` Marton Balint
  2025-06-16 23:54       ` Andreas Rheinhardt
  0 siblings, 1 reply; 12+ messages in thread
From: Marton Balint @ 2025-06-16 23:02 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On Tue, 17 Jun 2025, Andreas Rheinhardt wrote:

> Marton Balint:
>> Sinks without an activate callback (nullsink, anullsink) could cause
>> AVERROR(EAGAIN)-s in avfilter_graph_request_oldest() even when all the filter
>> graphs inputs were in EOF state.
>>
>> Fixes ticket #11624.
>> Fixes ticket #10988.
>> Fixes ticket #10990.
>>
>> Signed-off-by: Marton Balint <cus@passwd.hu>
>> ---
>>  libavfilter/avfiltergraph.c | 38 ++++++++++++++++++-------------------
>>  1 file changed, 18 insertions(+), 20 deletions(-)
>>
>> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
>> index 2d6036df74..6f9f46f1ea 100644
>> --- a/libavfilter/avfiltergraph.c
>> +++ b/libavfilter/avfiltergraph.c
>> @@ -1423,12 +1423,26 @@ void ff_avfilter_graph_update_heap(AVFilterGraph *graph, FilterLinkInternal *li)
>>      heap_bubble_down(graphi, li, li->age_index);
>>  }
>>
>> +static int process_legacy_sink_output(FilterLinkInternal *oldesti)
>
> Why is considered legacy (instead of being just a different API)?
>

The documentation calls it legacy:

doc/filtering_design:

"The design using filter_frame() and request_frame() is legacy, but it is
  suitable for filters that have a single input and process one frame at a
  time."

avfilter/avfilter.c:

"In order to activate a filter implementing the legacy filter_frame()
  and request_frame() methods, perform the first possible of the following
  actions:"

But if you have another name in mind for this, I can change it.

Regards,
Marton
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback
  2025-06-16 23:02     ` Marton Balint
@ 2025-06-16 23:54       ` Andreas Rheinhardt
  2025-06-17 20:07         ` Marton Balint
  0 siblings, 1 reply; 12+ messages in thread
From: Andreas Rheinhardt @ 2025-06-16 23:54 UTC (permalink / raw)
  To: ffmpeg-devel

Marton Balint:
> 
> 
> On Tue, 17 Jun 2025, Andreas Rheinhardt wrote:
> 
>> Marton Balint:
>>> Sinks without an activate callback (nullsink, anullsink) could cause
>>> AVERROR(EAGAIN)-s in avfilter_graph_request_oldest() even when all
>>> the filter
>>> graphs inputs were in EOF state.
>>>
>>> Fixes ticket #11624.
>>> Fixes ticket #10988.
>>> Fixes ticket #10990.
>>>
>>> Signed-off-by: Marton Balint <cus@passwd.hu>
>>> ---
>>>  libavfilter/avfiltergraph.c | 38 ++++++++++++++++++-------------------
>>>  1 file changed, 18 insertions(+), 20 deletions(-)
>>>
>>> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
>>> index 2d6036df74..6f9f46f1ea 100644
>>> --- a/libavfilter/avfiltergraph.c
>>> +++ b/libavfilter/avfiltergraph.c
>>> @@ -1423,12 +1423,26 @@ void
>>> ff_avfilter_graph_update_heap(AVFilterGraph *graph,
>>> FilterLinkInternal *li)
>>>      heap_bubble_down(graphi, li, li->age_index);
>>>  }
>>>
>>> +static int process_legacy_sink_output(FilterLinkInternal *oldesti)
>>
>> Why is considered legacy (instead of being just a different API)?
>>
> 
> The documentation calls it legacy:
> 
> doc/filtering_design:
> 
> "The design using filter_frame() and request_frame() is legacy, but it is
>  suitable for filters that have a single input and process one frame at a
>  time."
> 
> avfilter/avfilter.c:
> 
> "In order to activate a filter implementing the legacy filter_frame()
>  and request_frame() methods, perform the first possible of the following
>  actions:"
> 
> But if you have another name in mind for this, I can change it.
> 
Why not just call it the "simple" API?

- Andreas

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback
  2025-06-16 23:54       ` Andreas Rheinhardt
@ 2025-06-17 20:07         ` Marton Balint
  0 siblings, 0 replies; 12+ messages in thread
From: Marton Balint @ 2025-06-17 20:07 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On Tue, 17 Jun 2025, Andreas Rheinhardt wrote:

> Marton Balint:
>> 
>> 
>> On Tue, 17 Jun 2025, Andreas Rheinhardt wrote:
>> 
>>> Marton Balint:
>>>> Sinks without an activate callback (nullsink, anullsink) could cause
>>>> AVERROR(EAGAIN)-s in avfilter_graph_request_oldest() even when all
>>>> the filter
>>>> graphs inputs were in EOF state.
>>>>
>>>> Fixes ticket #11624.
>>>> Fixes ticket #10988.
>>>> Fixes ticket #10990.
>>>>
>>>> Signed-off-by: Marton Balint <cus@passwd.hu>
>>>> ---
>>>>  libavfilter/avfiltergraph.c | 38 ++++++++++++++++++-------------------
>>>>  1 file changed, 18 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
>>>> index 2d6036df74..6f9f46f1ea 100644
>>>> --- a/libavfilter/avfiltergraph.c
>>>> +++ b/libavfilter/avfiltergraph.c
>>>> @@ -1423,12 +1423,26 @@ void
>>>> ff_avfilter_graph_update_heap(AVFilterGraph *graph,
>>>> FilterLinkInternal *li)
>>>>      heap_bubble_down(graphi, li, li->age_index);
>>>>  }
>>>>
>>>> +static int process_legacy_sink_output(FilterLinkInternal *oldesti)
>>>
>>> Why is considered legacy (instead of being just a different API)?
>>>
>> 
>> The documentation calls it legacy:
>> 
>> doc/filtering_design:
>> 
>> "The design using filter_frame() and request_frame() is legacy, but it is
>>  suitable for filters that have a single input and process one frame at a
>>  time."
>> 
>> avfilter/avfilter.c:
>> 
>> "In order to activate a filter implementing the legacy filter_frame()
>>  and request_frame() methods, perform the first possible of the following
>>  actions:"
>> 
>> But if you have another name in mind for this, I can change it.
>> 
> Why not just call it the "simple" API?

Ok, changed locally the function name to process_simple_api_sink().

Regards,
Marton
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status
  2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status Marton Balint
@ 2025-06-18 11:39   ` Nicolas George
  0 siblings, 0 replies; 12+ messages in thread
From: Nicolas George @ 2025-06-18 11:39 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: Marton Balint

Marton Balint (HE12025-06-17):
> Signed-off-by: Marton Balint <cus@passwd.hu>
> ---
>  libavfilter/split.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/libavfilter/split.c b/libavfilter/split.c
> index bf004358d8..0557f54cce 100644
> --- a/libavfilter/split.c
> +++ b/libavfilter/split.c
> @@ -98,6 +98,7 @@ static int activate(AVFilterContext *ctx)
>          av_frame_free(&in);
>          if (ret < 0)
>              return ret;
> +        return 0;
>      }
>  
>      if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {

LGTM, good catch.

Regards,

-- 
  Nicolas George
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-06-18 11:40 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-16 22:43 [FFmpeg-devel] [PATCH 1/7] fftools/ffmpeg_filter: simplify control flow in read_frames Marton Balint
2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 2/7] avfilter/split: consume all frames before forwarding inlink status Marton Balint
2025-06-18 11:39   ` Nicolas George
2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 3/7] avfilter/f_select: port to activate Marton Balint
2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 4/7] avfilter/avfilter: simplify processing sinks without activate callback Marton Balint
2025-06-16 22:56   ` Andreas Rheinhardt
2025-06-16 23:02     ` Marton Balint
2025-06-16 23:54       ` Andreas Rheinhardt
2025-06-17 20:07         ` Marton Balint
2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 5/7] avfilter/af_aresample: merge request_frame into activate function Marton Balint
2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 6/7] avfilter/af_aresample: make aresample return FFERROR_NOT_READY when no progress can be made Marton Balint
2025-06-16 22:43 ` [FFmpeg-devel] [PATCH 7/7] avfilter/af_aresample: rework activate logic to follow the advised flow more strictly Marton Balint

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git