[FFmpeg-devel] [PATCH v4 4/5] lavfi/format: wrap auto filters into structures

Tong Wu tong1.wu at intel.com
Mon Jul 4 11:09:56 EEST 2022


This patch wraps auto conversion filters into new structures, making it
easier to add more auto filters. And it adds a loop to automatically insert
every possible conversion filter until merge succeeds.

Signed-off-by: Tong Wu <tong1.wu at intel.com>
---
 libavfilter/avfiltergraph.c | 76 +++++++++++++++++++++++++------------
 libavfilter/formats.c       | 22 +++++++++--
 libavfilter/formats.h       | 10 ++++-
 3 files changed, 78 insertions(+), 30 deletions(-)

diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 2e6938b049..102c1f7693 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -395,24 +395,22 @@ static int formats_declared(AVFilterContext *f)
 
 static int insert_auto_filter(AVFilterContext **convert, AVFilterGraph *graph,
                               AVFilterLink *link, const AVFilterNegotiation *neg,
-                              int *converter_count, void *log_ctx)
+                              unsigned conv_step, int *converter_count, void *log_ctx)
 {
     int ret;
     const AVFilter *filter;
     AVFilterContext *ctx;
     AVFilterLink *inlink, *outlink;
     char inst_name[30];
-    const char *opts;
+    const char *opts = FF_FIELD_AT(char *, neg->conversion_filters[conv_step].conversion_opts_offset, *graph);
+    const char *name = neg->conversion_filters[conv_step].conversion_filter;
 
-    if (!(filter = avfilter_get_by_name(neg->conversion_filter))) {
+    if (!(filter = avfilter_get_by_name(name))) {
         av_log(log_ctx, AV_LOG_ERROR,
-               "'%s' filter not present, cannot convert formats.\n",
-               neg->conversion_filter);
+               "'%s' filter not present, cannot convert formats.\n", name);
         return AVERROR(EINVAL);
     }
-    snprintf(inst_name, sizeof(inst_name), "auto_%s_%d",
-             neg->conversion_filter, (*converter_count)++);
-    opts = FF_FIELD_AT(char *, neg->conversion_opts_offset, *graph);
+    snprintf(inst_name, sizeof(inst_name), "auto_%s_%d", name, (*converter_count)++);
     ret = avfilter_graph_create_filter(&ctx, filter, inst_name, opts, NULL, graph);
     if (ret < 0)
         return ret;
@@ -501,7 +499,7 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx)
         for (j = 0; j < filter->nb_inputs; j++) {
             AVFilterLink *link = filter->inputs[j];
             const AVFilterNegotiation *neg;
-            unsigned neg_step;
+            unsigned neg_step, conv_step;
             int convert_needed = 0;
 
             if (!link)
@@ -537,8 +535,6 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx)
             }
 
             if (convert_needed) {
-                AVFilterContext *convert;
-
                 if (graph->disable_auto_convert) {
                     av_log(log_ctx, AV_LOG_ERROR,
                            "The filters '%s' and '%s' do not have a common format "
@@ -548,20 +544,52 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx)
                 }
 
                 /* couldn't merge format lists. auto-insert conversion filter */
-                ret = insert_auto_filter(&convert, graph, link, neg, &converter_count, log_ctx);
-                if (ret < 0) {
-                    av_log(log_ctx, AV_LOG_ERROR, "Failed to insert an auto filter.\n");
-                    return ret;
-                }
+                for (conv_step = 0; conv_step < neg->nb_conversion_filters; conv_step++) {
+                    AVFilterContext *convert;
+                    ret = insert_auto_filter(&convert, graph, link, neg,
+                                             conv_step, &converter_count, log_ctx);
+                    if (ret < 0) {
+                        av_log(log_ctx, AV_LOG_ERROR, "Failed to insert an auto filter.\n");
+                        return ret;
+                    }
 
-                ret = merge_auto_filter(convert, neg);
-                if (ret < 0)
-                    return ret;
-                else if (ret == 0) {
-                    av_log(log_ctx, AV_LOG_ERROR,
-                           "Impossible to convert between the formats supported by the filter "
-                           "'%s' and the filter '%s'\n", link->src->name, link->dst->name);
-                    return AVERROR(ENOSYS);
+                    ret = merge_auto_filter(convert, neg);
+                    if (ret < 0)
+                        return ret;
+                    else if (ret > 0)
+                        break;
+                    else if (conv_step < neg->nb_conversion_filters - 1) {
+                        AVFilterLink *inlink  = convert->inputs[0];
+                        AVFilterLink *outlink = convert->outputs[0];
+                        av_log(log_ctx, AV_LOG_VERBOSE,
+                               "Impossible to convert between the formats supported by the filter "
+                               "'%s' and the filter '%s', try another conversion filter.\n",
+                               link->src->name, link->dst->name);
+                        unsigned dstpad_idx = outlink->dstpad - outlink->dst->input_pads;
+                        converter_count--;
+                        /* re-hookup the link */
+                        inlink->dst                      = outlink->dst;
+                        inlink->dstpad                   = &outlink->dst->input_pads[dstpad_idx];
+                        outlink->dst->inputs[dstpad_idx] = inlink;
+                        if (outlink->outcfg.formats)
+                            ff_formats_changeref(&outlink->outcfg.formats,
+                                                 &inlink->outcfg.formats);
+                        if (outlink->outcfg.samplerates)
+                            ff_formats_changeref(&outlink->outcfg.samplerates,
+                                                 &inlink->outcfg.samplerates);
+                        if (outlink->outcfg.channel_layouts)
+                            ff_channel_layouts_changeref(&outlink->outcfg.channel_layouts,
+                                                         &inlink->outcfg.channel_layouts);
+                        /* remove the previous auto filter */
+                        convert->inputs[0]       = NULL;
+                        convert->outputs[0]->dst = NULL;
+                        avfilter_free(convert);
+                    } else {
+                        av_log(log_ctx, AV_LOG_ERROR,
+                               "Impossible to convert between the formats supported by the filter "
+                               "'%s' and the filter '%s'\n", link->src->name, link->dst->name);
+                        return AVERROR(ENOSYS);
+                    }
                 }
             }
         }
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index e8c2888c0c..c8e20e5b20 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -326,18 +326,32 @@ static const AVFilterFormatsMerger mergers_audio[] = {
     },
 };
 
+static const AVFilterFormatsFilter filters_video[] = {
+    {
+        .conversion_filter = "scale",
+        .conversion_opts_offset = offsetof(AVFilterGraph, scale_sws_opts),
+    },
+};
+
+static const AVFilterFormatsFilter filters_audio[] = {
+    {
+        .conversion_filter = "aresample",
+        .conversion_opts_offset = offsetof(AVFilterGraph, aresample_swr_opts),
+    }
+};
+
 static const AVFilterNegotiation negotiate_video = {
     .nb_mergers = FF_ARRAY_ELEMS(mergers_video),
     .mergers = mergers_video,
-    .conversion_filter = "scale",
-    .conversion_opts_offset = offsetof(AVFilterGraph, scale_sws_opts),
+    .nb_conversion_filters = FF_ARRAY_ELEMS(filters_video),
+    .conversion_filters = filters_video,
 };
 
 static const AVFilterNegotiation negotiate_audio = {
     .nb_mergers = FF_ARRAY_ELEMS(mergers_audio),
     .mergers = mergers_audio,
-    .conversion_filter = "aresample",
-    .conversion_opts_offset = offsetof(AVFilterGraph, aresample_swr_opts),
+    .nb_conversion_filters = FF_ARRAY_ELEMS(filters_audio),
+    .conversion_filters = filters_audio,
 };
 
 const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link)
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index 22224dce2d..868cbe98dd 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -330,6 +330,12 @@ typedef struct AVFilterFormatMerger {
     int (*can_merge)(const void *a, const void *b);
 } AVFilterFormatsMerger;
 
+typedef struct AVFilterFormatFilter {
+    const char *conversion_filter;
+    unsigned conversion_opts_offset;
+} AVFilterFormatsFilter;
+
+
 /**
  * Callbacks and properties to describe the steps of a format negotiation.
  *
@@ -418,8 +424,8 @@ typedef struct AVFilterFormatMerger {
 typedef struct AVFilterNegotiation {
     unsigned nb_mergers;
     const AVFilterFormatsMerger *mergers;
-    const char *conversion_filter;
-    unsigned conversion_opts_offset;
+    unsigned nb_conversion_filters;
+    const AVFilterFormatsFilter *conversion_filters;
 } AVFilterNegotiation;
 
 const AVFilterNegotiation *ff_filter_get_negotiation(AVFilterLink *link);
-- 
2.35.1.windows.2



More information about the ffmpeg-devel mailing list