avfiltergraph: try to reduce format conversions in filters.
authorAnton Khirnov <anton@khirnov.net>
Fri, 23 Mar 2012 14:14:40 +0000 (15:14 +0100)
committerAnton Khirnov <anton@khirnov.net>
Sun, 1 Apr 2012 07:04:09 +0000 (09:04 +0200)
Current code, with a filterchain such as
(input - yuv411) -> (scale - any) -> (sink - any)
will result in yuv420 being chosen for the second link, which is clearly
not right.

This commit attempts to improve in the following way:
repeat until convergence:
  loop over all filters
    find input link with exactly one format
    force this format on all output links of the same type (if possible)

libavfilter/avfiltergraph.c

index 9b73cc9..04d9027 100644 (file)
@@ -214,6 +214,49 @@ static void pick_format(AVFilterLink *link)
     avfilter_formats_unref(&link->out_formats);
 }
 
+static int reduce_formats_on_filter(AVFilterContext *filter)
+{
+    int i, j, k, ret = 0;
+
+    for (i = 0; i < filter->input_count; i++) {
+        AVFilterLink *link = filter->inputs[i];
+        int         format = link->out_formats->formats[0];
+
+        if (link->out_formats->format_count != 1)
+            continue;
+
+        for (j = 0; j < filter->output_count; j++) {
+            AVFilterLink *out_link = filter->outputs[j];
+            AVFilterFormats  *fmts = out_link->in_formats;
+
+            if (link->type != out_link->type ||
+                out_link->in_formats->format_count == 1)
+                continue;
+
+            for (k = 0; k < out_link->in_formats->format_count; k++)
+                if (fmts->formats[k] == format) {
+                    fmts->formats[0]   = format;
+                    fmts->format_count = 1;
+                    ret = 1;
+                    break;
+                }
+        }
+    }
+    return ret;
+}
+
+static void reduce_formats(AVFilterGraph *graph)
+{
+    int i, reduced;
+
+    do {
+        reduced = 0;
+
+        for (i = 0; i < graph->filter_count; i++)
+            reduced |= reduce_formats_on_filter(graph->filters[i]);
+    } while (reduced);
+}
+
 static void pick_formats(AVFilterGraph *graph)
 {
     int i, j;
@@ -237,7 +280,10 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
         return ret;
 
     /* Once everything is merged, it's possible that we'll still have
-     * multiple valid media format choices. We pick the first one. */
+     * multiple valid media format choices. We try to minimize the amount
+     * of format conversion inside filters */
+    reduce_formats(graph);
+
     pick_formats(graph);
 
     return 0;