Don't include common.h from avutil.h
[ffmpeg.git] / libavfilter / avfiltergraph.c
index 95e0a21..525a1dc 100644 (file)
@@ -29,6 +29,8 @@
 #include "internal.h"
 
 #include "libavutil/audioconvert.h"
+#include "libavutil/avassert.h"
+#include "libavutil/common.h"
 #include "libavutil/log.h"
 
 static const AVClass filtergraph_class = {
@@ -42,9 +44,7 @@ AVFilterGraph *avfilter_graph_alloc(void)
     AVFilterGraph *ret = av_mallocz(sizeof(AVFilterGraph));
     if (!ret)
         return NULL;
-#if FF_API_GRAPH_AVCLASS
     ret->av_class = &filtergraph_class;
-#endif
     return ret;
 }
 
@@ -425,11 +425,44 @@ static void swap_samplerates(AVFilterGraph *graph)
         swap_samplerates_on_filter(graph->filters[i]);
 }
 
+#define CH_CENTER_PAIR (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)
+#define CH_FRONT_PAIR  (AV_CH_FRONT_LEFT           | AV_CH_FRONT_RIGHT)
+#define CH_STEREO_PAIR (AV_CH_STEREO_LEFT          | AV_CH_STEREO_RIGHT)
+#define CH_WIDE_PAIR   (AV_CH_WIDE_LEFT            | AV_CH_WIDE_RIGHT)
+#define CH_SIDE_PAIR   (AV_CH_SIDE_LEFT            | AV_CH_SIDE_RIGHT)
+#define CH_DIRECT_PAIR (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT)
+#define CH_BACK_PAIR   (AV_CH_BACK_LEFT            | AV_CH_BACK_RIGHT)
+
+/* allowable substitutions for channel pairs when comparing layouts,
+ * ordered by priority for both values */
+static const uint64_t ch_subst[][2] = {
+    { CH_FRONT_PAIR,      CH_CENTER_PAIR     },
+    { CH_FRONT_PAIR,      CH_WIDE_PAIR       },
+    { CH_FRONT_PAIR,      AV_CH_FRONT_CENTER },
+    { CH_CENTER_PAIR,     CH_FRONT_PAIR      },
+    { CH_CENTER_PAIR,     CH_WIDE_PAIR       },
+    { CH_CENTER_PAIR,     AV_CH_FRONT_CENTER },
+    { CH_WIDE_PAIR,       CH_FRONT_PAIR      },
+    { CH_WIDE_PAIR,       CH_CENTER_PAIR     },
+    { CH_WIDE_PAIR,       AV_CH_FRONT_CENTER },
+    { AV_CH_FRONT_CENTER, CH_FRONT_PAIR      },
+    { AV_CH_FRONT_CENTER, CH_CENTER_PAIR     },
+    { AV_CH_FRONT_CENTER, CH_WIDE_PAIR       },
+    { CH_SIDE_PAIR,       CH_DIRECT_PAIR     },
+    { CH_SIDE_PAIR,       CH_BACK_PAIR       },
+    { CH_SIDE_PAIR,       AV_CH_BACK_CENTER  },
+    { CH_BACK_PAIR,       CH_DIRECT_PAIR     },
+    { CH_BACK_PAIR,       CH_SIDE_PAIR       },
+    { CH_BACK_PAIR,       AV_CH_BACK_CENTER  },
+    { AV_CH_BACK_CENTER,  CH_BACK_PAIR       },
+    { AV_CH_BACK_CENTER,  CH_DIRECT_PAIR     },
+    { AV_CH_BACK_CENTER,  CH_SIDE_PAIR       },
+};
+
 static void swap_channel_layouts_on_filter(AVFilterContext *filter)
 {
     AVFilterLink *link = NULL;
-    uint64_t chlayout;
-    int i, j;
+    int i, j, k;
 
     for (i = 0; i < filter->nb_inputs; i++) {
         link = filter->inputs[i];
@@ -441,27 +474,55 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter)
     if (i == filter->nb_inputs)
         return;
 
-    chlayout = link->out_channel_layouts->channel_layouts[0];
-
     for (i = 0; i < filter->nb_outputs; i++) {
         AVFilterLink *outlink = filter->outputs[i];
-        int best_idx, best_score = INT_MIN;
+        int best_idx, best_score = INT_MIN, best_count_diff = INT_MAX;
 
         if (outlink->type != AVMEDIA_TYPE_AUDIO ||
             outlink->in_channel_layouts->nb_channel_layouts < 2)
             continue;
 
         for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) {
+            uint64_t  in_chlayout = link->out_channel_layouts->channel_layouts[0];
             uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j];
-            int matched_channels  = av_get_channel_layout_nb_channels(chlayout &
-                                                                      out_chlayout);
-            int extra_channels     = av_get_channel_layout_nb_channels(out_chlayout &
-                                                                       (~chlayout));
-            int score = matched_channels - extra_channels;
+            int  in_channels      = av_get_channel_layout_nb_channels(in_chlayout);
+            int out_channels      = av_get_channel_layout_nb_channels(out_chlayout);
+            int count_diff        = out_channels - in_channels;
+            int matched_channels, extra_channels;
+            int score = 0;
+
+            /* channel substitution */
+            for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) {
+                uint64_t cmp0 = ch_subst[k][0];
+                uint64_t cmp1 = ch_subst[k][1];
+                if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) &&
+                    (out_chlayout & cmp1) && (!( in_chlayout & cmp1))) {
+                    in_chlayout  &= ~cmp0;
+                    out_chlayout &= ~cmp1;
+                    /* add score for channel match, minus a deduction for
+                       having to do the substitution */
+                    score += 10 * av_get_channel_layout_nb_channels(cmp1) - 2;
+                }
+            }
 
-            if (score > best_score) {
+            /* no penalty for LFE channel mismatch */
+            if ( (in_chlayout & AV_CH_LOW_FREQUENCY) &&
+                (out_chlayout & AV_CH_LOW_FREQUENCY))
+                score += 10;
+            in_chlayout  &= ~AV_CH_LOW_FREQUENCY;
+            out_chlayout &= ~AV_CH_LOW_FREQUENCY;
+
+            matched_channels = av_get_channel_layout_nb_channels(in_chlayout &
+                                                                 out_chlayout);
+            extra_channels   = av_get_channel_layout_nb_channels(out_chlayout &
+                                                                 (~in_chlayout));
+            score += 10 * matched_channels - 5 * extra_channels;
+
+            if (score > best_score ||
+                (count_diff < best_count_diff && score == best_score)) {
                 best_score = score;
                 best_idx   = j;
+                best_count_diff = count_diff;
             }
         }
         FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0],
@@ -499,7 +560,7 @@ static void swap_sample_fmts_on_filter(AVFilterContext *filter)
 
     for (i = 0; i < filter->nb_outputs; i++) {
         AVFilterLink *outlink = filter->outputs[i];
-        int best_idx, best_score = INT_MIN;
+        int best_idx = -1, best_score = INT_MIN;
 
         if (outlink->type != AVMEDIA_TYPE_AUDIO ||
             outlink->in_formats->format_count < 2)
@@ -532,6 +593,7 @@ static void swap_sample_fmts_on_filter(AVFilterContext *filter)
                 best_idx   = j;
             }
         }
+        av_assert0(best_idx >= 0);
         FFSWAP(int, outlink->in_formats->formats[0],
                outlink->in_formats->formats[best_idx]);
     }