diff mbox series

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

Message ID 20230425072620.512-4-tong1.wu@intel.com
State New
Headers show
Series [FFmpeg-devel,v5,1/5] avutil/hwcontext: add a function to get the AVHWDeviceType | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_fate_x86 success Make fate finished
andriy/make_x86 warning New warnings during build

Commit Message

Wu, Tong1 April 25, 2023, 7:26 a.m. UTC
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@intel.com>
---
 libavfilter/avfiltergraph.c | 76 +++++++++++++++++++++++++------------
 libavfilter/formats.c       | 22 +++++++++--
 libavfilter/formats.h       | 10 ++++-
 3 files changed, 78 insertions(+), 30 deletions(-)

Comments

Paul B Mahol May 13, 2023, 6:33 a.m. UTC | #1
Possibility for infinite loops?

In what cases this helps, have graphs examples to test?
Wu, Tong1 May 25, 2023, 7:06 a.m. UTC | #2
>Possibility for infinite loops?

>In what cases this helps, have graphs examples to test?

Now we only have scale filter that can be auto inserted. This patch set basically gives the potential capability to add more auto filters. An auto hwmap filter is introduced for now. It can be beneficial to hwmap use cases.

For example,
ffmpeg -init_hw_device d3d11va=d3d11 -init_hw_device qsv=qsv@d3d11 -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -vf “hwmap=derive_device=qsv:extra_hw_frames=16,format=qsv” -c:v h264_qsv output.mp4

Now we don’t have to explicitly specify hwmap. The auto filter mechanism will try to insert a hwmap filter automatically. The command line will be much simpler.

ffmpeg -init_hw_device d3d11va=d3d11 -init_hw_device qsv=qsv@d3d11 -hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -c:v h264_qsv output.mp4

Could you explain a little bit why the loop could be infinite?
Wu, Tong1 June 7, 2023, 8:42 a.m. UTC | #3
Kindly ping


>>Possibility for infinite loops?
>
>>In what cases this helps, have graphs examples to test?
>
>Now we only have scale filter that can be auto inserted. This patch set
>basically gives the potential capability to add more auto filters. An auto
>hwmap filter is introduced for now. It can be beneficial to hwmap use cases.
>
>For example,
>ffmpeg -init_hw_device d3d11va=d3d11 -init_hw_device qsv=qsv@d3d11 -
>hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -vf
>“hwmap=derive_device=qsv:extra_hw_frames=16,format=qsv” -c:v h264_qsv
>output.mp4
>
>Now we don’t have to explicitly specify hwmap. The auto filter mechanism will
>try to insert a hwmap filter automatically. The command line will be much
>simpler.
>
>ffmpeg -init_hw_device d3d11va=d3d11 -init_hw_device qsv=qsv@d3d11 -
>hwaccel d3d11va -hwaccel_output_format d3d11 -i input.mp4 -c:v h264_qsv
>output.mp4
>
>Could you explain a little bit why the loop could be infinite?
>_______________________________________________
>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".
diff mbox series

Patch

diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 9e5bb32886..8af0467bc5 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);