Signed-off-by: Vittorio Giovara <vittorio.giov...@gmail.com>
---
 libavfilter/af_aformat.c      |  30 +++++++++---
 libavfilter/af_channelmap.c   |   2 +-
 libavfilter/af_channelsplit.c |   6 ++-
 libavfilter/af_join.c         |   2 +-
 libavfilter/avfiltergraph.c   | 109 +++++++++++++++++++++++++++++++-----------
 libavfilter/buffersrc.c       |   2 +-
 libavfilter/formats.c         |  45 +++++++++++++++--
 libavfilter/formats.h         |   4 +-
 8 files changed, 153 insertions(+), 47 deletions(-)

diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
index c5aa4f7148..259ece4c0b 100644
--- a/libavfilter/af_aformat.c
+++ b/libavfilter/af_aformat.c
@@ -94,11 +94,29 @@ static int get_sample_rate(const char *samplerate)
     return FFMAX(ret, 0);
 }
 
-static int get_channel_layout(const char *channel_layout)
+static int parse_channel_layout_string(AVFilterContext *ctx)
 {
-    AVChannelLayout ch_layout = {0};
-    av_channel_layout_from_string(&ch_layout, channel_layout);
-    return ch_layout.u.mask;
+    AFormatContext *s = ctx->priv;
+    char *next, *cur = s->channel_layouts_str, sep = '|';
+    int ret;
+
+    while (cur) {
+        AVChannelLayout fmt = {0};
+        next = strchr(cur, sep);
+        if (next)
+            *next++ = 0;
+
+        ret = av_channel_layout_from_string(&fmt, cur);
+        if (ret < 0) {
+            av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", 
cur);\
+            return ret;
+        }
+        ff_add_channel_layout(&s->channel_layouts, &fmt);
+
+        cur = next;
+    }
+
+    return 0;
 }
 
 static av_cold int init(AVFilterContext *ctx)
@@ -109,10 +127,8 @@ static av_cold int init(AVFilterContext *ctx)
                   ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, 
"sample format");
     PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format,
                   get_sample_rate, 0, "sample rate");
-    PARSE_FORMATS(s->channel_layouts_str, uint64_t, s->channel_layouts,
-                  ff_add_channel_layout, get_channel_layout, 0, "channel 
layout");
 
-    return 0;
+    return parse_channel_layout_string(ctx);
 }
 
 static int query_formats(AVFilterContext *ctx)
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
index 939f056d6f..54ff146c5b 100644
--- a/libavfilter/af_channelmap.c
+++ b/libavfilter/af_channelmap.c
@@ -296,7 +296,7 @@ static int channelmap_query_formats(AVFilterContext *ctx)
     ChannelMapContext *s = ctx->priv;
     AVFilterChannelLayouts *channel_layouts = NULL;
 
-    ff_add_channel_layout(&channel_layouts, s->ch_layout.u.mask);
+    ff_add_channel_layout(&channel_layouts, &s->ch_layout);
 
     ff_set_common_formats(ctx, ff_planar_sample_fmts());
     ff_set_common_samplerates(ctx, ff_all_samplerates());
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index 41b3051c8c..b13919cdf0 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -85,16 +85,18 @@ static int query_formats(AVFilterContext *ctx)
     ff_set_common_formats    (ctx, ff_planar_sample_fmts());
     ff_set_common_samplerates(ctx, ff_all_samplerates());
 
-    ff_add_channel_layout(&in_layouts, s->ch_layout.u.mask);
+    ff_add_channel_layout(&in_layouts, &s->ch_layout);
     ff_channel_layouts_ref(in_layouts, &ctx->inputs[0]->out_channel_layouts);
 
     for (i = 0; i < ctx->nb_outputs; i++) {
         AVFilterChannelLayouts *out_layouts = NULL;
+        AVChannelLayout tmp = {0};
         int ret = av_channel_layout_get_channel(&s->ch_layout, i);
         if (ret < 0)
             return ret;
 
-        ff_add_channel_layout(&out_layouts, 1ULL << ret);
+        av_channel_layout_from_mask(&tmp, 1ULL << ret);
+        ff_add_channel_layout(&out_layouts, &tmp);
         ff_channel_layouts_ref(out_layouts, 
&ctx->outputs[i]->in_channel_layouts);
     }
 
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index 6c000b9257..70dc2d00d7 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -234,7 +234,7 @@ static int join_query_formats(AVFilterContext *ctx)
     AVFilterChannelLayouts *layouts = NULL;
     int i;
 
-    ff_add_channel_layout(&layouts, s->ch_layout.u.mask);
+    ff_add_channel_layout(&layouts, &s->ch_layout);
     ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
 
     for (i = 0; i < ctx->nb_inputs; i++)
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index c72016d2c8..936a791175 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -374,6 +374,8 @@ static int query_formats(AVFilterGraph *graph, AVClass 
*log_ctx)
 
 static int pick_format(AVFilterLink *link)
 {
+    int ret;
+
     if (!link || !link->in_formats)
         return 0;
 
@@ -399,11 +401,15 @@ static int pick_format(AVFilterLink *link)
         link->in_channel_layouts->nb_channel_layouts = 1;
 #if FF_API_OLD_CHANNEL_LAYOUT
 FF_DISABLE_DEPRECATION_WARNINGS
-        link->channel_layout = link->in_channel_layouts->channel_layouts[0];
+        if (link->in_channel_layouts->channel_layouts[0].order == 
AV_CHANNEL_ORDER_NATIVE ||
+            link->in_channel_layouts->channel_layouts[0].order == 
AV_CHANNEL_ORDER_UNSPEC)
+            link->channel_layout = 
link->in_channel_layouts->channel_layouts[0].u.mask;
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
-        av_channel_layout_from_mask(&link->ch_layout,
-                                    
link->in_channel_layouts->channel_layouts[0]);
+        ret = av_channel_layout_copy(&link->ch_layout,
+                                     
&link->in_channel_layouts->channel_layouts[0]);
+        if (ret < 0)
+            return ret;
     }
 
     ff_formats_unref(&link->in_formats);
@@ -451,6 +457,47 @@ do {                                                       
            \
     }                                                                  \
 } while (0)
 
+static int reduce_formats_channel_layout(AVFilterContext *filter)
+{
+    int i, j, k, ret = 0;
+
+    for (i = 0; i < filter->nb_inputs; i++) {
+        AVFilterLink *link = filter->inputs[i];
+        AVChannelLayout *fmt;
+
+        if (!link->out_channel_layouts || 
link->out_channel_layouts->nb_channel_layouts != 1)
+            continue;
+        fmt = &link->out_channel_layouts->channel_layouts[0];
+
+        for (j = 0; j < filter->nb_outputs; j++) {
+            AVFilterLink *out_link = filter->outputs[j];
+            AVFilterChannelLayouts *fmts;
+
+            if (link->type != out_link->type ||
+                out_link->in_channel_layouts->nb_channel_layouts == 1)
+                continue;
+            fmts = out_link->in_channel_layouts;
+
+            if (!out_link->in_channel_layouts->nb_channel_layouts) {
+                ff_add_channel_layout(&out_link->in_channel_layouts, fmt);
+                break;
+            }
+
+            for (k = 0; k < out_link->in_channel_layouts->nb_channel_layouts; 
k++)
+                if (!av_channel_layout_compare(&fmts->channel_layouts[k], 
fmt)) {
+                    ret = av_channel_layout_copy(&fmts->channel_layouts[0], 
fmt);
+                    if (ret < 0)
+                        return ret;
+                    fmts->nb_channel_layouts = 1;
+                    ret = 1;
+                    break;
+                }
+        }
+    }
+
+    return ret;
+}
+
 static int reduce_formats_on_filter(AVFilterContext *filter)
 {
     int i, j, k, ret = 0;
@@ -459,10 +506,11 @@ static int reduce_formats_on_filter(AVFilterContext 
*filter)
                    nb_formats, ff_add_format);
     REDUCE_FORMATS(int,      AVFilterFormats,        samplerates,     formats,
                    nb_formats, ff_add_format);
-    REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts,
-                   channel_layouts, nb_channel_layouts, ff_add_channel_layout);
 
-    return ret;
+    if (ret < 0)
+        return ret;
+
+    return reduce_formats_channel_layout(filter);
 }
 
 static void reduce_formats(AVFilterGraph *graph)
@@ -582,20 +630,22 @@ static void 
swap_channel_layouts_on_filter(AVFilterContext *filter)
             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];
+            AVChannelLayout  *in_ch_layout = 
&link->out_channel_layouts->channel_layouts[0];
+            AVChannelLayout *out_ch_layout = 
&outlink->in_channel_layouts->channel_layouts[j];
+            AVChannelLayout in = {0}, out = {0};
             int  in_channels;
             int out_channels;
+            uint64_t in_mask = 0, out_mask = 0;
             int count_diff;
             int matched_channels, extra_channels;
             int score = 0;
-            AVChannelLayout  in_ch_layout = {0};
-            AVChannelLayout out_ch_layout = {0};
 
-            av_channel_layout_from_mask( &in_ch_layout,  in_chlayout);
-            av_channel_layout_from_mask(&out_ch_layout, out_chlayout);
-            in_channels  =  in_ch_layout.nb_channels;
-            out_channels = out_ch_layout.nb_channels;
+            in_channels  =  in_ch_layout->nb_channels;
+            out_channels = out_ch_layout->nb_channels;
+            if ( in_ch_layout->order == AV_CHANNEL_ORDER_NATIVE)
+                in_mask  =  in_ch_layout->u.mask;
+            if (out_ch_layout->order == AV_CHANNEL_ORDER_NATIVE)
+                out_mask = out_ch_layout->u.mask;
             count_diff = out_channels - in_channels;
 
             /* channel substitution */
@@ -603,10 +653,13 @@ static void 
swap_channel_layouts_on_filter(AVFilterContext *filter)
                 uint64_t cmp0 = ch_subst[k][0];
                 uint64_t cmp1 = ch_subst[k][1];
                 AVChannelLayout tmp = {0};
-                if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) &&
-                    (out_chlayout & cmp1) && (!( in_chlayout & cmp1))) {
-                    in_chlayout  &= ~cmp0;
-                    out_chlayout &= ~cmp1;
+
+                if ( av_channel_layout_subset( in_ch_layout, cmp0) &&
+                    !av_channel_layout_subset(out_ch_layout, cmp0) &&
+                     av_channel_layout_subset(out_ch_layout, cmp1) &&
+                    !av_channel_layout_subset( in_ch_layout, cmp1)) {
+                    in_mask  &= ~cmp0;
+                    out_mask &= ~cmp1;
                     /* add score for channel match, minus a deduction for
                        having to do the substitution */
                     av_channel_layout_from_mask(&tmp, cmp1);
@@ -615,19 +668,17 @@ static void 
swap_channel_layouts_on_filter(AVFilterContext *filter)
             }
 
             /* no penalty for LFE channel mismatch */
-            if ( (in_chlayout & AV_CH_LOW_FREQUENCY) &&
-                (out_chlayout & AV_CH_LOW_FREQUENCY))
+            if (av_channel_layout_subset( in_ch_layout, AV_CH_LOW_FREQUENCY) &&
+                av_channel_layout_subset(out_ch_layout, AV_CH_LOW_FREQUENCY))
                 score += 10;
-            in_chlayout  &= ~AV_CH_LOW_FREQUENCY;
-            out_chlayout &= ~AV_CH_LOW_FREQUENCY;
+            in_mask  &= ~AV_CH_LOW_FREQUENCY;
+            out_mask &= ~AV_CH_LOW_FREQUENCY;
 
-            av_channel_layout_uninit( &in_ch_layout);
-            av_channel_layout_uninit(&out_ch_layout);
-            av_channel_layout_from_mask( &in_ch_layout,  in_chlayout &  
out_chlayout);
-            av_channel_layout_from_mask(&out_ch_layout, out_chlayout & 
(~in_chlayout));
+            av_channel_layout_from_mask( &in,  in_mask &  out_mask);
+            av_channel_layout_from_mask(&out, out_mask & (~in_mask));
 
-            matched_channels = in_ch_layout.nb_channels;
-            extra_channels   = out_ch_layout.nb_channels;
+            matched_channels =  in.nb_channels;
+            extra_channels   = out.nb_channels;
             score += 10 * matched_channels - 5 * extra_channels;
 
             if (score > best_score ||
@@ -638,7 +689,7 @@ static void swap_channel_layouts_on_filter(AVFilterContext 
*filter)
             }
         }
         av_assert0(best_idx >= 0);
-        FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0],
+        FFSWAP(AVChannelLayout, 
outlink->in_channel_layouts->channel_layouts[0],
                outlink->in_channel_layouts->channel_layouts[best_idx]);
     }
 
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 838e3ac08d..9f4e8dbf8a 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -347,7 +347,7 @@ static int query_formats(AVFilterContext *ctx)
         ff_add_format(&samplerates,       c->sample_rate);
         ff_set_common_samplerates(ctx, samplerates);
 
-        ff_add_channel_layout(&channel_layouts, c->ch_layout.u.mask);
+        ff_add_channel_layout(&channel_layouts, &c->ch_layout);
         ff_set_common_channel_layouts(ctx, channel_layouts);
         break;
     default:
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 7b5a93c325..251df0d721 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -131,8 +131,31 @@ AVFilterChannelLayouts 
*ff_merge_channel_layouts(AVFilterChannelLayouts *a,
     if (a == b) return a;
 
     if (a->nb_channel_layouts && b->nb_channel_layouts) {
-        MERGE_FORMATS(ret, a, b, channel_layouts, nb_channel_layouts,
-                      AVFilterChannelLayouts, fail);
+        int i, j, k = 0, count = FFMIN(a->nb_channel_layouts, 
b->nb_channel_layouts);
+
+        if (!(ret = av_mallocz(sizeof(*ret))))
+            goto fail;
+
+        if (count) {
+            if (!(ret->channel_layouts = 
av_malloc(sizeof(*ret->channel_layouts) * count)))
+                goto fail;
+            for (i = 0; i < a->nb_channel_layouts; i++)
+                for (j = 0; j < b->nb_channel_layouts; j++)
+                    if (!av_channel_layout_compare(&a->channel_layouts[i],
+                                                   &b->channel_layouts[j]))
+                        if (av_channel_layout_copy(&ret->channel_layouts[k++],
+                                                   &a->channel_layouts[i]) < 0)
+                            goto fail;
+
+            ret->nb_channel_layouts = k;
+        }
+        /* check that there was at least one common format */
+        if (!ret->nb_channel_layouts)
+            goto fail;
+
+        MERGE_REF(ret, a, channel_layouts, AVFilterChannelLayouts, fail);
+        MERGE_REF(ret, b, channel_layouts, AVFilterChannelLayouts, fail);
+
     } else if (a->nb_channel_layouts) {
         MERGE_REF(a, b, channel_layouts, AVFilterChannelLayouts, fail);
         ret = a;
@@ -210,9 +233,23 @@ int ff_add_format(AVFilterFormats **avff, int fmt)
     ADD_FORMAT(avff, fmt, int, formats, nb_formats);
 }
 
-int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
+int ff_add_channel_layout(AVFilterChannelLayouts **f, AVChannelLayout 
*channel_layout)
 {
-    ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, 
nb_channel_layouts);
+    AVChannelLayout *fmts;
+
+    if (!(*f) && !(*f = av_mallocz(sizeof(**f))))
+        return AVERROR(ENOMEM);
+
+    fmts = av_realloc((*f)->channel_layouts,
+                      sizeof(*(*f)->channel_layouts) * 
((*f)->nb_channel_layouts + 1));\
+    if (!fmts) {
+        av_freep(&f);
+        return AVERROR(ENOMEM);
+    }
+
+    (*f)->channel_layouts = fmts;
+    return 
av_channel_layout_copy(&(*f)->channel_layouts[(*f)->nb_channel_layouts++],
+                                  channel_layout);
 }
 
 AVFilterFormats *ff_all_formats(enum AVMediaType type)
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index b273f8aa03..157ef757b3 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -70,7 +70,7 @@ struct AVFilterFormats {
 };
 
 typedef struct AVFilterChannelLayouts {
-    uint64_t *channel_layouts;  ///< list of channel layouts
+    AVChannelLayout *channel_layouts;  ///< list of channel layouts
     int    nb_channel_layouts;  ///< number of channel layouts
 
     unsigned refcount;          ///< number of references to this list
@@ -114,7 +114,7 @@ void ff_set_common_samplerates(AVFilterContext *ctx,
  */
 void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
 
-int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
+int ff_add_channel_layout(AVFilterChannelLayouts **l, AVChannelLayout 
*channel_layout);
 
 /**
  * Add *ref as a new reference to f.
-- 
2.13.1

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to