diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index b7dbfc063b..0f12f2d802 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -393,6 +393,83 @@ static int formats_declared(AVFilterContext *f)
     return 1;
 }
 
+static int insert_auto_filter(AVFilterContext **convert, AVFilterGraph *graph,
+                              AVFilterLink *link, const AVFilterNegotiation *neg,
+                              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 = neg->conversion_filters[conv_step].conversion_opts_offset == 0 ? NULL :
+                       FF_FIELD_AT(char *, neg->conversion_filters[conv_step].conversion_opts_offset, *graph);
+    const char *name = neg->conversion_filters[conv_step].conversion_filter;
+
+    if (graph->disable_auto_convert) {
+        av_log(log_ctx, AV_LOG_ERROR,
+               "The filters '%s' and '%s' do not have a common format "
+               "and automatic conversion is disabled.\n",
+               link->src->name, link->dst->name);
+        return AVERROR(EINVAL);
+    }
+
+    if (!(filter = avfilter_get_by_name(name))) {
+        av_log(log_ctx, AV_LOG_ERROR,
+               "'%s' filter not present, cannot convert formats.\n",
+               name);
+        return AVERROR(EINVAL);
+    }
+    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;
+
+    if ((ret = avfilter_insert_filter(link, ctx, 0, 0)) < 0)
+        return ret;
+
+    if ((ret = filter_query_formats(ctx)) < 0)
+        return ret;
+
+    inlink  = ctx->inputs[0];
+    outlink = ctx->outputs[0];
+    av_assert0( inlink->incfg.formats->refcount > 0);
+    av_assert0( inlink->outcfg.formats->refcount > 0);
+    av_assert0(outlink->incfg.formats->refcount > 0);
+    av_assert0(outlink->outcfg.formats->refcount > 0);
+    if (outlink->type == AVMEDIA_TYPE_AUDIO) {
+        av_assert0( inlink-> incfg.samplerates->refcount > 0);
+        av_assert0( inlink->outcfg.samplerates->refcount > 0);
+        av_assert0(outlink-> incfg.samplerates->refcount > 0);
+        av_assert0(outlink->outcfg.samplerates->refcount > 0);
+        av_assert0( inlink-> incfg.channel_layouts->refcount > 0);
+        av_assert0( inlink->outcfg.channel_layouts->refcount > 0);
+        av_assert0(outlink-> incfg.channel_layouts->refcount > 0);
+        av_assert0(outlink->outcfg.channel_layouts->refcount > 0);
+    }
+
+    *convert = ctx;
+    return 0;
+}
+
+static int merge_auto_filter(AVFilterContext *convert, const AVFilterNegotiation *neg)
+{
+    int neg_step, ret;
+    AVFilterLink *inlink  = convert->inputs[0];
+    AVFilterLink *outlink = convert->outputs[0];
+#define MERGE(merger, link)                                                  \
+    ((merger)->merge(FF_FIELD_AT(void *, (merger)->offset, (link)->incfg),   \
+                     FF_FIELD_AT(void *, (merger)->offset, (link)->outcfg)))
+    for (neg_step = 0; neg_step < neg->nb_mergers; neg_step++) {
+        const AVFilterFormatsMerger *m = &neg->mergers[neg_step];
+        if ((ret = MERGE(m,  inlink)) <= 0 ||
+            (ret = MERGE(m, outlink)) <= 0)
+                break;
+    }
+    return ret;
+}
+
 /**
  * Perform one round of query_formats() and merging formats lists on the
  * filter graph.
@@ -433,7 +510,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)
@@ -469,68 +546,50 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx)
             }
 
             if (convert_needed) {
-                AVFilterContext *convert;
-                const AVFilter *filter;
-                AVFilterLink *inlink, *outlink;
-                char inst_name[30];
-                const char *opts;
-
-                if (graph->disable_auto_convert) {
-                    av_log(log_ctx, AV_LOG_ERROR,
-                           "The filters '%s' and '%s' do not have a common format "
-                           "and automatic conversion is disabled.\n",
-                           link->src->name, link->dst->name);
-                    return AVERROR(EINVAL);
-                }
-
-                /* couldn't merge format lists. auto-insert conversion filter */
-                if (!(filter = avfilter_get_by_name(neg->conversion_filter))) {
-                    av_log(log_ctx, AV_LOG_ERROR,
-                           "'%s' filter not present, cannot convert formats.\n",
-                           neg->conversion_filter);
-                    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);
-                ret = avfilter_graph_create_filter(&convert, filter, inst_name, opts, NULL, graph);
-                if (ret < 0)
-                    return ret;
-                if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0)
-                    return ret;
-
-                if ((ret = filter_query_formats(convert)) < 0)
-                    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;
+                    }
 
-                inlink  = convert->inputs[0];
-                outlink = convert->outputs[0];
-                av_assert0( inlink->incfg.formats->refcount > 0);
-                av_assert0( inlink->outcfg.formats->refcount > 0);
-                av_assert0(outlink->incfg.formats->refcount > 0);
-                av_assert0(outlink->outcfg.formats->refcount > 0);
-                if (outlink->type == AVMEDIA_TYPE_AUDIO) {
-                    av_assert0( inlink-> incfg.samplerates->refcount > 0);
-                    av_assert0( inlink->outcfg.samplerates->refcount > 0);
-                    av_assert0(outlink-> incfg.samplerates->refcount > 0);
-                    av_assert0(outlink->outcfg.samplerates->refcount > 0);
-                    av_assert0( inlink-> incfg.channel_layouts->refcount > 0);
-                    av_assert0( inlink->outcfg.channel_layouts->refcount > 0);
-                    av_assert0(outlink-> incfg.channel_layouts->refcount > 0);
-                    av_assert0(outlink->outcfg.channel_layouts->refcount > 0);
-                }
-#define MERGE(merger, link)                                                  \
-    ((merger)->merge(FF_FIELD_AT(void *, (merger)->offset, (link)->incfg),   \
-                     FF_FIELD_AT(void *, (merger)->offset, (link)->outcfg)))
-                for (neg_step = 0; neg_step < neg->nb_mergers; neg_step++) {
-                    const AVFilterFormatsMerger *m = &neg->mergers[neg_step];
-                    if ((ret = MERGE(m,  inlink)) <= 0 ||
-                        (ret = MERGE(m, outlink)) <= 0) {
-                        if (ret < 0)
-                            return ret;
-                        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);
                     }
                 }
             }
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index e8c2888c0c..fee10fa0ee 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -326,18 +326,36 @@ static const AVFilterFormatsMerger mergers_audio[] = {
     },
 };
 
+static const AVFilterFormatsFilter filters_video[] = {
+    {
+        .conversion_filter = "scale",
+        .conversion_opts_offset = offsetof(AVFilterGraph, scale_sws_opts),
+    },
+    {
+        .conversion_filter = "hwmap",
+        .conversion_opts_offset = 0,
+    }
+};
+
+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..9943fb8aa3 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -330,6 +330,11 @@ 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 +423,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);
