This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 3d667b147aab3bd4b1264a48ac293d994fc10c7c
Author:     Marton Balint <[email protected]>
AuthorDate: Fri Nov 28 23:59:18 2025 +0100
Commit:     Marton Balint <[email protected]>
CommitDate: Sun Dec 7 19:36:49 2025 +0000

    avfilter/af_amerge: add layout_mode option to control output channel layout
    
    Signed-off-by: Marton Balint <[email protected]>
---
 doc/filters.texi        | 49 +++++++++++++++++++++++++++++++++++----------
 libavfilter/af_amerge.c | 53 +++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 85 insertions(+), 17 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 168ea0d2da..464a602f8d 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2436,6 +2436,11 @@ Only used if option named @var{start} is set to 
@code{-1}.
 
 Merge two or more audio streams into a single multi-channel stream.
 
+All inputs must have the same sample rate, and format.
+
+If inputs do not have the same duration, the output will stop with the
+shortest.
+
 The filter accepts the following options:
 
 @table @option
@@ -2443,15 +2448,25 @@ The filter accepts the following options:
 @item inputs
 Set the number of inputs. Default is 2.
 
-@end table
+@item layout_mode
 
-If the channel layouts of the inputs are disjoint, and therefore compatible,
-the channel layout of the output will be set accordingly and the channels
-will be reordered as necessary. If the channel layouts of the inputs are not
-disjoint, the output will have all the channels of the first input then all
-the channels of the second input, in that order, and the channel layout of
-the output will be the default value corresponding to the total number of
-channels.
+This option controls how the output channel layout is determined and if the
+audio channels are reordered during merge.
+
+@table @option
+
+@item legacy
+
+This is the mode how the filter behaved historically so it is the default.
+
+If the channel layouts of the inputs are known and disjoint, and therefore
+compatible, the channel layout of the output will be set accordingly and the
+channels will be reordered as necessary. If the channel layouts of the inputs
+are not disjoint, some of them are unknown, or they are using special channel
+layouts, such as ambisonics, the output will have all the channels of the first
+input then all the channels of the second input, in that order, and the channel
+layout of the output will be the default value corresponding to the total
+number of channels.
 
 For example, if the first input is in 2.1 (FL+FR+LF) and the second input
 is FC+BL+BR, then the output will be in 5.1, with the channels in the
@@ -2462,10 +2477,22 @@ On the other hand, if both input are in stereo, the 
output channels will be
 in the default order: a1, a2, b1, b2, and the channel layout will be
 arbitrarily set to 4.0, which may or may not be the expected value.
 
-All inputs must have the same sample rate, and format.
+@item reset
+This mode ignores the input channel layouts and does no channel reordering.
+The output will have all the channels of the first input, then all the channels
+of the second input, in that order, and so on.
 
-If inputs do not have the same duration, the output will stop with the
-shortest.
+The output channel layout will only specify the total channel count.
+
+@item normal
+This mode keeps channel name and designation information from the input
+channels and does no channel reordering. The output will have all the channels
+of the first input, then all the channels of the second input, in that order,
+and so on.
+
+@end table
+
+@end table
 
 @subsection Examples
 
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
index 92afb4691f..e300cf9c7b 100644
--- a/libavfilter/af_amerge.c
+++ b/libavfilter/af_amerge.c
@@ -23,6 +23,7 @@
  * Audio merging filter
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
 #include "libavutil/bprint.h"
 #include "libavutil/channel_layout.h"
@@ -43,14 +44,27 @@ typedef struct AMergeContext {
     struct amerge_input {
         int nb_ch;         /**< number of channels for the input */
     } *in;
+    int layout_mode;       /**< the method for determining the output channel 
layout */
 } AMergeContext;
 
 #define OFFSET(x) offsetof(AMergeContext, x)
 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
 
+enum LayoutModes {
+    LM_LEGACY,
+    LM_RESET,
+    LM_NORMAL,
+    NB_LAYOUTMODES
+};
+
 static const AVOption amerge_options[] = {
     { "inputs", "specify the number of inputs", OFFSET(nb_inputs),
       AV_OPT_TYPE_INT, { .i64 = 2 }, 1, SWR_CH_MAX, FLAGS },
+    { "layout_mode",   "method used to determine the output channel layout", 
OFFSET(layout_mode),
+      AV_OPT_TYPE_INT, { .i64 = LM_LEGACY }, 0, NB_LAYOUTMODES - 1, FLAGS, 
.unit = "layout_mode"},
+        { "legacy",   NULL, 0, AV_OPT_TYPE_CONST, {.i64 = LM_LEGACY   }, 0, 0, 
FLAGS, .unit = "layout_mode" },
+        { "reset",    NULL, 0, AV_OPT_TYPE_CONST, {.i64 = LM_RESET    }, 0, 0, 
FLAGS, .unit = "layout_mode" },
+        { "normal",   NULL, 0, AV_OPT_TYPE_CONST, {.i64 = LM_NORMAL   }, 0, 0, 
FLAGS, .unit = "layout_mode" },
     { NULL }
 };
 
@@ -101,9 +115,16 @@ static int query_formats(AVFilterContext *ctx)
         av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
         return AVERROR(EINVAL);
     }
+    ret = av_channel_layout_custom_init(&outlayout, nb_ch);
+    if (ret < 0)
+        return ret;
     for (int i = 0, ch_idx = 0; i < s->nb_inputs; i++) {
         for (int j = 0; j < s->in[i].nb_ch; j++) {
             enum AVChannel id = 
av_channel_layout_channel_from_index(INLAYOUT(ctx, i), j);
+            if (INLAYOUT(ctx, i)->order == AV_CHANNEL_ORDER_CUSTOM)
+                outlayout.u.map[ch_idx] = INLAYOUT(ctx, i)->u.map[j];
+            else
+                outlayout.u.map[ch_idx].id = (id == AV_CHAN_NONE ? 
AV_CHAN_UNKNOWN : id);
             if (id >= 0 && id < 64) {
                 outmask |= (1ULL << id);
                 native_layout_routes[id] = ch_idx;
@@ -112,6 +133,9 @@ static int query_formats(AVFilterContext *ctx)
             ch_idx++;
         }
     }
+    switch (s->layout_mode) {
+    case LM_LEGACY:
+    av_channel_layout_uninit(&outlayout);
     if (av_popcount64(outmask) != nb_ch) {
         av_log(ctx, AV_LOG_WARNING,
                "Input channel layouts overlap: "
@@ -125,22 +149,39 @@ static int query_formats(AVFilterContext *ctx)
                 s->route[native_layout_routes[c]] = ch_idx++;
         av_channel_layout_from_mask(&outlayout, outmask);
     }
+    break;
+    case LM_RESET:
+        av_channel_layout_uninit(&outlayout);
+        outlayout.order = AV_CHANNEL_ORDER_UNSPEC;
+        outlayout.nb_channels = nb_ch;
+        break;
+    case LM_NORMAL:
+        ret = av_channel_layout_retype(&outlayout, 0, 
AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
+        if (ret < 0)
+            goto out;
+        break;
+    default:
+        av_unreachable("Invalid layout_mode");
+    }
     if ((ret = ff_set_common_formats_from_list(ctx, packed_sample_fmts)) < 0)
-        return ret;
+        goto out;
     for (i = 0; i < s->nb_inputs; i++) {
         layouts = NULL;
         if ((ret = ff_add_channel_layout(&layouts, INLAYOUT(ctx, i))) < 0)
-            return ret;
+            goto out;
         if ((ret = ff_channel_layouts_ref(layouts, 
&ctx->inputs[i]->outcfg.channel_layouts)) < 0)
-            return ret;
+            goto out;
     }
     layouts = NULL;
     if ((ret = ff_add_channel_layout(&layouts, &outlayout)) < 0)
-        return ret;
+        goto out;
     if ((ret = ff_channel_layouts_ref(layouts, 
&ctx->outputs[0]->incfg.channel_layouts)) < 0)
-        return ret;
+        goto out;
 
-    return ff_set_common_all_samplerates(ctx);
+    ret = ff_set_common_all_samplerates(ctx);
+out:
+    av_channel_layout_uninit(&outlayout);
+    return ret;
 }
 
 static int config_output(AVFilterLink *outlink)

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to