Browse code

lavfi: add amerge audio filter.

Nicolas George authored on 2011/11/07 05:28:05
Showing 6 changed files
... ...
@@ -13,6 +13,7 @@ version next:
13 13
 - asplit audio filter
14 14
 - tinterlace video filter
15 15
 - astreamsync audio filter
16
+- amerge audio filter
16 17
 
17 18
 
18 19
 version 0.9:
... ...
@@ -156,6 +156,39 @@ aformat=u8\\,s16:mono:packed
156 156
 aformat=s16:mono\\,stereo:all
157 157
 @end example
158 158
 
159
+@section amerge
160
+
161
+Merge two audio streams into a single multi-channel stream.
162
+
163
+This filter does not need any argument.
164
+
165
+If the channel layouts of the inputs are disjoint, and therefore compatible,
166
+the channel layout of the output will be set accordingly and the channels
167
+will be reordered as necessary. If the channel layouts of the inputs are not
168
+disjoint, the output will have all the channels of the first input then all
169
+the channels of the second input, in that order, and the channel layout of
170
+the output will be the default value corresponding to the total number of
171
+channels.
172
+
173
+For example, if the first input is in 2.1 (FL+FR+LF) and the second input
174
+is FC+BL+BR, then the output will be in 5.1, with the channels in the
175
+following order: a1, a2, b1, a3, b2, b3 (a1 is the first channel of the
176
+first input, b1 is the first channel of the second input).
177
+
178
+On the other hand, if both input are in stereo, the output channels will be
179
+in the default order: a1, a2, b1, b2, and the channel layout will be
180
+arbitrarily set to 4.0, which may or may not be the expected value.
181
+
182
+Both inputs must have the same sample rate, format and packing.
183
+
184
+If inputs do not have the same duration, the output will stop with the
185
+shortest.
186
+
187
+Example: merge two mono files into a stereo stream:
188
+@example
189
+amovie=left.wav [l] ; amovie=right.mp3 [r] ; [l] [r] amerge
190
+@end example
191
+
159 192
 @section anull
160 193
 
161 194
 Pass the audio source unchanged to the output.
... ...
@@ -26,6 +26,7 @@ OBJS-$(CONFIG_AVCODEC)                       += avcodec.o
26 26
 
27 27
 OBJS-$(CONFIG_ACONVERT_FILTER)               += af_aconvert.o
28 28
 OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
29
+OBJS-$(CONFIG_AMERGE_FILTER)                 += af_amerge.o
29 30
 OBJS-$(CONFIG_ANULL_FILTER)                  += af_anull.o
30 31
 OBJS-$(CONFIG_ARESAMPLE_FILTER)              += af_aresample.o
31 32
 OBJS-$(CONFIG_ASHOWINFO_FILTER)              += af_ashowinfo.o
32 33
new file mode 100644
... ...
@@ -0,0 +1,288 @@
0
+/*
1
+ * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+/**
21
+ * @file
22
+ * Audio merging filter
23
+ */
24
+
25
+#include "libswresample/swresample.h" // only for SWR_CH_MAX
26
+#include "avfilter.h"
27
+#include "internal.h"
28
+
29
+#define QUEUE_SIZE 16
30
+
31
+typedef struct {
32
+    int nb_in_ch[2];       /**< number of channels for each input */
33
+    int route[SWR_CH_MAX]; /**< channels routing, see copy_samples */
34
+    int bps;
35
+    struct amerge_queue {
36
+        AVFilterBufferRef *buf[QUEUE_SIZE];
37
+        int nb_buf, nb_samples, pos;
38
+    } queue[2];
39
+} AMergeContext;
40
+
41
+static av_cold void uninit(AVFilterContext *ctx)
42
+{
43
+    AMergeContext *am = ctx->priv;
44
+    int i, j;
45
+
46
+    for (i = 0; i < 2; i++)
47
+        for (j = 0; j < am->queue[i].nb_buf; j++)
48
+            avfilter_unref_buffer(am->queue[i].buf[j]);
49
+}
50
+
51
+static int query_formats(AVFilterContext *ctx)
52
+{
53
+    AMergeContext *am = ctx->priv;
54
+    int64_t inlayout[2], outlayout;
55
+    const int packing_fmts[] = { AVFILTER_PACKED, -1 };
56
+    AVFilterFormats *formats;
57
+    int i;
58
+
59
+    for (i = 0; i < 2; i++) {
60
+        if (!ctx->inputs[i]->in_chlayouts ||
61
+            !ctx->inputs[i]->in_chlayouts->format_count) {
62
+            av_log(ctx, AV_LOG_ERROR,
63
+                   "No channel layout for input %d\n", i + 1);
64
+            return AVERROR(EINVAL);
65
+        }
66
+        inlayout[i] = ctx->inputs[i]->in_chlayouts->formats[0];
67
+        if (ctx->inputs[i]->in_chlayouts->format_count > 1) {
68
+            char buf[256];
69
+            av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
70
+            av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
71
+        }
72
+        am->nb_in_ch[i] = av_get_channel_layout_nb_channels(inlayout[i]);
73
+    }
74
+    if (am->nb_in_ch[0] + am->nb_in_ch[1] > SWR_CH_MAX) {
75
+        av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
76
+        return AVERROR(EINVAL);
77
+    }
78
+    if (inlayout[0] & inlayout[1]) {
79
+        av_log(ctx, AV_LOG_WARNING,
80
+               "Inputs overlap: output layout will be meaningless\n");
81
+        for (i = 0; i < am->nb_in_ch[0] + am->nb_in_ch[1]; i++)
82
+            am->route[i] = i;
83
+        outlayout = av_get_default_channel_layout(am->nb_in_ch[0] +
84
+                                                  am->nb_in_ch[1]);
85
+        if (!outlayout)
86
+            outlayout = ((int64_t)1 << (am->nb_in_ch[0] + am->nb_in_ch[1])) - 1;
87
+    } else {
88
+        int *route[2] = { am->route, am->route + am->nb_in_ch[0] };
89
+        int c, out_ch_number = 0;
90
+
91
+        outlayout = inlayout[0] | inlayout[1];
92
+        for (c = 0; c < 64; c++)
93
+            for (i = 0; i < 2; i++)
94
+                if ((inlayout[i] >> c) & 1)
95
+                    *(route[i]++) = out_ch_number++;
96
+    }
97
+    formats = avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO);
98
+    avfilter_set_common_sample_formats(ctx, formats);
99
+    formats = avfilter_make_format_list(packing_fmts);
100
+    avfilter_set_common_packing_formats(ctx, formats);
101
+    for (i = 0; i < 2; i++) {
102
+        formats = NULL;
103
+        avfilter_add_format(&formats, inlayout[i]);
104
+        avfilter_formats_ref(formats, &ctx->inputs[i]->out_chlayouts);
105
+    }
106
+    formats = NULL;
107
+    avfilter_add_format(&formats, outlayout);
108
+    avfilter_formats_ref(formats, &ctx->outputs[0]->in_chlayouts);
109
+    return 0;
110
+}
111
+
112
+static int config_output(AVFilterLink *outlink)
113
+{
114
+    AVFilterContext *ctx = outlink->src;
115
+    AMergeContext *am = ctx->priv;
116
+    int64_t layout;
117
+    char name[3][256];
118
+    int i;
119
+
120
+    if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) {
121
+        av_log(ctx, AV_LOG_ERROR,
122
+               "Inputs must have the same sample rate "
123
+               "(%"PRIi64" vs %"PRIi64")\n",
124
+               ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate);
125
+        return AVERROR(EINVAL);
126
+    }
127
+    am->bps = av_get_bytes_per_sample(ctx->outputs[0]->format);
128
+    outlink->sample_rate = ctx->inputs[0]->sample_rate;
129
+    outlink->time_base   = ctx->inputs[0]->time_base;
130
+    for (i = 0; i < 3; i++) {
131
+        layout = (i < 2 ? ctx->inputs[i] : ctx->outputs[0])->channel_layout;
132
+        av_get_channel_layout_string(name[i], sizeof(name[i]), -1, layout);
133
+    }
134
+    av_log(ctx, AV_LOG_INFO,
135
+           "in1:%s + in2:%s -> out:%s\n", name[0], name[1], name[2]);
136
+    return 0;
137
+}
138
+
139
+static int request_frame(AVFilterLink *outlink)
140
+{
141
+    AVFilterContext *ctx = outlink->src;
142
+    AMergeContext *am = ctx->priv;
143
+    int i;
144
+
145
+    for (i = 0; i < 2; i++)
146
+        if (!am->queue[i].nb_samples)
147
+            avfilter_request_frame(ctx->inputs[i]);
148
+    return 0;
149
+}
150
+
151
+/**
152
+ * Copy samples from two input streams to one output stream.
153
+ * @param nb_in_ch  number of channels in each input stream
154
+ * @param route     routing values;
155
+ *                  input channel i goes to output channel route[i];
156
+ *                  i <  nb_in_ch[0] are the channels from the first output;
157
+ *                  i >= nb_in_ch[0] are the channels from the second output
158
+ * @param ins       pointer to the samples of each inputs, in packed format;
159
+ *                  will be left at the end of the copied samples
160
+ * @param outs      pointer to the samples of the output, in packet format;
161
+ *                  must point to a buffer big enough;
162
+ *                  will be left at the end of the copied samples
163
+ * @param ns        number of samples to copy
164
+ * @param bps       bytes per sample
165
+ */
166
+static inline void copy_samples(int nb_in_ch[2], int *route, uint8_t *ins[2],
167
+                                uint8_t **outs, int ns, int bps)
168
+{
169
+    int *route_cur;
170
+    int i, c;
171
+
172
+    while (ns--) {
173
+        route_cur = route;
174
+        for (i = 0; i < 2; i++) {
175
+            for (c = 0; c < nb_in_ch[i]; c++) {
176
+                memcpy((*outs) + bps * *(route_cur++), ins[i], bps);
177
+                ins[i] += bps;
178
+            }
179
+        }
180
+        *outs += (nb_in_ch[0] + nb_in_ch[1]) * bps;
181
+    }
182
+}
183
+
184
+static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
185
+{
186
+    AVFilterContext *ctx = inlink->dst;
187
+    AMergeContext *am = ctx->priv;
188
+    int input_number = inlink == ctx->inputs[1];
189
+    struct amerge_queue *inq = &am->queue[input_number];
190
+    int nb_samples, ns, i;
191
+    AVFilterBufferRef *outbuf, **inbuf[2];
192
+    uint8_t *ins[2], *outs;
193
+
194
+    if (inq->nb_buf == QUEUE_SIZE) {
195
+        av_log(ctx, AV_LOG_ERROR, "Packet queue overflow; dropped\n");
196
+        avfilter_unref_buffer(insamples);
197
+        return;
198
+    }
199
+    inq->buf[inq->nb_buf++] = avfilter_ref_buffer(insamples, AV_PERM_READ |
200
+                                                             AV_PERM_PRESERVE);
201
+    inq->nb_samples += insamples->audio->nb_samples;
202
+    avfilter_unref_buffer(insamples);
203
+    if (!am->queue[!input_number].nb_samples)
204
+        return;
205
+
206
+    nb_samples = FFMIN(am->queue[0].nb_samples,
207
+                       am->queue[1].nb_samples);
208
+    outbuf = avfilter_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE,
209
+                                       nb_samples);
210
+    outs = outbuf->data[0];
211
+    for (i = 0; i < 2; i++) {
212
+        inbuf[i] = am->queue[i].buf;
213
+        ins[i] = (*inbuf[i])->data[0] +
214
+                 am->queue[i].pos * am->nb_in_ch[i] * am->bps;
215
+    }
216
+    while (nb_samples) {
217
+        ns = nb_samples;
218
+        for (i = 0; i < 2; i++)
219
+            ns = FFMIN(ns, (*inbuf[i])->audio->nb_samples - am->queue[i].pos);
220
+        /* Unroll the most common sample formats: speed +~350% for the loop,
221
+           +~13% overall (including two common decoders) */
222
+        switch (am->bps) {
223
+            case 1:
224
+                copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 1);
225
+                break;
226
+            case 2:
227
+                copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 2);
228
+                break;
229
+            case 4:
230
+                copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 4);
231
+                break;
232
+            default:
233
+                copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, am->bps);
234
+                break;
235
+        }
236
+
237
+        nb_samples -= ns;
238
+        for (i = 0; i < 2; i++) {
239
+            am->queue[i].nb_samples -= ns;
240
+            am->queue[i].pos += ns;
241
+            if (am->queue[i].pos == (*inbuf[i])->audio->nb_samples) {
242
+                am->queue[i].pos = 0;
243
+                avfilter_unref_buffer(*inbuf[i]);
244
+                *inbuf[i] = NULL;
245
+                inbuf[i]++;
246
+                ins[i] = *inbuf[i] ? (*inbuf[i])->data[0] : NULL;
247
+            }
248
+        }
249
+    }
250
+    for (i = 0; i < 2; i++) {
251
+        int nbufused = inbuf[i] - am->queue[i].buf;
252
+        if (nbufused) {
253
+            am->queue[i].nb_buf -= nbufused;
254
+            memmove(am->queue[i].buf, inbuf[i],
255
+                    am->queue[i].nb_buf * sizeof(**inbuf));
256
+        }
257
+    }
258
+    avfilter_filter_samples(ctx->outputs[0], outbuf);
259
+}
260
+
261
+AVFilter avfilter_af_amerge = {
262
+    .name          = "amerge",
263
+    .description   = NULL_IF_CONFIG_SMALL("Merge two audio streams into "
264
+                                          "a single multi-channel stream."),
265
+    .priv_size     = sizeof(AMergeContext),
266
+    .uninit        = uninit,
267
+    .query_formats = query_formats,
268
+
269
+    .inputs    = (const AVFilterPad[]) {
270
+        { .name             = "in1",
271
+          .type             = AVMEDIA_TYPE_AUDIO,
272
+          .filter_samples   = filter_samples,
273
+          .min_perms        = AV_PERM_READ, },
274
+        { .name             = "in2",
275
+          .type             = AVMEDIA_TYPE_AUDIO,
276
+          .filter_samples   = filter_samples,
277
+          .min_perms        = AV_PERM_READ, },
278
+        { .name = NULL }
279
+    },
280
+    .outputs   = (const AVFilterPad[]) {
281
+        { .name             = "default",
282
+          .type             = AVMEDIA_TYPE_AUDIO,
283
+          .config_props     = config_output,
284
+          .request_frame    = request_frame, },
285
+        { .name = NULL }
286
+    },
287
+};
... ...
@@ -36,6 +36,7 @@ void avfilter_register_all(void)
36 36
 
37 37
     REGISTER_FILTER (ACONVERT,    aconvert,    af);
38 38
     REGISTER_FILTER (AFORMAT,     aformat,     af);
39
+    REGISTER_FILTER (AMERGE,      amerge,      af);
39 40
     REGISTER_FILTER (ANULL,       anull,       af);
40 41
     REGISTER_FILTER (ARESAMPLE,   aresample,   af);
41 42
     REGISTER_FILTER (ASHOWINFO,   ashowinfo,   af);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavcodec/avcodec.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR  2
33
-#define LIBAVFILTER_VERSION_MINOR 56
33
+#define LIBAVFILTER_VERSION_MINOR 57
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \