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 01/10] lavfi: set AVFilterLink.graph on link creation
@ 2024-08-11 14:42 Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 02/10] lavfi: add a new struct for private link properties Anton Khirnov
                   ` (8 more replies)
  0 siblings, 9 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

There is no reason to delay this.
---
 libavfilter/avfilter.c      | 1 +
 libavfilter/avfiltergraph.c | 2 --
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 2dc8820184..c4bd134fb2 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -185,6 +185,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad,
     link->srcpad  = &src->output_pads[srcpad];
     link->dstpad  = &dst->input_pads[dstpad];
     link->type    = src->output_pads[srcpad].type;
+    link->graph   = src->graph;
     av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
     link->format  = -1;
     link->colorspace = AVCOL_SPC_UNSPECIFIED;
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index bd3bed9a35..2791ffa64a 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1208,11 +1208,9 @@ static int graph_config_pointers(AVFilterGraph *graph, void *log_ctx)
     for (i = 0; i < graph->nb_filters; i++) {
         f = graph->filters[i];
         for (j = 0; j < f->nb_inputs; j++) {
-            f->inputs[j]->graph     = graph;
             ff_link_internal(f->inputs[j])->age_index  = -1;
         }
         for (j = 0; j < f->nb_outputs; j++) {
-            f->outputs[j]->graph    = graph;
             ff_link_internal(f->outputs[j])->age_index = -1;
         }
         if (!f->nb_outputs) {
-- 
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 02/10] lavfi: add a new struct for private link properties
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 03/10] lavfi: move AVFilterLink.m{ax, in}_samples to FilterLink Anton Khirnov
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

Specifically those that should be visible to filters, but hidden from
API callers. Such properties are currently located at the end of the
public AVFilterLink struct, demarcated by a comment marking them as
private. However it is generally better to hide them explicitly, using
the same pattern already employed in avformat or avcodec.

The new struct is currently trivial, but will become more useful in
following commits.
---
 libavfilter/avfilter.c          | 10 +++++-----
 libavfilter/avfilter_internal.h |  3 ++-
 libavfilter/avfiltergraph.c     | 10 +++++-----
 libavfilter/filters.h           | 10 ++++++++++
 4 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index c4bd134fb2..80c9cf7b51 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -176,7 +176,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad,
     li = av_mallocz(sizeof(*li));
     if (!li)
         return AVERROR(ENOMEM);
-    link = &li->l;
+    link = &li->l.pub;
 
     src->outputs[srcpad] = dst->inputs[dstpad] = link;
 
@@ -222,7 +222,7 @@ int avfilter_config_links(AVFilterContext *filter)
 
 static void update_link_current_pts(FilterLinkInternal *li, int64_t pts)
 {
-    AVFilterLink *const link = &li->l;
+    AVFilterLink *const link = &li->l.pub;
 
     if (pts == AV_NOPTS_VALUE)
         return;
@@ -1077,7 +1077,7 @@ static int samples_ready(FilterLinkInternal *link, unsigned min)
 static int take_samples(FilterLinkInternal *li, unsigned min, unsigned max,
                         AVFrame **rframe)
 {
-    AVFilterLink *link = &li->l;
+    AVFilterLink *link = &li->l.pub;
     AVFrame *frame0, *frame, *buf;
     unsigned nb_samples, nb_frames, i, p;
     int ret;
@@ -1169,7 +1169,7 @@ static int ff_filter_frame_to_filter(AVFilterLink *link)
 
 static int forward_status_change(AVFilterContext *filter, FilterLinkInternal *li_in)
 {
-    AVFilterLink *in = &li_in->l;
+    AVFilterLink *in = &li_in->l.pub;
     unsigned out = 0, progress = 0;
     int ret;
 
@@ -1431,7 +1431,7 @@ int ff_inlink_check_available_samples(AVFilterLink *link, unsigned min)
 
 static void consume_update(FilterLinkInternal *li, const AVFrame *frame)
 {
-    AVFilterLink *const link = &li->l;
+    AVFilterLink *const link = &li->l.pub;
     update_link_current_pts(li, frame->pts);
     ff_inlink_process_commands(link, frame);
     if (link == link->dst->inputs[0])
diff --git a/libavfilter/avfilter_internal.h b/libavfilter/avfilter_internal.h
index 2c31c3e7de..7084411d68 100644
--- a/libavfilter/avfilter_internal.h
+++ b/libavfilter/avfilter_internal.h
@@ -28,10 +28,11 @@
 #include <stdint.h>
 
 #include "avfilter.h"
+#include "filters.h"
 #include "framequeue.h"
 
 typedef struct FilterLinkInternal {
-    AVFilterLink l;
+    FilterLink l;
 
     struct FFFramePool *frame_pool;
 
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 2791ffa64a..47655703cd 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1326,7 +1326,7 @@ static void heap_bubble_up(FFFilterGraph *graph,
 
     while (index) {
         int parent = (index - 1) >> 1;
-        if (links[parent]->l.current_pts_us >= li->l.current_pts_us)
+        if (links[parent]->l.pub.current_pts_us >= li->l.pub.current_pts_us)
             break;
         links[index] = links[parent];
         links[index]->age_index = index;
@@ -1348,9 +1348,9 @@ static void heap_bubble_down(FFFilterGraph *graph,
         if (child >= graph->sink_links_count)
             break;
         if (child + 1 < graph->sink_links_count &&
-            links[child + 1]->l.current_pts_us < links[child]->l.current_pts_us)
+            links[child + 1]->l.pub.current_pts_us < links[child]->l.pub.current_pts_us)
             child++;
-        if (li->l.current_pts_us < links[child]->l.current_pts_us)
+        if (li->l.pub.current_pts_us < links[child]->l.pub.current_pts_us)
             break;
         links[index] = links[child];
         links[index]->age_index = index;
@@ -1372,13 +1372,13 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
 {
     FFFilterGraph *graphi = fffiltergraph(graph);
     FilterLinkInternal *oldesti = graphi->sink_links[0];
-    AVFilterLink *oldest = &oldesti->l;
+    AVFilterLink *oldest = &oldesti->l.pub;
     int64_t frame_count;
     int r;
 
     while (graphi->sink_links_count) {
         oldesti = graphi->sink_links[0];
-        oldest  = &oldesti->l;
+        oldest  = &oldesti->l.pub;
         if (oldest->dst->filter->activate) {
             r = av_buffersink_get_frame_flags(oldest->dst, NULL,
                                               AV_BUFFERSINK_FLAG_PEEK);
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 86bc49d459..2c856fead7 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -33,6 +33,16 @@
  */
 #define FFERROR_NOT_READY FFERRTAG('N','R','D','Y')
 
+/**
+ * Link properties exposed to filter code, but not external callers.
+ *
+ * Cf. AVFilterLink for public properties, FilterLinkInternal for
+ * properties private to the generic layer.
+ */
+typedef struct FilterLink {
+    AVFilterLink pub;
+} FilterLink;
+
 /**
  * Mark a filter ready and schedule it for activation.
  *
-- 
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 03/10] lavfi: move AVFilterLink.m{ax, in}_samples to FilterLink
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 02/10] lavfi: add a new struct for private link properties Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 04/10] lavfi/vf_*_cuda: do not access hw contexts before checking they exist Anton Khirnov
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

Also, document who sets these fields and when.
---
 libavfilter/af_firequalizer.c |  4 +++-
 libavfilter/af_lv2.c          |  3 ++-
 libavfilter/af_replaygain.c   |  6 ++++--
 libavfilter/avfilter.c        | 13 +++++++------
 libavfilter/avfilter.h        | 15 ---------------
 libavfilter/buffersink.c      |  5 +++--
 libavfilter/filters.h         | 21 +++++++++++++++++++++
 7 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c
index 5108edca48..b889872775 100644
--- a/libavfilter/af_firequalizer.c
+++ b/libavfilter/af_firequalizer.c
@@ -26,6 +26,7 @@
 #include "libavutil/avassert.h"
 #include "libavutil/tx.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "audio.h"
 
@@ -725,6 +726,7 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g
 
 static int config_input(AVFilterLink *inlink)
 {
+    FilterLink *l = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     FIREqualizerContext *s = ctx->priv;
     float iscale, scale = 1.f;
@@ -824,7 +826,7 @@ static int config_input(AVFilterLink *inlink)
            inlink->sample_rate, inlink->ch_layout.nb_channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max);
 
     if (s->fixed)
-        inlink->min_samples = inlink->max_samples = s->nsamples_max;
+        l->min_samples = l->max_samples = s->nsamples_max;
 
     return generate_kernel(ctx, SELECT_GAIN(s), SELECT_GAIN_ENTRY(s));
 }
diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c
index a5980d5e9c..f9425a5828 100644
--- a/libavfilter/af_lv2.c
+++ b/libavfilter/af_lv2.c
@@ -34,6 +34,7 @@
 #include "libavutil/opt.h"
 #include "audio.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 
@@ -381,7 +382,7 @@ static int config_output(AVFilterLink *outlink)
         (lilv_plugin_has_feature(s->plugin, s->powerOf2BlockLength) ||
          lilv_plugin_has_feature(s->plugin, s->fixedBlockLength) ||
          lilv_plugin_has_feature(s->plugin, s->boundedBlockLength))) {
-        AVFilterLink *inlink = ctx->inputs[0];
+        FilterLink *inlink = ff_filter_link(ctx->inputs[0]);
 
         inlink->min_samples = inlink->max_samples = 4096;
     }
diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c
index 266121e2c0..e7b0330e6c 100644
--- a/libavfilter/af_replaygain.c
+++ b/libavfilter/af_replaygain.c
@@ -30,6 +30,7 @@
 #include "libavutil/opt.h"
 #include "audio.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 
@@ -349,6 +350,7 @@ static int query_formats(AVFilterContext *ctx)
 
 static int config_input(AVFilterLink *inlink)
 {
+    FilterLink *l = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     ReplayGainContext *s = ctx->priv;
     int i;
@@ -366,8 +368,8 @@ static int config_input(AVFilterLink *inlink)
 
     s->yule_hist_i   = 20;
     s->butter_hist_i = 4;
-    inlink->min_samples =
-    inlink->max_samples = inlink->sample_rate / 20;
+    l->min_samples =
+    l->max_samples = inlink->sample_rate / 20;
 
     return 0;
 }
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 80c9cf7b51..75e9bf6724 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -1077,14 +1077,15 @@ static int samples_ready(FilterLinkInternal *link, unsigned min)
 static int take_samples(FilterLinkInternal *li, unsigned min, unsigned max,
                         AVFrame **rframe)
 {
-    AVFilterLink *link = &li->l.pub;
+    FilterLink *l = &li->l;
+    AVFilterLink *link = &l->pub;
     AVFrame *frame0, *frame, *buf;
     unsigned nb_samples, nb_frames, i, p;
     int ret;
 
     /* Note: this function relies on no format changes and must only be
        called with enough samples. */
-    av_assert1(samples_ready(li, link->min_samples));
+    av_assert1(samples_ready(li, l->min_samples));
     frame0 = frame = ff_framequeue_peek(&li->fifo, 0);
     if (!li->fifo.samples_skipped && frame->nb_samples >= min && frame->nb_samples <= max) {
         *rframe = ff_framequeue_take(&li->fifo);
@@ -1142,8 +1143,8 @@ static int ff_filter_frame_to_filter(AVFilterLink *link)
     int ret;
 
     av_assert1(ff_framequeue_queued_frames(&li->fifo));
-    ret = link->min_samples ?
-          ff_inlink_consume_samples(link, link->min_samples, link->max_samples, &frame) :
+    ret = li->l.min_samples ?
+          ff_inlink_consume_samples(link, li->l.min_samples, li->l.max_samples, &frame) :
           ff_inlink_consume_frame(link, &frame);
     av_assert1(ret);
     if (ret < 0) {
@@ -1218,8 +1219,8 @@ static int ff_filter_activate_default(AVFilterContext *filter)
     }
 
     for (i = 0; i < filter->nb_inputs; i++) {
-        if (samples_ready(ff_link_internal(filter->inputs[i]),
-                          filter->inputs[i]->min_samples)) {
+        FilterLinkInternal *li = ff_link_internal(filter->inputs[i]);
+        if (samples_ready(li, li->l.min_samples)) {
             return ff_filter_frame_to_filter(filter->inputs[i]);
         }
     }
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index a34e61f23c..2624b0cfca 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -625,21 +625,6 @@ struct AVFilterLink {
      */
     AVRational frame_rate;
 
-    /**
-     * Minimum number of samples to filter at once. If filter_frame() is
-     * called with fewer samples, it will accumulate them in fifo.
-     * This field and the related ones must not be changed after filtering
-     * has started.
-     * If 0, all related fields are ignored.
-     */
-    int min_samples;
-
-    /**
-     * Maximum number of samples to filter at once. If filter_frame() is
-     * called with more samples, it will split them.
-     */
-    int max_samples;
-
     /**
      * Number of past frames sent through the link.
      */
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index e05bd0a573..2c1fa4c293 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -119,7 +119,8 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i
 
 int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
 {
-    return get_frame_internal(ctx, frame, flags, ctx->inputs[0]->min_samples);
+    return get_frame_internal(ctx, frame, flags,
+                              ff_filter_link(ctx->inputs[0])->min_samples);
 }
 
 int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
@@ -163,7 +164,7 @@ static int activate(AVFilterContext *ctx)
 
 void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
 {
-    AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *inlink = ff_filter_link(ctx->inputs[0]);
 
     inlink->min_samples = inlink->max_samples = frame_size;
 }
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 2c856fead7..11064aee13 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -41,8 +41,29 @@
  */
 typedef struct FilterLink {
     AVFilterLink pub;
+
+    /**
+     * Minimum number of samples to filter at once.
+     *
+     * May be set by the link destination filter in its config_props().
+     * If 0, all related fields are ignored.
+     */
+    int min_samples;
+
+    /**
+     * Maximum number of samples to filter at once. If filter_frame() is
+     * called with more samples, it will split them.
+     *
+     * May be set by the link destination filter in its config_props().
+     */
+    int max_samples;
 } FilterLink;
 
+static inline FilterLink* ff_filter_link(AVFilterLink *link)
+{
+    return (FilterLink*)link;
+}
+
 /**
  * Mark a filter ready and schedule it for activation.
  *
-- 
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 04/10] lavfi/vf_*_cuda: do not access hw contexts before checking they exist
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 02/10] lavfi: add a new struct for private link properties Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 03/10] lavfi: move AVFilterLink.m{ax, in}_samples to FilterLink Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 05/10] lavfi: move AVFilterLink.hw_frames_ctx to FilterLink Anton Khirnov
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

The checks are performed in init_processing_chain().
---
 libavfilter/vf_bilateral_cuda.c  | 13 ++++++++-----
 libavfilter/vf_chromakey_cuda.c  | 13 ++++++++-----
 libavfilter/vf_colorspace_cuda.c | 14 ++++++++------
 libavfilter/vf_scale_cuda.c      | 13 ++++++++-----
 4 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/libavfilter/vf_bilateral_cuda.c b/libavfilter/vf_bilateral_cuda.c
index ba008b517a..037227af93 100644
--- a/libavfilter/vf_bilateral_cuda.c
+++ b/libavfilter/vf_bilateral_cuda.c
@@ -249,17 +249,20 @@ static av_cold int cuda_bilateral_config_props(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
     CUDABilateralContext *s  = ctx->priv;
-    AVHWFramesContext     *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
-    AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
+    AVHWFramesContext     *frames_ctx;
+    AVCUDADeviceContext *device_hwctx;
     int ret;
 
-    s->hwctx = device_hwctx;
-    s->cu_stream = s->hwctx->stream;
-
     ret = init_processing_chain(ctx, inlink->w, inlink->h);
     if (ret < 0)
         return ret;
 
+    frames_ctx   = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    device_hwctx = frames_ctx->device_ctx->hwctx;
+
+    s->hwctx = device_hwctx;
+    s->cu_stream = s->hwctx->stream;
+
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
 
     // the window_size makes more sense when it is odd, so add 1 if even
diff --git a/libavfilter/vf_chromakey_cuda.c b/libavfilter/vf_chromakey_cuda.c
index ac644caea7..e38521be0d 100644
--- a/libavfilter/vf_chromakey_cuda.c
+++ b/libavfilter/vf_chromakey_cuda.c
@@ -259,13 +259,10 @@ static av_cold int cudachromakey_config_props(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
     ChromakeyCUDAContext *s = ctx->priv;
-    AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
-    AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
+    AVHWFramesContext *frames_ctx;
+    AVCUDADeviceContext *device_hwctx;
     int ret;
 
-    s->hwctx = device_hwctx;
-    s->cu_stream = s->hwctx->stream;
-
     if (s->is_yuv) {
         s->chromakey_uv[0] = s->chromakey_rgba[1];
         s->chromakey_uv[1] = s->chromakey_rgba[2];
@@ -278,6 +275,12 @@ static av_cold int cudachromakey_config_props(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
+    frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    device_hwctx = frames_ctx->device_ctx->hwctx;
+
+    s->hwctx = device_hwctx;
+    s->cu_stream = s->hwctx->stream;
+
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
 
     ret = cudachromakey_load_functions(ctx);
diff --git a/libavfilter/vf_colorspace_cuda.c b/libavfilter/vf_colorspace_cuda.c
index 5ad81e959c..3949cb7ed8 100644
--- a/libavfilter/vf_colorspace_cuda.c
+++ b/libavfilter/vf_colorspace_cuda.c
@@ -226,14 +226,10 @@ static av_cold int cudacolorspace_config_props(AVFilterLink* outlink)
     AVFilterContext* ctx = outlink->src;
     AVFilterLink* inlink = outlink->src->inputs[0];
     CUDAColorspaceContext* s = ctx->priv;
-    AVHWFramesContext* frames_ctx =
-        (AVHWFramesContext*)inlink->hw_frames_ctx->data;
-    AVCUDADeviceContext* device_hwctx = frames_ctx->device_ctx->hwctx;
+    AVHWFramesContext* frames_ctx;
+    AVCUDADeviceContext* device_hwctx;
     int ret;
 
-    s->hwctx = device_hwctx;
-    s->cu_stream = s->hwctx->stream;
-
     outlink->w = inlink->w;
     outlink->h = inlink->h;
 
@@ -241,6 +237,12 @@ static av_cold int cudacolorspace_config_props(AVFilterLink* outlink)
     if (ret < 0)
         return ret;
 
+    frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    device_hwctx = frames_ctx->device_ctx->hwctx;
+
+    s->hwctx = device_hwctx;
+    s->cu_stream = s->hwctx->stream;
+
     if (inlink->sample_aspect_ratio.num) {
         outlink->sample_aspect_ratio = av_mul_q(
             (AVRational){outlink->h * inlink->w, outlink->w * inlink->h},
diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
index 5571a52b1e..68d17072e3 100644
--- a/libavfilter/vf_scale_cuda.c
+++ b/libavfilter/vf_scale_cuda.c
@@ -349,14 +349,11 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
     CUDAScaleContext *s  = ctx->priv;
-    AVHWFramesContext     *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
-    AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
+    AVHWFramesContext     *frames_ctx;
+    AVCUDADeviceContext *device_hwctx;
     int w, h;
     int ret;
 
-    s->hwctx = device_hwctx;
-    s->cu_stream = s->hwctx->stream;
-
     if ((ret = ff_scale_eval_dimensions(s,
                                         s->w_expr, s->h_expr,
                                         inlink, outlink,
@@ -377,6 +374,12 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
+    frames_ctx   = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    device_hwctx = frames_ctx->device_ctx->hwctx;
+
+    s->hwctx = device_hwctx;
+    s->cu_stream = s->hwctx->stream;
+
     if (inlink->sample_aspect_ratio.num) {
         outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
                                                              outlink->w*inlink->h},
-- 
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 05/10] lavfi: move AVFilterLink.hw_frames_ctx to FilterLink
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
                   ` (2 preceding siblings ...)
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 04/10] lavfi/vf_*_cuda: do not access hw contexts before checking they exist Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 06/10] lavfi: move AVFilterLink.current_pts(_us) " Anton Khirnov
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

---
 libavfilter/avfilter.c              | 24 +++++++++++++++---------
 libavfilter/avfilter.h              |  6 ------
 libavfilter/buffersink.c            |  7 ++++++-
 libavfilter/buffersrc.c             |  5 +++--
 libavfilter/filters.h               |  8 ++++++++
 libavfilter/opencl.c                | 11 +++++++----
 libavfilter/qsvvpp.c                | 19 ++++++++++++-------
 libavfilter/vaapi_vpp.c             | 23 ++++++++++++++---------
 libavfilter/vf_bilateral_cuda.c     | 14 +++++++++-----
 libavfilter/vf_bwdif_cuda.c         | 16 ++++++++++------
 libavfilter/vf_bwdif_vulkan.c       | 15 +++++++++------
 libavfilter/vf_chromakey_cuda.c     | 15 +++++++++------
 libavfilter/vf_colorspace_cuda.c    | 14 +++++++++-----
 libavfilter/vf_deshake_opencl.c     |  3 ++-
 libavfilter/vf_hwdownload.c         |  6 ++++--
 libavfilter/vf_hwmap.c              | 22 +++++++++++++---------
 libavfilter/vf_hwupload.c           | 17 ++++++++++-------
 libavfilter/vf_hwupload_cuda.c      | 11 +++++++----
 libavfilter/vf_libplacebo.c         |  3 ++-
 libavfilter/vf_libvmaf.c            |  7 +++++--
 libavfilter/vf_overlay_cuda.c       | 11 +++++++----
 libavfilter/vf_overlay_qsv.c        | 10 +++++++---
 libavfilter/vf_overlay_vaapi.c      |  4 +++-
 libavfilter/vf_scale_cuda.c         | 16 ++++++++++------
 libavfilter/vf_scale_npp.c          | 21 +++++++++++++--------
 libavfilter/vf_scale_vt.c           | 14 +++++++++-----
 libavfilter/vf_sharpen_npp.c        | 19 ++++++++++++-------
 libavfilter/vf_stack_qsv.c          | 10 ++++++----
 libavfilter/vf_stack_vaapi.c        | 10 ++++++----
 libavfilter/vf_thumbnail_cuda.c     | 11 +++++++----
 libavfilter/vf_transpose_npp.c      | 24 +++++++++++++++---------
 libavfilter/vf_transpose_opencl.c   |  9 ++++++---
 libavfilter/vf_transpose_vaapi.c    |  7 +++++--
 libavfilter/vf_transpose_vt.c       | 20 +++++++++++++-------
 libavfilter/vf_transpose_vulkan.c   |  8 ++++++--
 libavfilter/vf_vpp_qsv.c            | 16 +++++++++-------
 libavfilter/vf_yadif_cuda.c         | 16 ++++++++++------
 libavfilter/vf_yadif_videotoolbox.m | 15 +++++++++------
 libavfilter/video.c                 |  6 +++---
 libavfilter/vsrc_ddagrab.c          |  6 ++++--
 libavfilter/vsrc_testsrc_vulkan.c   |  5 +++--
 libavfilter/vulkan_filter.c         | 15 +++++++++------
 42 files changed, 326 insertions(+), 193 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 75e9bf6724..de74fc2abf 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -206,6 +206,8 @@ static void link_free(AVFilterLink **link)
     ff_frame_pool_uninit(&li->frame_pool);
     av_channel_layout_uninit(&(*link)->ch_layout);
 
+    av_buffer_unref(&li->l.hw_frames_ctx);
+
     av_freep(link);
 }
 
@@ -411,13 +413,18 @@ int ff_filter_config_links(AVFilterContext *filter)
                     link->time_base = (AVRational) {1, link->sample_rate};
             }
 
-            if (link->src->nb_inputs && link->src->inputs[0]->hw_frames_ctx &&
+            if (link->src->nb_inputs &&
                 !(link->src->filter->flags_internal & FF_FILTER_FLAG_HWFRAME_AWARE)) {
-                av_assert0(!link->hw_frames_ctx &&
+                FilterLink *l0 = ff_filter_link(link->src->inputs[0]);
+
+                av_assert0(!li->l.hw_frames_ctx &&
                            "should not be set by non-hwframe-aware filter");
-                link->hw_frames_ctx = av_buffer_ref(link->src->inputs[0]->hw_frames_ctx);
-                if (!link->hw_frames_ctx)
-                    return AVERROR(ENOMEM);
+
+                if (l0->hw_frames_ctx) {
+                    li->l.hw_frames_ctx = av_buffer_ref(l0->hw_frames_ctx);
+                    if (!li->l.hw_frames_ctx)
+                        return AVERROR(ENOMEM);
+                }
             }
 
             if ((config_link = link->dstpad->config_props))
@@ -765,8 +772,6 @@ static void free_link(AVFilterLink *link)
     if (link->dst)
         link->dst->inputs[link->dstpad - link->dst->input_pads] = NULL;
 
-    av_buffer_unref(&link->hw_frames_ctx);
-
     ff_formats_unref(&link->incfg.formats);
     ff_formats_unref(&link->outcfg.formats);
     ff_formats_unref(&link->incfg.color_spaces);
@@ -1615,12 +1620,13 @@ const AVClass *avfilter_get_class(void)
 int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link,
                              int default_pool_size)
 {
+    FilterLink *l = ff_filter_link(link);
     AVHWFramesContext *frames;
 
     // Must already be set by caller.
-    av_assert0(link->hw_frames_ctx);
+    av_assert0(l->hw_frames_ctx);
 
-    frames = (AVHWFramesContext*)link->hw_frames_ctx->data;
+    frames = (AVHWFramesContext*)l->hw_frames_ctx->data;
 
     if (frames->initial_pool_size == 0) {
         // Dynamic allocation is necessarily supported.
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 2624b0cfca..bf9a682bb7 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -641,12 +641,6 @@ struct AVFilterLink {
      * cleared when a frame is filtered.
      */
     int frame_wanted_out;
-
-    /**
-     * For hwaccel pixel formats, this should be a reference to the
-     * AVHWFramesContext describing the frames.
-     */
-    AVBufferRef *hw_frames_ctx;
 };
 
 /**
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 2c1fa4c293..a184677937 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -188,7 +188,12 @@ MAKE_AVFILTERLINK_ACCESSOR(enum AVColorRange, color_range)
 
 MAKE_AVFILTERLINK_ACCESSOR(int              , sample_rate        )
 
-MAKE_AVFILTERLINK_ACCESSOR(AVBufferRef *    , hw_frames_ctx      )
+AVBufferRef* av_buffersink_get_hw_frames_ctx(const AVFilterContext *ctx)
+{
+    FilterLink *l = ff_filter_link(ctx->inputs[0]);
+    av_assert0(ctx->filter->activate == activate);
+    return l->hw_frames_ctx;
+}
 
 int av_buffersink_get_channels(const AVFilterContext *ctx)
 {
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index a61960310b..b6e8f8036c 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -493,6 +493,7 @@ static int query_formats(AVFilterContext *ctx)
 
 static int config_props(AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     BufferSourceContext *c = link->src->priv;
 
     switch (link->type) {
@@ -502,8 +503,8 @@ static int config_props(AVFilterLink *link)
         link->sample_aspect_ratio = c->pixel_aspect;
 
         if (c->hw_frames_ctx) {
-            link->hw_frames_ctx = av_buffer_ref(c->hw_frames_ctx);
-            if (!link->hw_frames_ctx)
+            l->hw_frames_ctx = av_buffer_ref(c->hw_frames_ctx);
+            if (!l->hw_frames_ctx)
                 return AVERROR(ENOMEM);
         }
         break;
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 11064aee13..9e230dc987 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -57,6 +57,14 @@ typedef struct FilterLink {
      * May be set by the link destination filter in its config_props().
      */
     int max_samples;
+
+    /**
+     * For hwaccel pixel formats, this should be a reference to the
+     * AVHWFramesContext describing the frames.
+     *
+     * May be set by the link source filter in its config_props().
+     */
+    AVBufferRef *hw_frames_ctx;
 } FilterLink;
 
 static inline FilterLink* ff_filter_link(AVFilterLink *link)
diff --git a/libavfilter/opencl.c b/libavfilter/opencl.c
index 48752e9530..e91610a10e 100644
--- a/libavfilter/opencl.c
+++ b/libavfilter/opencl.c
@@ -23,6 +23,7 @@
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
 
+#include "filters.h"
 #include "opencl.h"
 
 static int opencl_filter_set_device(AVFilterContext *avctx,
@@ -44,12 +45,13 @@ static int opencl_filter_set_device(AVFilterContext *avctx,
 
 int ff_opencl_filter_config_input(AVFilterLink *inlink)
 {
+    FilterLink            *l = ff_filter_link(inlink);
     AVFilterContext   *avctx = inlink->dst;
     OpenCLFilterContext *ctx = avctx->priv;
     AVHWFramesContext *input_frames;
     int err;
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a "
                "hardware frames context on the input.\n");
         return AVERROR(EINVAL);
@@ -59,7 +61,7 @@ int ff_opencl_filter_config_input(AVFilterLink *inlink)
     if (avctx->inputs[0] != inlink)
         return 0;
 
-    input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    input_frames = (AVHWFramesContext*)l->hw_frames_ctx->data;
     if (input_frames->format != AV_PIX_FMT_OPENCL)
         return AVERROR(EINVAL);
 
@@ -80,13 +82,14 @@ int ff_opencl_filter_config_input(AVFilterLink *inlink)
 
 int ff_opencl_filter_config_output(AVFilterLink *outlink)
 {
+    FilterLink            *l = ff_filter_link(outlink);
     AVFilterContext   *avctx = outlink->src;
     OpenCLFilterContext *ctx = avctx->priv;
     AVBufferRef       *output_frames_ref = NULL;
     AVHWFramesContext *output_frames;
     int err;
 
-    av_buffer_unref(&outlink->hw_frames_ctx);
+    av_buffer_unref(&l->hw_frames_ctx);
 
     if (!ctx->device_ref) {
         if (!avctx->hw_device_ctx) {
@@ -119,7 +122,7 @@ int ff_opencl_filter_config_output(AVFilterLink *outlink)
         goto fail;
     }
 
-    outlink->hw_frames_ctx = output_frames_ref;
+    l->hw_frames_ctx = output_frames_ref;
     outlink->w = ctx->output_width;
     outlink->h = ctx->output_height;
 
diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c
index 6adf9f6e84..24e15020b2 100644
--- a/libavfilter/qsvvpp.c
+++ b/libavfilter/qsvvpp.c
@@ -28,6 +28,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "internal.h"
+#include "filters.h"
 #include "qsvvpp.h"
 #include "video.h"
 
@@ -303,10 +304,11 @@ static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link)
     const AVPixFmtDescriptor *desc;
 
     if (link->format == AV_PIX_FMT_QSV) {
-        if (!link->hw_frames_ctx)
+        FilterLink *l = ff_filter_link(link);
+        if (!l->hw_frames_ctx)
             return AVERROR(EINVAL);
 
-        frames_ctx   = (AVHWFramesContext *)link->hw_frames_ctx->data;
+        frames_ctx   = (AVHWFramesContext *)l->hw_frames_ctx->data;
         frames_hwctx = frames_ctx->hwctx;
         *frameinfo   = frames_hwctx->nb_surfaces ? frames_hwctx->surfaces[0].Info : *frames_hwctx->info;
     } else {
@@ -472,6 +474,7 @@ static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *p
 /* get the output surface */
 static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFrame *in)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     QSVFrame        *out_frame;
     int              ret;
@@ -489,7 +492,7 @@ static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFr
         if (!out_frame->frame)
             return NULL;
 
-        ret = av_hwframe_get_buffer(outlink->hw_frames_ctx, out_frame->frame, 0);
+        ret = av_hwframe_get_buffer(l->hw_frames_ctx, out_frame->frame, 0);
         if (ret < 0) {
             av_log(ctx, AV_LOG_ERROR, "Can't allocate a surface.\n");
             return NULL;
@@ -546,7 +549,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
 static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s)
 {
     AVFilterLink                 *inlink = avctx->inputs[0];
+    FilterLink                      *inl = ff_filter_link(inlink);
     AVFilterLink                *outlink = avctx->outputs[0];
+    FilterLink                     *outl = ff_filter_link(outlink);
     AVQSVFramesContext  *in_frames_hwctx = NULL;
     AVQSVFramesContext *out_frames_hwctx = NULL;
 
@@ -559,8 +564,8 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s)
     mfxIMPL impl;
     int ret, i;
 
-    if (inlink->hw_frames_ctx) {
-        AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    if (inl->hw_frames_ctx) {
+        AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data;
 
         device_ref      = frames_ctx->device_ref;
         in_frames_hwctx = frames_ctx->hwctx;
@@ -657,8 +662,8 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s)
             s->surface_ptrs_out[i] = out_frames_hwctx->surfaces + i;
         s->nb_surface_ptrs_out = out_frames_hwctx->nb_surfaces;
 
-        av_buffer_unref(&outlink->hw_frames_ctx);
-        outlink->hw_frames_ctx = out_frames_ref;
+        av_buffer_unref(&outl->hw_frames_ctx);
+        outl->hw_frames_ctx = out_frames_ref;
     } else
         s->out_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY;
 
diff --git a/libavfilter/vaapi_vpp.c b/libavfilter/vaapi_vpp.c
index 9ef7a289fb..496190a844 100644
--- a/libavfilter/vaapi_vpp.c
+++ b/libavfilter/vaapi_vpp.c
@@ -21,6 +21,8 @@
 #include "libavutil/avassert.h"
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "vaapi_vpp.h"
@@ -74,19 +76,20 @@ void ff_vaapi_vpp_pipeline_uninit(AVFilterContext *avctx)
 
 int ff_vaapi_vpp_config_input(AVFilterLink *inlink)
 {
+    FilterLink          *l = ff_filter_link(inlink);
     AVFilterContext *avctx = inlink->dst;
     VAAPIVPPContext *ctx   = avctx->priv;
 
     if (ctx->pipeline_uninit)
         ctx->pipeline_uninit(avctx);
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is "
                "required to associate the processing device.\n");
         return AVERROR(EINVAL);
     }
 
-    ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx);
+    ctx->input_frames_ref = av_buffer_ref(l->hw_frames_ctx);
     if (!ctx->input_frames_ref) {
         av_log(avctx, AV_LOG_ERROR, "A input frames reference create "
                "failed.\n");
@@ -99,8 +102,10 @@ int ff_vaapi_vpp_config_input(AVFilterLink *inlink)
 
 int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
 {
+    FilterLink       *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     AVFilterLink   *inlink = avctx->inputs[0];
+    FilterLink        *inl = ff_filter_link(inlink);
     VAAPIVPPContext *ctx   = avctx->priv;
     AVVAAPIHWConfig *hwconfig = NULL;
     AVHWFramesConstraints *constraints = NULL;
@@ -121,8 +126,8 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
     outlink->h = ctx->output_height;
 
     if (ctx->passthrough) {
-        if (inlink->hw_frames_ctx)
-            outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
+        if (inl->hw_frames_ctx)
+            outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
         av_log(ctx, AV_LOG_VERBOSE, "Using VAAPI filter passthrough mode.\n");
 
         return 0;
@@ -189,15 +194,15 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
         goto fail;
     }
 
-    outlink->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ref);
-    if (!outlink->hw_frames_ctx) {
+    outl->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ref);
+    if (!outl->hw_frames_ctx) {
         av_log(avctx, AV_LOG_ERROR, "Failed to create HW frame context "
                "for output.\n");
         err = AVERROR(ENOMEM);
         goto fail;
     }
 
-    output_frames = (AVHWFramesContext*)outlink->hw_frames_ctx->data;
+    output_frames = (AVHWFramesContext*)outl->hw_frames_ctx->data;
 
     output_frames->format    = AV_PIX_FMT_VAAPI;
     output_frames->sw_format = ctx->output_format;
@@ -213,7 +218,7 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
     if (err < 0)
         goto fail;
 
-    err = av_hwframe_ctx_init(outlink->hw_frames_ctx);
+    err = av_hwframe_ctx_init(outl->hw_frames_ctx);
     if (err < 0) {
         av_log(avctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame "
                "context for output: %d\n", err);
@@ -247,7 +252,7 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
     return 0;
 
 fail:
-    av_buffer_unref(&outlink->hw_frames_ctx);
+    av_buffer_unref(&outl->hw_frames_ctx);
     av_freep(&hwconfig);
     av_hwframe_constraints_free(&constraints);
     return err;
diff --git a/libavfilter/vf_bilateral_cuda.c b/libavfilter/vf_bilateral_cuda.c
index 037227af93..46acec91b9 100644
--- a/libavfilter/vf_bilateral_cuda.c
+++ b/libavfilter/vf_bilateral_cuda.c
@@ -30,6 +30,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 
 #include "cuda/load_helper.h"
@@ -178,16 +179,18 @@ static av_cold void set_format_info(AVFilterContext *ctx, enum AVPixelFormat in_
 
 static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int height)
 {
+    FilterLink         *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink        *outl = ff_filter_link(ctx->outputs[0]);
     CUDABilateralContext *s = ctx->priv;
     AVHWFramesContext *in_frames_ctx;
     int ret;
 
     /* check that we have a hw context */
-    if (!ctx->inputs[0]->hw_frames_ctx) {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         return AVERROR(EINVAL);
     }
-    in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
 
     if (!format_is_supported(in_frames_ctx->sw_format)) {
         av_log(ctx, AV_LOG_ERROR, "Unsupported format: %s\n", av_get_pix_fmt_name(in_frames_ctx->sw_format));
@@ -200,8 +203,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int he
     if (ret < 0)
         return ret;
 
-    ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
@@ -248,6 +251,7 @@ static av_cold int cuda_bilateral_config_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     CUDABilateralContext *s  = ctx->priv;
     AVHWFramesContext     *frames_ctx;
     AVCUDADeviceContext *device_hwctx;
@@ -257,7 +261,7 @@ static av_cold int cuda_bilateral_config_props(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
-    frames_ctx   = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    frames_ctx   = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     device_hwctx = frames_ctx->device_ctx->hwctx;
 
     s->hwctx = device_hwctx;
diff --git a/libavfilter/vf_bwdif_cuda.c b/libavfilter/vf_bwdif_cuda.c
index 8c37dc8800..a19d180bdd 100644
--- a/libavfilter/vf_bwdif_cuda.c
+++ b/libavfilter/vf_bwdif_cuda.c
@@ -22,6 +22,8 @@
 #include "libavutil/hwcontext.h"
 #include "libavutil/hwcontext_cuda_internal.h"
 #include "libavutil/cuda_check.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "yadif.h"
 
@@ -217,16 +219,17 @@ static av_cold void deint_cuda_uninit(AVFilterContext *ctx)
 
 static int config_input(AVFilterLink *inlink)
 {
+    FilterLink        *l = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     DeintCUDAContext *s  = ctx->priv;
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is "
                "required to associate the processing device.\n");
         return AVERROR(EINVAL);
     }
 
-    s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx);
+    s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx);
     if (!s->input_frames_ref) {
         av_log(ctx, AV_LOG_ERROR, "A input frames reference create "
                "failed.\n");
@@ -239,6 +242,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     AVHWFramesContext *output_frames;
     AVFilterContext *ctx = link->src;
     DeintCUDAContext *s = ctx->priv;
@@ -257,15 +261,15 @@ static int config_output(AVFilterLink *link)
     s->hwctx = ((AVHWDeviceContext*)s->device_ref->data)->hwctx;
     cu = s->hwctx->internal->cuda_dl;
 
-    link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
-    if (!link->hw_frames_ctx) {
+    l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context "
                "for output.\n");
         ret = AVERROR(ENOMEM);
         goto exit;
     }
 
-    output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data;
+    output_frames = (AVHWFramesContext*)l->hw_frames_ctx->data;
 
     output_frames->format    = AV_PIX_FMT_CUDA;
     output_frames->sw_format = s->input_frames->sw_format;
@@ -278,7 +282,7 @@ static int config_output(AVFilterLink *link)
     if (ret < 0)
         goto exit;
 
-    ret = av_hwframe_ctx_init(link->hw_frames_ctx);
+    ret = av_hwframe_ctx_init(l->hw_frames_ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failed to initialise CUDA frame "
                "context for output: %d\n", ret);
diff --git a/libavfilter/vf_bwdif_vulkan.c b/libavfilter/vf_bwdif_vulkan.c
index 57711fb672..3599047784 100644
--- a/libavfilter/vf_bwdif_vulkan.c
+++ b/libavfilter/vf_bwdif_vulkan.c
@@ -26,6 +26,7 @@
 #include "vulkan_spirv.h"
 #include "yadif.h"
 #include "internal.h"
+#include "filters.h"
 
 typedef struct BWDIFVulkanContext {
     YADIFContext yadif;
@@ -303,18 +304,19 @@ static void bwdif_vulkan_uninit(AVFilterContext *avctx)
 
 static int bwdif_vulkan_config_input(AVFilterLink *inlink)
 {
+    FilterLink *l = ff_filter_link(inlink);
     AVHWFramesContext *input_frames;
     AVFilterContext *avctx = inlink->dst;
     BWDIFVulkanContext *s = avctx->priv;
     FFVulkanContext *vkctx = &s->vkctx;
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(inlink->dst, AV_LOG_ERROR, "Vulkan filtering requires a "
                "hardware frames context on the input.\n");
         return AVERROR(EINVAL);
     }
 
-    input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    input_frames = (AVHWFramesContext *)l->hw_frames_ctx->data;
     if (input_frames->format != AV_PIX_FMT_VULKAN)
         return AVERROR(EINVAL);
 
@@ -323,7 +325,7 @@ static int bwdif_vulkan_config_input(AVFilterLink *inlink)
         return 0;
 
     /* Save the ref, without reffing it */
-    vkctx->input_frames_ref = inlink->hw_frames_ctx;
+    vkctx->input_frames_ref = l->hw_frames_ctx;
 
     /* Defaults */
     vkctx->output_format = input_frames->sw_format;
@@ -335,13 +337,14 @@ static int bwdif_vulkan_config_input(AVFilterLink *inlink)
 
 static int bwdif_vulkan_config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     int err;
     AVFilterContext *avctx = outlink->src;
     BWDIFVulkanContext *s = avctx->priv;
     YADIFContext *y = &s->yadif;
     FFVulkanContext *vkctx = &s->vkctx;
 
-    av_buffer_unref(&outlink->hw_frames_ctx);
+    av_buffer_unref(&l->hw_frames_ctx);
 
     err = ff_vk_filter_init_context(avctx, vkctx, vkctx->input_frames_ref,
                                     vkctx->output_width, vkctx->output_height,
@@ -352,8 +355,8 @@ static int bwdif_vulkan_config_output(AVFilterLink *outlink)
     /* For logging */
     vkctx->class = y->class;
 
-    outlink->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref);
-    if (!outlink->hw_frames_ctx)
+    l->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref);
+    if (!l->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     err = ff_yadif_config_output_common(outlink);
diff --git a/libavfilter/vf_chromakey_cuda.c b/libavfilter/vf_chromakey_cuda.c
index e38521be0d..86da92a4ea 100644
--- a/libavfilter/vf_chromakey_cuda.c
+++ b/libavfilter/vf_chromakey_cuda.c
@@ -30,6 +30,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "cuda/load_helper.h"
 
@@ -180,17 +181,18 @@ static av_cold void set_format_info(AVFilterContext *ctx, enum AVPixelFormat in_
 
 static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int height)
 {
+    FilterLink         *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink        *outl = ff_filter_link(ctx->outputs[0]);
     ChromakeyCUDAContext *s = ctx->priv;
     AVHWFramesContext *in_frames_ctx;
     int ret;
 
     /* check that we have a hw context */
-    if (!ctx->inputs[0]->hw_frames_ctx)
-    {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         return AVERROR(EINVAL);
     }
-    in_frames_ctx = (AVHWFramesContext *)ctx->inputs[0]->hw_frames_ctx->data;
+    in_frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data;
 
     if (!format_is_supported(in_frames_ctx->sw_format))
     {
@@ -204,8 +206,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int he
     if (ret < 0)
         return ret;
 
-    ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
@@ -258,6 +260,7 @@ static av_cold int cudachromakey_config_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     ChromakeyCUDAContext *s = ctx->priv;
     AVHWFramesContext *frames_ctx;
     AVCUDADeviceContext *device_hwctx;
@@ -275,7 +278,7 @@ static av_cold int cudachromakey_config_props(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
-    frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data;
     device_hwctx = frames_ctx->device_ctx->hwctx;
 
     s->hwctx = device_hwctx;
diff --git a/libavfilter/vf_colorspace_cuda.c b/libavfilter/vf_colorspace_cuda.c
index 3949cb7ed8..f089b20ed7 100644
--- a/libavfilter/vf_colorspace_cuda.c
+++ b/libavfilter/vf_colorspace_cuda.c
@@ -31,6 +31,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 
 #include "cuda/load_helper.h"
@@ -151,17 +152,19 @@ static int format_is_supported(enum AVPixelFormat fmt)
 static av_cold int init_processing_chain(AVFilterContext* ctx, int width,
                                          int height)
 {
+    FilterLink          *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink         *outl = ff_filter_link(ctx->outputs[0]);
     CUDAColorspaceContext* s = ctx->priv;
     AVHWFramesContext* in_frames_ctx;
 
     int ret;
 
-    if (!ctx->inputs[0]->hw_frames_ctx) {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         return AVERROR(EINVAL);
     }
 
-    in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     s->pix_fmt = in_frames_ctx->sw_format;
 
     if (!format_is_supported(s->pix_fmt)) {
@@ -181,8 +184,8 @@ static av_cold int init_processing_chain(AVFilterContext* ctx, int width,
     if (ret < 0)
         return ret;
 
-    ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
@@ -225,6 +228,7 @@ static av_cold int cudacolorspace_config_props(AVFilterLink* outlink)
 {
     AVFilterContext* ctx = outlink->src;
     AVFilterLink* inlink = outlink->src->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     CUDAColorspaceContext* s = ctx->priv;
     AVHWFramesContext* frames_ctx;
     AVCUDADeviceContext* device_hwctx;
@@ -237,7 +241,7 @@ static av_cold int cudacolorspace_config_props(AVFilterLink* outlink)
     if (ret < 0)
         return ret;
 
-    frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     device_hwctx = frames_ctx->device_ctx->hwctx;
 
     s->hwctx = device_hwctx;
diff --git a/libavfilter/vf_deshake_opencl.c b/libavfilter/vf_deshake_opencl.c
index 5c3848c3ed..9e87007cbb 100644
--- a/libavfilter/vf_deshake_opencl.c
+++ b/libavfilter/vf_deshake_opencl.c
@@ -1112,6 +1112,7 @@ static int deshake_opencl_init(AVFilterContext *avctx)
     DeshakeOpenCLContext *ctx = avctx->priv;
     AVFilterLink *outlink = avctx->outputs[0];
     AVFilterLink *inlink = avctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     // Pointer to the host-side pattern buffer to be initialized and then copied
     // to the GPU
     PointPair *pattern_host = NULL;
@@ -1146,7 +1147,7 @@ static int deshake_opencl_init(AVFilterContext *avctx)
     const int descriptor_buf_size = image_grid_32 * (BREIFN / 8);
     const int features_buf_size = image_grid_32 * sizeof(cl_float2);
 
-    const AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    const AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hw_frames_ctx->sw_format);
 
     av_assert0(hw_frames_ctx);
diff --git a/libavfilter/vf_hwdownload.c b/libavfilter/vf_hwdownload.c
index 5ef23cb5d4..75c4b215be 100644
--- a/libavfilter/vf_hwdownload.c
+++ b/libavfilter/vf_hwdownload.c
@@ -24,6 +24,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -50,18 +51,19 @@ static int hwdownload_query_formats(AVFilterContext *avctx)
 
 static int hwdownload_config_input(AVFilterLink *inlink)
 {
+    FilterLink          *l = ff_filter_link(inlink);
     AVFilterContext *avctx = inlink->dst;
     HWDownloadContext *ctx = avctx->priv;
 
     av_buffer_unref(&ctx->hwframes_ref);
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "The input must have a hardware frame "
                "reference.\n");
         return AVERROR(EINVAL);
     }
 
-    ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
+    ctx->hwframes_ref = av_buffer_ref(l->hw_frames_ctx);
     if (!ctx->hwframes_ref)
         return AVERROR(ENOMEM);
 
diff --git a/libavfilter/vf_hwmap.c b/libavfilter/vf_hwmap.c
index 3f37dab2c8..d3e84e39d7 100644
--- a/libavfilter/vf_hwmap.c
+++ b/libavfilter/vf_hwmap.c
@@ -23,6 +23,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -52,9 +53,11 @@ static int hwmap_query_formats(AVFilterContext *avctx)
 
 static int hwmap_config_output(AVFilterLink *outlink)
 {
+    FilterLink       *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     HWMapContext      *ctx = avctx->priv;
     AVFilterLink   *inlink = avctx->inputs[0];
+    FilterLink        *inl = ff_filter_link(inlink);
     AVHWFramesContext *hwfc;
     AVBufferRef *device;
     const AVPixFmtDescriptor *desc;
@@ -69,8 +72,8 @@ static int hwmap_config_output(AVFilterLink *outlink)
     device = avctx->hw_device_ctx;
     device_is_derived = 0;
 
-    if (inlink->hw_frames_ctx) {
-        hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    if (inl->hw_frames_ctx) {
+        hwfc = (AVHWFramesContext*)inl->hw_frames_ctx->data;
 
         if (ctx->derive_device_type) {
             enum AVHWDeviceType type;
@@ -114,7 +117,7 @@ static int hwmap_config_output(AVFilterLink *outlink)
             err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref,
                                                 outlink->format,
                                                 device,
-                                                inlink->hw_frames_ctx,
+                                                inl->hw_frames_ctx,
                                                 ctx->mode);
             if (err < 0) {
                 av_log(avctx, AV_LOG_ERROR, "Failed to create derived "
@@ -171,8 +174,8 @@ static int hwmap_config_output(AVFilterLink *outlink)
             // the format it expects.  If there were any additional
             // constraints on the output frames there then this may
             // break nastily.
-            av_buffer_unref(&inlink->hw_frames_ctx);
-            inlink->hw_frames_ctx = source;
+            av_buffer_unref(&inl->hw_frames_ctx);
+            inl->hw_frames_ctx = source;
 
         } else if ((outlink->format == hwfc->format &&
                     inlink->format  == hwfc->sw_format) ||
@@ -180,7 +183,7 @@ static int hwmap_config_output(AVFilterLink *outlink)
             // Map from a hardware format to a software format, or
             // undo an existing such mapping.
 
-            ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
+            ctx->hwframes_ref = av_buffer_ref(inl->hw_frames_ctx);
             if (!ctx->hwframes_ref) {
                 err = AVERROR(ENOMEM);
                 goto fail;
@@ -241,8 +244,8 @@ static int hwmap_config_output(AVFilterLink *outlink)
         return AVERROR(EINVAL);
     }
 
-    outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
-    if (!outlink->hw_frames_ctx) {
+    outl->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
+    if (!outl->hw_frames_ctx) {
         err = AVERROR(ENOMEM);
         goto fail;
     }
@@ -263,11 +266,12 @@ fail:
 
 static AVFrame *hwmap_get_buffer(AVFilterLink *inlink, int w, int h)
 {
+    FilterLink          *l = ff_filter_link(inlink);
     AVFilterContext *avctx = inlink->dst;
     AVFilterLink  *outlink = avctx->outputs[0];
     HWMapContext      *ctx = avctx->priv;
 
-    if (ctx->reverse && !inlink->hw_frames_ctx) {
+    if (ctx->reverse && !l->hw_frames_ctx) {
         AVFrame *src, *dst;
         int err;
 
diff --git a/libavfilter/vf_hwupload.c b/libavfilter/vf_hwupload.c
index ef61bb4137..9c11e72759 100644
--- a/libavfilter/vf_hwupload.c
+++ b/libavfilter/vf_hwupload.c
@@ -24,6 +24,7 @@
 #include "libavutil/opt.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -106,8 +107,10 @@ fail:
 
 static int hwupload_config_output(AVFilterLink *outlink)
 {
+    FilterLink       *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     AVFilterLink   *inlink = avctx->inputs[0];
+    FilterLink        *inl = ff_filter_link(inlink);
     HWUploadContext   *ctx = avctx->priv;
     int err;
 
@@ -116,13 +119,13 @@ static int hwupload_config_output(AVFilterLink *outlink)
     if (inlink->format == outlink->format) {
         // The input is already a hardware format, so we just want to
         // pass through the input frames in their own hardware context.
-        if (!inlink->hw_frames_ctx) {
+        if (!inl->hw_frames_ctx) {
             av_log(ctx, AV_LOG_ERROR, "No input hwframe context.\n");
             return AVERROR(EINVAL);
         }
 
-        outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
-        if (!outlink->hw_frames_ctx)
+        outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
+        if (!outl->hw_frames_ctx)
             return AVERROR(ENOMEM);
 
         return 0;
@@ -138,9 +141,9 @@ static int hwupload_config_output(AVFilterLink *outlink)
            av_get_pix_fmt_name(inlink->format));
 
     ctx->hwframes->format    = outlink->format;
-    if (inlink->hw_frames_ctx) {
+    if (inl->hw_frames_ctx) {
         AVHWFramesContext *in_hwframe_ctx =
-            (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+            (AVHWFramesContext*)inl->hw_frames_ctx->data;
         ctx->hwframes->sw_format = in_hwframe_ctx->sw_format;
     } else {
         ctx->hwframes->sw_format = inlink->format;
@@ -155,8 +158,8 @@ static int hwupload_config_output(AVFilterLink *outlink)
     if (err < 0)
         goto fail;
 
-    outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
-    if (!outlink->hw_frames_ctx) {
+    outl->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
+    if (!outl->hw_frames_ctx) {
         err = AVERROR(ENOMEM);
         goto fail;
     }
diff --git a/libavfilter/vf_hwupload_cuda.c b/libavfilter/vf_hwupload_cuda.c
index f5fe3ddbbe..fa96f06de1 100644
--- a/libavfilter/vf_hwupload_cuda.c
+++ b/libavfilter/vf_hwupload_cuda.c
@@ -22,6 +22,7 @@
 #include "libavutil/opt.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -86,8 +87,10 @@ static int cudaupload_query_formats(AVFilterContext *ctx)
 
 static int cudaupload_config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     CudaUploadContext *s = ctx->priv;
 
     AVHWFramesContext *hwframe_ctx;
@@ -100,8 +103,8 @@ static int cudaupload_config_output(AVFilterLink *outlink)
 
     hwframe_ctx            = (AVHWFramesContext*)s->hwframe->data;
     hwframe_ctx->format    = AV_PIX_FMT_CUDA;
-    if (inlink->hw_frames_ctx) {
-        AVHWFramesContext *in_hwframe_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    if (inl->hw_frames_ctx) {
+        AVHWFramesContext *in_hwframe_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
         hwframe_ctx->sw_format = in_hwframe_ctx->sw_format;
     } else {
         hwframe_ctx->sw_format = inlink->format;
@@ -113,8 +116,8 @@ static int cudaupload_config_output(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
-    outlink->hw_frames_ctx = av_buffer_ref(s->hwframe);
-    if (!outlink->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->hwframe);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index be9000aa8e..096064022d 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -1188,6 +1188,7 @@ static inline AVRational max_q(AVRational a, AVRational b)
 static int libplacebo_config_output(AVFilterLink *outlink)
 {
     int err;
+    FilterLink          *l = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     LibplaceboContext *s   = avctx->priv;
     AVFilterLink *inlink   = outlink->src->inputs[0];
@@ -1253,7 +1254,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
         s->vkctx.output_format = s->out_format;
     }
     RET(ff_vk_filter_config_output(outlink));
-    hwfc = (AVHWFramesContext *) outlink->hw_frames_ctx->data;
+    hwfc = (AVHWFramesContext *)l->hw_frames_ctx->data;
     vkfc = hwfc->hwctx;
     vkfc->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 
diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c
index 2c99d792af..a54af16000 100644
--- a/libavfilter/vf_libvmaf.c
+++ b/libavfilter/vf_libvmaf.c
@@ -34,6 +34,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "framesync.h"
 #include "internal.h"
@@ -651,7 +652,8 @@ static int config_props_cuda(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     LIBVMAFContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
-    AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inlink->hw_frames_ctx->data;
+    FilterLink      *inl = ff_filter_link(inlink);
+    AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inl->hw_frames_ctx->data;
     AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
     CUcontext cu_ctx = device_hwctx->cuda_ctx;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frames_ctx->sw_format);
@@ -756,7 +758,8 @@ static int do_vmaf_cuda(FFFrameSync* fs)
     AVFilterContext* ctx = fs->parent;
     LIBVMAFContext* s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
-    AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inlink->hw_frames_ctx->data;
+    FilterLink      *inl = ff_filter_link(inlink);
+    AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
     VmafPicture pic_ref, pic_dist;
     AVFrame *ref, *dist;
diff --git a/libavfilter/vf_overlay_cuda.c b/libavfilter/vf_overlay_cuda.c
index 77c7f9b4e7..1aee77b17c 100644
--- a/libavfilter/vf_overlay_cuda.c
+++ b/libavfilter/vf_overlay_cuda.c
@@ -436,14 +436,17 @@ static int overlay_cuda_config_output(AVFilterLink *outlink)
     extern const unsigned int ff_vf_overlay_cuda_ptx_len;
 
     int err;
+    FilterLink       *outl = ff_filter_link(outlink);
     AVFilterContext* avctx = outlink->src;
     OverlayCUDAContext* ctx = avctx->priv;
 
     AVFilterLink *inlink = avctx->inputs[0];
-    AVHWFramesContext  *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    FilterLink *inl = ff_filter_link(inlink);
+    AVHWFramesContext  *frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
 
     AVFilterLink *inlink_overlay = avctx->inputs[1];
-    AVHWFramesContext  *frames_ctx_overlay = (AVHWFramesContext*)inlink_overlay->hw_frames_ctx->data;
+    FilterLink *inl_overlay = ff_filter_link(inlink_overlay);
+    AVHWFramesContext  *frames_ctx_overlay = (AVHWFramesContext*)inl_overlay->hw_frames_ctx->data;
 
     CUcontext dummy, cuda_ctx;
     CudaFunctions *cu;
@@ -496,8 +499,8 @@ static int overlay_cuda_config_output(AVFilterLink *outlink)
 
     ctx->cu_stream = ctx->hwctx->stream;
 
-    outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
-    if (!outlink->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     // load functions
diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c
index 059602fe03..15dfe4e6f7 100644
--- a/libavfilter/vf_overlay_qsv.c
+++ b/libavfilter/vf_overlay_qsv.c
@@ -29,6 +29,7 @@
 #include "libavutil/hwcontext.h"
 #include "libavutil/mathematics.h"
 
+#include "filters.h"
 #include "internal.h"
 #include "avfilter.h"
 #include "formats.h"
@@ -156,12 +157,13 @@ release:
 
 static int have_alpha_planar(AVFilterLink *link)
 {
+    FilterLink              *l = ff_filter_link(link);
     enum AVPixelFormat pix_fmt = link->format;
     const AVPixFmtDescriptor *desc;
     AVHWFramesContext *fctx;
 
     if (link->format == AV_PIX_FMT_QSV) {
-        fctx    = (AVHWFramesContext *)link->hw_frames_ctx->data;
+        fctx    = (AVHWFramesContext *)l->hw_frames_ctx->data;
         pix_fmt = fctx->sw_format;
     }
 
@@ -273,6 +275,8 @@ static int config_output(AVFilterLink *outlink)
     QSVOverlayContext *vpp = ctx->priv;
     AVFilterLink      *in0 = ctx->inputs[0];
     AVFilterLink      *in1 = ctx->inputs[1];
+    FilterLink         *l0 = ff_filter_link(in0);
+    FilterLink         *l1 = ff_filter_link(in1);
     int ret;
 
     av_log(ctx, AV_LOG_DEBUG, "Output is of %s.\n", av_get_pix_fmt_name(outlink->format));
@@ -282,8 +286,8 @@ static int config_output(AVFilterLink *outlink)
         av_log(ctx, AV_LOG_ERROR, "Mixing hardware and software pixel formats is not supported.\n");
         return AVERROR(EINVAL);
     } else if (in0->format == AV_PIX_FMT_QSV) {
-        AVHWFramesContext *hw_frame0 = (AVHWFramesContext *)in0->hw_frames_ctx->data;
-        AVHWFramesContext *hw_frame1 = (AVHWFramesContext *)in1->hw_frames_ctx->data;
+        AVHWFramesContext *hw_frame0 = (AVHWFramesContext *)l0->hw_frames_ctx->data;
+        AVHWFramesContext *hw_frame1 = (AVHWFramesContext *)l1->hw_frames_ctx->data;
 
         if (hw_frame0->device_ctx != hw_frame1->device_ctx) {
             av_log(ctx, AV_LOG_ERROR, "Inputs with different underlying QSV devices are forbidden.\n");
diff --git a/libavfilter/vf_overlay_vaapi.c b/libavfilter/vf_overlay_vaapi.c
index 9b1e12bdc8..16477ad24b 100644
--- a/libavfilter/vf_overlay_vaapi.c
+++ b/libavfilter/vf_overlay_vaapi.c
@@ -21,6 +21,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "vaapi_vpp.h"
@@ -256,12 +257,13 @@ fail:
 
 static int have_alpha_planar(AVFilterLink *link)
 {
+    FilterLink              *l = ff_filter_link(link);
     enum AVPixelFormat pix_fmt = link->format;
     const AVPixFmtDescriptor *desc;
     AVHWFramesContext *fctx;
 
     if (link->format == AV_PIX_FMT_VAAPI) {
-        fctx    = (AVHWFramesContext *)link->hw_frames_ctx->data;
+        fctx    = (AVHWFramesContext *)l->hw_frames_ctx->data;
         pix_fmt = fctx->sw_format;
     }
 
diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
index 68d17072e3..83073f8b4b 100644
--- a/libavfilter/vf_scale_cuda.c
+++ b/libavfilter/vf_scale_cuda.c
@@ -32,6 +32,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "scale_eval.h"
 #include "video.h"
@@ -221,6 +222,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int
                                          int out_width, int out_height)
 {
     CUDAScaleContext *s = ctx->priv;
+    FilterLink     *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink    *outl = ff_filter_link(ctx->outputs[0]);
 
     AVHWFramesContext *in_frames_ctx;
 
@@ -229,11 +232,11 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int
     int ret;
 
     /* check that we have a hw context */
-    if (!ctx->inputs[0]->hw_frames_ctx) {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         return AVERROR(EINVAL);
     }
-    in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     in_format     = in_frames_ctx->sw_format;
     out_format    = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format;
 
@@ -251,7 +254,7 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int
     set_format_info(ctx, in_format, out_format);
 
     if (s->passthrough && in_width == out_width && in_height == out_height && in_format == out_format) {
-        s->frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx);
+        s->frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
         if (!s->frames_ctx)
             return AVERROR(ENOMEM);
     } else {
@@ -266,8 +269,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int
             s->interp_algo = INTERP_ALGO_NEAREST;
     }
 
-    ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
@@ -348,6 +351,7 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     CUDAScaleContext *s  = ctx->priv;
     AVHWFramesContext     *frames_ctx;
     AVCUDADeviceContext *device_hwctx;
@@ -374,7 +378,7 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
-    frames_ctx   = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    frames_ctx   = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     device_hwctx = frames_ctx->device_ctx->hwctx;
 
     s->hwctx = device_hwctx;
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index 27e5e584ae..0c4af074c9 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -36,6 +36,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "scale_eval.h"
@@ -536,6 +537,8 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
                                  int out_width, int out_height)
 {
     NPPScaleContext *s = ctx->priv;
+    FilterLink    *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink   *outl = ff_filter_link(ctx->outputs[0]);
 
     AVHWFramesContext *in_frames_ctx;
 
@@ -547,11 +550,11 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
     int i, ret, last_stage = -1;
 
     /* check that we have a hw context */
-    if (!ctx->inputs[0]->hw_frames_ctx) {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         return AVERROR(EINVAL);
     }
-    in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     in_format     = in_frames_ctx->sw_format;
     out_format    = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format;
 
@@ -629,11 +632,11 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
     }
 
     if (last_stage >= 0)
-        ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx);
+        outl->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx);
     else
-        ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx);
+        outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
 
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
@@ -686,8 +689,9 @@ fail:
 
 static int config_props_ref(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterLink *inlink = outlink->src->inputs[1];
-    AVFilterContext *ctx = outlink->src;
+    FilterLink      *inl = ff_filter_link(inlink);
 
     outlink->w = inlink->w;
     outlink->h = inlink->h;
@@ -695,7 +699,7 @@ static int config_props_ref(AVFilterLink *outlink)
     outlink->time_base = inlink->time_base;
     outlink->frame_rate = inlink->frame_rate;
 
-    ctx->outputs[1]->hw_frames_ctx = av_buffer_ref(ctx->inputs[1]->hw_frames_ctx);
+    outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
 
     return 0;
 }
@@ -900,7 +904,8 @@ static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in)
     AVFilterContext              *ctx = link->dst;
     NPPScaleContext                *s = ctx->priv;
     AVFilterLink             *outlink = ctx->outputs[0];
-    AVHWFramesContext     *frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data;
+    FilterLink                     *l = ff_filter_link(outlink);
+    AVHWFramesContext     *frames_ctx = (AVHWFramesContext*)l->hw_frames_ctx->data;
     AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
 
     AVFrame *out = NULL;
diff --git a/libavfilter/vf_scale_vt.c b/libavfilter/vf_scale_vt.c
index af4a8b32c6..7481af1747 100644
--- a/libavfilter/vf_scale_vt.c
+++ b/libavfilter/vf_scale_vt.c
@@ -24,6 +24,8 @@
 #include "libavutil/hwcontext_videotoolbox.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "scale_eval.h"
 #include "video.h"
@@ -174,9 +176,11 @@ fail:
 static int scale_vt_config_output(AVFilterLink *outlink)
 {
     int err;
+    FilterLink       *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     ScaleVtContext *s  = avctx->priv;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink        *inl = ff_filter_link(inlink);
     AVHWFramesContext *hw_frame_ctx_in;
     AVHWFramesContext *hw_frame_ctx_out;
 
@@ -196,11 +200,11 @@ static int scale_vt_config_output(AVFilterLink *outlink)
         outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     }
 
-    hw_frame_ctx_in = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    hw_frame_ctx_in = (AVHWFramesContext *)inl->hw_frames_ctx->data;
 
-    av_buffer_unref(&outlink->hw_frames_ctx);
-    outlink->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref);
-    hw_frame_ctx_out = (AVHWFramesContext *)outlink->hw_frames_ctx->data;
+    av_buffer_unref(&outl->hw_frames_ctx);
+    outl->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref);
+    hw_frame_ctx_out = (AVHWFramesContext *)outl->hw_frames_ctx->data;
     hw_frame_ctx_out->format = AV_PIX_FMT_VIDEOTOOLBOX;
     hw_frame_ctx_out->sw_format = hw_frame_ctx_in->sw_format;
     hw_frame_ctx_out->width = outlink->w;
@@ -210,7 +214,7 @@ static int scale_vt_config_output(AVFilterLink *outlink)
     if (err < 0)
         return err;
 
-    err = av_hwframe_ctx_init(outlink->hw_frames_ctx);
+    err = av_hwframe_ctx_init(outl->hw_frames_ctx);
     if (err < 0) {
         av_log(avctx, AV_LOG_ERROR,
                "Failed to init videotoolbox frame context, %s\n",
diff --git a/libavfilter/vf_sharpen_npp.c b/libavfilter/vf_sharpen_npp.c
index 73c77dd5df..437cfb23cc 100644
--- a/libavfilter/vf_sharpen_npp.c
+++ b/libavfilter/vf_sharpen_npp.c
@@ -24,6 +24,7 @@
 #include <nppi.h>
 #include <nppi_filtering_functions.h>
 
+#include "filters.h"
 #include "internal.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/cuda_check.h"
@@ -31,6 +32,7 @@
 #include "libavutil/hwcontext_cuda_internal.h"
 #include "libavutil/opt.h"
 
+
 #define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, device_hwctx->internal->cuda_dl, x)
 
 static const enum AVPixelFormat supported_formats[] = {
@@ -70,16 +72,18 @@ fail:
 
 static int nppsharpen_config(AVFilterContext* ctx, int width, int height)
 {
+    FilterLink      *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink     *outl = ff_filter_link(ctx->outputs[0]);
     NPPSharpenContext* s = ctx->priv;
     AVHWFramesContext *out_ctx, *in_ctx;
     int i, ret, supported_format = 0;
 
-    if (!ctx->inputs[0]->hw_frames_ctx) {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         goto fail;
     }
 
-    in_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    in_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
 
     s->frames_ctx = av_hwframe_ctx_alloc(in_ctx->device_ref);
     if (!s->frames_ctx)
@@ -111,8 +115,8 @@ static int nppsharpen_config(AVFilterContext* ctx, int width, int height)
     if (ret < 0)
         goto fail;
 
-    ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx);
+    if (!outl->hw_frames_ctx)
         goto fail;
 
     return 0;
@@ -152,8 +156,8 @@ static int nppsharpen_config_props(AVFilterLink* outlink)
 
 static int nppsharpen_sharpen(AVFilterContext* ctx, AVFrame* out, AVFrame* in)
 {
-    AVHWFramesContext* in_ctx =
-        (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    FilterLink *inl = ff_filter_link(ctx->inputs[0]);
+    AVHWFramesContext* in_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     NPPSharpenContext* s = ctx->priv;
 
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(in_ctx->sw_format);
@@ -179,8 +183,9 @@ static int nppsharpen_filter_frame(AVFilterLink* link, AVFrame* in)
     AVFilterContext* ctx = link->dst;
     NPPSharpenContext* s = ctx->priv;
     AVFilterLink* outlink = ctx->outputs[0];
+    FilterLink      *outl = ff_filter_link(outlink);
     AVHWFramesContext* frames_ctx =
-        (AVHWFramesContext*)outlink->hw_frames_ctx->data;
+        (AVHWFramesContext*)outl->hw_frames_ctx->data;
     AVCUDADeviceContext* device_hwctx = frames_ctx->device_ctx->hwctx;
 
     AVFrame* out = NULL;
diff --git a/libavfilter/vf_stack_qsv.c b/libavfilter/vf_stack_qsv.c
index d4c1ac997f..a23e4f3e7e 100644
--- a/libavfilter/vf_stack_qsv.c
+++ b/libavfilter/vf_stack_qsv.c
@@ -100,15 +100,16 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     StackQSVContext *sctx = ctx->priv;
     AVFilterLink *inlink0 = ctx->inputs[0];
+    FilterLink      *inl0 = ff_filter_link(inlink0);
     enum AVPixelFormat in_format;
     int depth = 8, ret;
     mfxVPPCompInputStream *is = sctx->comp_conf.InputStream;
 
     if (inlink0->format == AV_PIX_FMT_QSV) {
-         if (!inlink0->hw_frames_ctx || !inlink0->hw_frames_ctx->data)
+         if (!inl0->hw_frames_ctx || !inl0->hw_frames_ctx->data)
              return AVERROR(EINVAL);
 
-         in_format = ((AVHWFramesContext*)inlink0->hw_frames_ctx->data)->sw_format;
+         in_format = ((AVHWFramesContext*)inl0->hw_frames_ctx->data)->sw_format;
     } else
         in_format = inlink0->format;
 
@@ -116,10 +117,11 @@ static int config_output(AVFilterLink *outlink)
 
     for (int i = 1; i < sctx->base.nb_inputs; i++) {
         AVFilterLink *inlink = ctx->inputs[i];
+        FilterLink      *inl = ff_filter_link(inlink);
 
         if (inlink0->format == AV_PIX_FMT_QSV) {
-            AVHWFramesContext *hwfc0 = (AVHWFramesContext *)inlink0->hw_frames_ctx->data;
-            AVHWFramesContext *hwfc = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+            AVHWFramesContext *hwfc0 = (AVHWFramesContext *)inl0->hw_frames_ctx->data;
+            AVHWFramesContext *hwfc = (AVHWFramesContext *)inl->hw_frames_ctx->data;
 
             if (inlink0->format != inlink->format) {
                 av_log(ctx, AV_LOG_ERROR, "Mixing hardware and software pixel formats is not supported.\n");
diff --git a/libavfilter/vf_stack_vaapi.c b/libavfilter/vf_stack_vaapi.c
index 8e9471e6d7..612ef97efe 100644
--- a/libavfilter/vf_stack_vaapi.c
+++ b/libavfilter/vf_stack_vaapi.c
@@ -137,26 +137,28 @@ static int config_output(AVFilterLink *outlink)
     StackVAAPIContext *sctx = avctx->priv;
     VAAPIVPPContext *vppctx = avctx->priv;
     AVFilterLink *inlink0 = avctx->inputs[0];
+    FilterLink      *inl0 = ff_filter_link(inlink0);
     AVHWFramesContext *hwfc0 = NULL;
     int ret;
 
-    if (inlink0->format != AV_PIX_FMT_VAAPI || !inlink0->hw_frames_ctx || !inlink0->hw_frames_ctx->data) {
+    if (inlink0->format != AV_PIX_FMT_VAAPI || !inl0->hw_frames_ctx || !inl0->hw_frames_ctx->data) {
         av_log(avctx, AV_LOG_ERROR, "Software pixel format is not supported.\n");
         return AVERROR(EINVAL);
     }
 
-    hwfc0 = (AVHWFramesContext *)inlink0->hw_frames_ctx->data;
+    hwfc0 = (AVHWFramesContext *)inl0->hw_frames_ctx->data;
 
     for (int i = 1; i < sctx->base.nb_inputs; i++) {
         AVFilterLink *inlink = avctx->inputs[i];
+        FilterLink      *inl = ff_filter_link(inlink);
         AVHWFramesContext *hwfc = NULL;
 
-        if (inlink->format != AV_PIX_FMT_VAAPI || !inlink->hw_frames_ctx || !inlink->hw_frames_ctx->data) {
+        if (inlink->format != AV_PIX_FMT_VAAPI || !inl->hw_frames_ctx || !inl->hw_frames_ctx->data) {
             av_log(avctx, AV_LOG_ERROR, "Software pixel format is not supported.\n");
             return AVERROR(EINVAL);
         }
 
-        hwfc = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+        hwfc = (AVHWFramesContext *)inl->hw_frames_ctx->data;
 
         if (hwfc0->sw_format != hwfc->sw_format) {
             av_log(avctx, AV_LOG_ERROR, "All inputs should have the same underlying software pixel format.\n");
diff --git a/libavfilter/vf_thumbnail_cuda.c b/libavfilter/vf_thumbnail_cuda.c
index 8efb54f079..be27d85dc7 100644
--- a/libavfilter/vf_thumbnail_cuda.c
+++ b/libavfilter/vf_thumbnail_cuda.c
@@ -28,6 +28,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 
 #include "cuda/load_helper.h"
@@ -358,8 +359,10 @@ static int format_is_supported(enum AVPixelFormat fmt)
 static int config_props(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
+    FilterLink      *inl = ff_filter_link(inlink);
+    FilterLink     *outl = ff_filter_link(ctx->outputs[0]);
     ThumbnailCudaContext *s = ctx->priv;
-    AVHWFramesContext     *hw_frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
+    AVHWFramesContext     *hw_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     AVCUDADeviceContext *device_hwctx = hw_frames_ctx->device_ctx->hwctx;
     CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
     CudaFunctions *cu = device_hwctx->internal->cuda_dl;
@@ -401,10 +404,10 @@ static int config_props(AVFilterLink *inlink)
 
     CHECK_CU(cu->cuCtxPopCurrent(&dummy));
 
-    s->hw_frames_ctx = ctx->inputs[0]->hw_frames_ctx;
+    s->hw_frames_ctx = inl->hw_frames_ctx;
 
-    ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx);
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    outl->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx);
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     s->tb = inlink->time_base;
diff --git a/libavfilter/vf_transpose_npp.c b/libavfilter/vf_transpose_npp.c
index 96c008cda9..2e3a0296f5 100644
--- a/libavfilter/vf_transpose_npp.c
+++ b/libavfilter/vf_transpose_npp.c
@@ -29,6 +29,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -178,6 +179,8 @@ static int format_is_supported(enum AVPixelFormat fmt)
 static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_height,
                                  int out_width, int out_height)
 {
+    FilterLink        *inl = ff_filter_link(ctx->inputs[0]);
+    FilterLink       *outl = ff_filter_link(ctx->outputs[0]);
     NPPTransposeContext *s = ctx->priv;
     AVHWFramesContext *in_frames_ctx;
     enum AVPixelFormat format;
@@ -185,12 +188,12 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
     int rot_width = out_width, rot_height = out_height;
 
     /* check that we have a hw context */
-    if (!ctx->inputs[0]->hw_frames_ctx) {
+    if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
         return AVERROR(EINVAL);
     }
 
-    in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
+    in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data;
     format        = in_frames_ctx->sw_format;
 
     if (!format_is_supported(format)) {
@@ -235,13 +238,13 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
     }
 
     if (last_stage >= 0) {
-        ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx);
+        outl->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx);
     } else {
-        ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx);
+        outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
         s->passthrough = 1;
     }
 
-    if (!ctx->outputs[0]->hw_frames_ctx)
+    if (!outl->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     return 0;
@@ -249,17 +252,19 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
 
 static int npptranspose_config_props(AVFilterLink *outlink)
 {
+    FilterLink     *outl   = ff_filter_link(outlink);
     AVFilterContext *ctx   = outlink->src;
     AVFilterLink *inlink   = ctx->inputs[0];
+    FilterLink      *inl   = ff_filter_link(inlink);
     NPPTransposeContext *s = ctx->priv;
     int ret;
 
     if ((inlink->w >= inlink->h && s->passthrough == NPP_TRANSPOSE_PT_TYPE_LANDSCAPE) ||
         (inlink->w <= inlink->h && s->passthrough == NPP_TRANSPOSE_PT_TYPE_PORTRAIT))
     {
-        if (inlink->hw_frames_ctx) {
-            outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
-            if (!outlink->hw_frames_ctx)
+        if (inl->hw_frames_ctx) {
+            outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
+            if (!outl->hw_frames_ctx)
                 return AVERROR(ENOMEM);
         }
 
@@ -387,7 +392,8 @@ static int npptranspose_filter_frame(AVFilterLink *link, AVFrame *in)
     AVFilterContext              *ctx = link->dst;
     NPPTransposeContext            *s = ctx->priv;
     AVFilterLink             *outlink = ctx->outputs[0];
-    AVHWFramesContext     *frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data;
+    FilterLink                  *outl = ff_filter_link(outlink);
+    AVHWFramesContext     *frames_ctx = (AVHWFramesContext*)outl->hw_frames_ctx->data;
     AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
     AVFrame *out = NULL;
     CUcontext dummy;
diff --git a/libavfilter/vf_transpose_opencl.c b/libavfilter/vf_transpose_opencl.c
index 262dec0a8a..aef880a9a4 100644
--- a/libavfilter/vf_transpose_opencl.c
+++ b/libavfilter/vf_transpose_opencl.c
@@ -23,6 +23,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "opencl.h"
 #include "opencl_source.h"
@@ -71,9 +72,11 @@ fail:
 
 static int transpose_opencl_config_output(AVFilterLink *outlink)
 {
+    FilterLink       *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     TransposeOpenCLContext *s = avctx->priv;
     AVFilterLink *inlink = avctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     const AVPixFmtDescriptor *desc_in  = av_pix_fmt_desc_get(inlink->format);
     int ret;
 
@@ -81,9 +84,9 @@ static int transpose_opencl_config_output(AVFilterLink *outlink)
          s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
         (inlink->w <= inlink->h &&
          s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
-        if (inlink->hw_frames_ctx) {
-            outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
-            if (!outlink->hw_frames_ctx)
+        if (inl->hw_frames_ctx) {
+            outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
+            if (!outl->hw_frames_ctx)
                 return AVERROR(ENOMEM);
         }
         av_log(avctx, AV_LOG_VERBOSE,
diff --git a/libavfilter/vf_transpose_vaapi.c b/libavfilter/vf_transpose_vaapi.c
index 165a97de30..bc8fc3c284 100644
--- a/libavfilter/vf_transpose_vaapi.c
+++ b/libavfilter/vf_transpose_vaapi.c
@@ -21,6 +21,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "transpose.h"
 #include "vaapi_vpp.h"
@@ -185,15 +186,17 @@ static av_cold int transpose_vaapi_init(AVFilterContext *avctx)
 
 static int transpose_vaapi_vpp_config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl           = ff_filter_link(outlink);
     AVFilterContext *avctx     = outlink->src;
     VAAPIVPPContext *vpp_ctx   = avctx->priv;
     TransposeVAAPIContext *ctx = avctx->priv;
     AVFilterLink *inlink       = avctx->inputs[0];
+    FilterLink *inl            = ff_filter_link(inlink);
 
     if ((inlink->w >= inlink->h && ctx->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
         (inlink->w <= inlink->h && ctx->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
-        outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
-        if (!outlink->hw_frames_ctx)
+        outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
+        if (!outl->hw_frames_ctx)
             return AVERROR(ENOMEM);
         av_log(avctx, AV_LOG_VERBOSE,
                "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
diff --git a/libavfilter/vf_transpose_vt.c b/libavfilter/vf_transpose_vt.c
index e0f35fdb5a..72bab3d53b 100644
--- a/libavfilter/vf_transpose_vt.c
+++ b/libavfilter/vf_transpose_vt.c
@@ -24,6 +24,8 @@
 #include "libavutil/hwcontext_videotoolbox.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "transpose.h"
 #include "video.h"
@@ -105,17 +107,19 @@ fail:
 
 static int transpose_vt_recreate_hw_ctx(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
     AVHWFramesContext *hw_frame_ctx_in;
     AVHWFramesContext *hw_frame_ctx_out;
     int err;
 
-    av_buffer_unref(&outlink->hw_frames_ctx);
+    av_buffer_unref(&outl->hw_frames_ctx);
 
-    hw_frame_ctx_in = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
-    outlink->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref);
-    hw_frame_ctx_out = (AVHWFramesContext *)outlink->hw_frames_ctx->data;
+    hw_frame_ctx_in = (AVHWFramesContext *)inl->hw_frames_ctx->data;
+    outl->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref);
+    hw_frame_ctx_out = (AVHWFramesContext *)outl->hw_frames_ctx->data;
     hw_frame_ctx_out->format = AV_PIX_FMT_VIDEOTOOLBOX;
     hw_frame_ctx_out->sw_format = hw_frame_ctx_in->sw_format;
     hw_frame_ctx_out->width = outlink->w;
@@ -125,7 +129,7 @@ static int transpose_vt_recreate_hw_ctx(AVFilterLink *outlink)
     if (err < 0)
         return err;
 
-    err = av_hwframe_ctx_init(outlink->hw_frames_ctx);
+    err = av_hwframe_ctx_init(outl->hw_frames_ctx);
     if (err < 0) {
         av_log(avctx, AV_LOG_ERROR,
                "Failed to init videotoolbox frame context, %s\n",
@@ -139,16 +143,18 @@ static int transpose_vt_recreate_hw_ctx(AVFilterLink *outlink)
 static int transpose_vt_config_output(AVFilterLink *outlink)
 {
     int err;
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     TransposeVtContext *s  = avctx->priv;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
     CFStringRef rotation = kVTRotation_0;
     CFBooleanRef vflip = kCFBooleanFalse;
     CFBooleanRef hflip = kCFBooleanFalse;
     int swap_w_h = 0;
 
-    av_buffer_unref(&outlink->hw_frames_ctx);
-    outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
+    av_buffer_unref(&outl->hw_frames_ctx);
+    outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
 
     if ((inlink->w >= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
         (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
diff --git a/libavfilter/vf_transpose_vulkan.c b/libavfilter/vf_transpose_vulkan.c
index 263a934dc5..e04461b3bb 100644
--- a/libavfilter/vf_transpose_vulkan.c
+++ b/libavfilter/vf_transpose_vulkan.c
@@ -23,6 +23,8 @@
 #include "libavutil/opt.h"
 #include "vulkan_filter.h"
 #include "vulkan_spirv.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "transpose.h"
 #include "video.h"
@@ -193,18 +195,20 @@ static av_cold void transpose_vulkan_uninit(AVFilterContext *avctx)
 
 static int config_props_output(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     TransposeVulkanContext *s = avctx->priv;
     FFVulkanContext *vkctx = &s->vkctx;
     AVFilterLink *inlink = avctx->inputs[0];
+    FilterLink *inlink = ff_filter_link(inlink);
 
     if ((inlink->w >= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
         (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
         av_log(avctx, AV_LOG_VERBOSE,
                "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
                inlink->w, inlink->h, inlink->w, inlink->h);
-        outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
-        return outlink->hw_frames_ctx ? 0 : AVERROR(ENOMEM);
+        outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
+        return outl->hw_frames_ctx ? 0 : AVERROR(ENOMEM);
     } else {
         s->passthrough = TRANSPOSE_PT_TYPE_NONE;
     }
diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c
index 6071c46ca1..f368b6ce24 100644
--- a/libavfilter/vf_vpp_qsv.c
+++ b/libavfilter/vf_vpp_qsv.c
@@ -364,13 +364,13 @@ static int config_input(AVFilterLink *inlink)
 
 static mfxStatus get_mfx_version(const AVFilterContext *ctx, mfxVersion *mfx_version)
 {
-    const AVFilterLink *inlink = ctx->inputs[0];
+    const FilterLink *l = ff_filter_link(ctx->inputs[0]);
     AVBufferRef *device_ref;
     AVHWDeviceContext *device_ctx;
     AVQSVDeviceContext *device_hwctx;
 
-    if (inlink->hw_frames_ctx) {
-        AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    if (l->hw_frames_ctx) {
+        AVHWFramesContext *frames_ctx = (AVHWFramesContext *)l->hw_frames_ctx->data;
         device_ref = frames_ctx->device_ref;
     } else if (ctx->hw_device_ctx) {
         device_ref = ctx->hw_device_ctx;
@@ -524,6 +524,7 @@ static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVF
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     VPPContext      *vpp = ctx->priv;
     QSVVPPParam     param = { NULL };
@@ -531,6 +532,7 @@ static int config_output(AVFilterLink *outlink)
     mfxExtBuffer    *ext_buf[ENH_FILTERS_COUNT];
     mfxVersion      mfx_version;
     AVFilterLink    *inlink = ctx->inputs[0];
+    FilterLink         *inl = ff_filter_link(inlink);
     enum AVPixelFormat in_format;
 
     outlink->w          = vpp->out_width;
@@ -552,10 +554,10 @@ static int config_output(AVFilterLink *outlink)
     }
 
     if (inlink->format == AV_PIX_FMT_QSV) {
-         if (!inlink->hw_frames_ctx || !inlink->hw_frames_ctx->data)
+         if (!inl->hw_frames_ctx || !inl->hw_frames_ctx->data)
              return AVERROR(EINVAL);
          else
-             in_format = ((AVHWFramesContext*)inlink->hw_frames_ctx->data)->sw_format;
+             in_format = ((AVHWFramesContext*)inl->hw_frames_ctx->data)->sw_format;
     } else
         in_format = inlink->format;
 
@@ -716,8 +718,8 @@ static int config_output(AVFilterLink *outlink)
     else {
         /* No MFX session is created in this case */
         av_log(ctx, AV_LOG_VERBOSE, "qsv vpp pass through mode.\n");
-        if (inlink->hw_frames_ctx)
-            outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
+        if (inl->hw_frames_ctx)
+            outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
     }
 
     return 0;
diff --git a/libavfilter/vf_yadif_cuda.c b/libavfilter/vf_yadif_cuda.c
index 79080e71c2..e74bd87092 100644
--- a/libavfilter/vf_yadif_cuda.c
+++ b/libavfilter/vf_yadif_cuda.c
@@ -22,6 +22,8 @@
 #include "libavutil/hwcontext.h"
 #include "libavutil/hwcontext_cuda_internal.h"
 #include "libavutil/cuda_check.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "yadif.h"
 
@@ -209,16 +211,17 @@ static av_cold void deint_cuda_uninit(AVFilterContext *ctx)
 
 static int config_input(AVFilterLink *inlink)
 {
+    FilterLink        *l = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     DeintCUDAContext *s  = ctx->priv;
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is "
                "required to associate the processing device.\n");
         return AVERROR(EINVAL);
     }
 
-    s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx);
+    s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx);
     if (!s->input_frames_ref) {
         av_log(ctx, AV_LOG_ERROR, "A input frames reference create "
                "failed.\n");
@@ -231,6 +234,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     AVHWFramesContext *output_frames;
     AVFilterContext *ctx = link->src;
     DeintCUDAContext *s = ctx->priv;
@@ -249,15 +253,15 @@ static int config_output(AVFilterLink *link)
     s->hwctx = ((AVHWDeviceContext*)s->device_ref->data)->hwctx;
     cu = s->hwctx->internal->cuda_dl;
 
-    link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
-    if (!link->hw_frames_ctx) {
+    l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context "
                "for output.\n");
         ret = AVERROR(ENOMEM);
         goto exit;
     }
 
-    output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data;
+    output_frames = (AVHWFramesContext*)l->hw_frames_ctx->data;
 
     output_frames->format    = AV_PIX_FMT_CUDA;
     output_frames->sw_format = s->input_frames->sw_format;
@@ -270,7 +274,7 @@ static int config_output(AVFilterLink *link)
     if (ret < 0)
         goto exit;
 
-    ret = av_hwframe_ctx_init(link->hw_frames_ctx);
+    ret = av_hwframe_ctx_init(l->hw_frames_ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failed to initialise CUDA frame "
                "context for output: %d\n", ret);
diff --git a/libavfilter/vf_yadif_videotoolbox.m b/libavfilter/vf_yadif_videotoolbox.m
index c47d3edfb8..f77e7e86b5 100644
--- a/libavfilter/vf_yadif_videotoolbox.m
+++ b/libavfilter/vf_yadif_videotoolbox.m
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "filters.h"
 #include "internal.h"
 #include "metal/utils.h"
 #include "yadif.h"
@@ -288,16 +289,17 @@ static av_cold int yadif_videotoolbox_init(AVFilterContext *ctx)
 
 static int do_config_input(AVFilterLink *inlink) API_AVAILABLE(macos(10.11), ios(8.0))
 {
+    FilterLink *l = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     YADIFVTContext *s = ctx->priv;
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is "
                "required to associate the processing device.\n");
         return AVERROR(EINVAL);
     }
 
-    s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx);
+    s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx);
     if (!s->input_frames_ref) {
         av_log(ctx, AV_LOG_ERROR, "A input frames reference create "
                "failed.\n");
@@ -321,6 +323,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int do_config_output(AVFilterLink *link) API_AVAILABLE(macos(10.11), ios(8.0))
 {
+    FilterLink *l = ff_filter_link(link);
     AVHWFramesContext *output_frames;
     AVFilterContext *ctx = link->src;
     YADIFVTContext *s = ctx->priv;
@@ -335,15 +338,15 @@ static int do_config_output(AVFilterLink *link) API_AVAILABLE(macos(10.11), ios(
         return AVERROR(ENOMEM);
     }
 
-    link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
-    if (!link->hw_frames_ctx) {
+    l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
+    if (!l->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context "
                "for output.\n");
         ret = AVERROR(ENOMEM);
         goto exit;
     }
 
-    output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data;
+    output_frames = (AVHWFramesContext*)l->hw_frames_ctx->data;
 
     output_frames->format    = AV_PIX_FMT_VIDEOTOOLBOX;
     output_frames->sw_format = s->input_frames->sw_format;
@@ -354,7 +357,7 @@ static int do_config_output(AVFilterLink *link) API_AVAILABLE(macos(10.11), ios(
     if (ret < 0)
         goto exit;
 
-    ret = av_hwframe_ctx_init(link->hw_frames_ctx);
+    ret = av_hwframe_ctx_init(l->hw_frames_ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failed to initialise VideoToolbox frame "
                "context for output: %d\n", ret);
diff --git a/libavfilter/video.c b/libavfilter/video.c
index 89d0797ab5..b09c3bd10a 100644
--- a/libavfilter/video.c
+++ b/libavfilter/video.c
@@ -55,15 +55,15 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig
     int pool_align = 0;
     enum AVPixelFormat pool_format = AV_PIX_FMT_NONE;
 
-    if (link->hw_frames_ctx &&
-        ((AVHWFramesContext*)link->hw_frames_ctx->data)->format == link->format) {
+    if (li->l.hw_frames_ctx &&
+        ((AVHWFramesContext*)li->l.hw_frames_ctx->data)->format == link->format) {
         int ret;
         frame = av_frame_alloc();
 
         if (!frame)
             return NULL;
 
-        ret = av_hwframe_get_buffer(link->hw_frames_ctx, frame, 0);
+        ret = av_hwframe_get_buffer(li->l.hw_frames_ctx, frame, 0);
         if (ret < 0)
             av_frame_free(&frame);
 
diff --git a/libavfilter/vsrc_ddagrab.c b/libavfilter/vsrc_ddagrab.c
index 2fb109dede..dc53e15c6d 100644
--- a/libavfilter/vsrc_ddagrab.c
+++ b/libavfilter/vsrc_ddagrab.c
@@ -43,6 +43,7 @@
 #include "libavutil/hwcontext_d3d11va.h"
 #include "compat/w32dlfcn.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -854,6 +855,7 @@ fail:
 
 static int ddagrab_config_props(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     DdagrabContext *dda = avctx->priv;
     int ret;
@@ -915,8 +917,8 @@ static int ddagrab_config_props(AVFilterLink *outlink)
     if (ret < 0)
         return ret;
 
-    outlink->hw_frames_ctx = av_buffer_ref(dda->frames_ref);
-    if (!outlink->hw_frames_ctx)
+    l->hw_frames_ctx = av_buffer_ref(dda->frames_ref);
+    if (!l->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     outlink->w = dda->width;
diff --git a/libavfilter/vsrc_testsrc_vulkan.c b/libavfilter/vsrc_testsrc_vulkan.c
index 480b23ac9f..2b16ee2b6b 100644
--- a/libavfilter/vsrc_testsrc_vulkan.c
+++ b/libavfilter/vsrc_testsrc_vulkan.c
@@ -266,6 +266,7 @@ static int testsrc_vulkan_activate(AVFilterContext *ctx)
 static int testsrc_vulkan_config_props(AVFilterLink *outlink)
 {
     int err;
+    FilterLink *l = ff_filter_link(outlink);
     TestSrcVulkanContext *s = outlink->src->priv;
     FFVulkanContext *vkctx = &s->vkctx;
 
@@ -284,8 +285,8 @@ static int testsrc_vulkan_config_props(AVFilterLink *outlink)
     if (err < 0)
         return err;
 
-    outlink->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref);
-    if (!outlink->hw_frames_ctx)
+    l->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref);
+    if (!l->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     s->time_base = av_inv_q(s->frame_rate);
diff --git a/libavfilter/vulkan_filter.c b/libavfilter/vulkan_filter.c
index cef42eeb4d..2878d9063b 100644
--- a/libavfilter/vulkan_filter.c
+++ b/libavfilter/vulkan_filter.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "filters.h"
 #include "vulkan_filter.h"
 #include "libavutil/vulkan_loader.h"
 
@@ -165,17 +166,18 @@ skip:
 
 int ff_vk_filter_config_input(AVFilterLink *inlink)
 {
+    FilterLink *l = ff_filter_link(inlink);
     AVHWFramesContext *input_frames;
     AVFilterContext *avctx = inlink->dst;
     FFVulkanContext *s = inlink->dst->priv;
 
-    if (!inlink->hw_frames_ctx) {
+    if (!l->hw_frames_ctx) {
         av_log(inlink->dst, AV_LOG_ERROR, "Vulkan filtering requires a "
                "hardware frames context on the input.\n");
         return AVERROR(EINVAL);
     }
 
-    input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
+    input_frames = (AVHWFramesContext *)l->hw_frames_ctx->data;
     if (input_frames->format != AV_PIX_FMT_VULKAN)
         return AVERROR(EINVAL);
 
@@ -184,7 +186,7 @@ int ff_vk_filter_config_input(AVFilterLink *inlink)
         return 0;
 
     /* Save the ref, without reffing it */
-    s->input_frames_ref = inlink->hw_frames_ctx;
+    s->input_frames_ref = l->hw_frames_ctx;
 
     /* Defaults */
     s->input_format = input_frames->sw_format;
@@ -198,9 +200,10 @@ int ff_vk_filter_config_input(AVFilterLink *inlink)
 int ff_vk_filter_config_output(AVFilterLink *outlink)
 {
     int err;
+    FilterLink *l = ff_filter_link(outlink);
     FFVulkanContext *s = outlink->src->priv;
 
-    av_buffer_unref(&outlink->hw_frames_ctx);
+    av_buffer_unref(&l->hw_frames_ctx);
 
     err = ff_vk_filter_init_context(outlink->src, s, s->input_frames_ref,
                                     s->output_width, s->output_height,
@@ -208,8 +211,8 @@ int ff_vk_filter_config_output(AVFilterLink *outlink)
     if (err < 0)
         return err;
 
-    outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
-    if (!outlink->hw_frames_ctx)
+    l->hw_frames_ctx = av_buffer_ref(s->frames_ref);
+    if (!l->hw_frames_ctx)
         return AVERROR(ENOMEM);
 
     outlink->w = s->output_width;
-- 
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 06/10] lavfi: move AVFilterLink.current_pts(_us) to FilterLink
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
                   ` (3 preceding siblings ...)
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 05/10] lavfi: move AVFilterLink.hw_frames_ctx to FilterLink Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 07/10] lavfi: move AVFilterLink.frame_rate " Anton Khirnov
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

---
 libavfilter/avfilter.c       | 14 +++++++-------
 libavfilter/avfilter.h       | 12 ------------
 libavfilter/avfiltergraph.c  |  6 +++---
 libavfilter/f_graphmonitor.c |  5 +++--
 libavfilter/filters.h        | 12 ++++++++++++
 5 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index de74fc2abf..9b72b6162f 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -228,8 +228,8 @@ static void update_link_current_pts(FilterLinkInternal *li, int64_t pts)
 
     if (pts == AV_NOPTS_VALUE)
         return;
-    link->current_pts = pts;
-    link->current_pts_us = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q);
+    li->l.current_pts = pts;
+    li->l.current_pts_us = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q);
     /* TODO use duration */
     if (link->graph && li->age_index >= 0)
         ff_avfilter_graph_update_heap(link->graph, li);
@@ -349,8 +349,8 @@ int ff_filter_config_links(AVFilterContext *filter)
         }
 
         inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL;
-        link->current_pts =
-        link->current_pts_us = AV_NOPTS_VALUE;
+        li->l.current_pts =
+        li->l.current_pts_us = AV_NOPTS_VALUE;
 
         switch (li->init_state) {
         case AVLINK_INIT:
@@ -503,7 +503,7 @@ static int64_t guess_status_pts(AVFilterContext *ctx, int status, AVRational lin
     for (i = 0; i < ctx->nb_inputs; i++) {
         FilterLinkInternal * const li = ff_link_internal(ctx->inputs[i]);
         if (li->status_out == status)
-            r = FFMIN(r, av_rescale_q(ctx->inputs[i]->current_pts, ctx->inputs[i]->time_base, link_time_base));
+            r = FFMIN(r, av_rescale_q(li->l.current_pts, ctx->inputs[i]->time_base, link_time_base));
     }
     if (r < INT64_MAX)
         return r;
@@ -1396,7 +1396,7 @@ int ff_filter_activate(AVFilterContext *filter)
 int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
 {
     FilterLinkInternal * const li = ff_link_internal(link);
-    *rpts = link->current_pts;
+    *rpts = li->l.current_pts;
     if (ff_framequeue_queued_frames(&li->fifo))
         return *rstatus = 0;
     if (li->status_out)
@@ -1405,7 +1405,7 @@ int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts
         return *rstatus = 0;
     *rstatus = li->status_out = li->status_in;
     update_link_current_pts(li, li->status_in_pts);
-    *rpts = link->current_pts;
+    *rpts = li->l.current_pts;
     return 1;
 }
 
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index bf9a682bb7..0d1fdf980b 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -600,18 +600,6 @@ struct AVFilterLink {
      */
     struct AVFilterGraph *graph;
 
-    /**
-     * Current timestamp of the link, as defined by the most recent
-     * frame(s), in link time_base units.
-     */
-    int64_t current_pts;
-
-    /**
-     * Current timestamp of the link, as defined by the most recent
-     * frame(s), in AV_TIME_BASE units.
-     */
-    int64_t current_pts_us;
-
     /**
      * Frame rate of the stream on the link, or 1/0 if unknown or variable;
      * if left to 0/0, will be automatically copied from the first input
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 47655703cd..e589ac2415 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1326,7 +1326,7 @@ static void heap_bubble_up(FFFilterGraph *graph,
 
     while (index) {
         int parent = (index - 1) >> 1;
-        if (links[parent]->l.pub.current_pts_us >= li->l.pub.current_pts_us)
+        if (links[parent]->l.current_pts_us >= li->l.current_pts_us)
             break;
         links[index] = links[parent];
         links[index]->age_index = index;
@@ -1348,9 +1348,9 @@ static void heap_bubble_down(FFFilterGraph *graph,
         if (child >= graph->sink_links_count)
             break;
         if (child + 1 < graph->sink_links_count &&
-            links[child + 1]->l.pub.current_pts_us < links[child]->l.pub.current_pts_us)
+            links[child + 1]->l.current_pts_us < links[child]->l.current_pts_us)
             child++;
-        if (li->l.pub.current_pts_us < links[child]->l.pub.current_pts_us)
+        if (li->l.current_pts_us < links[child]->l.current_pts_us)
             break;
         links[index] = links[child];
         links[index]->age_index = index;
diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c
index 3996261318..06573dbb96 100644
--- a/libavfilter/f_graphmonitor.c
+++ b/libavfilter/f_graphmonitor.c
@@ -258,8 +258,9 @@ static int draw_items(AVFilterContext *ctx,
                       size_t frames)
 {
     GraphMonitorContext *s = ctx->priv;
+    FilterLink *fl = ff_filter_link(l);
     int64_t previous_pts_us = s->cache[s->cache_index].previous_pts_us;
-    int64_t current_pts_us = l->current_pts_us;
+    int64_t current_pts_us = fl->current_pts_us;
     const int flags = s->flags;
     const int mode = s->mode;
     char buffer[1024] = { 0 };
@@ -368,7 +369,7 @@ static int draw_items(AVFilterContext *ctx,
         xpos += len * 8;
     }
 
-    s->cache[s->cache_index].previous_pts_us = l->current_pts_us;
+    s->cache[s->cache_index].previous_pts_us = current_pts_us;
 
     if (s->cache_index + 1 >= s->cache_size / sizeof(*(s->cache))) {
         void *ptr = av_fast_realloc(s->cache, &s->cache_size, s->cache_size * 2);
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 9e230dc987..98b2442389 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -42,6 +42,18 @@
 typedef struct FilterLink {
     AVFilterLink pub;
 
+    /**
+     * Current timestamp of the link, as defined by the most recent
+     * frame(s), in link time_base units.
+     */
+    int64_t current_pts;
+
+    /**
+     * Current timestamp of the link, as defined by the most recent
+     * frame(s), in AV_TIME_BASE units.
+     */
+    int64_t current_pts_us;
+
     /**
      * Minimum number of samples to filter at once.
      *
-- 
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 07/10] lavfi: move AVFilterLink.frame_rate to FilterLink
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
                   ` (4 preceding siblings ...)
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 06/10] lavfi: move AVFilterLink.current_pts(_us) " Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} " Anton Khirnov
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

Co-developed-by: James Almer <jamrial@gmail.com>
---
 libavfilter/af_aiir.c              |  6 ++++--
 libavfilter/avf_a3dscope.c         |  5 +++--
 libavfilter/avf_abitscope.c        |  5 +++--
 libavfilter/avf_ahistogram.c       |  5 +++--
 libavfilter/avf_aphasemeter.c      |  5 +++--
 libavfilter/avf_avectorscope.c     |  5 +++--
 libavfilter/avf_concat.c           | 11 +++++++----
 libavfilter/avf_showcqt.c          |  3 ++-
 libavfilter/avf_showcwt.c          |  5 +++--
 libavfilter/avf_showfreqs.c        |  5 +++--
 libavfilter/avf_showspatial.c      |  5 +++--
 libavfilter/avf_showspectrum.c     |  5 +++--
 libavfilter/avf_showvolume.c       |  5 +++--
 libavfilter/avf_showwaves.c        | 11 ++++++-----
 libavfilter/avfilter.c             |  6 ++++--
 libavfilter/avfilter.h             | 13 -------------
 libavfilter/buffersink.c           |  8 +++++++-
 libavfilter/buffersrc.c            |  2 +-
 libavfilter/f_drawgraph.c          |  6 ++++--
 libavfilter/f_ebur128.c            |  5 +++--
 libavfilter/f_graphmonitor.c       |  5 +++--
 libavfilter/f_interleave.c         |  3 ++-
 libavfilter/f_loop.c               |  3 ++-
 libavfilter/f_streamselect.c       |  4 +++-
 libavfilter/filters.h              | 15 +++++++++++++++
 libavfilter/qrencode.c             |  4 +++-
 libavfilter/qsvvpp.c               | 10 +++++-----
 libavfilter/setpts.c               |  9 ++++++---
 libavfilter/src_avsynctest.c       |  3 ++-
 libavfilter/src_movie.c            |  3 ++-
 libavfilter/stack_internal.c       | 12 +++++++-----
 libavfilter/vaf_spectrumsynth.c    | 10 ++++++----
 libavfilter/vf_alphamerge.c        |  4 +++-
 libavfilter/vf_blend.c             |  5 ++++-
 libavfilter/vf_blend_vulkan.c      |  6 +++++-
 libavfilter/vf_bm3d.c              |  4 +++-
 libavfilter/vf_ccrepack.c          |  4 +++-
 libavfilter/vf_colormap.c          |  5 ++++-
 libavfilter/vf_convolve.c          |  5 ++++-
 libavfilter/vf_coreimage.m         |  4 +++-
 libavfilter/vf_corr.c              |  5 ++++-
 libavfilter/vf_decimate.c          |  8 +++++---
 libavfilter/vf_deinterlace_vaapi.c |  7 +++++--
 libavfilter/vf_dejudder.c          |  5 ++++-
 libavfilter/vf_deshake_opencl.c    |  5 +++--
 libavfilter/vf_detelecine.c        |  9 ++++++---
 libavfilter/vf_displace.c          |  5 ++++-
 libavfilter/vf_eq.c                |  7 +++++--
 libavfilter/vf_estdif.c            |  8 ++++++--
 libavfilter/vf_fieldmatch.c        |  4 +++-
 libavfilter/vf_fps.c               | 12 +++++++-----
 libavfilter/vf_framepack.c         | 18 +++++++++++-------
 libavfilter/vf_framerate.c         |  3 ++-
 libavfilter/vf_framestep.c         | 11 +++++++----
 libavfilter/vf_freezedetect.c      |  3 ++-
 libavfilter/vf_freezeframes.c      |  4 +++-
 libavfilter/vf_frei0r.c            |  4 +++-
 libavfilter/vf_fsync.c             |  3 ++-
 libavfilter/vf_guided.c            |  4 +++-
 libavfilter/vf_hue.c               |  6 ++++--
 libavfilter/vf_hysteresis.c        |  5 ++++-
 libavfilter/vf_identity.c          |  5 ++++-
 libavfilter/vf_libplacebo.c        | 17 +++++++++++------
 libavfilter/vf_libvmaf.c           |  4 +++-
 libavfilter/vf_limitdiff.c         |  5 ++++-
 libavfilter/vf_lut2.c              |  5 ++++-
 libavfilter/vf_maskedclamp.c       |  5 ++++-
 libavfilter/vf_maskedmerge.c       |  5 ++++-
 libavfilter/vf_maskedminmax.c      |  5 ++++-
 libavfilter/vf_maskedthreshold.c   |  5 ++++-
 libavfilter/vf_mergeplanes.c       |  5 ++++-
 libavfilter/vf_midequalizer.c      |  5 ++++-
 libavfilter/vf_minterpolate.c      |  4 +++-
 libavfilter/vf_mix.c               |  6 ++++--
 libavfilter/vf_morpho.c            |  5 ++++-
 libavfilter/vf_multiply.c          |  5 ++++-
 libavfilter/vf_nnedi.c             | 12 ++++++++----
 libavfilter/vf_overlay_qsv.c       |  5 +++--
 libavfilter/vf_premultiply.c       |  4 +++-
 libavfilter/vf_psnr.c              |  5 ++++-
 libavfilter/vf_remap.c             |  5 ++++-
 libavfilter/vf_remap_opencl.c      |  5 ++++-
 libavfilter/vf_repeatfields.c      |  4 +++-
 libavfilter/vf_scale.c             |  5 ++++-
 libavfilter/vf_scale_npp.c         |  3 ++-
 libavfilter/vf_separatefields.c    |  6 ++++--
 libavfilter/vf_showinfo.c          | 11 +++++++----
 libavfilter/vf_signature.c         |  5 ++++-
 libavfilter/vf_ssim.c              |  5 ++++-
 libavfilter/vf_ssim360.c           |  5 ++++-
 libavfilter/vf_stack.c             | 15 +++++++++------
 libavfilter/vf_stereo3d.c          |  7 +++++--
 libavfilter/vf_telecine.c          | 10 ++++++----
 libavfilter/vf_threshold.c         |  5 ++++-
 libavfilter/vf_tile.c              |  6 ++++--
 libavfilter/vf_tinterlace.c        | 14 +++++++++-----
 libavfilter/vf_tpad.c              | 12 +++++++-----
 libavfilter/vf_untile.c            |  8 +++++---
 libavfilter/vf_varblur.c           |  5 ++++-
 libavfilter/vf_vif.c               |  5 ++++-
 libavfilter/vf_vignette.c          |  6 ++++--
 libavfilter/vf_vpp_qsv.c           | 15 +++++++++------
 libavfilter/vf_w3fdif.c            |  5 ++++-
 libavfilter/vf_weave.c             |  7 +++++--
 libavfilter/vf_xfade.c             | 17 ++++++++++-------
 libavfilter/vf_xfade_opencl.c      |  4 +++-
 libavfilter/vf_xfade_vulkan.c      |  4 +++-
 libavfilter/vf_xmedian.c           |  9 ++++++---
 libavfilter/vf_zoompan.c           |  3 ++-
 libavfilter/vsrc_cellauto.c        |  4 +++-
 libavfilter/vsrc_ddagrab.c         |  2 +-
 libavfilter/vsrc_gradients.c       |  3 ++-
 libavfilter/vsrc_life.c            |  4 +++-
 libavfilter/vsrc_mandelbrot.c      |  4 +++-
 libavfilter/vsrc_mptestsrc.c       |  4 +++-
 libavfilter/vsrc_perlin.c          |  4 +++-
 libavfilter/vsrc_sierpinski.c      |  4 +++-
 libavfilter/vsrc_testsrc.c         |  4 +++-
 libavfilter/vsrc_testsrc_vulkan.c  |  2 +-
 libavfilter/yadif_common.c         |  9 ++++++---
 120 files changed, 503 insertions(+), 239 deletions(-)

diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c
index 7bd9e37e43..9704a9e0a3 100644
--- a/libavfilter/af_aiir.c
+++ b/libavfilter/af_aiir.c
@@ -27,6 +27,7 @@
 #include "libavutil/xga_font_data.h"
 #include "audio.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -1434,14 +1435,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
 static int config_video(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AudioIIRContext *s = ctx->priv;
 
     outlink->sample_aspect_ratio = (AVRational){1,1};
     outlink->w = s->w;
     outlink->h = s->h;
-    outlink->frame_rate = s->rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     return 0;
 }
diff --git a/libavfilter/avf_a3dscope.c b/libavfilter/avf_a3dscope.c
index d7fe2dcb75..27eb73effb 100644
--- a/libavfilter/avf_a3dscope.c
+++ b/libavfilter/avf_a3dscope.c
@@ -115,13 +115,14 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     Audio3dScopeContext *s = outlink->src->priv;
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     return 0;
 }
diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c
index 13c704ff27..749c78fe14 100644
--- a/libavfilter/avf_abitscope.c
+++ b/libavfilter/avf_abitscope.c
@@ -139,12 +139,13 @@ static int config_input(AVFilterLink *inlink)
 static int config_output(AVFilterLink *outlink)
 {
     AudioBitScopeContext *s = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     return 0;
 }
diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c
index 6fb3f64ac9..23239b1b72 100644
--- a/libavfilter/avf_ahistogram.c
+++ b/libavfilter/avf_ahistogram.c
@@ -161,12 +161,13 @@ static int get_log_bin_sign(float in, int w)
 static int config_output(AVFilterLink *outlink)
 {
     AudioHistogramContext *s = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     s->histogram_h = s->h * s->phisto;
     s->ypos = s->h * s->phisto;
diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c
index 6632bae3ec..bf7ae0823f 100644
--- a/libavfilter/avf_aphasemeter.c
+++ b/libavfilter/avf_aphasemeter.c
@@ -142,14 +142,15 @@ static int config_video_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AudioPhaseMeterContext *s = ctx->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     s->last_pts = AV_NOPTS_VALUE;
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     if (!strcmp(s->mpc_str, "none"))
         s->draw_median_phase = 0;
diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c
index 1b3461d91d..be5656f13b 100644
--- a/libavfilter/avf_avectorscope.c
+++ b/libavfilter/avf_avectorscope.c
@@ -271,12 +271,13 @@ static int config_input(AVFilterLink *inlink)
 static int config_output(AVFilterLink *outlink)
 {
     AudioVectorScopeContext *s = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     s->prev_x = s->hw = s->w / 2;
     s->prev_y = s->hh = s->mode == POLAR ? s->h - 1 : s->h / 2;
diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c
index 5d11631798..67cdc39fd8 100644
--- a/libavfilter/avf_concat.c
+++ b/libavfilter/avf_concat.c
@@ -120,11 +120,13 @@ static int query_formats(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl     = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     ConcatContext *cat   = ctx->priv;
     unsigned out_no = FF_OUTLINK_IDX(outlink);
     unsigned in_no  = out_no, seg;
     AVFilterLink *inlink = ctx->inputs[in_no];
+    FilterLink *inl = ff_filter_link(inlink);
 
     /* enhancement: find a common one */
     outlink->time_base           = AV_TIME_BASE_Q;
@@ -132,15 +134,16 @@ static int config_output(AVFilterLink *outlink)
     outlink->h                   = inlink->h;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     outlink->format              = inlink->format;
-    outlink->frame_rate          = inlink->frame_rate;
+    outl->frame_rate             = inl->frame_rate;
 
     for (seg = 1; seg < cat->nb_segments; seg++) {
         inlink = ctx->inputs[in_no + seg * ctx->nb_outputs];
-        if (outlink->frame_rate.num != inlink->frame_rate.num ||
-            outlink->frame_rate.den != inlink->frame_rate.den) {
+        inl    = ff_filter_link(inlink);
+        if (outl->frame_rate.num != inl->frame_rate.num ||
+            outl->frame_rate.den != inl->frame_rate.den) {
             av_log(ctx, AV_LOG_VERBOSE,
                     "Video inputs have different frame rates, output will be VFR\n");
-            outlink->frame_rate = av_make_q(1, 0);
+            outl->frame_rate = av_make_q(1, 0);
             break;
         }
     }
diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c
index 249b6245ca..fa0c82e996 100644
--- a/libavfilter/avf_showcqt.c
+++ b/libavfilter/avf_showcqt.c
@@ -1353,6 +1353,7 @@ static int query_formats(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowCQTContext *s = ctx->priv;
@@ -1365,7 +1366,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = s->height;
     s->format = outlink->format;
     outlink->sample_aspect_ratio = av_make_q(1, 1);
-    outlink->frame_rate = s->rate;
+    l->frame_rate = s->rate;
     outlink->time_base = av_inv_q(s->rate);
     av_log(ctx, AV_LOG_VERBOSE, "video: %dx%d %s %d/%d fps, bar_h = %d, axis_h = %d, sono_h = %d.\n",
            s->width, s->height, av_get_pix_fmt_name(s->format), s->rate.num, s->rate.den,
diff --git a/libavfilter/avf_showcwt.c b/libavfilter/avf_showcwt.c
index 89a019a0d4..c6fa8ac821 100644
--- a/libavfilter/avf_showcwt.c
+++ b/libavfilter/avf_showcwt.c
@@ -810,6 +810,7 @@ static int compute_kernel(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowCWTContext *s = ctx->priv;
@@ -1033,8 +1034,8 @@ static int config_output(AVFilterLink *outlink)
     } else {
         s->frame_rate = s->auto_frame_rate;
     }
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     ret = compute_kernel(ctx);
     if (ret < 0)
diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c
index 23083ad50a..f5b86a7f17 100644
--- a/libavfilter/avf_showfreqs.c
+++ b/libavfilter/avf_showfreqs.c
@@ -150,6 +150,7 @@ static int query_formats(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowFreqsContext *s = ctx->priv;
@@ -223,8 +224,8 @@ static int config_output(AVFilterLink *outlink)
     if (!s->window)
         return AVERROR(ENOMEM);
 
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
     outlink->sample_aspect_ratio = (AVRational){1,1};
     outlink->w = s->w;
     outlink->h = s->h;
diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c
index ec85f90635..ef67340465 100644
--- a/libavfilter/avf_showspatial.c
+++ b/libavfilter/avf_showspatial.c
@@ -128,6 +128,7 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowSpatialContext *s = ctx->priv;
@@ -138,8 +139,8 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
 
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     /* (re-)configuration if the video output changed (or first init) */
     if (s->win_size != s->buf_size) {
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 3a4b489af3..cb2a5a6ae3 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -1061,6 +1061,7 @@ static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowSpectrumContext *s = ctx->priv;
@@ -1283,8 +1284,8 @@ static int config_output(AVFilterLink *outlink)
     } else {
         s->frame_rate = s->auto_frame_rate;
     }
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     if (s->orientation == VERTICAL) {
         s->combine_buffer =
diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c
index 2ae43de211..06550157fd 100644
--- a/libavfilter/avf_showvolume.c
+++ b/libavfilter/avf_showvolume.c
@@ -196,6 +196,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink        *l = ff_filter_link(outlink);
     ShowVolumeContext *s = outlink->src->priv;
     AVFilterLink *inlink = outlink->src->inputs[0];
     int ch;
@@ -209,8 +210,8 @@ static int config_output(AVFilterLink *outlink)
     }
 
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
 
     for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) {
         int i;
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
index 63e0b36e09..823f1c6fd3 100644
--- a/libavfilter/avf_showwaves.c
+++ b/libavfilter/avf_showwaves.c
@@ -409,6 +409,7 @@ static void draw_sample_cline_gray(uint8_t *buf, int height, int linesize,
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowWavesContext *showwaves = ctx->priv;
@@ -422,14 +423,14 @@ static int config_output(AVFilterLink *outlink)
 
     if (showwaves->single_pic) {
         showwaves->n = av_make_q(1, 1);
-        outlink->frame_rate = av_make_q(1, 1);
+        l->frame_rate = av_make_q(1, 1);
     } else {
         if (!showwaves->n.num || !showwaves->n.den) {
             showwaves->n = av_mul_q(av_make_q(inlink->sample_rate,
                                               showwaves->w), av_inv_q(showwaves->rate));
-            outlink->frame_rate = showwaves->rate;
+            l->frame_rate = showwaves->rate;
         } else {
-            outlink->frame_rate = av_div_q(av_make_q(inlink->sample_rate, showwaves->w), showwaves->n);
+            l->frame_rate = av_div_q(av_make_q(inlink->sample_rate, showwaves->w), showwaves->n);
         }
     }
 
@@ -448,13 +449,13 @@ static int config_output(AVFilterLink *outlink)
     if (!showwaves->history)
         return AVERROR(ENOMEM);
 
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    outlink->time_base = av_inv_q(l->frame_rate);
     outlink->w = showwaves->w;
     outlink->h = showwaves->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
 
     av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%f\n",
-           showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), av_q2d(showwaves->n));
+           showwaves->w, showwaves->h, av_q2d(l->frame_rate), av_q2d(showwaves->n));
 
     switch (outlink->format) {
     case AV_PIX_FMT_GRAY8:
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 9b72b6162f..66dda6584d 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -340,6 +340,7 @@ int ff_filter_config_links(AVFilterContext *filter)
         AVFilterLink *link = filter->inputs[i];
         AVFilterLink *inlink;
         FilterLinkInternal *li = ff_link_internal(link);
+        FilterLinkInternal *li_in;
 
         if (!link) continue;
         if (!link->src || !link->dst) {
@@ -349,6 +350,7 @@ int ff_filter_config_links(AVFilterContext *filter)
         }
 
         inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL;
+        li_in  = inlink ? ff_link_internal(inlink) : NULL;
         li->l.current_pts =
         li->l.current_pts_us = AV_NOPTS_VALUE;
 
@@ -389,8 +391,8 @@ int ff_filter_config_links(AVFilterContext *filter)
                         inlink->sample_aspect_ratio : (AVRational){1,1};
 
                 if (inlink) {
-                    if (!link->frame_rate.num && !link->frame_rate.den)
-                        link->frame_rate = inlink->frame_rate;
+                    if (!li->l.frame_rate.num && !li->l.frame_rate.den)
+                        li->l.frame_rate = li_in->l.frame_rate;
                     if (!link->w)
                         link->w = inlink->w;
                     if (!link->h)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 0d1fdf980b..3498514459 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -600,19 +600,6 @@ struct AVFilterLink {
      */
     struct AVFilterGraph *graph;
 
-    /**
-     * Frame rate of the stream on the link, or 1/0 if unknown or variable;
-     * if left to 0/0, will be automatically copied from the first input
-     * of the source filter if it exists.
-     *
-     * Sources should set it to the best estimation of the real frame rate.
-     * If the source frame rate is unknown or variable, set this to 1/0.
-     * Filters should update it if necessary depending on their function.
-     * Sinks can use it to set a default output frame rate.
-     * It is similar to the r_frame_rate field in AVStream.
-     */
-    AVRational frame_rate;
-
     /**
      * Number of past frames sent through the link.
      */
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index a184677937..f76d0af7ff 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -179,7 +179,6 @@ MAKE_AVFILTERLINK_ACCESSOR(enum AVMediaType , type               )
 MAKE_AVFILTERLINK_ACCESSOR(AVRational       , time_base          )
 MAKE_AVFILTERLINK_ACCESSOR(int              , format             )
 
-MAKE_AVFILTERLINK_ACCESSOR(AVRational       , frame_rate         )
 MAKE_AVFILTERLINK_ACCESSOR(int              , w                  )
 MAKE_AVFILTERLINK_ACCESSOR(int              , h                  )
 MAKE_AVFILTERLINK_ACCESSOR(AVRational       , sample_aspect_ratio)
@@ -188,6 +187,13 @@ MAKE_AVFILTERLINK_ACCESSOR(enum AVColorRange, color_range)
 
 MAKE_AVFILTERLINK_ACCESSOR(int              , sample_rate        )
 
+AVRational av_buffersink_get_frame_rate(const AVFilterContext *ctx)
+{
+    FilterLink *l = ff_filter_link(ctx->inputs[0]);
+    av_assert0(ctx->filter->activate == activate);
+    return l->frame_rate;
+}
+
 AVBufferRef* av_buffersink_get_hw_frames_ctx(const AVFilterContext *ctx)
 {
     FilterLink *l = ff_filter_link(ctx->inputs[0]);
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index b6e8f8036c..2743493d5d 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -520,7 +520,7 @@ static int config_props(AVFilterLink *link)
     }
 
     link->time_base = c->time_base;
-    link->frame_rate = c->frame_rate;
+    l->frame_rate = c->frame_rate;
     return 0;
 }
 
diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c
index 1109780550..8144a9c385 100644
--- a/libavfilter/f_drawgraph.c
+++ b/libavfilter/f_drawgraph.c
@@ -26,6 +26,7 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -424,13 +425,14 @@ static int request_frame(AVFilterLink *outlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     DrawGraphContext *s = outlink->src->priv;
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = s->frame_rate;
+    outlink->time_base = av_inv_q(l->frame_rate);
     s->prev_pts = AV_NOPTS_VALUE;
 
     return 0;
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 436a9eb7a9..b2495aed9b 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -294,6 +294,7 @@ static int config_video_output(AVFilterLink *outlink)
 {
     int i, x, y;
     uint8_t *p;
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     EBUR128Context *ebur128 = ctx->priv;
     AVFrame *outpicref;
@@ -307,8 +308,8 @@ static int config_video_output(AVFilterLink *outlink)
     outlink->w = ebur128->w;
     outlink->h = ebur128->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = av_make_q(10, 1);
-    outlink->time_base = av_inv_q(outlink->frame_rate);
+    l->frame_rate = av_make_q(10, 1);
+    outlink->time_base = av_inv_q(l->frame_rate);
 
 #define PAD 8
 
diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c
index 06573dbb96..72ca5cea15 100644
--- a/libavfilter/f_graphmonitor.c
+++ b/libavfilter/f_graphmonitor.c
@@ -288,7 +288,7 @@ static int draw_items(AVFilterContext *ctx,
     }
     if (flags & FLAG_RATE) {
         if (l->type == AVMEDIA_TYPE_VIDEO) {
-            len = snprintf(buffer, sizeof(buffer)-1, " | fps: %d/%d", l->frame_rate.num, l->frame_rate.den);
+            len = snprintf(buffer, sizeof(buffer)-1, " | fps: %d/%d", fl->frame_rate.num, fl->frame_rate.den);
         } else if (l->type == AVMEDIA_TYPE_AUDIO) {
             len = snprintf(buffer, sizeof(buffer)-1, " | samplerate: %d", l->sample_rate);
         }
@@ -538,6 +538,7 @@ static int activate(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     GraphMonitorContext *s = outlink->src->priv;
 
     s->white[0] = s->white[1] = s->white[2] = 255;
@@ -551,7 +552,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
     outlink->time_base = av_inv_q(s->frame_rate);
 
     return 0;
diff --git a/libavfilter/f_interleave.c b/libavfilter/f_interleave.c
index 93ad548826..e989fbc927 100644
--- a/libavfilter/f_interleave.c
+++ b/libavfilter/f_interleave.c
@@ -183,6 +183,7 @@ static av_cold int init(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink0 = ctx->inputs[0];
     int i;
@@ -193,7 +194,7 @@ static int config_output(AVFilterLink *outlink)
         outlink->h                   = inlink0->h;
         outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
         outlink->format              = inlink0->format;
-        outlink->frame_rate = (AVRational) {1, 0};
+        l->frame_rate = (AVRational) {1, 0};
         for (i = 1; i < ctx->nb_inputs; i++) {
             AVFilterLink *inlink = ctx->inputs[i];
 
diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c
index f58436e679..9c9c03fb05 100644
--- a/libavfilter/f_loop.c
+++ b/libavfilter/f_loop.c
@@ -376,6 +376,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     LoopContext *s = ctx->priv;
     int64_t duration;
     int ret = 0;
@@ -394,7 +395,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
             if (frame->duration)
                 duration = frame->duration;
             else
-                duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+                duration = av_rescale_q(1, av_inv_q(outl->frame_rate), outlink->time_base);
             s->duration += duration;
             s->pts_offset = s->duration;
             ret = ff_filter_frame(outlink, frame);
diff --git a/libavfilter/f_streamselect.c b/libavfilter/f_streamselect.c
index c17b019969..285e7d7315 100644
--- a/libavfilter/f_streamselect.c
+++ b/libavfilter/f_streamselect.c
@@ -98,11 +98,13 @@ static int activate(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl     = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     StreamSelectContext *s = ctx->priv;
     const int outlink_idx = FF_OUTLINK_IDX(outlink);
     const int inlink_idx  = s->map[outlink_idx];
     AVFilterLink *inlink = ctx->inputs[inlink_idx];
+    FilterLink      *inl = ff_filter_link(inlink);
     FFFrameSyncIn *in;
     int i, ret;
 
@@ -115,7 +117,7 @@ static int config_output(AVFilterLink *outlink)
         outlink->w = inlink->w;
         outlink->h = inlink->h;
         outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
-        outlink->frame_rate = inlink->frame_rate;
+        outl->frame_rate = inl->frame_rate;
         break;
     case AVMEDIA_TYPE_AUDIO:
         outlink->sample_rate    = inlink->sample_rate;
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 98b2442389..fc65f1df20 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -70,6 +70,21 @@ typedef struct FilterLink {
      */
     int max_samples;
 
+    /**
+     * Frame rate of the stream on the link, or 1/0 if unknown or variable.
+     *
+     * May be set by the link source filter in its config_props(); if left to
+     * 0/0, will be automatically copied from the first input of the source
+     * filter if it exists.
+     *
+     * Sources should set it to the best estimation of the real frame rate.
+     * If the source frame rate is unknown or variable, set this to 1/0.
+     * Filters should update it if necessary depending on their function.
+     * Sinks can use it to set a default output frame rate.
+     * It is similar to the r_frame_rate field in AVStream.
+     */
+    AVRational frame_rate;
+
     /**
      * For hwaccel pixel formats, this should be a reference to the
      * AVHWFramesContext describing the frames.
diff --git a/libavfilter/qrencode.c b/libavfilter/qrencode.c
index 1c7ce23e6e..f308de7646 100644
--- a/libavfilter/qrencode.c
+++ b/libavfilter/qrencode.c
@@ -41,6 +41,7 @@
 #include "avfilter.h"
 #include "drawutils.h"
 #include "internal.h"
+#include "filters.h"
 #include "formats.h"
 #include "textutils.h"
 #include "video.h"
@@ -586,6 +587,7 @@ AVFILTER_DEFINE_CLASS(qrencodesrc);
 
 static int qrencodesrc_config_props(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     QREncodeContext *qr = ctx->priv;
     int ret;
@@ -645,7 +647,7 @@ static int qrencodesrc_config_props(AVFilterLink *outlink)
     outlink->w = qr->rendered_padded_qrcode_width;
     outlink->h = qr->rendered_padded_qrcode_width;
     outlink->time_base = av_inv_q(qr->frame_rate);
-    outlink->frame_rate = qr->frame_rate;
+    l->frame_rate = qr->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c
index 24e15020b2..3f6f4620b6 100644
--- a/libavfilter/qsvvpp.c
+++ b/libavfilter/qsvvpp.c
@@ -298,13 +298,13 @@ static int map_frame_to_surface(AVFrame *frame, mfxFrameSurface1 *surface)
 /* fill the surface info */
 static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     enum AVPixelFormat        pix_fmt;
     AVHWFramesContext        *frames_ctx;
     AVQSVFramesContext       *frames_hwctx;
     const AVPixFmtDescriptor *desc;
 
     if (link->format == AV_PIX_FMT_QSV) {
-        FilterLink *l = ff_filter_link(link);
         if (!l->hw_frames_ctx)
             return AVERROR(EINVAL);
 
@@ -336,8 +336,8 @@ static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link)
 
     frameinfo->CropW          = link->w;
     frameinfo->CropH          = link->h;
-    frameinfo->FrameRateExtN  = link->frame_rate.num;
-    frameinfo->FrameRateExtD  = link->frame_rate.den;
+    frameinfo->FrameRateExtN  = l->frame_rate.num;
+    frameinfo->FrameRateExtD  = l->frame_rate.den;
 
     /* Apparently VPP in the SDK requires the frame rate to be set to some value, otherwise
      * init will fail */
@@ -514,8 +514,8 @@ static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFr
             return NULL;
     }
 
-    if (outlink->frame_rate.num && outlink->frame_rate.den)
-        out_frame->frame->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+    if (l->frame_rate.num && l->frame_rate.den)
+        out_frame->frame->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
     else
         out_frame->frame->duration = 0;
 
diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c
index 60cf2b642e..9931387c61 100644
--- a/libavfilter/setpts.c
+++ b/libavfilter/setpts.c
@@ -131,6 +131,7 @@ static av_cold int init(AVFilterContext *ctx)
 
 static int config_input(AVFilterLink *inlink)
 {
+    FilterLink *l = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     SetPTSContext *setpts = ctx->priv;
 
@@ -142,8 +143,8 @@ static int config_input(AVFilterLink *inlink)
         setpts->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN;
 
     V(FRAME_RATE) = V(FR) =
-        inlink->frame_rate.num && inlink->frame_rate.den ?
-        av_q2d(inlink->frame_rate) : NAN;
+        l->frame_rate.num && l->frame_rate.den ?
+        av_q2d(l->frame_rate) : NAN;
 
     av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f FRAME_RATE:%f SAMPLE_RATE:%f\n",
            V(TB), V(FRAME_RATE), V(SAMPLE_RATE));
@@ -152,7 +153,9 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output_video(AVFilterLink *outlink)
 {
-    outlink->frame_rate = (AVRational){ 1, 0 };
+    FilterLink *l = ff_filter_link(outlink);
+
+    l->frame_rate = (AVRational){ 1, 0 };
 
     return 0;
 }
diff --git a/libavfilter/src_avsynctest.c b/libavfilter/src_avsynctest.c
index 9fd0b590c1..f69ae08b84 100644
--- a/libavfilter/src_avsynctest.c
+++ b/libavfilter/src_avsynctest.c
@@ -145,13 +145,14 @@ static av_cold int aconfig_props(AVFilterLink *outlink)
 
 static av_cold int config_props(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVSyncTestContext *s = ctx->priv;
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->time_base = av_inv_q(s->frame_rate);
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
     outlink->sample_aspect_ratio = (AVRational) {1, 1};
     s->delay_min = av_mul_q(s->frame_rate, av_make_q(-1, 2));
     s->delay_max = av_mul_q(s->delay_min, av_make_q(-1, 1));
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
index e2cdcf17db..e6e08cdda4 100644
--- a/libavfilter/src_movie.c
+++ b/libavfilter/src_movie.c
@@ -450,6 +450,7 @@ static int movie_query_formats(AVFilterContext *ctx)
 
 static int movie_config_output_props(AVFilterLink *outlink)
 {
+    FilterLink *l = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     MovieContext *movie  = ctx->priv;
     unsigned out_id = FF_OUTLINK_IDX(outlink);
@@ -462,7 +463,7 @@ static int movie_config_output_props(AVFilterLink *outlink)
     case AVMEDIA_TYPE_VIDEO:
         outlink->w          = c->width;
         outlink->h          = c->height;
-        outlink->frame_rate = st->st->r_frame_rate;
+        l->frame_rate = st->st->r_frame_rate;
         break;
     case AVMEDIA_TYPE_AUDIO:
         break;
diff --git a/libavfilter/stack_internal.c b/libavfilter/stack_internal.c
index 1ee20d66cf..b473fa982d 100644
--- a/libavfilter/stack_internal.c
+++ b/libavfilter/stack_internal.c
@@ -52,9 +52,11 @@ static int init_framesync(AVFilterContext *avctx)
 
 static int config_comm_output(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     StackBaseContext *sctx = avctx->priv;
     AVFilterLink *inlink0 = avctx->inputs[0];
+    FilterLink *inl0 = ff_filter_link(inlink0);
     int width, height, ret;
 
     if (sctx->mode == STACK_H) {
@@ -197,16 +199,16 @@ static int config_comm_output(AVFilterLink *outlink)
 
     outlink->w = width;
     outlink->h = height;
-    outlink->frame_rate = inlink0->frame_rate;
+    outl->frame_rate = inl0->frame_rate;
     outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
 
     for (int i = 1; i < sctx->nb_inputs; i++) {
-        AVFilterLink *inlink = avctx->inputs[i];
-        if (outlink->frame_rate.num != inlink->frame_rate.num ||
-            outlink->frame_rate.den != inlink->frame_rate.den) {
+        FilterLink *inlink = ff_filter_link(avctx->inputs[i]);
+        if (outl->frame_rate.num != inlink->frame_rate.num ||
+            outl->frame_rate.den != inlink->frame_rate.den) {
             av_log(avctx, AV_LOG_VERBOSE,
                     "Video inputs have different frame rates, output will be VFR\n");
-            outlink->frame_rate = av_make_q(1, 0);
+            outl->frame_rate = av_make_q(1, 0);
             break;
         }
     }
diff --git a/libavfilter/vaf_spectrumsynth.c b/libavfilter/vaf_spectrumsynth.c
index f4bc0f3025..027b9c6842 100644
--- a/libavfilter/vaf_spectrumsynth.c
+++ b/libavfilter/vaf_spectrumsynth.c
@@ -140,10 +140,12 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     SpectrumSynthContext *s = ctx->priv;
+    FilterLink *inl0 = ff_filter_link(ctx->inputs[0]);
+    FilterLink *inl1 = ff_filter_link(ctx->inputs[1]);
     int width = ctx->inputs[0]->w;
     int height = ctx->inputs[0]->h;
     AVRational time_base  = ctx->inputs[0]->time_base;
-    AVRational frame_rate = ctx->inputs[0]->frame_rate;
+    AVRational frame_rate = inl0->frame_rate;
     float factor, overlap, scale;
     int i, ch, ret;
 
@@ -164,12 +166,12 @@ static int config_output(AVFilterLink *outlink)
                ctx->inputs[1]->time_base.num,
                ctx->inputs[1]->time_base.den);
         return AVERROR_INVALIDDATA;
-    } else if (av_cmp_q(frame_rate, ctx->inputs[1]->frame_rate) != 0) {
+    } else if (av_cmp_q(frame_rate, inl1->frame_rate) != 0) {
         av_log(ctx, AV_LOG_ERROR,
                "Magnitude and Phase framerates differ (%d/%d vs %d/%d).\n",
                frame_rate.num, frame_rate.den,
-               ctx->inputs[1]->frame_rate.num,
-               ctx->inputs[1]->frame_rate.den);
+               inl1->frame_rate.num,
+               inl1->frame_rate.den);
         return AVERROR_INVALIDDATA;
     }
 
diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c
index a5f5baf77e..f3fc1529aa 100644
--- a/libavfilter/vf_alphamerge.c
+++ b/libavfilter/vf_alphamerge.c
@@ -128,9 +128,11 @@ static int config_input_main(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AlphaMergeContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *ml = ff_filter_link(mainlink);
     AVFilterLink *alphalink = ctx->inputs[1];
     int ret;
 
@@ -149,7 +151,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    outl->frame_rate = ml->frame_rate;
 
     return ff_framesync_configure(&s->fs);
 }
diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c
index 5ea6df2e75..d93daa1fac 100644
--- a/libavfilter/vf_blend.c
+++ b/libavfilter/vf_blend.c
@@ -25,6 +25,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixfmt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "vf_blend_init.h"
@@ -339,8 +340,10 @@ static int config_params(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *toplink = ctx->inputs[TOP];
+    FilterLink *tl = ff_filter_link(toplink);
     BlendContext *s = ctx->priv;
     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(toplink->format);
     int ret;
@@ -362,7 +365,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = toplink->h;
     outlink->time_base = toplink->time_base;
     outlink->sample_aspect_ratio = toplink->sample_aspect_ratio;
-    outlink->frame_rate = toplink->frame_rate;
+    outl->frame_rate = tl->frame_rate;
 
     s->hsub = pix_desc->log2_chroma_w;
     s->vsub = pix_desc->log2_chroma_h;
diff --git a/libavfilter/vf_blend_vulkan.c b/libavfilter/vf_blend_vulkan.c
index 417be766b8..05ecfa0830 100644
--- a/libavfilter/vf_blend_vulkan.c
+++ b/libavfilter/vf_blend_vulkan.c
@@ -25,6 +25,8 @@
 #include "libavutil/opt.h"
 #include "vulkan_filter.h"
 #include "vulkan_spirv.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "framesync.h"
 #include "blend.h"
@@ -299,9 +301,11 @@ static av_cold void uninit(AVFilterContext *avctx)
 static int config_props_output(AVFilterLink *outlink)
 {
     int err;
+    FilterLink *outl       = ff_filter_link(outlink);
     AVFilterContext *avctx = outlink->src;
     BlendVulkanContext *s = avctx->priv;
     AVFilterLink *toplink = avctx->inputs[IN_TOP];
+    FilterLink   *tl      = ff_filter_link(toplink);
     AVFilterLink *bottomlink = avctx->inputs[IN_BOTTOM];
 
     if (toplink->w != bottomlink->w || toplink->h != bottomlink->h) {
@@ -314,7 +318,7 @@ static int config_props_output(AVFilterLink *outlink)
     }
 
     outlink->sample_aspect_ratio = toplink->sample_aspect_ratio;
-    outlink->frame_rate = toplink->frame_rate;
+    outl->frame_rate = tl->frame_rate;
 
     RET(ff_vk_filter_config_output(outlink));
 
diff --git a/libavfilter/vf_bm3d.c b/libavfilter/vf_bm3d.c
index eb7f6d34d9..408ce20891 100644
--- a/libavfilter/vf_bm3d.c
+++ b/libavfilter/vf_bm3d.c
@@ -953,9 +953,11 @@ static av_cold int init(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl     = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     BM3DContext *s = ctx->priv;
     AVFilterLink *src = ctx->inputs[0];
+    FilterLink  *srcl = ff_filter_link(src);
     AVFilterLink *ref;
     FFFrameSyncIn *in;
     int ret;
@@ -978,7 +980,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = src->h;
     outlink->time_base = src->time_base;
     outlink->sample_aspect_ratio = src->sample_aspect_ratio;
-    outlink->frame_rate = src->frame_rate;
+    outl->frame_rate = srcl->frame_rate;
 
     if (!s->ref)
         return 0;
diff --git a/libavfilter/vf_ccrepack.c b/libavfilter/vf_ccrepack.c
index 5213eab82b..a6aad87864 100644
--- a/libavfilter/vf_ccrepack.c
+++ b/libavfilter/vf_ccrepack.c
@@ -30,6 +30,7 @@
  */
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "ccfifo.h"
 #include "video.h"
@@ -49,9 +50,10 @@ AVFILTER_DEFINE_CLASS(ccrepack);
 
 static int config_input(AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     CCRepackContext *ctx = link->dst->priv;
 
-    int ret = ff_ccfifo_init(&ctx->cc_fifo, link->frame_rate, ctx);
+    int ret = ff_ccfifo_init(&ctx->cc_fifo, l->frame_rate, ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n");
         return ret;
diff --git a/libavfilter/vf_colormap.c b/libavfilter/vf_colormap.c
index 31f33e7ebd..aa09d0cf67 100644
--- a/libavfilter/vf_colormap.c
+++ b/libavfilter/vf_colormap.c
@@ -28,6 +28,7 @@
 #include "libavutil/common.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "framesync.h"
 #include "video.h"
@@ -482,16 +483,18 @@ static int process_frame(FFFrameSync *fs)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl     = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     ColorMapContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     AVFilterLink *source = ctx->inputs[1];
     AVFilterLink *target = ctx->inputs[2];
     FFFrameSyncIn *in;
     int ret;
 
     outlink->time_base = inlink->time_base;
-    outlink->frame_rate = inlink->frame_rate;
+    outl->frame_rate   = inl->frame_rate;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     outlink->w = inlink->w;
     outlink->h = inlink->h;
diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c
index 971494f3d5..eb83794b88 100644
--- a/libavfilter/vf_convolve.c
+++ b/libavfilter/vf_convolve.c
@@ -28,6 +28,7 @@
 #include "libavutil/tx.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 
@@ -744,10 +745,12 @@ static int do_convolve(FFFrameSync *fs)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     AVFilterContext *ctx = outlink->src;
     ConvolveContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink         *ml = ff_filter_link(mainlink);
     AVFilterLink *secondlink = ctx->inputs[1];
     int ret, i, j;
 
@@ -769,7 +772,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    outl->frame_rate = ml->frame_rate;
 
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
diff --git a/libavfilter/vf_coreimage.m b/libavfilter/vf_coreimage.m
index 4d4cdfb7c7..5c77e8a554 100644
--- a/libavfilter/vf_coreimage.m
+++ b/libavfilter/vf_coreimage.m
@@ -27,6 +27,7 @@
 #import <AppKit/AppKit.h>
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -65,12 +66,13 @@ typedef struct CoreImageContext {
 
 static int config_output(AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     CoreImageContext *ctx = link->src->priv;
 
     link->w                   = ctx->w;
     link->h                   = ctx->h;
     link->sample_aspect_ratio = ctx->sar;
-    link->frame_rate          = ctx->frame_rate;
+    l->frame_rate             = ctx->frame_rate;
     link->time_base           = ctx->time_base;
 
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
diff --git a/libavfilter/vf_corr.c b/libavfilter/vf_corr.c
index 27e01b8775..928eafff96 100644
--- a/libavfilter/vf_corr.c
+++ b/libavfilter/vf_corr.c
@@ -27,6 +27,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 
@@ -330,9 +331,11 @@ static int config_input_ref(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     CorrContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *ml = ff_filter_link(mainlink);
     int ret;
 
     ret = ff_framesync_init_dualinput(&s->fs, ctx);
@@ -342,7 +345,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    outl->frame_rate = ml->frame_rate;
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
 
diff --git a/libavfilter/vf_decimate.c b/libavfilter/vf_decimate.c
index 30910bd0c4..d3b03e76f6 100644
--- a/libavfilter/vf_decimate.c
+++ b/libavfilter/vf_decimate.c
@@ -381,10 +381,12 @@ static const enum AVPixelFormat pix_fmts[] = {
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink *outl     = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     DecimateContext *dm = ctx->priv;
     const AVFilterLink *inlink = ctx->inputs[INPUT_MAIN];
-    AVRational fps = inlink->frame_rate;
+    FilterLink *inl = ff_filter_link(ctx->inputs[INPUT_MAIN]);
+    AVRational fps = inl->frame_rate;
     int max_value;
     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
     const int w = inlink->w;
@@ -426,9 +428,9 @@ static int config_output(AVFilterLink *outlink)
             fps.num, fps.den, outlink->time_base.den, outlink->time_base.num);
     } else {
         outlink->time_base = dm->dec_tb;
-        outlink->frame_rate = av_inv_q(outlink->time_base);
+        outl->frame_rate = av_inv_q(outlink->time_base);
         av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
-            fps.num, fps.den, outlink->frame_rate.num, outlink->frame_rate.den);
+            fps.num, fps.den, outl->frame_rate.num, outl->frame_rate.den);
     }
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     if (dm->ppsrc) {
diff --git a/libavfilter/vf_deinterlace_vaapi.c b/libavfilter/vf_deinterlace_vaapi.c
index dbaba26ab4..5a64e5f33a 100644
--- a/libavfilter/vf_deinterlace_vaapi.c
+++ b/libavfilter/vf_deinterlace_vaapi.c
@@ -23,6 +23,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "vaapi_vpp.h"
@@ -158,7 +159,9 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx)
 
 static int deint_vaapi_config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     AVFilterContext *avctx = outlink->src;
     DeintVAAPIContext *ctx = avctx->priv;
     int err;
@@ -168,8 +171,8 @@ static int deint_vaapi_config_output(AVFilterLink *outlink)
         return err;
     outlink->time_base  = av_mul_q(inlink->time_base,
                                    (AVRational) { 1, ctx->field_rate });
-    outlink->frame_rate = av_mul_q(inlink->frame_rate,
-                                   (AVRational) { ctx->field_rate, 1 });
+    outl->frame_rate = av_mul_q(inl->frame_rate,
+                                (AVRational) { ctx->field_rate, 1 });
 
     return 0;
 }
diff --git a/libavfilter/vf_dejudder.c b/libavfilter/vf_dejudder.c
index f8c35ae34c..0a4a68bd8d 100644
--- a/libavfilter/vf_dejudder.c
+++ b/libavfilter/vf_dejudder.c
@@ -52,6 +52,7 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 
 typedef struct DejudderContext {
@@ -78,12 +79,14 @@ AVFILTER_DEFINE_CLASS(dejudder);
 
 static int config_out_props(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     DejudderContext *s = ctx->priv;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
 
     outlink->time_base = av_mul_q(inlink->time_base, av_make_q(1, 2 * s->cycle));
-    outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(2 * s->cycle, 1));
+    outl->frame_rate = av_mul_q(inl->frame_rate, av_make_q(2 * s->cycle, 1));
 
     av_log(ctx, AV_LOG_VERBOSE, "cycle:%d\n", s->cycle);
 
diff --git a/libavfilter/vf_deshake_opencl.c b/libavfilter/vf_deshake_opencl.c
index 9e87007cbb..47b74a8606 100644
--- a/libavfilter/vf_deshake_opencl.c
+++ b/libavfilter/vf_deshake_opencl.c
@@ -1156,7 +1156,7 @@ static int deshake_opencl_init(AVFilterContext *avctx)
     ff_framequeue_global_init(&fqg);
     ff_framequeue_init(&ctx->fq, &fqg);
     ctx->eof = 0;
-    ctx->smooth_window = (int)(av_q2d(avctx->inputs[0]->frame_rate) * ctx->smooth_window_multiplier);
+    ctx->smooth_window = (int)(av_q2d(inl->frame_rate) * ctx->smooth_window_multiplier);
     ctx->curr_frame = 0;
 
     memset(&zeroed_ulong8, 0, sizeof(cl_ulong8));
@@ -1370,6 +1370,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame)
 {
     AVFilterContext *avctx = link->dst;
     AVFilterLink *outlink = avctx->outputs[0];
+    FilterLink      *outl = ff_filter_link(outlink);
     DeshakeOpenCLContext *deshake_ctx = avctx->priv;
     AVFrame *cropped_frame = NULL, *transformed_frame = NULL;
     int err;
@@ -1416,7 +1417,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame)
     if (input_frame->duration) {
         duration = input_frame->duration;
     } else {
-        duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+        duration = av_rescale_q(1, av_inv_q(outl->frame_rate), outlink->time_base);
     }
     deshake_ctx->duration = input_frame->pts + duration;
 
diff --git a/libavfilter/vf_detelecine.c b/libavfilter/vf_detelecine.c
index 255126da4e..eb81e3424e 100644
--- a/libavfilter/vf_detelecine.c
+++ b/libavfilter/vf_detelecine.c
@@ -28,6 +28,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -162,10 +163,12 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     DetelecineContext *s = ctx->priv;
     const AVFilterLink *inlink = ctx->inputs[0];
-    AVRational fps = inlink->frame_rate;
+    const FilterLink      *inl = ff_filter_link(ctx->inputs[0]);
+    AVRational fps = inl->frame_rate;
 
     if (!fps.num || !fps.den) {
         av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
@@ -174,9 +177,9 @@ static int config_output(AVFilterLink *outlink)
     }
     fps = av_mul_q(fps, av_inv_q(s->pts));
     av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
-           inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den);
+           inl->frame_rate.num, inl->frame_rate.den, fps.num, fps.den);
 
-    outlink->frame_rate = fps;
+    outl->frame_rate = fps;
     outlink->time_base = av_mul_q(inlink->time_base, s->pts);
     av_log(ctx, AV_LOG_VERBOSE, "TB: %d/%d -> %d/%d\n",
            inlink->time_base.num, inlink->time_base.den, outlink->time_base.num, outlink->time_base.den);
diff --git a/libavfilter/vf_displace.c b/libavfilter/vf_displace.c
index 93de62fb5c..c243d422d8 100644
--- a/libavfilter/vf_displace.c
+++ b/libavfilter/vf_displace.c
@@ -21,6 +21,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "video.h"
@@ -318,9 +319,11 @@ static int config_input(AVFilterLink *inlink)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     DisplaceContext *s = ctx->priv;
     AVFilterLink *srclink = ctx->inputs[0];
+    FilterLink        *sl = ff_filter_link(srclink);
     AVFilterLink *xlink = ctx->inputs[1];
     AVFilterLink *ylink = ctx->inputs[2];
     FFFrameSyncIn *in;
@@ -343,7 +346,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = srclink->w;
     outlink->h = srclink->h;
     outlink->sample_aspect_ratio = srclink->sample_aspect_ratio;
-    outlink->frame_rate = srclink->frame_rate;
+    outl->frame_rate = sl->frame_rate;
 
     ret = ff_framesync_init(&s->fs, ctx, 3);
     if (ret < 0)
diff --git a/libavfilter/vf_eq.c b/libavfilter/vf_eq.c
index 30ff976940..38a13b0cfb 100644
--- a/libavfilter/vf_eq.c
+++ b/libavfilter/vf_eq.c
@@ -31,6 +31,8 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "vf_eq.h"
 #include "video.h"
@@ -197,11 +199,12 @@ static av_cold void uninit(AVFilterContext *ctx)
 
 static int config_props(AVFilterLink *inlink)
 {
+    FilterLink *l = ff_filter_link(inlink);
     EQContext *eq = inlink->dst->priv;
 
     eq->var_values[VAR_N] = 0;
-    eq->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ?
-        NAN : av_q2d(inlink->frame_rate);
+    eq->var_values[VAR_R] = l->frame_rate.num == 0 || l->frame_rate.den == 0 ?
+        NAN : av_q2d(l->frame_rate);
 
     return 0;
 }
diff --git a/libavfilter/vf_estdif.c b/libavfilter/vf_estdif.c
index b785c290ff..fccbec7853 100644
--- a/libavfilter/vf_estdif.c
+++ b/libavfilter/vf_estdif.c
@@ -23,6 +23,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -133,13 +134,15 @@ static const enum AVPixelFormat pix_fmts[] = {
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl = ff_filter_link(outlink);
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     ESTDIFContext *s = ctx->priv;
 
     outlink->time_base = av_mul_q(inlink->time_base, (AVRational){1, 2});
     if (s->mode)
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2, 1});
+        outl->frame_rate = av_mul_q(inl->frame_rate, (AVRational){2, 1});
 
     return 0;
 }
@@ -526,6 +529,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int request_frame(AVFilterLink *link)
 {
+    FilterLink *l = ff_filter_link(link);
     AVFilterContext *ctx = link->src;
     ESTDIFContext *s = ctx->priv;
     int ret;
@@ -541,7 +545,7 @@ static int request_frame(AVFilterLink *link)
         if (!next)
             return AVERROR(ENOMEM);
 
-        next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(ctx->outputs[0]->frame_rate),
+        next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(l->frame_rate),
                                                 ctx->outputs[0]->time_base);
         s->eof = 1;
         ret = filter_frame(ctx->inputs[0], next);
diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c
index ffa36c9449..1625c08306 100644
--- a/libavfilter/vf_fieldmatch.c
+++ b/libavfilter/vf_fieldmatch.c
@@ -1046,16 +1046,18 @@ static av_cold void fieldmatch_uninit(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    FilterLink     *outl  = ff_filter_link(outlink);
     AVFilterContext *ctx  = outlink->src;
     FieldMatchContext *fm = ctx->priv;
     const AVFilterLink *inlink =
         ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN];
+    FilterLink *inl = ff_filter_link(ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN]);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
 
     fm->bpc = (desc->comp[0].depth + 7) / 8;
     outlink->time_base = inlink->time_base;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
-    outlink->frame_rate = inlink->frame_rate;
+    outl->frame_rate = inl->frame_rate;
     outlink->w = inlink->w;
     outlink->h = inlink->h;
     return 0;
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index 02636d0f78..c422c5e9a6 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -178,12 +178,14 @@ static int config_props(AVFilterLink* outlink)
 {
     AVFilterContext *ctx    = outlink->src;
     AVFilterLink    *inlink = ctx->inputs[0];
+    FilterLink      *il     = ff_filter_link(inlink);
+    FilterLink      *ol     = ff_filter_link(outlink);
     FPSContext      *s      = ctx->priv;
 
     double var_values[VARS_NB], res;
     int ret;
 
-    var_values[VAR_SOURCE_FPS]    = av_q2d(inlink->frame_rate);
+    var_values[VAR_SOURCE_FPS]    = av_q2d(il->frame_rate);
     var_values[VAR_FPS_NTSC]      = ntsc_fps;
     var_values[VAR_FPS_PAL]       = pal_fps;
     var_values[VAR_FPS_FILM]      = film_fps;
@@ -194,8 +196,8 @@ static int config_props(AVFilterLink* outlink)
     if (ret < 0)
         return ret;
 
-    outlink->frame_rate = av_d2q(res, INT_MAX);
-    outlink->time_base  = av_inv_q(outlink->frame_rate);
+    ol->frame_rate      = av_d2q(res, INT_MAX);
+    outlink->time_base  = av_inv_q(ol->frame_rate);
 
     /* Calculate the input and output pts offsets for start_time */
     if (s->start_time != DBL_MAX && s->start_time != AV_NOPTS_VALUE) {
@@ -214,13 +216,13 @@ static int config_props(AVFilterLink* outlink)
                s->in_pts_off, s->out_pts_off, s->start_time);
     }
 
-    ret = ff_ccfifo_init(&s->cc_fifo, outlink->frame_rate, ctx);
+    ret = ff_ccfifo_init(&s->cc_fifo, ol->frame_rate, ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n");
         return ret;
     }
 
-    av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", outlink->frame_rate.num, outlink->frame_rate.den);
+    av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", ol->frame_rate.num, ol->frame_rate.den);
 
     return 0;
 }
diff --git a/libavfilter/vf_framepack.c b/libavfilter/vf_framepack.c
index 3b915ddddf..d3a195c024 100644
--- a/libavfilter/vf_framepack.c
+++ b/libavfilter/vf_framepack.c
@@ -91,11 +91,14 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx  = outlink->src;
     FramepackContext *s   = outlink->src->priv;
+    FilterLink     *leftl = ff_filter_link(ctx->inputs[LEFT]);
+    FilterLink    *rightl = ff_filter_link(ctx->inputs[RIGHT]);
+    FilterLink        *ol = ff_filter_link(outlink);
 
     int width             = ctx->inputs[LEFT]->w;
     int height            = ctx->inputs[LEFT]->h;
     AVRational time_base  = ctx->inputs[LEFT]->time_base;
-    AVRational frame_rate = ctx->inputs[LEFT]->frame_rate;
+    AVRational frame_rate = leftl->frame_rate;
 
     // check size and fps match on the other input
     if (width  != ctx->inputs[RIGHT]->w ||
@@ -112,12 +115,12 @@ static int config_output(AVFilterLink *outlink)
                ctx->inputs[RIGHT]->time_base.num,
                ctx->inputs[RIGHT]->time_base.den);
         return AVERROR_INVALIDDATA;
-    } else if (av_cmp_q(frame_rate, ctx->inputs[RIGHT]->frame_rate) != 0) {
+    } else if (av_cmp_q(frame_rate, rightl->frame_rate) != 0) {
         av_log(ctx, AV_LOG_ERROR,
                "Left and right framerates differ (%d/%d vs %d/%d).\n",
                frame_rate.num, frame_rate.den,
-               ctx->inputs[RIGHT]->frame_rate.num,
-               ctx->inputs[RIGHT]->frame_rate.den);
+               rightl->frame_rate.num,
+               rightl->frame_rate.den);
         return AVERROR_INVALIDDATA;
     }
 
@@ -148,7 +151,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w          = width;
     outlink->h          = height;
     outlink->time_base  = time_base;
-    outlink->frame_rate = frame_rate;
+    ol->frame_rate      = frame_rate;
 
     return 0;
 }
@@ -312,6 +315,7 @@ static int try_push_frame(AVFilterContext *ctx)
 {
     FramepackContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink       *l = ff_filter_link(outlink);
     AVStereo3D *stereo;
     int ret, i;
 
@@ -323,8 +327,8 @@ static int try_push_frame(AVFilterContext *ctx)
         for (i = 0; i < 2; i++) {
             // set correct timestamps
             if (pts != AV_NOPTS_VALUE) {
-                s->input_views[i]->pts = i == 0 ? pts * 2 : pts * 2 + av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
-                s->input_views[i]->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+                s->input_views[i]->pts = i == 0 ? pts * 2 : pts * 2 + av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
+                s->input_views[i]->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
             }
 
             // set stereo3d side data
diff --git a/libavfilter/vf_framerate.c b/libavfilter/vf_framerate.c
index 0c31f77cc4..f525ab1b65 100644
--- a/libavfilter/vf_framerate.c
+++ b/libavfilter/vf_framerate.c
@@ -374,6 +374,7 @@ retry:
 static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *l = ff_filter_link(outlink);
     FrameRateContext *s = ctx->priv;
     int exact;
 
@@ -399,7 +400,7 @@ static int config_output(AVFilterLink *outlink)
         av_log(ctx, AV_LOG_WARNING, "Timebase conversion is not exact\n");
     }
 
-    outlink->frame_rate = s->dest_frame_rate;
+    l->frame_rate = s->dest_frame_rate;
     outlink->time_base = s->dest_time_base;
 
     ff_dlog(ctx,
diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c
index b8eee53b59..da69e2ba6c 100644
--- a/libavfilter/vf_framestep.c
+++ b/libavfilter/vf_framestep.c
@@ -25,6 +25,7 @@
 
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -48,14 +49,16 @@ static int config_output_props(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     FrameStepContext *framestep = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink       *il = ff_filter_link(inlink);
+    FilterLink       *ol = ff_filter_link(outlink);
 
-    outlink->frame_rate =
-        av_div_q(inlink->frame_rate, (AVRational){framestep->frame_step, 1});
+    ol->frame_rate =
+        av_div_q(il->frame_rate, (AVRational){framestep->frame_step, 1});
 
     av_log(ctx, AV_LOG_VERBOSE, "step:%d frame_rate:%d/%d(%f) -> frame_rate:%d/%d(%f)\n",
            framestep->frame_step,
-           inlink->frame_rate.num, inlink->frame_rate.den, av_q2d(inlink->frame_rate),
-           outlink->frame_rate.num, outlink->frame_rate.den, av_q2d(outlink->frame_rate));
+           il->frame_rate.num, il->frame_rate.den, av_q2d(il->frame_rate),
+           ol->frame_rate.num, ol->frame_rate.den, av_q2d(ol->frame_rate));
     return 0;
 }
 
diff --git a/libavfilter/vf_freezedetect.c b/libavfilter/vf_freezedetect.c
index 18d392d9ae..ef04a2764c 100644
--- a/libavfilter/vf_freezedetect.c
+++ b/libavfilter/vf_freezedetect.c
@@ -146,6 +146,7 @@ static int activate(AVFilterContext *ctx)
     int ret;
     AVFilterLink *inlink = ctx->inputs[0];
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink         *l = ff_filter_link(inlink);
     FreezeDetectContext *s = ctx->priv;
     AVFrame *frame;
 
@@ -162,7 +163,7 @@ static int activate(AVFilterContext *ctx)
         if (s->reference_frame) {
             int64_t duration;
             if (s->reference_frame->pts == AV_NOPTS_VALUE || frame->pts == AV_NOPTS_VALUE || frame->pts < s->reference_frame->pts)     // Discontinuity?
-                duration = inlink->frame_rate.num > 0 ? av_rescale_q(s->n - s->reference_n, av_inv_q(inlink->frame_rate), AV_TIME_BASE_Q) : 0;
+                duration = l->frame_rate.num > 0 ? av_rescale_q(s->n - s->reference_n, av_inv_q(l->frame_rate), AV_TIME_BASE_Q) : 0;
             else
                 duration = av_rescale_q(frame->pts - s->reference_frame->pts, inlink->time_base, AV_TIME_BASE_Q);
 
diff --git a/libavfilter/vf_freezeframes.c b/libavfilter/vf_freezeframes.c
index a272336ff2..b630ad85fe 100644
--- a/libavfilter/vf_freezeframes.c
+++ b/libavfilter/vf_freezeframes.c
@@ -52,6 +52,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *sourcelink = ctx->inputs[0];
     AVFilterLink *replacelink = ctx->inputs[1];
+    FilterLink       *il = ff_filter_link(sourcelink);
+    FilterLink       *ol = ff_filter_link(outlink);
 
     if (sourcelink->w != replacelink->w || sourcelink->h != replacelink->h) {
         av_log(ctx, AV_LOG_ERROR,
@@ -65,7 +67,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = sourcelink->h;
     outlink->time_base = sourcelink->time_base;
     outlink->sample_aspect_ratio = sourcelink->sample_aspect_ratio;
-    outlink->frame_rate = sourcelink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index 7dccd5946f..eeaf7ad2b4 100644
--- a/libavfilter/vf_frei0r.c
+++ b/libavfilter/vf_frei0r.c
@@ -39,6 +39,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/parseutils.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -450,6 +451,7 @@ static av_cold int source_init(AVFilterContext *ctx)
 static int source_config_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink        *l = ff_filter_link(outlink);
     Frei0rContext *s = ctx->priv;
 
     if (av_image_check_size(s->w, s->h, 0, ctx) < 0)
@@ -457,7 +459,7 @@ static int source_config_props(AVFilterLink *outlink)
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->time_base = s->time_base;
-    outlink->frame_rate = av_inv_q(s->time_base);
+    l->frame_rate = av_inv_q(s->time_base);
     outlink->sample_aspect_ratio = (AVRational){1,1};
 
     if (s->destruct && s->instance)
diff --git a/libavfilter/vf_fsync.c b/libavfilter/vf_fsync.c
index 63a5446fa3..8636ada0f8 100644
--- a/libavfilter/vf_fsync.c
+++ b/libavfilter/vf_fsync.c
@@ -224,6 +224,7 @@ end:
 static int fsync_config_props(AVFilterLink* outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink      *l   = ff_filter_link(outlink);
     FsyncContext    *s   = ctx->priv;
     int ret;
 
@@ -235,7 +236,7 @@ static int fsync_config_props(AVFilterLink* outlink)
         return AVERROR_INVALIDDATA;
     }
 
-    outlink->frame_rate = av_make_q(1, 0); // unknown or dynamic
+    l->frame_rate = av_make_q(1, 0); // unknown or dynamic
     outlink->time_base  = av_make_q(s->tb_num, s->tb_den);
 
     return 0;
diff --git a/libavfilter/vf_guided.c b/libavfilter/vf_guided.c
index 68a1b97d1c..262d1df996 100644
--- a/libavfilter/vf_guided.c
+++ b/libavfilter/vf_guided.c
@@ -337,6 +337,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     GuidedContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink         *il = ff_filter_link(mainlink);
+    FilterLink         *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int w, h, ret;
 
@@ -352,7 +354,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     s->I      = av_calloc(w * h, sizeof(*s->I));
     s->II     = av_calloc(w * h, sizeof(*s->II));
diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c
index bf390a03fc..049f835c61 100644
--- a/libavfilter/vf_hue.c
+++ b/libavfilter/vf_hue.c
@@ -33,6 +33,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -265,6 +266,7 @@ static const enum AVPixelFormat pix_fmts[] = {
 static int config_props(AVFilterLink *inlink)
 {
     HueContext *hue = inlink->dst->priv;
+    FilterLink   *l = ff_filter_link(inlink);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
 
     hue->hsub = desc->log2_chroma_w;
@@ -272,8 +274,8 @@ static int config_props(AVFilterLink *inlink)
 
     hue->var_values[VAR_N]  = 0;
     hue->var_values[VAR_TB] = av_q2d(inlink->time_base);
-    hue->var_values[VAR_R]  = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ?
-        NAN : av_q2d(inlink->frame_rate);
+    hue->var_values[VAR_R]  = l->frame_rate.num == 0 || l->frame_rate.den == 0 ?
+        NAN : av_q2d(l->frame_rate);
 
     return 0;
 }
diff --git a/libavfilter/vf_hysteresis.c b/libavfilter/vf_hysteresis.c
index 42678a034c..70df8b4375 100644
--- a/libavfilter/vf_hysteresis.c
+++ b/libavfilter/vf_hysteresis.c
@@ -24,6 +24,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -287,6 +288,8 @@ static int config_output(AVFilterLink *outlink)
     HysteresisContext *s = ctx->priv;
     AVFilterLink *base = ctx->inputs[0];
     AVFilterLink *alt = ctx->inputs[1];
+    FilterLink   *il = ff_filter_link(base);
+    FilterLink   *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -303,7 +306,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = base->w;
     outlink->h = base->h;
     outlink->sample_aspect_ratio = base->sample_aspect_ratio;
-    outlink->frame_rate = base->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0)
         return ret;
diff --git a/libavfilter/vf_identity.c b/libavfilter/vf_identity.c
index ed94069647..2446658bb9 100644
--- a/libavfilter/vf_identity.c
+++ b/libavfilter/vf_identity.c
@@ -31,6 +31,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "scene_sad.h"
@@ -316,6 +317,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     IdentityContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(mainlink);
+    FilterLink *ol = ff_filter_link(outlink);
     int ret;
 
     ret = ff_framesync_init_dualinput(&s->fs, ctx);
@@ -325,7 +328,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
 
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 096064022d..64c1ad6d4d 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -886,7 +886,9 @@ static int output_frame(AVFilterContext *ctx, int64_t pts)
     opts->params.blend_params = NULL;
     for (int i = 0; i < s->nb_inputs; i++) {
         LibplaceboInput *in = &s->inputs[i];
-        int high_fps = av_cmp_q(in->link->frame_rate, outlink->frame_rate) >= 0;
+        FilterLink *il = ff_filter_link(in->link);
+        FilterLink *ol = ff_filter_link(outlink);
+        int high_fps = av_cmp_q(il->frame_rate, ol->frame_rate) >= 0;
         if (in->qstatus != PL_QUEUE_OK)
             continue;
         opts->params.skip_caching_single_frame = high_fps;
@@ -1031,6 +1033,7 @@ static int libplacebo_activate(AVFilterContext *ctx)
         /* Update all input queues to the chosen out_pts */
         for (int i = 0; i < s->nb_inputs; i++) {
             LibplaceboInput *in = &s->inputs[i];
+            FilterLink *l = ff_filter_link(outlink);
             if (in->status && out_pts >= in->status_pts) {
                 in->qstatus = PL_QUEUE_EOF;
                 continue;
@@ -1039,7 +1042,7 @@ static int libplacebo_activate(AVFilterContext *ctx)
             in->qstatus = pl_queue_update(in->queue, &in->mix, pl_queue_params(
                 .pts            = out_pts * av_q2d(outlink->time_base),
                 .radius         = pl_frame_mix_radius(&s->opts->params),
-                .vsync_duration = av_q2d(av_inv_q(outlink->frame_rate)),
+                .vsync_duration = av_q2d(av_inv_q(l->frame_rate)),
             ));
 
             switch (in->qstatus) {
@@ -1192,6 +1195,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
     AVFilterContext *avctx = outlink->src;
     LibplaceboContext *s   = avctx->priv;
     AVFilterLink *inlink   = outlink->src->inputs[0];
+    FilterLink       *ol   = ff_filter_link(outlink);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
     AVHWFramesContext *hwfc;
@@ -1218,14 +1222,15 @@ static int libplacebo_config_output(AVFilterLink *outlink)
 
     /* Frame rate */
     if (s->fps.num) {
-        outlink->frame_rate = s->fps;
+        ol->frame_rate = s->fps;
         outlink->time_base = av_inv_q(s->fps);
     } else {
-        outlink->frame_rate = avctx->inputs[0]->frame_rate;
+        FilterLink *il = ff_filter_link(avctx->inputs[0]);
+        ol->frame_rate = il->frame_rate;
         outlink->time_base = avctx->inputs[0]->time_base;
         for (int i = 1; i < s->nb_inputs; i++) {
-            outlink->frame_rate = max_q(outlink->frame_rate,
-                                        avctx->inputs[i]->frame_rate);
+            il = ff_filter_link(avctx->inputs[i]);
+            ol->frame_rate = max_q(ol->frame_rate, il->frame_rate);
             outlink->time_base = av_gcd_q(outlink->time_base,
                                           avctx->inputs[i]->time_base,
                                           AV_TIME_BASE / 2, AV_TIME_BASE_Q);
diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c
index a54af16000..b06f09e834 100644
--- a/libavfilter/vf_libvmaf.c
+++ b/libavfilter/vf_libvmaf.c
@@ -498,6 +498,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     LIBVMAFContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(mainlink);
+    FilterLink *ol = ff_filter_link(outlink);
     int ret;
 
     ret = ff_framesync_init_dualinput(&s->fs, ctx);
@@ -507,7 +509,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
 
diff --git a/libavfilter/vf_limitdiff.c b/libavfilter/vf_limitdiff.c
index 1e903d45a8..b30b3bc93b 100644
--- a/libavfilter/vf_limitdiff.c
+++ b/libavfilter/vf_limitdiff.c
@@ -22,6 +22,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -243,6 +244,8 @@ static int config_output(AVFilterLink *outlink)
     LimitDiffContext *s = ctx->priv;
     AVFilterLink *filtered = ctx->inputs[0];
     AVFilterLink *source = ctx->inputs[1];
+    FilterLink *il = ff_filter_link(filtered);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -271,7 +274,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = filtered->w;
     outlink->h = filtered->h;
     outlink->sample_aspect_ratio = filtered->sample_aspect_ratio;
-    outlink->frame_rate = filtered->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 2 + !!s->reference)) < 0)
         return ret;
diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c
index 1f0661a0f5..e1bcadb101 100644
--- a/libavfilter/vf_lut2.c
+++ b/libavfilter/vf_lut2.c
@@ -27,6 +27,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -406,6 +407,8 @@ static int lut2_config_output(AVFilterLink *outlink)
     LUT2Context *s = ctx->priv;
     AVFilterLink *srcx = ctx->inputs[0];
     AVFilterLink *srcy = ctx->inputs[1];
+    FilterLink *il = ff_filter_link(srcx);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     int hsub = desc->log2_chroma_w;
@@ -416,7 +419,7 @@ static int lut2_config_output(AVFilterLink *outlink)
     outlink->h = srcx->h;
     outlink->time_base = srcx->time_base;
     outlink->sample_aspect_ratio = srcx->sample_aspect_ratio;
-    outlink->frame_rate = srcx->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     s->nb_planes = av_pix_fmt_count_planes(outlink->format);
     s->height[1] = s->height[2] = AV_CEIL_RSHIFT(outlink->h, vsub);
diff --git a/libavfilter/vf_maskedclamp.c b/libavfilter/vf_maskedclamp.c
index e6fbb1a6d5..787d7493fd 100644
--- a/libavfilter/vf_maskedclamp.c
+++ b/libavfilter/vf_maskedclamp.c
@@ -22,6 +22,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -222,6 +223,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *base = ctx->inputs[0];
     AVFilterLink *dark = ctx->inputs[1];
     AVFilterLink *bright = ctx->inputs[2];
+    FilterLink *il = ff_filter_link(base);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -240,7 +243,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = base->w;
     outlink->h = base->h;
     outlink->sample_aspect_ratio = base->sample_aspect_ratio;
-    outlink->frame_rate = base->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 3)) < 0)
         return ret;
diff --git a/libavfilter/vf_maskedmerge.c b/libavfilter/vf_maskedmerge.c
index 4ca0c571c8..aa5aebb0f8 100644
--- a/libavfilter/vf_maskedmerge.c
+++ b/libavfilter/vf_maskedmerge.c
@@ -22,6 +22,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "maskedmerge.h"
@@ -215,6 +216,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *base = ctx->inputs[0];
     AVFilterLink *overlay = ctx->inputs[1];
     AVFilterLink *mask = ctx->inputs[2];
+    FilterLink *il = ff_filter_link(base);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -233,7 +236,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = base->w;
     outlink->h = base->h;
     outlink->sample_aspect_ratio = base->sample_aspect_ratio;
-    outlink->frame_rate = base->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = av_image_fill_linesizes(s->linesize, outlink->format, outlink->w)) < 0)
         return ret;
diff --git a/libavfilter/vf_maskedminmax.c b/libavfilter/vf_maskedminmax.c
index b1c309cc7d..dd439f5424 100644
--- a/libavfilter/vf_maskedminmax.c
+++ b/libavfilter/vf_maskedminmax.c
@@ -22,6 +22,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -220,6 +221,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *source = ctx->inputs[0];
     AVFilterLink *f1 = ctx->inputs[1];
     AVFilterLink *f2 = ctx->inputs[2];
+    FilterLink *il = ff_filter_link(source);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -238,7 +241,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = source->w;
     outlink->h = source->h;
     outlink->sample_aspect_ratio = source->sample_aspect_ratio;
-    outlink->frame_rate = source->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 3)) < 0)
         return ret;
diff --git a/libavfilter/vf_maskedthreshold.c b/libavfilter/vf_maskedthreshold.c
index e78e11810e..a79063b980 100644
--- a/libavfilter/vf_maskedthreshold.c
+++ b/libavfilter/vf_maskedthreshold.c
@@ -22,6 +22,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -220,6 +221,8 @@ static int config_output(AVFilterLink *outlink)
     MaskedThresholdContext *s = ctx->priv;
     AVFilterLink *source = ctx->inputs[0];
     AVFilterLink *ref = ctx->inputs[1];
+    FilterLink *il = ff_filter_link(source);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -235,7 +238,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = source->w;
     outlink->h = source->h;
     outlink->sample_aspect_ratio = source->sample_aspect_ratio;
-    outlink->frame_rate = source->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0)
         return ret;
diff --git a/libavfilter/vf_mergeplanes.c b/libavfilter/vf_mergeplanes.c
index 91bc0d2c55..e74c12407f 100644
--- a/libavfilter/vf_mergeplanes.c
+++ b/libavfilter/vf_mergeplanes.c
@@ -24,6 +24,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "framesync.h"
@@ -185,6 +186,8 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     MergePlanesContext *s = ctx->priv;
+    FilterLink *il = ff_filter_link(ctx->inputs[0]);
+    FilterLink *ol = ff_filter_link(outlink);
     InputParam inputsp[4];
     FFFrameSyncIn *in;
     int i, ret;
@@ -199,7 +202,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = ctx->inputs[0]->w;
     outlink->h = ctx->inputs[0]->h;
     outlink->time_base = ctx->inputs[0]->time_base;
-    outlink->frame_rate = ctx->inputs[0]->frame_rate;
+    ol->frame_rate = il->frame_rate;
     outlink->sample_aspect_ratio = ctx->inputs[0]->sample_aspect_ratio;
 
     s->planewidth[1]  =
diff --git a/libavfilter/vf_midequalizer.c b/libavfilter/vf_midequalizer.c
index 37a4df7105..89917847b8 100644
--- a/libavfilter/vf_midequalizer.c
+++ b/libavfilter/vf_midequalizer.c
@@ -23,6 +23,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -297,13 +298,15 @@ static int config_output(AVFilterLink *outlink)
     MidEqualizerContext *s = ctx->priv;
     AVFilterLink *in0 = ctx->inputs[0];
     AVFilterLink *in1 = ctx->inputs[1];
+    FilterLink    *il = ff_filter_link(in0);
+    FilterLink    *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
     outlink->w = in0->w;
     outlink->h = in0->h;
     outlink->sample_aspect_ratio = in0->sample_aspect_ratio;
-    outlink->frame_rate = in0->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0)
         return ret;
diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c
index 27743d2f46..f39e514100 100644
--- a/libavfilter/vf_minterpolate.c
+++ b/libavfilter/vf_minterpolate.c
@@ -26,6 +26,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "scene_sad.h"
@@ -398,8 +399,9 @@ static int config_input(AVFilterLink *inlink)
 static int config_output(AVFilterLink *outlink)
 {
     MIContext *mi_ctx = outlink->src->priv;
+    FilterLink     *l = ff_filter_link(outlink);
 
-    outlink->frame_rate = mi_ctx->frame_rate;
+    l->frame_rate       = mi_ctx->frame_rate;
     outlink->time_base  = av_inv_q(mi_ctx->frame_rate);
 
     return 0;
diff --git a/libavfilter/vf_mix.c b/libavfilter/vf_mix.c
index bfbdc2c83e..13a0dc43f6 100644
--- a/libavfilter/vf_mix.c
+++ b/libavfilter/vf_mix.c
@@ -27,6 +27,7 @@
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "framesync.h"
@@ -316,7 +317,8 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     MixContext *s = ctx->priv;
-    AVRational frame_rate = ctx->inputs[0]->frame_rate;
+    FilterLink *il = ff_filter_link(ctx->inputs[0]);
+    FilterLink *ol = ff_filter_link(outlink);
     AVRational sar = ctx->inputs[0]->sample_aspect_ratio;
     AVFilterLink *inlink = ctx->inputs[0];
     int height = ctx->inputs[0]->h;
@@ -366,7 +368,7 @@ static int config_output(AVFilterLink *outlink)
 
     outlink->w          = width;
     outlink->h          = height;
-    outlink->frame_rate = frame_rate;
+    ol->frame_rate     = il->frame_rate;
     outlink->sample_aspect_ratio = sar;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0)
diff --git a/libavfilter/vf_morpho.c b/libavfilter/vf_morpho.c
index ce0f01c9c0..bd1723b906 100644
--- a/libavfilter/vf_morpho.c
+++ b/libavfilter/vf_morpho.c
@@ -30,6 +30,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "video.h"
@@ -1002,6 +1003,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     MorphoContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(mainlink);
+    FilterLink *ol = ff_filter_link(outlink);
     int ret;
 
     s->fs.on_event = do_morpho;
@@ -1012,7 +1015,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
diff --git a/libavfilter/vf_multiply.c b/libavfilter/vf_multiply.c
index 54fbeff483..9ebcb85b6b 100644
--- a/libavfilter/vf_multiply.c
+++ b/libavfilter/vf_multiply.c
@@ -22,6 +22,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "framesync.h"
@@ -164,6 +165,8 @@ static int config_output(AVFilterLink *outlink)
     MultiplyContext *s = ctx->priv;
     AVFilterLink *source = ctx->inputs[0];
     AVFilterLink *ref = ctx->inputs[1];
+    FilterLink *il = ff_filter_link(source);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -179,7 +182,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = source->w;
     outlink->h = source->h;
     outlink->sample_aspect_ratio = source->sample_aspect_ratio;
-    outlink->frame_rate = source->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0)
         return ret;
diff --git a/libavfilter/vf_nnedi.c b/libavfilter/vf_nnedi.c
index 2168c5dbc5..4b8b11a722 100644
--- a/libavfilter/vf_nnedi.c
+++ b/libavfilter/vf_nnedi.c
@@ -30,6 +30,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -173,9 +174,11 @@ static int config_output(AVFilterLink *outlink)
     outlink->w             = ctx->inputs[0]->w;
     outlink->h             = ctx->inputs[0]->h;
 
-    if (s->field == -2 || s->field > 1)
-        outlink->frame_rate = av_mul_q(ctx->inputs[0]->frame_rate,
-                                       (AVRational){2, 1});
+    if (s->field == -2 || s->field > 1) {
+        FilterLink *il = ff_filter_link(ctx->inputs[0]);
+        FilterLink *ol = ff_filter_link(outlink);
+        ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2, 1});
+    }
 
     return 0;
 }
@@ -729,11 +732,12 @@ static int request_frame(AVFilterLink *link)
 
     if (ret == AVERROR_EOF && s->prev) {
         AVFrame *next = av_frame_clone(s->prev);
+        FilterLink *l = ff_filter_link(ctx->outputs[0]);
 
         if (!next)
             return AVERROR(ENOMEM);
 
-        next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(ctx->outputs[0]->frame_rate),
+        next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(l->frame_rate),
                                                 ctx->outputs[0]->time_base);
         s->eof = 1;
 
diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c
index 15dfe4e6f7..37a0d4c2c8 100644
--- a/libavfilter/vf_overlay_qsv.c
+++ b/libavfilter/vf_overlay_qsv.c
@@ -277,6 +277,7 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink      *in1 = ctx->inputs[1];
     FilterLink         *l0 = ff_filter_link(in0);
     FilterLink         *l1 = ff_filter_link(in1);
+    FilterLink         *ol = ff_filter_link(outlink);
     int ret;
 
     av_log(ctx, AV_LOG_DEBUG, "Output is of %s.\n", av_get_pix_fmt_name(outlink->format));
@@ -298,8 +299,8 @@ static int config_output(AVFilterLink *outlink)
 
     outlink->w          = vpp->var_values[VAR_MW];
     outlink->h          = vpp->var_values[VAR_MH];
-    outlink->frame_rate = in0->frame_rate;
-    outlink->time_base  = av_inv_q(outlink->frame_rate);
+    ol->frame_rate      = l0->frame_rate;
+    outlink->time_base  = av_inv_q(ol->frame_rate);
 
     ret = init_framesync(ctx);
     if (ret < 0)
diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c
index 5e97c2000f..c9fabf7ae7 100644
--- a/libavfilter/vf_premultiply.c
+++ b/libavfilter/vf_premultiply.c
@@ -696,6 +696,8 @@ static int config_output(AVFilterLink *outlink)
     PreMultiplyContext *s = ctx->priv;
     AVFilterLink *base = ctx->inputs[0];
     AVFilterLink *alpha;
+    FilterLink *il = ff_filter_link(base);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -717,7 +719,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = base->h;
     outlink->time_base = base->time_base;
     outlink->sample_aspect_ratio = base->sample_aspect_ratio;
-    outlink->frame_rate = base->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if (s->inplace)
         return 0;
diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c
index 413d1fa1ee..b1488effde 100644
--- a/libavfilter/vf_psnr.c
+++ b/libavfilter/vf_psnr.c
@@ -32,6 +32,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "psnr.h"
@@ -383,6 +384,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     PSNRContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(mainlink);
+    FilterLink *ol = ff_filter_link(outlink);
     int ret;
 
     ret = ff_framesync_init_dualinput(&s->fs, ctx);
@@ -392,7 +395,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
 
diff --git a/libavfilter/vf_remap.c b/libavfilter/vf_remap.c
index 7cc56fa5f0..1b23a3ac86 100644
--- a/libavfilter/vf_remap.c
+++ b/libavfilter/vf_remap.c
@@ -42,6 +42,7 @@
 #include "libavutil/opt.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "framesync.h"
 #include "internal.h"
@@ -313,6 +314,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *srclink = ctx->inputs[0];
     AVFilterLink *xlink = ctx->inputs[1];
     AVFilterLink *ylink = ctx->inputs[2];
+    FilterLink *il = ff_filter_link(srclink);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -328,7 +331,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = xlink->w;
     outlink->h = xlink->h;
     outlink->sample_aspect_ratio = srclink->sample_aspect_ratio;
-    outlink->frame_rate = srclink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     ret = ff_framesync_init(&s->fs, ctx, 3);
     if (ret < 0)
diff --git a/libavfilter/vf_remap_opencl.c b/libavfilter/vf_remap_opencl.c
index 8da48096de..852c88d44c 100644
--- a/libavfilter/vf_remap_opencl.c
+++ b/libavfilter/vf_remap_opencl.c
@@ -23,6 +23,7 @@
 #include "libavutil/opt.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "opencl.h"
@@ -233,6 +234,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *srclink = ctx->inputs[0];
     AVFilterLink *xlink = ctx->inputs[1];
     AVFilterLink *ylink = ctx->inputs[2];
+    FilterLink *il = ff_filter_link(srclink);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -248,7 +251,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = xlink->w;
     outlink->h = xlink->h;
     outlink->sample_aspect_ratio = srclink->sample_aspect_ratio;
-    outlink->frame_rate = srclink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     ret = ff_framesync_init(&s->fs, ctx, 3);
     if (ret < 0)
diff --git a/libavfilter/vf_repeatfields.c b/libavfilter/vf_repeatfields.c
index bf0edb5440..612c2f9049 100644
--- a/libavfilter/vf_repeatfields.c
+++ b/libavfilter/vf_repeatfields.c
@@ -69,7 +69,9 @@ static int config_input(AVFilterLink *inlink)
 
 static void update_pts(AVFilterLink *link, AVFrame *f, int64_t pts, int fields)
 {
-    if (av_cmp_q(link->frame_rate, (AVRational){30000, 1001}) == 0 &&
+    FilterLink *l = ff_filter_link(link);
+
+    if (av_cmp_q(l->frame_rate, (AVRational){30000, 1001}) == 0 &&
          av_cmp_q(link->time_base, (AVRational){1001, 60000}) <= 0
     ) {
         f->pts = pts + av_rescale_q(fields, (AVRational){1001, 60000}, link->time_base);
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 680d264ec9..febb3178de 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "framesync.h"
 #include "internal.h"
@@ -800,12 +801,14 @@ fail:
 static int config_props_ref(AVFilterLink *outlink)
 {
     AVFilterLink *inlink = outlink->src->inputs[1];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
 
     outlink->w = inlink->w;
     outlink->h = inlink->h;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     outlink->time_base = inlink->time_base;
-    outlink->frame_rate = inlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
     outlink->colorspace = inlink->colorspace;
     outlink->color_range = inlink->color_range;
 
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index 0c4af074c9..7b67d33296 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -692,12 +692,13 @@ static int config_props_ref(AVFilterLink *outlink)
     FilterLink     *outl = ff_filter_link(outlink);
     AVFilterLink *inlink = outlink->src->inputs[1];
     FilterLink      *inl = ff_filter_link(inlink);
+    FilterLink       *ol = ff_filter_link(outlink);
 
     outlink->w = inlink->w;
     outlink->h = inlink->h;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     outlink->time_base = inlink->time_base;
-    outlink->frame_rate = inlink->frame_rate;
+    ol->frame_rate = inl->frame_rate;
 
     outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx);
 
diff --git a/libavfilter/vf_separatefields.c b/libavfilter/vf_separatefields.c
index b7ddb26377..91df45980f 100644
--- a/libavfilter/vf_separatefields.c
+++ b/libavfilter/vf_separatefields.c
@@ -34,6 +34,8 @@ static int config_props_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     SeparateFieldsContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink       *il = ff_filter_link(inlink);
+    FilterLink       *ol = ff_filter_link(outlink);
 
     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
 
@@ -44,8 +46,8 @@ static int config_props_output(AVFilterLink *outlink)
 
     outlink->time_base.num = inlink->time_base.num;
     outlink->time_base.den = inlink->time_base.den * 2;
-    outlink->frame_rate.num = inlink->frame_rate.num * 2;
-    outlink->frame_rate.den = inlink->frame_rate.den;
+    ol->frame_rate.num = il->frame_rate.num * 2;
+    ol->frame_rate.den = il->frame_rate.den;
     outlink->w = inlink->w;
     outlink->h = inlink->h / 2;
 
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index d79707ce49..f6ffcc39bb 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -47,6 +47,7 @@
 #include "libavutil/uuid.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -114,8 +115,9 @@ static void dump_stereo3d(AVFilterContext *ctx, const AVFrameSideData *sd)
         av_log(ctx, AV_LOG_INFO, ", horizontal_field_of_view: %0.3f", av_q2d(stereo->horizontal_field_of_view));
 }
 
-static void dump_s12m_timecode(AVFilterContext *ctx, AVRational frame_rate, const AVFrameSideData *sd)
+static void dump_s12m_timecode(AVFilterContext *ctx, AVFilterLink *inlink, const AVFrameSideData *sd)
 {
+    FilterLink      *l = ff_filter_link(inlink);
     const uint32_t *tc = (const uint32_t *)sd->data;
 
     if ((sd->size != sizeof(uint32_t) * 4) || (tc[0] > 3)) {
@@ -125,7 +127,7 @@ static void dump_s12m_timecode(AVFilterContext *ctx, AVRational frame_rate, cons
 
     for (int j = 1; j <= tc[0]; j++) {
         char tcbuf[AV_TIMECODE_STR_SIZE];
-        av_timecode_make_smpte_tc_string2(tcbuf, frame_rate, tc[j], 0, 0);
+        av_timecode_make_smpte_tc_string2(tcbuf, l->frame_rate, tc[j], 0, 0);
         av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0]  ? ", " : "");
     }
 }
@@ -806,7 +808,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
             dump_stereo3d(ctx, sd);
             break;
         case AV_FRAME_DATA_S12M_TIMECODE: {
-            dump_s12m_timecode(ctx, inlink->frame_rate, sd);
+            dump_s12m_timecode(ctx, inlink, sd);
             break;
         }
         case AV_FRAME_DATA_DISPLAYMATRIX:
@@ -875,11 +877,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 
 static int config_props(AVFilterContext *ctx, AVFilterLink *link, int is_out)
 {
+    FilterLink *l = ff_filter_link(link);
 
     av_log(ctx, AV_LOG_INFO, "config %s time_base: %d/%d, frame_rate: %d/%d\n",
            is_out ? "out" : "in",
            link->time_base.num, link->time_base.den,
-           link->frame_rate.num, link->frame_rate.den);
+           l->frame_rate.num, l->frame_rate.den);
 
     return 0;
 }
diff --git a/libavfilter/vf_signature.c b/libavfilter/vf_signature.c
index d5c0df57e6..d5df683642 100644
--- a/libavfilter/vf_signature.c
+++ b/libavfilter/vf_signature.c
@@ -31,6 +31,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/file_open.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "signature.h"
 #include "signature_lookup.c"
@@ -726,9 +727,11 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink       *il = ff_filter_link(inlink);
+    FilterLink       *ol = ff_filter_link(outlink);
 
     outlink->time_base = inlink->time_base;
-    outlink->frame_rate = inlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     outlink->w = inlink->w;
     outlink->h = inlink->h;
diff --git a/libavfilter/vf_ssim.c b/libavfilter/vf_ssim.c
index 2210ea40ec..609d082ef7 100644
--- a/libavfilter/vf_ssim.c
+++ b/libavfilter/vf_ssim.c
@@ -41,6 +41,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "ssim.h"
@@ -507,6 +508,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     SSIMContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(mainlink);
+    FilterLink *ol = ff_filter_link(outlink);
     int ret;
 
     ret = ff_framesync_init_dualinput(&s->fs, ctx);
@@ -516,7 +519,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_configure(&s->fs)) < 0)
         return ret;
diff --git a/libavfilter/vf_ssim360.c b/libavfilter/vf_ssim360.c
index 33606ea599..ca0545e178 100644
--- a/libavfilter/vf_ssim360.c
+++ b/libavfilter/vf_ssim360.c
@@ -51,6 +51,7 @@
 
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "internal.h"
 #include "framesync.h"
 
@@ -1594,6 +1595,8 @@ static int config_output(AVFilterLink *outlink)
     SSIM360Context      *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
     AVFilterLink  *reflink = ctx->inputs[0];
+    FilterLink         *il = ff_filter_link(mainlink);
+    FilterLink         *ol = ff_filter_link(outlink);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     int ret;
 
@@ -1643,7 +1646,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     s->fs.opt_shortest   = 1;
     s->fs.opt_repeatlast = 1;
diff --git a/libavfilter/vf_stack.c b/libavfilter/vf_stack.c
index 5bb50148a7..4d42d9b5c5 100644
--- a/libavfilter/vf_stack.c
+++ b/libavfilter/vf_stack.c
@@ -29,6 +29,7 @@
 
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "framesync.h"
@@ -196,7 +197,9 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     StackContext *s = ctx->priv;
-    AVRational frame_rate = ctx->inputs[0]->frame_rate;
+    FilterLink *il = ff_filter_link(ctx->inputs[0]);
+    FilterLink *ol = ff_filter_link(outlink);
+    AVRational frame_rate = il->frame_rate;
     AVRational sar = ctx->inputs[0]->sample_aspect_ratio;
     int height = ctx->inputs[0]->h;
     int width = ctx->inputs[0]->w;
@@ -383,16 +386,16 @@ static int config_output(AVFilterLink *outlink)
 
     outlink->w          = width;
     outlink->h          = height;
-    outlink->frame_rate = frame_rate;
+    ol->frame_rate      = frame_rate;
     outlink->sample_aspect_ratio = sar;
 
     for (i = 1; i < s->nb_inputs; i++) {
-        AVFilterLink *inlink = ctx->inputs[i];
-        if (outlink->frame_rate.num != inlink->frame_rate.num ||
-            outlink->frame_rate.den != inlink->frame_rate.den) {
+        il = ff_filter_link(ctx->inputs[i]);
+        if (ol->frame_rate.num != il->frame_rate.num ||
+            ol->frame_rate.den != il->frame_rate.den) {
             av_log(ctx, AV_LOG_VERBOSE,
                     "Video inputs have different frame rates, output will be VFR\n");
-            outlink->frame_rate = av_make_q(1, 0);
+            ol->frame_rate = av_make_q(1, 0);
             break;
         }
     }
diff --git a/libavfilter/vf_stereo3d.c b/libavfilter/vf_stereo3d.c
index 6bd4158f6d..67c34bccb0 100644
--- a/libavfilter/vf_stereo3d.c
+++ b/libavfilter/vf_stereo3d.c
@@ -27,6 +27,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -364,7 +365,9 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     Stereo3DContext *s = ctx->priv;
-    AVRational fps = inlink->frame_rate;
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
+    AVRational fps = il->frame_rate;
     AVRational tb = inlink->time_base;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     int ret;
@@ -577,7 +580,7 @@ static int config_output(AVFilterLink *outlink)
 
     outlink->w = s->out.width;
     outlink->h = s->out.height;
-    outlink->frame_rate = fps;
+    ol->frame_rate = fps;
     outlink->time_base = tb;
     outlink->sample_aspect_ratio = s->aspect;
 
diff --git a/libavfilter/vf_telecine.c b/libavfilter/vf_telecine.c
index 44ef2b74d9..fee3e43aff 100644
--- a/libavfilter/vf_telecine.c
+++ b/libavfilter/vf_telecine.c
@@ -139,8 +139,10 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     TelecineContext *s = ctx->priv;
-    const AVFilterLink *inlink = ctx->inputs[0];
-    AVRational fps = inlink->frame_rate;
+    AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
+    AVRational fps = il->frame_rate;
 
     if (!fps.num || !fps.den) {
         av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
@@ -149,9 +151,9 @@ static int config_output(AVFilterLink *outlink)
     }
     fps = av_mul_q(fps, av_inv_q(s->pts));
     av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
-           inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den);
+           il->frame_rate.num, il->frame_rate.den, fps.num, fps.den);
 
-    outlink->frame_rate = fps;
+    ol->frame_rate = fps;
     outlink->time_base = av_mul_q(inlink->time_base, s->pts);
     av_log(ctx, AV_LOG_VERBOSE, "TB: %d/%d -> %d/%d\n",
            inlink->time_base.num, inlink->time_base.den, outlink->time_base.num, outlink->time_base.den);
diff --git a/libavfilter/vf_threshold.c b/libavfilter/vf_threshold.c
index dc73c277d3..2ec35eed51 100644
--- a/libavfilter/vf_threshold.c
+++ b/libavfilter/vf_threshold.c
@@ -28,6 +28,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "video.h"
@@ -181,6 +182,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *threshold = ctx->inputs[1];
     AVFilterLink *min = ctx->inputs[2];
     AVFilterLink *max = ctx->inputs[3];
+    FilterLink *il = ff_filter_link(base);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -205,7 +208,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = base->w;
     outlink->h = base->h;
     outlink->sample_aspect_ratio = base->sample_aspect_ratio;
-    outlink->frame_rate = base->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, 4)) < 0)
         return ret;
diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c
index b45e739bb6..ca382f748d 100644
--- a/libavfilter/vf_tile.c
+++ b/libavfilter/vf_tile.c
@@ -28,6 +28,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "video.h"
 #include "internal.h"
@@ -121,6 +122,8 @@ static int config_props(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     TileContext *tile    = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
     const unsigned total_margin_w = (tile->w - 1) * tile->padding + 2*tile->margin;
     const unsigned total_margin_h = (tile->h - 1) * tile->padding + 2*tile->margin;
 
@@ -137,8 +140,7 @@ static int config_props(AVFilterLink *outlink)
     outlink->w = tile->w * inlink->w + total_margin_w;
     outlink->h = tile->h * inlink->h + total_margin_h;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
-    outlink->frame_rate = av_mul_q(inlink->frame_rate,
-                                   av_make_q(1, tile->nb_frames - tile->overlap));
+    ol->frame_rate = av_mul_q(il->frame_rate, av_make_q(1, tile->nb_frames - tile->overlap));
     ff_draw_init2(&tile->draw, inlink->format, inlink->colorspace, inlink->color_range, 0);
     ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color);
 
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 89af1b89c5..9c976eddd9 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -31,6 +31,7 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/avassert.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "tinterlace.h"
 #include "video.h"
@@ -212,6 +213,8 @@ static int config_out_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     TInterlaceContext *tinterlace = ctx->priv;
     int ret, i;
@@ -256,13 +259,13 @@ static int config_out_props(AVFilterLink *outlink)
     tinterlace->preout_time_base = inlink->time_base;
     if (tinterlace->mode == MODE_INTERLACEX2) {
         tinterlace->preout_time_base.den *= 2;
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
+        ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2,1});
         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){1,2});
     } else if (tinterlace->mode == MODE_MERGEX2) {
-        outlink->frame_rate = inlink->frame_rate;
+        ol->frame_rate = il->frame_rate;
         outlink->time_base  = inlink->time_base;
     } else if (tinterlace->mode != MODE_PAD) {
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
+        ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){1,2});
         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
     }
 
@@ -293,7 +296,7 @@ static int config_out_props(AVFilterLink *outlink)
 #endif
     }
 
-    ret = ff_ccfifo_init(&tinterlace->cc_fifo, outlink->frame_rate, ctx);
+    ret = ff_ccfifo_init(&tinterlace->cc_fifo, ol->frame_rate, ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n");
         return ret;
@@ -375,6 +378,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *l = ff_filter_link(outlink);
     TInterlaceContext *tinterlace = ctx->priv;
     AVFrame *cur, *next, *out;
     int field, tff, full, ret;
@@ -560,7 +564,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
     }
 
     out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
-    out->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+    out->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
     ff_ccfifo_inject(&tinterlace->cc_fifo, out);
     ret = ff_filter_frame(outlink, out);
 
diff --git a/libavfilter/vf_tpad.c b/libavfilter/vf_tpad.c
index 72d0bf338f..2df99e75f0 100644
--- a/libavfilter/vf_tpad.c
+++ b/libavfilter/vf_tpad.c
@@ -90,6 +90,7 @@ static int activate(AVFilterContext *ctx)
 {
     AVFilterLink *inlink = ctx->inputs[0];
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *l = ff_filter_link(outlink);
     TPadContext *s = ctx->priv;
     AVFrame *frame = NULL;
     int ret, status;
@@ -116,7 +117,7 @@ static int activate(AVFilterContext *ctx)
         ff_fill_rectangle(&s->draw, &s->color,
                           frame->data, frame->linesize,
                           0, 0, frame->width, frame->height);
-        duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+        duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
         frame->pts = s->pts;
         frame->duration = duration;
         s->pts += duration;
@@ -136,7 +137,7 @@ static int activate(AVFilterContext *ctx)
         frame = av_frame_clone(s->cache_start);
         if (!frame)
             return AVERROR(ENOMEM);
-        duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+        duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
         frame->pts = s->pts;
         frame->duration = duration;
         s->pts += duration;
@@ -182,7 +183,7 @@ static int activate(AVFilterContext *ctx)
             if (!frame)
                 return AVERROR(ENOMEM);
         }
-        duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+        duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base);
         frame->pts = s->pts;
         frame->duration = duration;
         s->pts += duration;
@@ -200,6 +201,7 @@ static int activate(AVFilterContext *ctx)
 static int config_input(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
+    FilterLink *l = ff_filter_link(inlink);
     TPadContext *s = ctx->priv;
 
     if (needs_drawing(s)) {
@@ -208,9 +210,9 @@ static int config_input(AVFilterLink *inlink)
     }
 
     if (s->start_duration)
-        s->pad_start = av_rescale_q(s->start_duration, inlink->frame_rate, av_inv_q(AV_TIME_BASE_Q));
+        s->pad_start = av_rescale_q(s->start_duration, l->frame_rate, av_inv_q(AV_TIME_BASE_Q));
     if (s->stop_duration)
-        s->pad_stop = av_rescale_q(s->stop_duration, inlink->frame_rate, av_inv_q(AV_TIME_BASE_Q));
+        s->pad_stop = av_rescale_q(s->stop_duration, l->frame_rate, av_inv_q(AV_TIME_BASE_Q));
 
     return 0;
 }
diff --git a/libavfilter/vf_untile.c b/libavfilter/vf_untile.c
index f32f3e186b..486cce31ee 100644
--- a/libavfilter/vf_untile.c
+++ b/libavfilter/vf_untile.c
@@ -75,6 +75,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     UntileContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
     AVRational dt;
 
     s->desc = av_pix_fmt_desc_get(outlink->format);
@@ -88,9 +90,9 @@ static int config_output(AVFilterLink *outlink)
     outlink->w = inlink->w / s->w;
     outlink->h = inlink->h / s->h;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
-    outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(s->nb_frames, 1));
-    if (outlink->frame_rate.num)
-        dt = av_inv_q(outlink->frame_rate);
+    ol->frame_rate = av_mul_q(il->frame_rate, av_make_q(s->nb_frames, 1));
+    if (ol->frame_rate.num)
+        dt = av_inv_q(ol->frame_rate);
     else
         dt = av_mul_q(inlink->time_base, av_make_q(1, s->nb_frames));
     outlink->time_base = av_gcd_q(inlink->time_base, dt, AV_TIME_BASE / 2, AV_TIME_BASE_Q);
diff --git a/libavfilter/vf_varblur.c b/libavfilter/vf_varblur.c
index 7a022099e9..5f0126fccf 100644
--- a/libavfilter/vf_varblur.c
+++ b/libavfilter/vf_varblur.c
@@ -23,6 +23,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 #include "video.h"
@@ -320,6 +321,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     AVFilterLink *radiuslink = ctx->inputs[1];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
     VarBlurContext *s = ctx->priv;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     int ret;
@@ -337,7 +340,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = inlink->h;
     outlink->time_base = inlink->time_base;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
-    outlink->frame_rate = inlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     s->depth = desc->comp[0].depth;
     s->blur_plane = s->depth <= 8 ? blur_plane8 : s->depth <= 16 ? blur_plane16 : blur_plane32;
diff --git a/libavfilter/vf_vif.c b/libavfilter/vf_vif.c
index 38b6a32365..3def065e84 100644
--- a/libavfilter/vf_vif.c
+++ b/libavfilter/vf_vif.c
@@ -31,6 +31,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "framesync.h"
 #include "internal.h"
 
@@ -550,6 +551,8 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     VIFContext *s = ctx->priv;
     AVFilterLink *mainlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(mainlink);
+    FilterLink *ol = ff_filter_link(outlink);
     FFFrameSyncIn *in;
     int ret;
 
@@ -557,7 +560,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = mainlink->h;
     outlink->time_base = mainlink->time_base;
     outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
-    outlink->frame_rate = mainlink->frame_rate;
+    ol->frame_rate = il->frame_rate;
     if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0)
         return ret;
 
diff --git a/libavfilter/vf_vignette.c b/libavfilter/vf_vignette.c
index 13c511fdc7..9d35ea8b13 100644
--- a/libavfilter/vf_vignette.c
+++ b/libavfilter/vf_vignette.c
@@ -25,6 +25,7 @@
 #include "libavutil/eval.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -283,14 +284,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 static int config_props(AVFilterLink *inlink)
 {
     VignetteContext *s = inlink->dst->priv;
+    FilterLink *l = ff_filter_link(inlink);
     AVRational sar = inlink->sample_aspect_ratio;
 
     s->desc = av_pix_fmt_desc_get(inlink->format);
     s->var_values[VAR_W]  = inlink->w;
     s->var_values[VAR_H]  = inlink->h;
     s->var_values[VAR_TB] = av_q2d(inlink->time_base);
-    s->var_values[VAR_R]  = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ?
-        NAN : av_q2d(inlink->frame_rate);
+    s->var_values[VAR_R]  = l->frame_rate.num == 0 || l->frame_rate.den == 0 ?
+        NAN : av_q2d(l->frame_rate);
 
     if (!sar.num || !sar.den)
         sar.num = sar.den = 1;
diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c
index f368b6ce24..7de3b6dda3 100644
--- a/libavfilter/vf_vpp_qsv.c
+++ b/libavfilter/vf_vpp_qsv.c
@@ -297,18 +297,19 @@ static int config_input(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
     VPPContext      *vpp = ctx->priv;
+    FilterLink      *inl = ff_filter_link(inlink);
     int              ret;
     int64_t          ow, oh;
 
     if (vpp->framerate.den == 0 || vpp->framerate.num == 0) {
-        vpp->framerate = inlink->frame_rate;
+        vpp->framerate = inl->frame_rate;
 
         if (vpp->deinterlace && vpp->field_rate)
-            vpp->framerate = av_mul_q(inlink->frame_rate,
+            vpp->framerate = av_mul_q(inl->frame_rate,
                                       (AVRational){ 2, 1 });
     }
 
-    if (av_cmp_q(vpp->framerate, inlink->frame_rate))
+    if (av_cmp_q(vpp->framerate, inl->frame_rate))
         vpp->use_frc = 1;
 
     ret = eval_expr(ctx);
@@ -533,11 +534,12 @@ static int config_output(AVFilterLink *outlink)
     mfxVersion      mfx_version;
     AVFilterLink    *inlink = ctx->inputs[0];
     FilterLink         *inl = ff_filter_link(inlink);
+    FilterLink          *ol = ff_filter_link(outlink);
     enum AVPixelFormat in_format;
 
     outlink->w          = vpp->out_width;
     outlink->h          = vpp->out_height;
-    outlink->frame_rate = vpp->framerate;
+    ol->frame_rate      = vpp->framerate;
     if (vpp->framerate.num == 0 || vpp->framerate.den == 0)
         outlink->time_base = inlink->time_base;
     else
@@ -768,11 +770,12 @@ static int activate(AVFilterContext *ctx)
     } else {
         /* No MFX session is created in pass-through mode */
         if (in) {
+            FilterLink *ol = ff_filter_link(outlink);
             if (in->pts != AV_NOPTS_VALUE)
                 in->pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base);
 
-            if (outlink->frame_rate.num && outlink->frame_rate.den)
-                in->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
+            if (ol->frame_rate.num && ol->frame_rate.den)
+                in->duration = av_rescale_q(1, av_inv_q(ol->frame_rate), outlink->time_base);
             else
                 in->duration = 0;
 
diff --git a/libavfilter/vf_w3fdif.c b/libavfilter/vf_w3fdif.c
index a5a9cdd5cb..bbb4ea3c47 100644
--- a/libavfilter/vf_w3fdif.c
+++ b/libavfilter/vf_w3fdif.c
@@ -27,6 +27,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "w3fdif.h"
@@ -328,11 +329,13 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
     W3FDIFContext *s = ctx->priv;
 
     outlink->time_base = av_mul_q(inlink->time_base, (AVRational){1, 2});
     if (s->mode)
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2, 1});
+        ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2, 1});
 
     return 0;
 }
diff --git a/libavfilter/vf_weave.c b/libavfilter/vf_weave.c
index f0e8b0927a..84e8e3dab5 100644
--- a/libavfilter/vf_weave.c
+++ b/libavfilter/vf_weave.c
@@ -22,6 +22,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -68,10 +69,12 @@ static int config_props_output(AVFilterLink *outlink)
     int ret;
 
     if (!s->double_weave) {
+        FilterLink *il = ff_filter_link(inlink);
+        FilterLink *ol = ff_filter_link(outlink);
         outlink->time_base.num = inlink->time_base.num * 2;
         outlink->time_base.den = inlink->time_base.den;
-        outlink->frame_rate.num = inlink->frame_rate.num;
-        outlink->frame_rate.den = inlink->frame_rate.den * 2;
+        ol->frame_rate.num = il->frame_rate.num;
+        ol->frame_rate.den = il->frame_rate.den * 2;
     }
     outlink->w = inlink->w;
     outlink->h = inlink->h * 2;
diff --git a/libavfilter/vf_xfade.c b/libavfilter/vf_xfade.c
index f61c7083dc..c9d6388475 100644
--- a/libavfilter/vf_xfade.c
+++ b/libavfilter/vf_xfade.c
@@ -2041,6 +2041,9 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink0 = ctx->inputs[0];
     AVFilterLink *inlink1 = ctx->inputs[1];
+    FilterLink      *inl0 = ff_filter_link(inlink0);
+    FilterLink      *inl1 = ff_filter_link(inlink1);
+    FilterLink        *ol = ff_filter_link(outlink);
     XFadeContext *s = ctx->priv;
     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink0->format);
 
@@ -2063,19 +2066,19 @@ static int config_output(AVFilterLink *outlink)
         return AVERROR(EINVAL);
     }
 
-    if (!inlink0->frame_rate.num || !inlink0->frame_rate.den) {
+    if (!inl0->frame_rate.num || !inl0->frame_rate.den) {
         av_log(ctx, AV_LOG_ERROR, "The inputs needs to be a constant frame rate; "
-               "current rate of %d/%d is invalid\n", inlink0->frame_rate.num, inlink0->frame_rate.den);
+               "current rate of %d/%d is invalid\n", inl0->frame_rate.num, inl0->frame_rate.den);
         return AVERROR(EINVAL);
     }
 
-    if (inlink0->frame_rate.num != inlink1->frame_rate.num ||
-        inlink0->frame_rate.den != inlink1->frame_rate.den) {
+    if (inl0->frame_rate.num != inl1->frame_rate.num ||
+        inl0->frame_rate.den != inl1->frame_rate.den) {
         av_log(ctx, AV_LOG_ERROR, "First input link %s frame rate "
                "(%d/%d) do not match the corresponding "
                "second input link %s frame rate (%d/%d)\n",
-               ctx->input_pads[0].name, inlink0->frame_rate.num, inlink0->frame_rate.den,
-               ctx->input_pads[1].name, inlink1->frame_rate.num, inlink1->frame_rate.den);
+               ctx->input_pads[0].name, inl0->frame_rate.num, inl0->frame_rate.den,
+               ctx->input_pads[1].name, inl1->frame_rate.num, inl1->frame_rate.den);
         return AVERROR(EINVAL);
     }
 
@@ -2083,7 +2086,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = inlink0->h;
     outlink->time_base = inlink0->time_base;
     outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
-    outlink->frame_rate = inlink0->frame_rate;
+    ol->frame_rate = inl0->frame_rate;
 
     s->depth = pix_desc->comp[0].depth;
     s->is_rgb = !!(pix_desc->flags & AV_PIX_FMT_FLAG_RGB);
diff --git a/libavfilter/vf_xfade_opencl.c b/libavfilter/vf_xfade_opencl.c
index 2368c046b4..3d568a9a17 100644
--- a/libavfilter/vf_xfade_opencl.c
+++ b/libavfilter/vf_xfade_opencl.c
@@ -216,6 +216,8 @@ static int xfade_opencl_config_output(AVFilterLink *outlink)
     XFadeOpenCLContext *ctx = avctx->priv;
     AVFilterLink *inlink0 = avctx->inputs[0];
     AVFilterLink *inlink1 = avctx->inputs[1];
+    FilterLink *il = ff_filter_link(inlink0);
+    FilterLink *ol = ff_filter_link(outlink);
     int err;
 
     err = ff_opencl_filter_config_output(outlink);
@@ -245,7 +247,7 @@ static int xfade_opencl_config_output(AVFilterLink *outlink)
 
     outlink->time_base = inlink0->time_base;
     outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
-    outlink->frame_rate = inlink0->frame_rate;
+    ol->frame_rate = il->frame_rate;
 
     if (ctx->duration)
         ctx->duration_pts = av_rescale_q(ctx->duration, AV_TIME_BASE_Q, outlink->time_base);
diff --git a/libavfilter/vf_xfade_vulkan.c b/libavfilter/vf_xfade_vulkan.c
index be041eaef4..2076f3e7a4 100644
--- a/libavfilter/vf_xfade_vulkan.c
+++ b/libavfilter/vf_xfade_vulkan.c
@@ -460,6 +460,8 @@ static int config_props_output(AVFilterLink *outlink)
     XFadeVulkanContext *s = avctx->priv;
     AVFilterLink *inlink_a = avctx->inputs[IN_A];
     AVFilterLink *inlink_b = avctx->inputs[IN_B];
+    FilterLink *il = ff_filter_link(inlink_a);
+    FilterLink *ol = ff_filter_link(outlink);
 
     if (inlink_a->w != inlink_b->w || inlink_a->h != inlink_b->h) {
         av_log(avctx, AV_LOG_ERROR, "First input link %s parameters "
@@ -483,7 +485,7 @@ static int config_props_output(AVFilterLink *outlink)
     s->start_pts = s->inputs_offset_pts = AV_NOPTS_VALUE;
 
     outlink->time_base = inlink_a->time_base;
-    outlink->frame_rate = inlink_a->frame_rate;
+    ol->frame_rate = il->frame_rate;
     outlink->sample_aspect_ratio = inlink_a->sample_aspect_ratio;
 
     if (s->duration)
diff --git a/libavfilter/vf_xmedian.c b/libavfilter/vf_xmedian.c
index 4e83b48843..e86920cb1a 100644
--- a/libavfilter/vf_xmedian.c
+++ b/libavfilter/vf_xmedian.c
@@ -29,6 +29,7 @@
 
 #include "avfilter.h"
 #include "internal.h"
+#include "filters.h"
 #include "framesync.h"
 #include "video.h"
 
@@ -239,9 +240,11 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     XMedianContext *s = ctx->priv;
-    AVRational frame_rate = ctx->inputs[0]->frame_rate;
-    AVRational sar = ctx->inputs[0]->sample_aspect_ratio;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *il = ff_filter_link(inlink);
+    FilterLink *ol = ff_filter_link(outlink);
+    AVRational frame_rate = il->frame_rate;
+    AVRational sar = ctx->inputs[0]->sample_aspect_ratio;
     int height = ctx->inputs[0]->h;
     int width = ctx->inputs[0]->w;
     FFFrameSyncIn *in;
@@ -288,7 +291,7 @@ static int config_output(AVFilterLink *outlink)
 
     outlink->w          = width;
     outlink->h          = height;
-    outlink->frame_rate = frame_rate;
+    ol->frame_rate      = frame_rate;
     outlink->sample_aspect_ratio = sar;
 
     if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0)
diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c
index e729bda56d..e50484cbef 100644
--- a/libavfilter/vf_zoompan.c
+++ b/libavfilter/vf_zoompan.c
@@ -125,13 +125,14 @@ static av_cold int init(AVFilterContext *ctx)
 static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *l = ff_filter_link(outlink);
     ZPContext *s = ctx->priv;
     int ret;
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->time_base = av_inv_q(s->framerate);
-    outlink->frame_rate = s->framerate;
+    l->frame_rate = s->framerate;
     s->desc = av_pix_fmt_desc_get(outlink->format);
     s->finished = 1;
 
diff --git a/libavfilter/vsrc_cellauto.c b/libavfilter/vsrc_cellauto.c
index f9223fd848..0159d1e508 100644
--- a/libavfilter/vsrc_cellauto.c
+++ b/libavfilter/vsrc_cellauto.c
@@ -33,6 +33,7 @@
 #include "libavutil/random_seed.h"
 #include "libavutil/avstring.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -217,11 +218,12 @@ static av_cold void uninit(AVFilterContext *ctx)
 static int config_props(AVFilterLink *outlink)
 {
     CellAutoContext *s = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->time_base = av_inv_q(s->frame_rate);
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/vsrc_ddagrab.c b/libavfilter/vsrc_ddagrab.c
index dc53e15c6d..c900e123b6 100644
--- a/libavfilter/vsrc_ddagrab.c
+++ b/libavfilter/vsrc_ddagrab.c
@@ -924,7 +924,7 @@ static int ddagrab_config_props(AVFilterLink *outlink)
     outlink->w = dda->width;
     outlink->h = dda->height;
     outlink->time_base = (AVRational){1, TIMER_RES};
-    outlink->frame_rate = dda->framerate;
+    l->frame_rate = dda->framerate;
 
     return 0;
 }
diff --git a/libavfilter/vsrc_gradients.c b/libavfilter/vsrc_gradients.c
index 567a4a311d..02c4965df6 100644
--- a/libavfilter/vsrc_gradients.c
+++ b/libavfilter/vsrc_gradients.c
@@ -334,6 +334,7 @@ static int draw_gradients_slice32_planar(AVFilterContext *ctx, void *arg, int jo
 static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *l = ff_filter_link(outlink);
     GradientsContext *s = ctx->priv;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
 
@@ -344,7 +345,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = s->h;
     outlink->time_base = av_inv_q(s->frame_rate);
     outlink->sample_aspect_ratio = (AVRational) {1, 1};
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
     if (s->seed == -1)
         s->seed = av_get_random_seed();
     av_lfg_init(&s->lfg, s->seed);
diff --git a/libavfilter/vsrc_life.c b/libavfilter/vsrc_life.c
index 65e510dbdb..79200a6d0e 100644
--- a/libavfilter/vsrc_life.c
+++ b/libavfilter/vsrc_life.c
@@ -35,6 +35,7 @@
 #include "libavutil/avstring.h"
 #include "avfilter.h"
 #include "internal.h"
+#include "filters.h"
 #include "formats.h"
 #include "video.h"
 
@@ -280,11 +281,12 @@ static av_cold void uninit(AVFilterContext *ctx)
 static int config_props(AVFilterLink *outlink)
 {
     LifeContext *life = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = life->w;
     outlink->h = life->h;
     outlink->time_base = av_inv_q(life->frame_rate);
-    outlink->frame_rate = life->frame_rate;
+    l->frame_rate = life->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/vsrc_mandelbrot.c b/libavfilter/vsrc_mandelbrot.c
index 982ef71814..c1a59fea6d 100644
--- a/libavfilter/vsrc_mandelbrot.c
+++ b/libavfilter/vsrc_mandelbrot.c
@@ -27,6 +27,7 @@
  */
 
 #include "avfilter.h"
+#include "filters.h"
 #include "video.h"
 #include "internal.h"
 #include "libavutil/imgutils.h"
@@ -151,6 +152,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 static int config_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *l = ff_filter_link(outlink);
     MBContext *s = ctx->priv;
 
     if (av_image_check_size(s->w, s->h, 0, ctx) < 0)
@@ -159,7 +161,7 @@ static int config_props(AVFilterLink *outlink)
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->time_base = av_inv_q(s->frame_rate);
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/vsrc_mptestsrc.c b/libavfilter/vsrc_mptestsrc.c
index 0395af35e8..3b9be4c8ed 100644
--- a/libavfilter/vsrc_mptestsrc.c
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -26,6 +26,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -274,6 +275,7 @@ static av_cold int init(AVFilterContext *ctx)
 static int config_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *l = ff_filter_link(outlink);
     MPTestContext *test = ctx->priv;
     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(outlink->format);
 
@@ -283,7 +285,7 @@ static int config_props(AVFilterLink *outlink)
     outlink->w = WIDTH;
     outlink->h = HEIGHT;
     outlink->time_base = av_inv_q(test->frame_rate);
-    outlink->frame_rate = test->frame_rate;
+    l->frame_rate = test->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/vsrc_perlin.c b/libavfilter/vsrc_perlin.c
index fb2eb4c9bb..8fd140f225 100644
--- a/libavfilter/vsrc_perlin.c
+++ b/libavfilter/vsrc_perlin.c
@@ -28,6 +28,7 @@
 #include "libavutil/opt.h"
 #include "avfilter.h"
 #include "internal.h"
+#include "filters.h"
 #include "formats.h"
 #include "video.h"
 
@@ -95,11 +96,12 @@ static av_cold int init(AVFilterContext *ctx)
 static int config_props(AVFilterLink *outlink)
 {
     PerlinContext *perlin = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = perlin->w;
     outlink->h = perlin->h;
     outlink->time_base = av_inv_q(perlin->frame_rate);
-    outlink->frame_rate = perlin->frame_rate;
+    l->frame_rate = perlin->frame_rate;
 
     return 0;
 }
diff --git a/libavfilter/vsrc_sierpinski.c b/libavfilter/vsrc_sierpinski.c
index 2f31081901..e982422549 100644
--- a/libavfilter/vsrc_sierpinski.c
+++ b/libavfilter/vsrc_sierpinski.c
@@ -24,6 +24,7 @@
  */
 
 #include "avfilter.h"
+#include "filters.h"
 #include "video.h"
 #include "internal.h"
 #include "libavutil/imgutils.h"
@@ -138,6 +139,7 @@ static int draw_carpet_slice(AVFilterContext *ctx, void *arg, int job, int nb_jo
 static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *l = ff_filter_link(outlink);
     SierpinskiContext *s = ctx->priv;
 
     if (av_image_check_size(s->w, s->h, 0, ctx) < 0)
@@ -147,7 +149,7 @@ static int config_output(AVFilterLink *outlink)
     outlink->h = s->h;
     outlink->time_base = av_inv_q(s->frame_rate);
     outlink->sample_aspect_ratio = (AVRational) {1, 1};
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
     if (s->seed == -1)
         s->seed = av_get_random_seed();
     av_lfg_init(&s->lfg, s->seed);
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index 4dc12c8a01..ce4013643c 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -46,6 +46,7 @@
 #include "avfilter.h"
 #include "drawutils.h"
 #include "filters.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -148,11 +149,12 @@ static av_cold void uninit(AVFilterContext *ctx)
 static int config_props(AVFilterLink *outlink)
 {
     TestSourceContext *test = outlink->src->priv;
+    FilterLink *l = ff_filter_link(outlink);
 
     outlink->w = test->w;
     outlink->h = test->h;
     outlink->sample_aspect_ratio = test->sar;
-    outlink->frame_rate = test->frame_rate;
+    l->frame_rate = test->frame_rate;
     outlink->time_base  = test->time_base;
 
     return 0;
diff --git a/libavfilter/vsrc_testsrc_vulkan.c b/libavfilter/vsrc_testsrc_vulkan.c
index 2b16ee2b6b..4b297af158 100644
--- a/libavfilter/vsrc_testsrc_vulkan.c
+++ b/libavfilter/vsrc_testsrc_vulkan.c
@@ -298,7 +298,7 @@ static int testsrc_vulkan_config_props(AVFilterLink *outlink)
     outlink->w = s->w;
     outlink->h = s->h;
     outlink->sample_aspect_ratio = s->sar;
-    outlink->frame_rate = s->frame_rate;
+    l->frame_rate = s->frame_rate;
     outlink->time_base  = s->time_base;
 
     return 0;
diff --git a/libavfilter/yadif_common.c b/libavfilter/yadif_common.c
index 35be87e8d5..3f5e0ebfb8 100644
--- a/libavfilter/yadif_common.c
+++ b/libavfilter/yadif_common.c
@@ -21,6 +21,7 @@
 
 #include "libavutil/avassert.h"
 #include "libavutil/imgutils.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "yadif.h"
@@ -218,6 +219,8 @@ int ff_yadif_request_frame(AVFilterLink *link)
 int ff_yadif_config_output_common(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
+    FilterLink *il = ff_filter_link(ctx->inputs[0]);
+    FilterLink *ol = ff_filter_link(outlink);
     YADIFContext *yadif = ctx->priv;
     AVRational tb = ctx->inputs[0]->time_base;
     int ret;
@@ -239,12 +242,12 @@ int ff_yadif_config_output_common(AVFilterLink *outlink)
     }
 
     if(yadif->mode & 1)
-        outlink->frame_rate = av_mul_q(ctx->inputs[0]->frame_rate,
+        ol->frame_rate = av_mul_q(il->frame_rate,
                                     (AVRational){2, 1});
     else
-        outlink->frame_rate = ctx->inputs[0]->frame_rate;
+        ol->frame_rate = il->frame_rate;
 
-    ret = ff_ccfifo_init(&yadif->cc_fifo, outlink->frame_rate, ctx);
+    ret = ff_ccfifo_init(&yadif->cc_fifo, ol->frame_rate, ctx);
     if (ret < 0) {
         av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n");
         return ret;
-- 
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 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} to FilterLink
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
                   ` (5 preceding siblings ...)
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 07/10] lavfi: move AVFilterLink.frame_rate " Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-12 20:19   ` Michael Niedermayer
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 09/10] lavfi: move AVFilterLink.frame_wanted_out to FilterLinkInternal Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 10/10] lavfi: move AVFilterLink.graph to FilterLink Anton Khirnov
  8 siblings, 1 reply; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

---
 libavfilter/af_adrc.c         |  3 ++-
 libavfilter/af_afftdn.c       |  3 ++-
 libavfilter/af_ashowinfo.c    |  4 +++-
 libavfilter/af_dynaudnorm.c   |  3 ++-
 libavfilter/af_volume.c       |  4 +++-
 libavfilter/asrc_sine.c       |  3 ++-
 libavfilter/avf_showfreqs.c   |  5 +++--
 libavfilter/avfilter.c        | 16 +++++++++-------
 libavfilter/avfilter.h        | 10 ----------
 libavfilter/avfiltergraph.c   |  4 ++--
 libavfilter/f_graphmonitor.c  | 24 ++++++++++++------------
 libavfilter/f_latency.c       |  6 ++++--
 libavfilter/f_loop.c          |  6 ++++--
 libavfilter/f_metadata.c      |  6 ++++--
 libavfilter/f_segment.c       | 10 ++++++----
 libavfilter/f_select.c        |  4 +++-
 libavfilter/f_sendcmd.c       |  4 +++-
 libavfilter/f_streamselect.c  |  3 ++-
 libavfilter/filters.h         | 10 ++++++++++
 libavfilter/qrencode.c        |  3 ++-
 libavfilter/vf_bbox.c         |  4 +++-
 libavfilter/vf_blackdetect.c  |  4 +++-
 libavfilter/vf_blend.c        |  3 ++-
 libavfilter/vf_blockdetect.c  |  5 ++++-
 libavfilter/vf_blurdetect.c   |  5 ++++-
 libavfilter/vf_crop.c         |  4 +++-
 libavfilter/vf_datascope.c    |  4 +++-
 libavfilter/vf_delogo.c       |  4 +++-
 libavfilter/vf_detelecine.c   |  3 ++-
 libavfilter/vf_drawtext.c     |  8 +++++---
 libavfilter/vf_eq.c           |  3 ++-
 libavfilter/vf_fade.c         | 10 ++++++----
 libavfilter/vf_fftfilt.c      |  4 +++-
 libavfilter/vf_fieldhint.c    | 17 ++++++++++-------
 libavfilter/vf_fieldmatch.c   |  7 ++++---
 libavfilter/vf_find_rect.c    |  5 ++++-
 libavfilter/vf_framestep.c    |  3 ++-
 libavfilter/vf_freezeframes.c |  8 +++++---
 libavfilter/vf_geq.c          |  5 ++++-
 libavfilter/vf_hue.c          |  3 ++-
 libavfilter/vf_libplacebo.c   |  6 ++++--
 libavfilter/vf_overlay.c      |  4 +++-
 libavfilter/vf_overlay_cuda.c |  3 ++-
 libavfilter/vf_perspective.c  |  7 +++++--
 libavfilter/vf_quirc.c        |  3 ++-
 libavfilter/vf_rotate.c       |  4 +++-
 libavfilter/vf_scale.c        | 12 ++++++++----
 libavfilter/vf_scale_npp.c    |  8 +++++---
 libavfilter/vf_showinfo.c     |  3 ++-
 libavfilter/vf_swaprect.c     |  4 +++-
 libavfilter/vf_telecine.c     |  3 ++-
 libavfilter/vf_tinterlace.c   |  7 ++++---
 libavfilter/vf_vignette.c     |  3 ++-
 libavfilter/vf_weave.c        |  3 ++-
 libavfilter/vf_zoompan.c      |  9 ++++++---
 libavfilter/vsrc_mptestsrc.c  |  5 +++--
 56 files changed, 208 insertions(+), 116 deletions(-)

diff --git a/libavfilter/af_adrc.c b/libavfilter/af_adrc.c
index 7a7d5e0370..e11db05f70 100644
--- a/libavfilter/af_adrc.c
+++ b/libavfilter/af_adrc.c
@@ -363,6 +363,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     AudioDRCContext *s = ctx->priv;
     AVFrame *out;
     int ret;
@@ -373,7 +374,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         goto fail;
     }
 
-    s->var_values[VAR_SN] = outlink->sample_count_in;
+    s->var_values[VAR_SN] = outl->sample_count_in;
     s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate;
 
     s->in = in;
diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c
index a2e6ca6107..fd6b2b2685 100644
--- a/libavfilter/af_afftdn.c
+++ b/libavfilter/af_afftdn.c
@@ -355,8 +355,9 @@ static void process_frame(AVFilterContext *ctx,
                           double *prior, double *prior_band_excit, int track_noise)
 {
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink      *outl = ff_filter_link(outlink);
     const double *abs_var = dnch->abs_var;
-    const double ratio = outlink->frame_count_out ? s->ratio : 1.0;
+    const double ratio = outl->frame_count_out ? s->ratio : 1.0;
     const double rratio = 1. - ratio;
     const int *bin2band = s->bin2band;
     double *noisy_data = dnch->noisy_data;
diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c
index de3c81f90b..9ca97c609f 100644
--- a/libavfilter/af_ashowinfo.c
+++ b/libavfilter/af_ashowinfo.c
@@ -38,6 +38,7 @@
 
 #include "audio.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 
 typedef struct AShowInfoContext {
@@ -173,6 +174,7 @@ static void dump_unknown(AVFilterContext *ctx, AVFrameSideData *sd)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
+    FilterLink      *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AShowInfoContext *s  = ctx->priv;
     char chlayout_str[128];
@@ -203,7 +205,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
            "n:%"PRId64" pts:%s pts_time:%s "
            "fmt:%s channels:%d chlayout:%s rate:%d nb_samples:%d "
            "checksum:%08"PRIX32" ",
-           inlink->frame_count_out,
+           inl->frame_count_out,
            av_ts2str(buf->pts), av_ts2timestr(buf->pts, &inlink->time_base),
            av_get_sample_fmt_name(buf->format), buf->ch_layout.nb_channels, chlayout_str,
            buf->sample_rate, buf->nb_samples,
diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c
index 846d62584b..a3d3c47d17 100644
--- a/libavfilter/af_dynaudnorm.c
+++ b/libavfilter/af_dynaudnorm.c
@@ -725,6 +725,7 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame
 
 static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **frame)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     DynamicAudioNormalizerContext *s = ctx->priv;
     AVFrame *analyze_frame;
 
@@ -780,7 +781,7 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **
         analyze_frame = *frame;
     }
 
-    s->var_values[VAR_SN] = outlink->sample_count_in;
+    s->var_values[VAR_SN] = outl->sample_count_in;
     s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate;
 
     if (s->channels_coupled) {
diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
index b3dd57c5e5..827415fc1c 100644
--- a/libavfilter/af_volume.c
+++ b/libavfilter/af_volume.c
@@ -35,6 +35,7 @@
 
 #include "audio.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "af_volume.h"
@@ -328,6 +329,7 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
+    FilterLink      *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     VolumeContext *vol    = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
@@ -380,7 +382,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     }
     vol->var_values[VAR_PTS] = TS2D(buf->pts);
     vol->var_values[VAR_T  ] = TS2T(buf->pts, inlink->time_base);
-    vol->var_values[VAR_N  ] = inlink->frame_count_out;
+    vol->var_values[VAR_N  ] = inl->frame_count_out;
 
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c
index 72a24cce65..bbfe37ba53 100644
--- a/libavfilter/asrc_sine.c
+++ b/libavfilter/asrc_sine.c
@@ -207,10 +207,11 @@ static av_cold int config_props(AVFilterLink *outlink)
 static int activate(AVFilterContext *ctx)
 {
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     SineContext *sine = ctx->priv;
     AVFrame *frame;
     double values[VAR_VARS_NB] = {
-        [VAR_N]   = outlink->frame_count_in,
+        [VAR_N]   = outl->frame_count_in,
         [VAR_PTS] = sine->pts,
         [VAR_T]   = sine->pts * av_q2d(outlink->time_base),
         [VAR_TB]  = av_q2d(outlink->time_base),
diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c
index f5b86a7f17..245d62dec4 100644
--- a/libavfilter/avf_showfreqs.c
+++ b/libavfilter/avf_showfreqs.c
@@ -298,6 +298,7 @@ static inline void plot_freq(ShowFreqsContext *s, int ch,
                              double a, int f, uint8_t fg[4], int *prev_y,
                              AVFrame *out, AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     const int w = s->w;
     const float min = s->minamp;
     const float avg = s->avg_data[ch][f];
@@ -337,12 +338,12 @@ static inline void plot_freq(ShowFreqsContext *s, int ch,
 
     switch (s->avg) {
     case 0:
-        y = s->avg_data[ch][f] = !outlink->frame_count_in ? y : FFMIN(0, y);
+        y = s->avg_data[ch][f] = !outl->frame_count_in ? y : FFMIN(0, y);
         break;
     case 1:
         break;
     default:
-        s->avg_data[ch][f] = avg + y * (y - avg) / (FFMIN(outlink->frame_count_in + 1, s->avg) * (float)y);
+        s->avg_data[ch][f] = avg + y * (y - avg) / (FFMIN(outl->frame_count_in + 1, s->avg) * (float)y);
         y = av_clip(s->avg_data[ch][f], 0, outlink->h - 1);
         break;
     }
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 66dda6584d..9a01bc1c4e 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -991,6 +991,7 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame)
 
 static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
 {
+    FilterLink *l = ff_filter_link(link);
     int (*filter_frame)(AVFilterLink *, AVFrame *);
     AVFilterContext *dstctx = link->dst;
     AVFilterPad *dst = link->dstpad;
@@ -1012,7 +1013,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
         (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC))
         filter_frame = default_filter_frame;
     ret = filter_frame(link, frame);
-    link->frame_count_out++;
+    l->frame_count_out++;
     return ret;
 
 fail:
@@ -1058,8 +1059,8 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
     }
 
     li->frame_blocked_in = link->frame_wanted_out = 0;
-    link->frame_count_in++;
-    link->sample_count_in += frame->nb_samples;
+    li->l.frame_count_in++;
+    li->l.sample_count_in += frame->nb_samples;
     filter_unblock(link->dst);
     ret = ff_framequeue_add(&li->fifo, frame);
     if (ret < 0) {
@@ -1163,7 +1164,7 @@ static int ff_filter_frame_to_filter(AVFilterLink *link)
     filter_unblock(dst);
     /* AVFilterPad.filter_frame() expect frame_count_out to have the value
        before the frame; ff_filter_frame_framed() will re-increment it. */
-    link->frame_count_out--;
+    li->l.frame_count_out--;
     ret = ff_filter_frame_framed(link, frame);
     if (ret < 0 && ret != li->status_out) {
         link_set_out_status(link, ret, AV_NOPTS_VALUE);
@@ -1444,8 +1445,8 @@ static void consume_update(FilterLinkInternal *li, const AVFrame *frame)
     ff_inlink_process_commands(link, frame);
     if (link == link->dst->inputs[0])
         link->dst->is_disabled = !ff_inlink_evaluate_timeline_at_frame(link, frame);
-    link->frame_count_out++;
-    link->sample_count_out += frame->nb_samples;
+    li->l.frame_count_out++;
+    li->l.sample_count_out += frame->nb_samples;
 }
 
 int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
@@ -1552,6 +1553,7 @@ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame)
 
 int ff_inlink_evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame)
 {
+    FilterLink *l = ff_filter_link(link);
     AVFilterContext *dstctx = link->dst;
     int64_t pts = frame->pts;
 #if FF_API_FRAME_PKT
@@ -1563,7 +1565,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
     if (!dstctx->enable_str)
         return 1;
 
-    dstctx->var_values[VAR_N] = link->frame_count_out;
+    dstctx->var_values[VAR_N] = l->frame_count_out;
     dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base);
     dstctx->var_values[VAR_W] = link->w;
     dstctx->var_values[VAR_H] = link->h;
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 3498514459..176498cdb4 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -600,16 +600,6 @@ struct AVFilterLink {
      */
     struct AVFilterGraph *graph;
 
-    /**
-     * Number of past frames sent through the link.
-     */
-    int64_t frame_count_in, frame_count_out;
-
-    /**
-     * Number of past samples sent through the link.
-     */
-    int64_t sample_count_in, sample_count_out;
-
     /**
      * True if a frame is currently wanted on the output of this filter.
      * Set when ff_request_frame() is called by the output,
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index e589ac2415..18a3f54759 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1402,8 +1402,8 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
         return AVERROR_EOF;
     av_assert1(!oldest->dst->filter->activate);
     av_assert1(oldesti->age_index >= 0);
-    frame_count = oldest->frame_count_out;
-    while (frame_count == oldest->frame_count_out) {
+    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) &&
             !oldest->frame_wanted_out && !oldesti->frame_blocked_in &&
diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c
index 72ca5cea15..c02a205e7e 100644
--- a/libavfilter/f_graphmonitor.c
+++ b/libavfilter/f_graphmonitor.c
@@ -308,33 +308,33 @@ static int draw_items(AVFilterContext *ctx,
         drawtext(out, xpos, ypos, buffer, len, frames > 0 ? frames >= 10 ? frames >= 50 ? s->red : s->yellow : s->green : s->white);
         xpos += len * 8;
     }
-    if ((flags & FLAG_FCIN) && (!(mode & MODE_NOZERO) || l->frame_count_in)) {
-        len = snprintf(buffer, sizeof(buffer)-1, " | in: %"PRId64, l->frame_count_in);
+    if ((flags & FLAG_FCIN) && (!(mode & MODE_NOZERO) || fl->frame_count_in)) {
+        len = snprintf(buffer, sizeof(buffer)-1, " | in: %"PRId64, fl->frame_count_in);
         drawtext(out, xpos, ypos, buffer, len, s->white);
         xpos += len * 8;
     }
-    if ((flags & FLAG_FCOUT) && (!(mode & MODE_NOZERO) || l->frame_count_out)) {
-        len = snprintf(buffer, sizeof(buffer)-1, " | out: %"PRId64, l->frame_count_out);
+    if ((flags & FLAG_FCOUT) && (!(mode & MODE_NOZERO) || fl->frame_count_out)) {
+        len = snprintf(buffer, sizeof(buffer)-1, " | out: %"PRId64, fl->frame_count_out);
         drawtext(out, xpos, ypos, buffer, len, s->white);
         xpos += len * 8;
     }
-    if ((flags & FLAG_FC_DELTA) && (!(mode & MODE_NOZERO) || (l->frame_count_in - l->frame_count_out))) {
-        len = snprintf(buffer, sizeof(buffer)-1, " | delta: %"PRId64, l->frame_count_in - l->frame_count_out);
+    if ((flags & FLAG_FC_DELTA) && (!(mode & MODE_NOZERO) || (fl->frame_count_in - fl->frame_count_out))) {
+        len = snprintf(buffer, sizeof(buffer)-1, " | delta: %"PRId64, fl->frame_count_in - fl->frame_count_out);
         drawtext(out, xpos, ypos, buffer, len, s->white);
         xpos += len * 8;
     }
-    if ((flags & FLAG_SCIN) && (!(mode & MODE_NOZERO) || l->sample_count_in)) {
-        len = snprintf(buffer, sizeof(buffer)-1, " | sin: %"PRId64, l->sample_count_in);
+    if ((flags & FLAG_SCIN) && (!(mode & MODE_NOZERO) || fl->sample_count_in)) {
+        len = snprintf(buffer, sizeof(buffer)-1, " | sin: %"PRId64, fl->sample_count_in);
         drawtext(out, xpos, ypos, buffer, len, s->white);
         xpos += len * 8;
     }
-    if ((flags & FLAG_SCOUT) && (!(mode & MODE_NOZERO) || l->sample_count_out)) {
-        len = snprintf(buffer, sizeof(buffer)-1, " | sout: %"PRId64, l->sample_count_out);
+    if ((flags & FLAG_SCOUT) && (!(mode & MODE_NOZERO) || fl->sample_count_out)) {
+        len = snprintf(buffer, sizeof(buffer)-1, " | sout: %"PRId64, fl->sample_count_out);
         drawtext(out, xpos, ypos, buffer, len, s->white);
         xpos += len * 8;
     }
-    if ((flags & FLAG_SC_DELTA) && (!(mode & MODE_NOZERO) || (l->sample_count_in - l->sample_count_out))) {
-        len = snprintf(buffer, sizeof(buffer)-1, " | sdelta: %"PRId64, l->sample_count_in - l->sample_count_out);
+    if ((flags & FLAG_SC_DELTA) && (!(mode & MODE_NOZERO) || (fl->sample_count_in - fl->sample_count_out))) {
+        len = snprintf(buffer, sizeof(buffer)-1, " | sdelta: %"PRId64, fl->sample_count_in - fl->sample_count_out);
         drawtext(out, xpos, ypos, buffer, len, s->white);
         xpos += len * 8;
     }
diff --git a/libavfilter/f_latency.c b/libavfilter/f_latency.c
index a39c3c7d24..5315545873 100644
--- a/libavfilter/f_latency.c
+++ b/libavfilter/f_latency.c
@@ -46,6 +46,7 @@ static int activate(AVFilterContext *ctx)
 {
     LatencyContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     AVFilterLink *outlink = ctx->outputs[0];
 
     FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
@@ -53,14 +54,15 @@ static int activate(AVFilterContext *ctx)
     if (!ctx->is_disabled && ctx->inputs[0]->src &&
         ctx->inputs[0]->src->nb_inputs > 0) {
         AVFilterLink *prevlink = ctx->inputs[0]->src->inputs[0];
+        FilterLink *prevl = ff_filter_link(prevlink);
         int64_t delta = 0;
 
         switch (prevlink->type) {
         case AVMEDIA_TYPE_AUDIO:
-            delta = prevlink->sample_count_in - inlink->sample_count_out;
+            delta = prevl->sample_count_in - inl->sample_count_out;
             break;
         case AVMEDIA_TYPE_VIDEO:
-            delta = prevlink->frame_count_in - inlink->frame_count_out;
+            delta = prevl->frame_count_in - inl->frame_count_out;
             break;
         }
 
diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c
index 9c9c03fb05..51cf2dbf4d 100644
--- a/libavfilter/f_loop.c
+++ b/libavfilter/f_loop.c
@@ -144,6 +144,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples)
 
 static int afilter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     LoopContext *s = ctx->priv;
@@ -158,7 +159,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame)
             int drain = 0;
 
             if (s->start < 0)
-                s->start = inlink->sample_count_out - written;
+                s->start = inl->sample_count_out - written;
 
             ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written);
             if (ret < 0)
@@ -374,6 +375,7 @@ static int push_frame(AVFilterContext *ctx)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     FilterLink *outl = ff_filter_link(outlink);
@@ -381,7 +383,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     int64_t duration;
     int ret = 0;
 
-    if (((s->start >= 0 && inlink->frame_count_out >= s->start) ||
+    if (((s->start >= 0 && inl->frame_count_out >= s->start) ||
          (s->time_pts != AV_NOPTS_VALUE &&
           frame->pts >= s->time_pts)) &&
         s->size > 0 && s->loop != 0) {
diff --git a/libavfilter/f_metadata.c b/libavfilter/f_metadata.c
index b6d548612b..e18d477850 100644
--- a/libavfilter/f_metadata.c
+++ b/libavfilter/f_metadata.c
@@ -36,6 +36,7 @@
 #include "libavformat/avio.h"
 #include "avfilter.h"
 #include "audio.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -303,6 +304,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     MetadataContext *s = ctx->priv;
@@ -336,14 +338,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     case METADATA_PRINT:
         if (!s->key && e) {
             s->print(ctx, "frame:%-4"PRId64" pts:%-7s pts_time:%s\n",
-                     inlink->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
+                     inl->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
             s->print(ctx, "%s=%s\n", e->key, e->value);
             while ((e = av_dict_iterate(*metadata, e)) != NULL) {
                 s->print(ctx, "%s=%s\n", e->key, e->value);
             }
         } else if (e && e->value && (!s->value || (e->value && s->compare(s, e->value, s->value)))) {
             s->print(ctx, "frame:%-4"PRId64" pts:%-7s pts_time:%s\n",
-                     inlink->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
+                     inl->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
             s->print(ctx, "%s=%s\n", s->key, e->value);
         }
         return ff_filter_frame(outlink, frame);
diff --git a/libavfilter/f_segment.c b/libavfilter/f_segment.c
index 16c611b4a8..f655c1e675 100644
--- a/libavfilter/f_segment.c
+++ b/libavfilter/f_segment.c
@@ -162,6 +162,7 @@ static int current_segment_finished(AVFilterContext *ctx, AVFrame *frame)
 {
     SegmentContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     int ret = 0;
 
     if (s->use_timestamps) {
@@ -169,10 +170,10 @@ static int current_segment_finished(AVFilterContext *ctx, AVFrame *frame)
     } else {
         switch (inlink->type) {
         case AVMEDIA_TYPE_VIDEO:
-            ret = inlink->frame_count_out - 1 >= s->points[s->current_point];
+            ret = inl->frame_count_out - 1 >= s->points[s->current_point];
             break;
         case AVMEDIA_TYPE_AUDIO:
-            ret = inlink->sample_count_out - frame->nb_samples >= s->points[s->current_point];
+            ret = inl->sample_count_out - frame->nb_samples >= s->points[s->current_point];
             break;
         }
     }
@@ -183,6 +184,7 @@ static int current_segment_finished(AVFilterContext *ctx, AVFrame *frame)
 static int activate(AVFilterContext *ctx)
 {
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     SegmentContext *s = ctx->priv;
     AVFrame *frame = NULL;
     int ret, status;
@@ -199,14 +201,14 @@ static int activate(AVFilterContext *ctx)
         ret = ff_inlink_consume_frame(inlink, &frame);
         break;
     case AVMEDIA_TYPE_AUDIO:
-        diff = s->points[s->current_point] - inlink->sample_count_out;
+        diff = s->points[s->current_point] - inl->sample_count_out;
         while (diff <= 0) {
             ff_outlink_set_status(ctx->outputs[s->current_point], AVERROR_EOF, s->last_pts);
             s->current_point++;
             if (s->current_point >= s->nb_points)
                 return AVERROR(EINVAL);
 
-            diff = s->points[s->current_point] - inlink->sample_count_out;
+            diff = s->points[s->current_point] - inl->sample_count_out;
         }
         if (s->use_timestamps) {
             max_samples = av_rescale_q(diff, av_make_q(1, inlink->sample_rate), inlink->time_base);
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index 7402d3169f..d834397ea6 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -34,6 +34,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "audio.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -342,6 +343,7 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
 {
     SelectContext *select = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink      *inl = ff_filter_link(inlink);
     double res;
 
     if (isnan(select->var_values[VAR_START_PTS]))
@@ -349,7 +351,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  ] = inlink->frame_count_out;
+    select->var_values[VAR_N  ] = inl->frame_count_out;
     select->var_values[VAR_PTS] = TS2D(frame->pts);
     select->var_values[VAR_T  ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
 #if FF_API_FRAME_PKT
diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c
index 47bfaba9c9..86f9d522e9 100644
--- a/libavfilter/f_sendcmd.c
+++ b/libavfilter/f_sendcmd.c
@@ -33,6 +33,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/parseutils.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "audio.h"
 #include "video.h"
@@ -488,6 +489,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     SendCmdContext *s = ctx->priv;
     int64_t ts;
@@ -535,7 +537,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
                         double end = TS2T(interval->end_ts, AV_TIME_BASE_Q);
                         double current = TS2T(ref->pts, inlink->time_base);
 
-                        var_values[VAR_N]   = inlink->frame_count_in;
+                        var_values[VAR_N]   = inl->frame_count_in;
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
                         var_values[VAR_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos;
diff --git a/libavfilter/f_streamselect.c b/libavfilter/f_streamselect.c
index 285e7d7315..07d55a7506 100644
--- a/libavfilter/f_streamselect.c
+++ b/libavfilter/f_streamselect.c
@@ -65,11 +65,12 @@ static int process_frame(FFFrameSync *fs)
 
     for (j = 0; j < ctx->nb_inputs; j++) {
         for (i = 0; i < s->nb_map; i++) {
+            FilterLink *outl = ff_filter_link(ctx->outputs[i]);
             if (s->map[i] == j) {
                 AVFrame *out;
 
                 if (s->is_audio && s->last_pts[j] == in[j]->pts &&
-                    ctx->outputs[i]->frame_count_in > 0)
+                    outl->frame_count_in > 0)
                     continue;
                 out = av_frame_clone(in[j]);
                 if (!out)
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index fc65f1df20..3f591e6f9d 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -70,6 +70,16 @@ typedef struct FilterLink {
      */
     int max_samples;
 
+    /**
+     * Number of past frames sent through the link.
+     */
+    int64_t frame_count_in, frame_count_out;
+
+    /**
+     * Number of past samples sent through the link.
+     */
+    int64_t sample_count_in, sample_count_out;
+
     /**
      * Frame rate of the stream on the link, or 1/0 if unknown or variable.
      *
diff --git a/libavfilter/qrencode.c b/libavfilter/qrencode.c
index f308de7646..d184ac994d 100644
--- a/libavfilter/qrencode.c
+++ b/libavfilter/qrencode.c
@@ -780,12 +780,13 @@ static int qrencode_query_formats(AVFilterContext *ctx)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     QREncodeContext *qr = ctx->priv;
     int ret;
 
-    V(n) = inlink->frame_count_out;
+    V(n) = inl->frame_count_out;
     V(t) = frame->pts == AV_NOPTS_VALUE ?
         NAN : frame->pts * av_q2d(inlink->time_base);
     V(pict_type) = frame->pict_type;
diff --git a/libavfilter/vf_bbox.c b/libavfilter/vf_bbox.c
index 02893d500d..2f6edf9393 100644
--- a/libavfilter/vf_bbox.c
+++ b/libavfilter/vf_bbox.c
@@ -28,6 +28,7 @@
 #include "libavutil/timestamp.h"
 #include "avfilter.h"
 #include "bbox.h"
+#include "filters.h"
 #include "internal.h"
 
 typedef struct BBoxContext {
@@ -75,6 +76,7 @@ static const enum AVPixelFormat pix_fmts[] = {
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     BBoxContext *bbox = ctx->priv;
     FFBoundingBox box;
@@ -88,7 +90,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     h = box.y2 - box.y1 + 1;
 
     av_log(ctx, AV_LOG_INFO,
-           "n:%"PRId64" pts:%s pts_time:%s", inlink->frame_count_out,
+           "n:%"PRId64" pts:%s pts_time:%s", inl->frame_count_out,
            av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
 
     if (has_bbox) {
diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
index 23ff8600ca..973216e883 100644
--- a/libavfilter/vf_blackdetect.c
+++ b/libavfilter/vf_blackdetect.c
@@ -30,6 +30,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/timestamp.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -173,6 +174,7 @@ static int black_counter(AVFilterContext *ctx, void *arg,
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     BlackDetectContext *s = ctx->priv;
     double picture_black_ratio = 0;
@@ -195,7 +197,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 
     av_log(ctx, AV_LOG_DEBUG,
            "frame:%"PRId64" picture_black_ratio:%f pts:%s t:%s type:%c\n",
-           inlink->frame_count_out, picture_black_ratio,
+           inl->frame_count_out, picture_black_ratio,
            av_ts2str(picref->pts), av_ts2timestr(picref->pts, &s->time_base),
            av_get_picture_type_char(picref->pict_type));
 
diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c
index d93daa1fac..a38cae2db3 100644
--- a/libavfilter/vf_blend.c
+++ b/libavfilter/vf_blend.c
@@ -174,10 +174,11 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     const uint8_t *top    = td->top->data[td->plane];
     const uint8_t *bottom = td->bottom->data[td->plane];
     uint8_t *dst    = td->dst->data[td->plane];
+    FilterLink *inl = ff_filter_link(td->inlink);
     double values[VAR_VARS_NB];
     SliceParams sliceparam = {.values = &values[0], .starty = slice_start, .e = td->param->e ? td->param->e[jobnr] : NULL};
 
-    values[VAR_N]  = td->inlink->frame_count_out;
+    values[VAR_N]  = inl->frame_count_out;
     values[VAR_T]  = td->dst->pts == AV_NOPTS_VALUE ? NAN : td->dst->pts * av_q2d(td->inlink->time_base);
     values[VAR_W]  = td->w;
     values[VAR_H]  = td->h;
diff --git a/libavfilter/vf_blockdetect.c b/libavfilter/vf_blockdetect.c
index b7f68722fe..6b1f35c974 100644
--- a/libavfilter/vf_blockdetect.c
+++ b/libavfilter/vf_blockdetect.c
@@ -32,6 +32,8 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -198,6 +200,7 @@ static void set_meta(AVDictionary **metadata, const char *key, float d)
 
 static int blockdetect_filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink      *inl  = ff_filter_link(inlink);
     AVFilterContext *ctx  = inlink->dst;
     BLKContext *s         = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -236,7 +239,7 @@ static int blockdetect_filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     set_meta(metadata, "lavfi.block", block);
 
-    s->nb_frames = inlink->frame_count_in;
+    s->nb_frames = inl->frame_count_in;
 
     return ff_filter_frame(outlink, in);
 }
diff --git a/libavfilter/vf_blurdetect.c b/libavfilter/vf_blurdetect.c
index f1c5be6b0f..2b85a9e95a 100644
--- a/libavfilter/vf_blurdetect.c
+++ b/libavfilter/vf_blurdetect.c
@@ -34,6 +34,8 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/qsort.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "edge_common.h"
 #include "video.h"
@@ -256,6 +258,7 @@ static void set_meta(AVDictionary **metadata, const char *key, float d)
 
 static int blurdetect_filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink      *inl  = ff_filter_link(inlink);
     AVFilterContext *ctx  = inlink->dst;
     BLRContext *s         = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -316,7 +319,7 @@ static int blurdetect_filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     set_meta(metadata, "lavfi.blur", blur);
 
-    s->nb_frames = inlink->frame_count_in;
+    s->nb_frames = inl->frame_count_in;
 
     return ff_filter_frame(outlink, in);
 }
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index d4966323f5..a16fc22743 100644
--- a/libavfilter/vf_crop.c
+++ b/libavfilter/vf_crop.c
@@ -26,6 +26,7 @@
 #include <stdio.h>
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -255,12 +256,13 @@ static int config_output(AVFilterLink *link)
 
 static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
+    FilterLink        *l = ff_filter_link(link);
     AVFilterContext *ctx = link->dst;
     CropContext *s = ctx->priv;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
     int i;
 
-    s->var_values[VAR_N] = link->frame_count_out;
+    s->var_values[VAR_N] = l->frame_count_out;
     s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
         NAN : frame->pts * av_q2d(link->time_base);
 #if FF_API_FRAME_PKT
diff --git a/libavfilter/vf_datascope.c b/libavfilter/vf_datascope.c
index 52b1939cd2..b4496eca2d 100644
--- a/libavfilter/vf_datascope.c
+++ b/libavfilter/vf_datascope.c
@@ -25,6 +25,7 @@
 #include "libavutil/xga_font_data.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -1038,6 +1039,7 @@ static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1,
 
 static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx  = inlink->dst;
     OscilloscopeContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -1047,7 +1049,7 @@ static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame)
     int i, c;
 
     s->nb_values = 0;
-    draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1);
+    draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inl->frame_count_in & 1);
     ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize,
                        frame->width, frame->height,
                        s->ox, s->oy, s->width, s->height + 20 * s->statistics);
diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c
index c049f273b0..a321b805a2 100644
--- a/libavfilter/vf_delogo.c
+++ b/libavfilter/vf_delogo.c
@@ -33,6 +33,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/eval.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 static const char * const var_names[] = {
@@ -286,6 +287,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     DelogoContext *s = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
@@ -297,7 +299,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     AVRational sar;
     int ret;
 
-    s->var_values[VAR_N] = inlink->frame_count_out;
+    s->var_values[VAR_N] = inl->frame_count_out;
     s->var_values[VAR_T] = TS2T(in->pts, inlink->time_base);
     s->x = av_expr_eval(s->x_pexpr, s->var_values, s);
     s->y = av_expr_eval(s->y_pexpr, s->var_values, s);
diff --git a/libavfilter/vf_detelecine.c b/libavfilter/vf_detelecine.c
index eb81e3424e..ecf1de7da1 100644
--- a/libavfilter/vf_detelecine.c
+++ b/libavfilter/vf_detelecine.c
@@ -193,6 +193,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     DetelecineContext *s = ctx->priv;
     int i, len = 0, ret = 0, out = 0;
 
@@ -332,7 +333,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 
         av_frame_copy_props(frame, inpicref);
         frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) +
-                     av_rescale(outlink->frame_count_in, s->ts_unit.num,
+                     av_rescale(outl->frame_count_in, s->ts_unit.num,
                                 s->ts_unit.den);
         ret = ff_filter_frame(outlink, frame);
     }
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 0ac0a0721c..b168c5260b 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -1553,6 +1553,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
 {
     DrawTextContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
     int x = 0, y = 0, ret;
     int shift_x64, shift_y64;
     int x64, y64;
@@ -1596,7 +1597,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
 
     if (s->tc_opt_string) {
         char tcbuf[AV_TIMECODE_STR_SIZE];
-        av_timecode_make_string(&s->tc, tcbuf, inlink->frame_count_out);
+        av_timecode_make_string(&s->tc, tcbuf, inl->frame_count_out);
         av_bprint_clear(bp);
         av_bprintf(bp, "%s%s", s->text, tcbuf);
     }
@@ -1828,6 +1829,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     DrawTextContext *s = ctx->priv;
@@ -1848,7 +1850,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
         }
     }
 
-    if (s->reload && !(inlink->frame_count_out % s->reload)) {
+    if (s->reload && !(inl->frame_count_out % s->reload)) {
         if ((ret = ff_load_textfile(ctx, (const char *)s->textfile, &s->text, NULL)) < 0) {
             av_frame_free(&frame);
             return ret;
@@ -1862,7 +1864,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 #endif
     }
 
-    s->var_values[VAR_N] = inlink->frame_count_out + s->start_number;
+    s->var_values[VAR_N] = inl->frame_count_out + s->start_number;
     s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
         NAN : frame->pts * av_q2d(inlink->time_base);
 
diff --git a/libavfilter/vf_eq.c b/libavfilter/vf_eq.c
index 38a13b0cfb..377bc848bf 100644
--- a/libavfilter/vf_eq.c
+++ b/libavfilter/vf_eq.c
@@ -221,6 +221,7 @@ static const enum AVPixelFormat pixel_fmts_eq[] = {
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     EQContext *eq = ctx->priv;
@@ -237,7 +238,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     av_frame_copy_props(out, in);
     desc = av_pix_fmt_desc_get(inlink->format);
 
-    eq->var_values[VAR_N]   = inlink->frame_count_out;
+    eq->var_values[VAR_N]   = inl->frame_count_out;
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
     {
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index cd64a82f25..6db60f06f5 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -33,6 +33,7 @@
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -442,6 +443,7 @@ static int config_input(AVFilterLink *inlink)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink      *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     FadeContext *s       = ctx->priv;
 
@@ -449,7 +451,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     if (s->fade_state == VF_FADE_WAITING) {
         s->factor=0;
         if (frame->pts >= s->start_time_pts
-            && inlink->frame_count_out >= s->start_frame) {
+            && inl->frame_count_out >= s->start_frame) {
             // Time to start fading
             s->fade_state = VF_FADE_FADING;
 
@@ -460,15 +462,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 
             // Save start frame in case we are starting based on time and fading based on frames
             if (s->start_time_pts != 0 && s->start_frame == 0) {
-                s->start_frame = inlink->frame_count_out;
+                s->start_frame = inl->frame_count_out;
             }
         }
     }
     if (s->fade_state == VF_FADE_FADING) {
         if (s->duration_pts == 0) {
             // Fading based on frame count
-            s->factor = (inlink->frame_count_out - s->start_frame) * s->fade_per_frame;
-            if (inlink->frame_count_out > s->start_frame + s->nb_frames) {
+            s->factor = (inl->frame_count_out - s->start_frame) * s->fade_per_frame;
+            if (inl->frame_count_out > s->start_frame + s->nb_frames) {
                 s->fade_state = VF_FADE_DONE;
             }
 
diff --git a/libavfilter/vf_fftfilt.c b/libavfilter/vf_fftfilt.c
index af0e1f51d2..e2a8adb7b4 100644
--- a/libavfilter/vf_fftfilt.c
+++ b/libavfilter/vf_fftfilt.c
@@ -24,6 +24,7 @@
  * FFT domain filtering.
  */
 
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 #include "libavutil/common.h"
@@ -284,10 +285,11 @@ static av_cold int initialize(AVFilterContext *ctx)
 
 static void do_eval(FFTFILTContext *s, AVFilterLink *inlink, int plane)
 {
+    FilterLink *l = ff_filter_link(inlink);
     double values[VAR_VARS_NB];
     int i, j;
 
-    values[VAR_N] = inlink->frame_count_out;
+    values[VAR_N] = l->frame_count_out;
     values[VAR_W] = s->planewidth[plane];
     values[VAR_H] = s->planeheight[plane];
     values[VAR_WS] = s->rdft_hlen[plane];
diff --git a/libavfilter/vf_fieldhint.c b/libavfilter/vf_fieldhint.c
index 8d0e715749..0320484d5c 100644
--- a/libavfilter/vf_fieldhint.c
+++ b/libavfilter/vf_fieldhint.c
@@ -25,6 +25,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -113,8 +114,10 @@ static int config_input(AVFilterLink *inlink)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     FieldHintContext *s = ctx->priv;
     AVFrame *out, *top, *bottom;
     char buf[1024] = { 0 };
@@ -152,9 +155,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             }
             switch (s->mode) {
             case ABSOLUTE_HINT:
-                if (tf > outlink->frame_count_in + 1 || tf < FFMAX(0, outlink->frame_count_in - 1) ||
-                    bf > outlink->frame_count_in + 1 || bf < FFMAX(0, outlink->frame_count_in - 1)) {
-                    av_log(ctx, AV_LOG_ERROR, "Out of range frames %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inlink->frame_count_out);
+                if (tf > outl->frame_count_in + 1 || tf < FFMAX(0, outl->frame_count_in - 1) ||
+                    bf > outl->frame_count_in + 1 || bf < FFMAX(0, outl->frame_count_in - 1)) {
+                    av_log(ctx, AV_LOG_ERROR, "Out of range frames %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inl->frame_count_out);
                     return AVERROR_INVALIDDATA;
                 }
                 break;
@@ -162,7 +165,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             case RELATIVE_HINT:
                 if (tf > 1 || tf < -1 ||
                     bf > 1 || bf < -1) {
-                    av_log(ctx, AV_LOG_ERROR, "Out of range %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inlink->frame_count_out);
+                    av_log(ctx, AV_LOG_ERROR, "Out of range %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inl->frame_count_out);
                     return AVERROR_INVALIDDATA;
                 }
                 break;
@@ -175,7 +178,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
                 fseek(s->hint, 0, SEEK_SET);
                 continue;
             }
-            av_log(ctx, AV_LOG_ERROR, "Missing entry for %"PRId64". input frame.\n", inlink->frame_count_out);
+            av_log(ctx, AV_LOG_ERROR, "Missing entry for %"PRId64". input frame.\n", inl->frame_count_out);
             return AVERROR_INVALIDDATA;
         }
     }
@@ -187,8 +190,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     switch (s->mode) {
     case ABSOLUTE_HINT:
-        top    = s->frame[tf - outlink->frame_count_in + 1];
-        bottom = s->frame[bf - outlink->frame_count_in + 1];
+        top    = s->frame[tf - outl->frame_count_in + 1];
+        bottom = s->frame[bf - outl->frame_count_in + 1];
         break;
     case PATTERN_HINT:
     case RELATIVE_HINT:
diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c
index 1625c08306..555ae81bc6 100644
--- a/libavfilter/vf_fieldmatch.c
+++ b/libavfilter/vf_fieldmatch.c
@@ -681,6 +681,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx  = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink      *outl = ff_filter_link(outlink);
     FieldMatchContext *fm = ctx->priv;
     int combs[] = { -1, -1, -1, -1, -1 };
     int order, field, i, match, interlaced_frame, sc = 0, ret = 0;
@@ -753,7 +754,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
     /* scene change check */
     if (fm->combmatch == COMBMATCH_SC) {
-        if (fm->lastn == outlink->frame_count_in - 1) {
+        if (fm->lastn == outl->frame_count_in - 1) {
             if (fm->lastscdiff > fm->scthresh)
                 sc = 1;
         } else if (luma_abs_diff(fm->prv, fm->src) > fm->scthresh) {
@@ -761,7 +762,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         }
 
         if (!sc) {
-            fm->lastn = outlink->frame_count_in;
+            fm->lastn = outl->frame_count_in;
             fm->lastscdiff = luma_abs_diff(fm->src, fm->nxt);
             sc = fm->lastscdiff > fm->scthresh;
         }
@@ -831,7 +832,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
     if (interlaced_frame) {
         dst->flags |= AV_FRAME_FLAG_INTERLACED;
         av_log(ctx, AV_LOG_WARNING, "Frame #%"PRId64" at %s is still interlaced\n",
-               outlink->frame_count_in, av_ts2timestr(in->pts, &inlink->time_base));
+               outl->frame_count_in, av_ts2timestr(in->pts, &inlink->time_base));
 #if FF_API_INTERLACED_FRAME
 FF_DISABLE_DEPRECATION_WARNINGS
         dst->top_field_first = field;
diff --git a/libavfilter/vf_find_rect.c b/libavfilter/vf_find_rect.c
index f50052ded2..bfd6cc583c 100644
--- a/libavfilter/vf_find_rect.c
+++ b/libavfilter/vf_find_rect.c
@@ -24,6 +24,8 @@
 
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
+
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -172,6 +174,7 @@ static float search(FOCContext *foc, int pass, int maxpass, int xmin, int xmax,
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     FOCContext *foc = ctx->priv;
     float best_score;
@@ -208,7 +211,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
 
     av_log(ctx, AV_LOG_INFO, "Found at n=%"PRId64" pts_time=%f x=%d y=%d with score=%f\n",
-           inlink->frame_count_out, TS2D(in->pts) * av_q2d(inlink->time_base),
+           inl->frame_count_out, TS2D(in->pts) * av_q2d(inlink->time_base),
            best_x, best_y, best_score);
     foc->last_x = best_x;
     foc->last_y = best_y;
diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c
index da69e2ba6c..115ac45fe4 100644
--- a/libavfilter/vf_framestep.c
+++ b/libavfilter/vf_framestep.c
@@ -64,9 +64,10 @@ static int config_output_props(AVFilterLink *outlink)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
 {
+    FilterLink             *inl = ff_filter_link(inlink);
     FrameStepContext *framestep = inlink->dst->priv;
 
-    if (!(inlink->frame_count_out % framestep->frame_step)) {
+    if (!(inl->frame_count_out % framestep->frame_step)) {
         return ff_filter_frame(inlink->dst->outputs[0], ref);
     } else {
         av_frame_free(&ref);
diff --git a/libavfilter/vf_freezeframes.c b/libavfilter/vf_freezeframes.c
index b630ad85fe..fffe86a2df 100644
--- a/libavfilter/vf_freezeframes.c
+++ b/libavfilter/vf_freezeframes.c
@@ -74,12 +74,14 @@ static int config_output(AVFilterLink *outlink)
 
 static int activate(AVFilterContext *ctx)
 {
+    FilterLink *inl0 = ff_filter_link(ctx->inputs[0]);
+    FilterLink *inl1 = ff_filter_link(ctx->inputs[1]);
     AVFilterLink *outlink = ctx->outputs[0];
     FreezeFramesContext *s = ctx->priv;
     AVFrame *frame = NULL;
-    int drop = ctx->inputs[0]->frame_count_out >= s->first &&
-               ctx->inputs[0]->frame_count_out <= s->last;
-    int replace = ctx->inputs[1]->frame_count_out == s->replace;
+    int drop = inl0->frame_count_out >= s->first &&
+               inl0->frame_count_out <= s->last;
+    int replace = inl1->frame_count_out == s->replace;
     int ret;
 
     FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c
index 0efbce4d4f..b23c3e170c 100644
--- a/libavfilter/vf_geq.c
+++ b/libavfilter/vf_geq.c
@@ -32,6 +32,8 @@
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -453,13 +455,14 @@ static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
 static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     int plane;
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     const int nb_threads = FFMIN(MAX_NB_THREADS, ff_filter_get_nb_threads(ctx));
     GEQContext *geq = ctx->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     AVFrame *out;
 
-    geq->values[VAR_N] = inlink->frame_count_out,
+    geq->values[VAR_N] = inl->frame_count_out,
     geq->values[VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base),
 
     geq->picref = in;
diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c
index 049f835c61..42f774772e 100644
--- a/libavfilter/vf_hue.c
+++ b/libavfilter/vf_hue.c
@@ -360,6 +360,7 @@ static void apply_lut10(HueContext *s,
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     HueContext *hue = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     AVFrame *outpic;
@@ -381,7 +382,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
         av_frame_copy_props(outpic, inpic);
     }
 
-    hue->var_values[VAR_N]   = inlink->frame_count_out;
+    hue->var_values[VAR_N]   = inl->frame_count_out;
     hue->var_values[VAR_T]   = TS2T(inpic->pts, inlink->time_base);
     hue->var_values[VAR_PTS] = TS2D(inpic->pts);
 
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 64c1ad6d4d..268bba8e38 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -742,6 +742,7 @@ static const AVFrame *ref_frame(const struct pl_frame_mix *mix)
 static void update_crops(AVFilterContext *ctx, LibplaceboInput *in,
                          struct pl_frame *target, double target_pts)
 {
+    FilterLink     *outl = ff_filter_link(ctx->outputs[0]);
     LibplaceboContext *s = ctx->priv;
     const AVFrame *ref = ref_frame(&in->mix);
 
@@ -761,7 +762,7 @@ static void update_crops(AVFilterContext *ctx, LibplaceboInput *in,
             av_q2d(in->link->sample_aspect_ratio) : 1.0;
         s->var_values[VAR_IN_T]   = s->var_values[VAR_T]  = image_pts;
         s->var_values[VAR_OUT_T]  = s->var_values[VAR_OT] = target_pts;
-        s->var_values[VAR_N]      = ctx->outputs[0]->frame_count_out;
+        s->var_values[VAR_N]      = outl->frame_count_out;
 
         /* Clear these explicitly to avoid leaking previous frames' state */
         s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] = NAN;
@@ -1000,6 +1001,7 @@ static int libplacebo_activate(AVFilterContext *ctx)
     int ret, ok = 0, retry = 0;
     LibplaceboContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl      = ff_filter_link(outlink);
     int64_t pts, out_pts;
 
     FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
@@ -1012,7 +1014,7 @@ static int libplacebo_activate(AVFilterContext *ctx)
 
     if (ff_outlink_frame_wanted(outlink)) {
         if (s->fps.num) {
-            out_pts = outlink->frame_count_out;
+            out_pts = outl->frame_count_out;
         } else {
             /* Determine the PTS of the next frame from any active input */
             out_pts = INT64_MAX;
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index 349b8d588c..d8ac36495d 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -36,6 +36,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/timestamp.h"
 #include "internal.h"
+#include "filters.h"
 #include "drawutils.h"
 #include "framesync.h"
 #include "video.h"
@@ -881,6 +882,7 @@ static int do_blend(FFFrameSync *fs)
     AVFrame *mainpic, *second;
     OverlayContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
     int ret;
 
     ret = ff_framesync_dualinput_get_writable(fs, &mainpic, &second);
@@ -891,7 +893,7 @@ static int do_blend(FFFrameSync *fs)
 
     if (s->eval_mode == EVAL_MODE_FRAME) {
 
-        s->var_values[VAR_N] = inlink->frame_count_out;
+        s->var_values[VAR_N] = inl->frame_count_out;
         s->var_values[VAR_T] = mainpic->pts == AV_NOPTS_VALUE ?
             NAN : mainpic->pts * av_q2d(inlink->time_base);
 #if FF_API_FRAME_PKT
diff --git a/libavfilter/vf_overlay_cuda.c b/libavfilter/vf_overlay_cuda.c
index 1aee77b17c..5bc1e275fa 100644
--- a/libavfilter/vf_overlay_cuda.c
+++ b/libavfilter/vf_overlay_cuda.c
@@ -236,6 +236,7 @@ static int overlay_cuda_blend(FFFrameSync *fs)
     OverlayCUDAContext *ctx = avctx->priv;
     AVFilterLink *outlink = avctx->outputs[0];
     AVFilterLink *inlink = avctx->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
 
     CudaFunctions *cu = ctx->hwctx->internal->cuda_dl;
     CUcontext dummy, cuda_ctx = ctx->hwctx->cuda_ctx;
@@ -270,7 +271,7 @@ static int overlay_cuda_blend(FFFrameSync *fs)
     }
 
     if (ctx->eval_mode == EVAL_MODE_FRAME) {
-        ctx->var_values[VAR_N] = inlink->frame_count_out;
+        ctx->var_values[VAR_N] = inl->frame_count_out;
         ctx->var_values[VAR_T] = input_main->pts == AV_NOPTS_VALUE ?
             NAN : input_main->pts * av_q2d(inlink->time_base);
 
diff --git a/libavfilter/vf_perspective.c b/libavfilter/vf_perspective.c
index a97b97bcb8..fedf8a03f1 100644
--- a/libavfilter/vf_perspective.c
+++ b/libavfilter/vf_perspective.c
@@ -26,6 +26,7 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/opt.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -122,13 +123,15 @@ enum                                   { VAR_W, VAR_H, VAR_IN, VAR_ON, VAR_VARS_
 
 static int calc_persp_luts(AVFilterContext *ctx, AVFilterLink *inlink)
 {
+    FilterLink *inl       = ff_filter_link(inlink);
     PerspectiveContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl      = ff_filter_link(outlink);
     double (*ref)[2]      = s->ref;
 
     double values[VAR_VARS_NB] = { [VAR_W] = inlink->w, [VAR_H] = inlink->h,
-                                   [VAR_IN] = inlink->frame_count_out + 1,
-                                   [VAR_ON] = outlink->frame_count_in + 1 };
+                                   [VAR_IN] = inl->frame_count_out + 1,
+                                   [VAR_ON] = outl->frame_count_in + 1 };
     const int h = values[VAR_H];
     const int w = values[VAR_W];
     double x0, x1, x2, x3, x4, x5, x6, x7, x8, q;
diff --git a/libavfilter/vf_quirc.c b/libavfilter/vf_quirc.c
index 62eb29b7ce..760f5d97de 100644
--- a/libavfilter/vf_quirc.c
+++ b/libavfilter/vf_quirc.c
@@ -89,6 +89,7 @@ static int query_formats(AVFilterContext *ctx)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     QuircContext *quirc = ctx->priv;
@@ -104,7 +105,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 
     codes_count = quirc_count(quirc->quirc);
     av_log(ctx, AV_LOG_VERBOSE,
-           "Found count %d codes in image #%ld\n", codes_count, inlink->frame_count_out);
+           "Found count %d codes in image #%ld\n", codes_count, inl->frame_count_out);
 
     if (codes_count) {
         int i, j;
diff --git a/libavfilter/vf_rotate.c b/libavfilter/vf_rotate.c
index 3e65f26552..2c598921d1 100644
--- a/libavfilter/vf_rotate.c
+++ b/libavfilter/vf_rotate.c
@@ -33,6 +33,7 @@
 
 #include "avfilter.h"
 #include "drawutils.h"
+#include "filters.h"
 #include "internal.h"
 #include "video.h"
 
@@ -501,6 +502,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     AVFrame *out;
@@ -515,7 +517,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     }
     av_frame_copy_props(out, in);
 
-    rot->var_values[VAR_N] = inlink->frame_count_out;
+    rot->var_values[VAR_N] = inl->frame_count_out;
     rot->var_values[VAR_T] = TS2T(in->pts, inlink->time_base);
     rot->angle = res = av_expr_eval(rot->angle_expr, rot->var_values, rot);
 
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index febb3178de..454fb812e4 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -879,6 +879,7 @@ static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src,
 static int scale_frame(AVFilterLink *link, AVFrame **frame_in,
                        AVFrame **frame_out)
 {
+    FilterLink *inl = ff_filter_link(link);
     AVFilterContext *ctx = link->dst;
     ScaleContext *scale = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -938,7 +939,7 @@ static int scale_frame(AVFilterLink *link, AVFrame **frame_in,
         }
 
         if (ctx->filter == &ff_vf_scale2ref) {
-            scale->var_values[VAR_S2R_MAIN_N] = link->frame_count_out;
+            scale->var_values[VAR_S2R_MAIN_N] = inl->frame_count_out;
             scale->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -946,7 +947,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
         } else {
-            scale->var_values[VAR_N] = link->frame_count_out;
+            scale->var_values[VAR_N] = inl->frame_count_out;
             scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -1035,6 +1036,8 @@ static int do_scale(FFFrameSync *fs)
 
     if (ref) {
         AVFilterLink *reflink = ctx->inputs[1];
+        FilterLink      *rl   = ff_filter_link(reflink);
+
         frame_changed = ref->width  != reflink->w ||
                         ref->height != reflink->h ||
                         ref->format != reflink->format ||
@@ -1058,7 +1061,7 @@ static int do_scale(FFFrameSync *fs)
         }
 
         if (scale->eval_mode == EVAL_MODE_FRAME) {
-            scale->var_values[VAR_REF_N] = reflink->frame_count_out;
+            scale->var_values[VAR_REF_N] = rl->frame_count_out;
             scale->var_values[VAR_REF_T] = TS2T(ref->pts, reflink->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -1097,6 +1100,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
 
 static int filter_frame_ref(AVFilterLink *link, AVFrame *in)
 {
+    FilterLink *l = ff_filter_link(link);
     ScaleContext *scale = link->dst->priv;
     AVFilterLink *outlink = link->dst->outputs[1];
     int frame_changed;
@@ -1122,7 +1126,7 @@ static int filter_frame_ref(AVFilterLink *link, AVFrame *in)
     }
 
     if (scale->eval_mode == EVAL_MODE_FRAME) {
-        scale->var_values[VAR_N] = link->frame_count_out;
+        scale->var_values[VAR_N] = l->frame_count_out;
         scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index 7b67d33296..d229083e8a 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -791,6 +791,7 @@ static int (*const nppscale_process[])(AVFilterContext *ctx, NPPScaleStageContex
 
 static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(link);
     AVFilterContext *ctx = link->dst;
     NPPScaleContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -840,7 +841,7 @@ static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in)
         }
 
         if (ctx->filter == &ff_vf_scale2ref_npp) {
-            s->var_values[VAR_S2R_MAIN_N] = link->frame_count_out;
+            s->var_values[VAR_S2R_MAIN_N] = inl->frame_count_out;
             s->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -848,7 +849,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
         } else {
-            s->var_values[VAR_N] = link->frame_count_out;
+            s->var_values[VAR_N] = inl->frame_count_out;
             s->var_values[VAR_T] = TS2T(in->pts, link->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -947,6 +948,7 @@ fail:
 
 static int nppscale_filter_frame_ref(AVFilterLink *link, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(link);
     NPPScaleContext *scale = link->dst->priv;
     AVFilterLink *outlink = link->dst->outputs[1];
     int frame_changed;
@@ -968,7 +970,7 @@ static int nppscale_filter_frame_ref(AVFilterLink *link, AVFrame *in)
     }
 
     if (scale->eval_mode == EVAL_MODE_FRAME) {
-        scale->var_values[VAR_N] = link->frame_count_out;
+        scale->var_values[VAR_N] = inl->frame_count_out;
         scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index f6ffcc39bb..6118e1a19a 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -728,6 +728,7 @@ static void update_sample_stats(int depth, int be, const uint8_t *src, int len,
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     ShowInfoContext *s = ctx->priv;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
@@ -761,7 +762,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
            "n:%4"PRId64" pts:%7s pts_time:%-7s duration:%7"PRId64
            " duration_time:%-7s "
            "fmt:%s cl:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c ",
-           inlink->frame_count_out,
+           inl->frame_count_out,
            av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base),
            frame->duration, av_ts2timestr(frame->duration, &inlink->time_base),
            desc->name, av_chroma_location_name(frame->chroma_location),
diff --git a/libavfilter/vf_swaprect.c b/libavfilter/vf_swaprect.c
index 54400f0304..e94e23b02b 100644
--- a/libavfilter/vf_swaprect.c
+++ b/libavfilter/vf_swaprect.c
@@ -25,6 +25,7 @@
 #include "libavutil/opt.h"
 
 #include "avfilter.h"
+#include "filters.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
@@ -78,6 +79,7 @@ enum                                   { VAR_W, VAR_H, VAR_A, VAR_N, VAR_T,
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     SwapRectContext *s = ctx->priv;
@@ -97,7 +99,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     var_values[VAR_A]   = (float) inlink->w / inlink->h;
     var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
     var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
-    var_values[VAR_N]   = inlink->frame_count_out;
+    var_values[VAR_N]   = inl->frame_count_out;
     var_values[VAR_T]   = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base);
 #if FF_API_FRAME_PKT
 FF_DISABLE_DEPRECATION_WARNINGS
diff --git a/libavfilter/vf_telecine.c b/libavfilter/vf_telecine.c
index fee3e43aff..652535142e 100644
--- a/libavfilter/vf_telecine.c
+++ b/libavfilter/vf_telecine.c
@@ -167,6 +167,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     TelecineContext *s = ctx->priv;
     int i, len, ret = 0, nout = 0;
 
@@ -281,7 +282,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
         else
             frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
         frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) +
-                     av_rescale(outlink->frame_count_in, s->ts_unit.num,
+                     av_rescale(outl->frame_count_in, s->ts_unit.num,
                                 s->ts_unit.den);
         ret = ff_filter_frame(outlink, frame);
     }
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 9c976eddd9..e864a84213 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -376,6 +376,7 @@ void copy_picture_field(TInterlaceContext *tinterlace,
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     FilterLink *l = ff_filter_link(outlink);
@@ -418,12 +419,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
         copy_picture_field(tinterlace, out->data, out->linesize,
                            (const uint8_t **)cur->data, cur->linesize,
                            inlink->format, inlink->w, inlink->h,
-                           FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inlink->frame_count_out) & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags);
+                           FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inl->frame_count_out) & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags);
         /* write even frame lines into the lower field of the new frame */
         copy_picture_field(tinterlace, out->data, out->linesize,
                            (const uint8_t **)next->data, next->linesize,
                            inlink->format, inlink->w, inlink->h,
-                           FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inlink->frame_count_out) & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags);
+                           FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inl->frame_count_out) & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags);
         if (tinterlace->mode != MODE_MERGEX2)
             av_frame_free(&tinterlace->next);
         break;
@@ -445,7 +446,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
         out->height = outlink->h;
         out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
 
-        field = (1 + outlink->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER;
+        field = (1 + l->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER;
         full = out->color_range == AVCOL_RANGE_JPEG || ff_fmt_is_in(out->format, full_scale_yuvj_pix_fmts);
         /* copy upper and lower fields */
         copy_picture_field(tinterlace, out->data, out->linesize,
diff --git a/libavfilter/vf_vignette.c b/libavfilter/vf_vignette.c
index 9d35ea8b13..cfce54264d 100644
--- a/libavfilter/vf_vignette.c
+++ b/libavfilter/vf_vignette.c
@@ -150,12 +150,13 @@ static double get_natural_factor(const VignetteContext *s, int x, int y)
 
 static void update_context(VignetteContext *s, AVFilterLink *inlink, AVFrame *frame)
 {
+    FilterLink *inl = ff_filter_link(inlink);
     int x, y;
     float *dst = s->fmap;
     int dst_linesize = s->fmap_linesize;
 
     if (frame) {
-        s->var_values[VAR_N]   = inlink->frame_count_out;
+        s->var_values[VAR_N]   = inl->frame_count_out;
         s->var_values[VAR_T]   = TS2T(frame->pts, inlink->time_base);
         s->var_values[VAR_PTS] = TS2D(frame->pts);
     } else {
diff --git a/libavfilter/vf_weave.c b/libavfilter/vf_weave.c
index 84e8e3dab5..c545e43d6d 100644
--- a/libavfilter/vf_weave.c
+++ b/libavfilter/vf_weave.c
@@ -100,12 +100,13 @@ typedef struct ThreadData {
 static int weave_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
     WeaveContext *s = ctx->priv;
     ThreadData *td = arg;
     AVFrame *in = td->in;
     AVFrame *out = td->out;
 
-    const int weave = (s->double_weave && !(inlink->frame_count_out & 1));
+    const int weave = (s->double_weave && !(inl->frame_count_out & 1));
     const int field1 = weave ? s->first_field : (!s->first_field);
     const int field2 = weave ? (!s->first_field) : s->first_field;
 
diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c
index e50484cbef..e98a8ea408 100644
--- a/libavfilter/vf_zoompan.c
+++ b/libavfilter/vf_zoompan.c
@@ -156,6 +156,7 @@ static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_va
 {
     ZPContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     AVFilterLink *inlink = ctx->inputs[0];
     int64_t pts = s->frame_count;
     int k, x, y, w, h, ret = 0;
@@ -172,7 +173,7 @@ static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_va
     var_values[VAR_OUT_TIME] = pts * av_q2d(outlink->time_base);
     var_values[VAR_TIME] = var_values[VAR_OT] = var_values[VAR_OUT_TIME];
     var_values[VAR_FRAME] = i;
-    var_values[VAR_ON] = outlink->frame_count_in;
+    var_values[VAR_ON] = outl->frame_count_in;
 
     *zoom = av_expr_eval(s->zoom_expr, var_values, NULL);
 
@@ -260,7 +261,9 @@ static int activate(AVFilterContext *ctx)
 {
     ZPContext *s = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLink *inl = ff_filter_link(inlink);
     AVFilterLink *outlink = ctx->outputs[0];
+    FilterLink *outl = ff_filter_link(outlink);
     int status, ret = 0;
     int64_t pts;
 
@@ -283,8 +286,8 @@ static int activate(AVFilterContext *ctx)
         s->var_values[VAR_IN_H]  = s->var_values[VAR_IH] = s->in->height;
         s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = s->w;
         s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = s->h;
-        s->var_values[VAR_IN]    = inlink->frame_count_out - 1;
-        s->var_values[VAR_ON]    = outlink->frame_count_in;
+        s->var_values[VAR_IN]    = inl->frame_count_out - 1;
+        s->var_values[VAR_ON]    = outl->frame_count_in;
         s->var_values[VAR_PX]    = s->x;
         s->var_values[VAR_PY]    = s->y;
         s->var_values[VAR_X]     = 0;
diff --git a/libavfilter/vsrc_mptestsrc.c b/libavfilter/vsrc_mptestsrc.c
index 3b9be4c8ed..8383370470 100644
--- a/libavfilter/vsrc_mptestsrc.c
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -292,12 +292,13 @@ static int config_props(AVFilterLink *outlink)
 
 static int request_frame(AVFilterLink *outlink)
 {
+    FilterLink *outl = ff_filter_link(outlink);
     MPTestContext *test = outlink->src->priv;
     AVFrame *picref;
     int w = WIDTH, h = HEIGHT,
         cw = AV_CEIL_RSHIFT(w, test->hsub), ch = AV_CEIL_RSHIFT(h, test->vsub);
-    uint64_t frame = outlink->frame_count_in / test->max_frames;
-    uint64_t mod = outlink->frame_count_in % test->max_frames;
+    uint64_t frame = outl->frame_count_in / test->max_frames;
+    uint64_t mod = outl->frame_count_in % test->max_frames;
     enum test_type tt = test->test;
     int i;
 
-- 
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 09/10] lavfi: move AVFilterLink.frame_wanted_out to FilterLinkInternal
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
                   ` (6 preceding siblings ...)
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} " Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 10/10] lavfi: move AVFilterLink.graph to FilterLink Anton Khirnov
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

---
 libavfilter/avfilter.c          | 22 ++++++++++++++--------
 libavfilter/avfilter.h          |  7 -------
 libavfilter/avfilter_internal.h |  7 +++++++
 libavfilter/avfiltergraph.c     |  2 +-
 libavfilter/buffersink.c        |  3 ++-
 libavfilter/filters.h           |  5 +----
 6 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 9a01bc1c4e..055db01e02 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -264,7 +264,7 @@ void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts)
     av_assert0(!li->status_in);
     li->status_in = status;
     li->status_in_pts = pts;
-    link->frame_wanted_out = 0;
+    li->frame_wanted_out = 0;
     li->frame_blocked_in = 0;
     filter_unblock(link->dst);
     ff_filter_set_ready(link->dst, 200);
@@ -278,7 +278,7 @@ static void link_set_out_status(AVFilterLink *link, int status, int64_t pts)
 {
     FilterLinkInternal * const li = ff_link_internal(link);
 
-    av_assert0(!link->frame_wanted_out);
+    av_assert0(!li->frame_wanted_out);
     av_assert0(!li->status_out);
     li->status_out = status;
     if (pts != AV_NOPTS_VALUE)
@@ -481,7 +481,7 @@ int ff_request_frame(AVFilterLink *link)
         return li->status_out;
     if (li->status_in) {
         if (ff_framequeue_queued_frames(&li->fifo)) {
-            av_assert1(!link->frame_wanted_out);
+            av_assert1(!li->frame_wanted_out);
             av_assert1(link->dst->ready >= 300);
             return 0;
         } else {
@@ -492,7 +492,7 @@ int ff_request_frame(AVFilterLink *link)
             return li->status_out;
         }
     }
-    link->frame_wanted_out = 1;
+    li->frame_wanted_out = 1;
     ff_filter_set_ready(link->src, 100);
     return 0;
 }
@@ -1058,7 +1058,7 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
                                        link->time_base);
     }
 
-    li->frame_blocked_in = link->frame_wanted_out = 0;
+    li->frame_blocked_in = li->frame_wanted_out = 0;
     li->l.frame_count_in++;
     li->l.sample_count_in += frame->nb_samples;
     filter_unblock(link->dst);
@@ -1241,7 +1241,7 @@ static int ff_filter_activate_default(AVFilterContext *filter)
     }
     for (i = 0; i < filter->nb_outputs; i++) {
         FilterLinkInternal * const li = ff_link_internal(filter->outputs[i]);
-        if (filter->outputs[i]->frame_wanted_out &&
+        if (li->frame_wanted_out &&
             !li->frame_blocked_in) {
             return ff_request_frame_to_filter(filter->outputs[i]);
         }
@@ -1581,7 +1581,7 @@ void ff_inlink_request_frame(AVFilterLink *link)
     av_unused FilterLinkInternal *li = ff_link_internal(link);
     av_assert1(!li->status_in);
     av_assert1(!li->status_out);
-    link->frame_wanted_out = 1;
+    li->frame_wanted_out = 1;
     ff_filter_set_ready(link->src, 100);
 }
 
@@ -1590,7 +1590,7 @@ void ff_inlink_set_status(AVFilterLink *link, int status)
     FilterLinkInternal * const li = ff_link_internal(link);
     if (li->status_out)
         return;
-    link->frame_wanted_out = 0;
+    li->frame_wanted_out = 0;
     li->frame_blocked_in = 0;
     link_set_out_status(link, status, AV_NOPTS_VALUE);
     while (ff_framequeue_queued_frames(&li->fifo)) {
@@ -1642,3 +1642,9 @@ int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link,
 
     return 0;
 }
+
+int ff_outlink_frame_wanted(AVFilterLink *link)
+{
+    FilterLinkInternal * const li = ff_link_internal(link);
+    return li->frame_wanted_out;
+}
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 176498cdb4..a91b543f5e 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -599,13 +599,6 @@ struct AVFilterLink {
      * Graph the filter belongs to.
      */
     struct AVFilterGraph *graph;
-
-    /**
-     * True if a frame is currently wanted on the output of this filter.
-     * Set when ff_request_frame() is called by the output,
-     * cleared when a frame is filtered.
-     */
-    int frame_wanted_out;
 };
 
 /**
diff --git a/libavfilter/avfilter_internal.h b/libavfilter/avfilter_internal.h
index 7084411d68..974024254f 100644
--- a/libavfilter/avfilter_internal.h
+++ b/libavfilter/avfilter_internal.h
@@ -67,6 +67,13 @@ typedef struct FilterLinkInternal {
      */
     int status_out;
 
+    /**
+     * True if a frame is currently wanted on the output of this filter.
+     * Set when ff_request_frame() is called by the output,
+     * cleared when a frame is filtered.
+     */
+    int frame_wanted_out;
+
     /**
      * Index in the age array.
      */
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 18a3f54759..2d46dd7637 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1406,7 +1406,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
     while (frame_count == oldesti->l.frame_count_out) {
         r = ff_filter_graph_run_once(graph);
         if (r == AVERROR(EAGAIN) &&
-            !oldest->frame_wanted_out && !oldesti->frame_blocked_in &&
+            !oldesti->frame_wanted_out && !oldesti->frame_blocked_in &&
             !oldesti->status_in)
             (void)ff_request_frame(oldest);
         else if (r < 0)
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index f76d0af7ff..bc4c4ebd43 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -88,6 +88,7 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i
 {
     BufferSinkContext *buf = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
+    FilterLinkInternal *li = ff_link_internal(inlink);
     int status, ret;
     AVFrame *cur_frame;
     int64_t pts;
@@ -107,7 +108,7 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i
             return status;
         } else if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST)) {
             return AVERROR(EAGAIN);
-        } else if (inlink->frame_wanted_out) {
+        } else if (li->frame_wanted_out) {
             ret = ff_filter_graph_run_once(ctx->graph);
             if (ret < 0)
                 return ret;
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 3f591e6f9d..36164c171e 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -245,10 +245,7 @@ void ff_inlink_set_status(AVFilterLink *link, int status);
 /**
  * Test if a frame is wanted on an output link.
  */
-static inline int ff_outlink_frame_wanted(AVFilterLink *link)
-{
-    return link->frame_wanted_out;
-}
+int ff_outlink_frame_wanted(AVFilterLink *link);
 
 /**
  * Get the status on an output link.
-- 
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 10/10] lavfi: move AVFilterLink.graph to FilterLink
  2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
                   ` (7 preceding siblings ...)
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 09/10] lavfi: move AVFilterLink.frame_wanted_out to FilterLinkInternal Anton Khirnov
@ 2024-08-11 14:42 ` Anton Khirnov
  8 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-11 14:42 UTC (permalink / raw)
  To: ffmpeg-devel

---
 libavfilter/avfilter.c      | 6 +++---
 libavfilter/avfilter.h      | 5 -----
 libavfilter/avfiltergraph.c | 2 +-
 libavfilter/f_sendcmd.c     | 2 +-
 libavfilter/filters.h       | 5 +++++
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 055db01e02..43d7c9f4ab 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -185,7 +185,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad,
     link->srcpad  = &src->output_pads[srcpad];
     link->dstpad  = &dst->input_pads[dstpad];
     link->type    = src->output_pads[srcpad].type;
-    link->graph   = src->graph;
+    li->l.graph   = src->graph;
     av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
     link->format  = -1;
     link->colorspace = AVCOL_SPC_UNSPECIFIED;
@@ -231,8 +231,8 @@ static void update_link_current_pts(FilterLinkInternal *li, int64_t pts)
     li->l.current_pts = pts;
     li->l.current_pts_us = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q);
     /* TODO use duration */
-    if (link->graph && li->age_index >= 0)
-        ff_avfilter_graph_update_heap(link->graph, li);
+    if (li->l.graph && li->age_index >= 0)
+        ff_avfilter_graph_update_heap(li->l.graph, li);
 }
 
 void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index a91b543f5e..549fe6ce3a 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -594,11 +594,6 @@ struct AVFilterLink {
      * Lists of supported formats / etc. supported by the output filter.
      */
     AVFilterFormatsConfig outcfg;
-
-    /**
-     * Graph the filter belongs to.
-     */
-    struct AVFilterGraph *graph;
 };
 
 /**
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 2d46dd7637..6bfcc42430 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -106,7 +106,7 @@ void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter
             filter->graph = NULL;
             for (j = 0; j<filter->nb_outputs; j++)
                 if (filter->outputs[j])
-                    filter->outputs[j]->graph = NULL;
+                    ff_filter_link(filter->outputs[j])->graph = NULL;
 
             return;
         }
diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c
index 86f9d522e9..8ba0878e81 100644
--- a/libavfilter/f_sendcmd.c
+++ b/libavfilter/f_sendcmd.c
@@ -567,7 +567,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
                     av_log(ctx, AV_LOG_VERBOSE,
                            "Processing command #%d target:%s command:%s arg:%s\n",
                            cmd->index, cmd->target, cmd->command, cmd_arg);
-                    ret = avfilter_graph_send_command(inlink->graph,
+                    ret = avfilter_graph_send_command(inl->graph,
                                                       cmd->target, cmd->command, cmd_arg,
                                                       buf, sizeof(buf),
                                                       AVFILTER_CMD_FLAG_ONE);
diff --git a/libavfilter/filters.h b/libavfilter/filters.h
index 36164c171e..ab16047e12 100644
--- a/libavfilter/filters.h
+++ b/libavfilter/filters.h
@@ -42,6 +42,11 @@
 typedef struct FilterLink {
     AVFilterLink pub;
 
+    /**
+     * Graph the filter belongs to.
+     */
+    struct AVFilterGraph *graph;
+
     /**
      * Current timestamp of the link, as defined by the most recent
      * frame(s), in link time_base units.
-- 
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 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} to FilterLink
  2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} " Anton Khirnov
@ 2024-08-12 20:19   ` Michael Niedermayer
  2024-08-13  8:28     ` Anton Khirnov
  0 siblings, 1 reply; 12+ messages in thread
From: Michael Niedermayer @ 2024-08-12 20:19 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 5053 bytes --]

On Sun, Aug 11, 2024 at 04:42:09PM +0200, Anton Khirnov wrote:
> ---
>  libavfilter/af_adrc.c         |  3 ++-
>  libavfilter/af_afftdn.c       |  3 ++-
>  libavfilter/af_ashowinfo.c    |  4 +++-
>  libavfilter/af_dynaudnorm.c   |  3 ++-
>  libavfilter/af_volume.c       |  4 +++-
>  libavfilter/asrc_sine.c       |  3 ++-
>  libavfilter/avf_showfreqs.c   |  5 +++--
>  libavfilter/avfilter.c        | 16 +++++++++-------
>  libavfilter/avfilter.h        | 10 ----------
>  libavfilter/avfiltergraph.c   |  4 ++--
>  libavfilter/f_graphmonitor.c  | 24 ++++++++++++------------
>  libavfilter/f_latency.c       |  6 ++++--
>  libavfilter/f_loop.c          |  6 ++++--
>  libavfilter/f_metadata.c      |  6 ++++--
>  libavfilter/f_segment.c       | 10 ++++++----
>  libavfilter/f_select.c        |  4 +++-
>  libavfilter/f_sendcmd.c       |  4 +++-
>  libavfilter/f_streamselect.c  |  3 ++-
>  libavfilter/filters.h         | 10 ++++++++++
>  libavfilter/qrencode.c        |  3 ++-
>  libavfilter/vf_bbox.c         |  4 +++-
>  libavfilter/vf_blackdetect.c  |  4 +++-
>  libavfilter/vf_blend.c        |  3 ++-
>  libavfilter/vf_blockdetect.c  |  5 ++++-
>  libavfilter/vf_blurdetect.c   |  5 ++++-
>  libavfilter/vf_crop.c         |  4 +++-
>  libavfilter/vf_datascope.c    |  4 +++-
>  libavfilter/vf_delogo.c       |  4 +++-
>  libavfilter/vf_detelecine.c   |  3 ++-
>  libavfilter/vf_drawtext.c     |  8 +++++---
>  libavfilter/vf_eq.c           |  3 ++-
>  libavfilter/vf_fade.c         | 10 ++++++----
>  libavfilter/vf_fftfilt.c      |  4 +++-
>  libavfilter/vf_fieldhint.c    | 17 ++++++++++-------
>  libavfilter/vf_fieldmatch.c   |  7 ++++---
>  libavfilter/vf_find_rect.c    |  5 ++++-
>  libavfilter/vf_framestep.c    |  3 ++-
>  libavfilter/vf_freezeframes.c |  8 +++++---
>  libavfilter/vf_geq.c          |  5 ++++-
>  libavfilter/vf_hue.c          |  3 ++-
>  libavfilter/vf_libplacebo.c   |  6 ++++--
>  libavfilter/vf_overlay.c      |  4 +++-
>  libavfilter/vf_overlay_cuda.c |  3 ++-
>  libavfilter/vf_perspective.c  |  7 +++++--
>  libavfilter/vf_quirc.c        |  3 ++-
>  libavfilter/vf_rotate.c       |  4 +++-
>  libavfilter/vf_scale.c        | 12 ++++++++----
>  libavfilter/vf_scale_npp.c    |  8 +++++---
>  libavfilter/vf_showinfo.c     |  3 ++-
>  libavfilter/vf_swaprect.c     |  4 +++-
>  libavfilter/vf_telecine.c     |  3 ++-
>  libavfilter/vf_tinterlace.c   |  7 ++++---
>  libavfilter/vf_vignette.c     |  3 ++-
>  libavfilter/vf_weave.c        |  3 ++-
>  libavfilter/vf_zoompan.c      |  9 ++++++---
>  libavfilter/vsrc_mptestsrc.c  |  5 +++--
>  56 files changed, 208 insertions(+), 116 deletions(-)

this seems to break build here:

libavfilter/vf_drawtext.c: In function ‘draw_text’:
libavfilter/vf_drawtext.c:1556:5: error: unknown type name ‘FilterLink’; did you mean ‘AVFilterLink’?
 1556 |     FilterLink *inl = ff_filter_link(inlink);
      |     ^~~~~~~~~~
      |     AVFilterLink
libavfilter/vf_drawtext.c:1556:23: error: implicit declaration of function ‘ff_filter_link’; did you mean ‘avfilter_link’? [-Werror=implicit-function-declaration]
 1556 |     FilterLink *inl = ff_filter_link(inlink);
      |                       ^~~~~~~~~~~~~~
      |                       avfilter_link
libavfilter/vf_drawtext.c:1556:23: warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
libavfilter/vf_drawtext.c:1600:51: error: request for member ‘frame_count_out’ in something not a structure or union
 1600 |         av_timecode_make_string(&s->tc, tcbuf, inl->frame_count_out);
      |                                                   ^~
libavfilter/vf_drawtext.c: In function ‘filter_frame’:
libavfilter/vf_drawtext.c:1832:5: error: unknown type name ‘FilterLink’; did you mean ‘AVFilterLink’?
 1832 |     FilterLink *inl = ff_filter_link(inlink);
      |     ^~~~~~~~~~
      |     AVFilterLink
libavfilter/vf_drawtext.c:1832:23: warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
 1832 |     FilterLink *inl = ff_filter_link(inlink);
      |                       ^~~~~~~~~~~~~~
libavfilter/vf_drawtext.c:1853:27: error: request for member ‘frame_count_out’ in something not a structure or union
 1853 |     if (s->reload && !(inl->frame_count_out % s->reload)) {
      |                           ^~
libavfilter/vf_drawtext.c:1867:31: error: request for member ‘frame_count_out’ in something not a structure or union
 1867 |     s->var_values[VAR_N] = inl->frame_count_out + s->start_number;
      |                               ^~
cc1: some warnings being treated as errors
make: *** [ffbuild/common.mak:81: libavfilter/vf_drawtext.o] Error 1
make: *** Waiting for unfinished jobs....

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Never trust a computer, one day, it may think you are the virus. -- Compn

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
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 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} to FilterLink
  2024-08-12 20:19   ` Michael Niedermayer
@ 2024-08-13  8:28     ` Anton Khirnov
  0 siblings, 0 replies; 12+ messages in thread
From: Anton Khirnov @ 2024-08-13  8:28 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Michael Niedermayer (2024-08-12 22:19:30)
> On Sun, Aug 11, 2024 at 04:42:09PM +0200, Anton Khirnov wrote:
> > ---
> >  libavfilter/af_adrc.c         |  3 ++-
> >  libavfilter/af_afftdn.c       |  3 ++-
> >  libavfilter/af_ashowinfo.c    |  4 +++-
> >  libavfilter/af_dynaudnorm.c   |  3 ++-
> >  libavfilter/af_volume.c       |  4 +++-
> >  libavfilter/asrc_sine.c       |  3 ++-
> >  libavfilter/avf_showfreqs.c   |  5 +++--
> >  libavfilter/avfilter.c        | 16 +++++++++-------
> >  libavfilter/avfilter.h        | 10 ----------
> >  libavfilter/avfiltergraph.c   |  4 ++--
> >  libavfilter/f_graphmonitor.c  | 24 ++++++++++++------------
> >  libavfilter/f_latency.c       |  6 ++++--
> >  libavfilter/f_loop.c          |  6 ++++--
> >  libavfilter/f_metadata.c      |  6 ++++--
> >  libavfilter/f_segment.c       | 10 ++++++----
> >  libavfilter/f_select.c        |  4 +++-
> >  libavfilter/f_sendcmd.c       |  4 +++-
> >  libavfilter/f_streamselect.c  |  3 ++-
> >  libavfilter/filters.h         | 10 ++++++++++
> >  libavfilter/qrencode.c        |  3 ++-
> >  libavfilter/vf_bbox.c         |  4 +++-
> >  libavfilter/vf_blackdetect.c  |  4 +++-
> >  libavfilter/vf_blend.c        |  3 ++-
> >  libavfilter/vf_blockdetect.c  |  5 ++++-
> >  libavfilter/vf_blurdetect.c   |  5 ++++-
> >  libavfilter/vf_crop.c         |  4 +++-
> >  libavfilter/vf_datascope.c    |  4 +++-
> >  libavfilter/vf_delogo.c       |  4 +++-
> >  libavfilter/vf_detelecine.c   |  3 ++-
> >  libavfilter/vf_drawtext.c     |  8 +++++---
> >  libavfilter/vf_eq.c           |  3 ++-
> >  libavfilter/vf_fade.c         | 10 ++++++----
> >  libavfilter/vf_fftfilt.c      |  4 +++-
> >  libavfilter/vf_fieldhint.c    | 17 ++++++++++-------
> >  libavfilter/vf_fieldmatch.c   |  7 ++++---
> >  libavfilter/vf_find_rect.c    |  5 ++++-
> >  libavfilter/vf_framestep.c    |  3 ++-
> >  libavfilter/vf_freezeframes.c |  8 +++++---
> >  libavfilter/vf_geq.c          |  5 ++++-
> >  libavfilter/vf_hue.c          |  3 ++-
> >  libavfilter/vf_libplacebo.c   |  6 ++++--
> >  libavfilter/vf_overlay.c      |  4 +++-
> >  libavfilter/vf_overlay_cuda.c |  3 ++-
> >  libavfilter/vf_perspective.c  |  7 +++++--
> >  libavfilter/vf_quirc.c        |  3 ++-
> >  libavfilter/vf_rotate.c       |  4 +++-
> >  libavfilter/vf_scale.c        | 12 ++++++++----
> >  libavfilter/vf_scale_npp.c    |  8 +++++---
> >  libavfilter/vf_showinfo.c     |  3 ++-
> >  libavfilter/vf_swaprect.c     |  4 +++-
> >  libavfilter/vf_telecine.c     |  3 ++-
> >  libavfilter/vf_tinterlace.c   |  7 ++++---
> >  libavfilter/vf_vignette.c     |  3 ++-
> >  libavfilter/vf_weave.c        |  3 ++-
> >  libavfilter/vf_zoompan.c      |  9 ++++++---
> >  libavfilter/vsrc_mptestsrc.c  |  5 +++--
> >  56 files changed, 208 insertions(+), 116 deletions(-)
> 
> this seems to break build here:

Huh, seems my config doesn't build drawtext anymore.

Fixed locally.

-- 
Anton Khirnov
_______________________________________________
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:[~2024-08-13  8:28 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-11 14:42 [FFmpeg-devel] [PATCH 01/10] lavfi: set AVFilterLink.graph on link creation Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 02/10] lavfi: add a new struct for private link properties Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 03/10] lavfi: move AVFilterLink.m{ax, in}_samples to FilterLink Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 04/10] lavfi/vf_*_cuda: do not access hw contexts before checking they exist Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 05/10] lavfi: move AVFilterLink.hw_frames_ctx to FilterLink Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 06/10] lavfi: move AVFilterLink.current_pts(_us) " Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 07/10] lavfi: move AVFilterLink.frame_rate " Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 08/10] lavfi: move AVFilterLink.{frame, sample}_count_{in, out} " Anton Khirnov
2024-08-12 20:19   ` Michael Niedermayer
2024-08-13  8:28     ` Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 09/10] lavfi: move AVFilterLink.frame_wanted_out to FilterLinkInternal Anton Khirnov
2024-08-11 14:42 ` [FFmpeg-devel] [PATCH 10/10] lavfi: move AVFilterLink.graph to FilterLink Anton Khirnov

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