00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "libswresample/swresample.h"
00027 #include "avfilter.h"
00028 #include "audio.h"
00029 #include "internal.h"
00030
00031 #define QUEUE_SIZE 16
00032
00033 typedef struct {
00034 int nb_in_ch[2];
00035 int route[SWR_CH_MAX];
00036 int bps;
00037 struct amerge_queue {
00038 AVFilterBufferRef *buf[QUEUE_SIZE];
00039 int nb_buf, nb_samples, pos;
00040 } queue[2];
00041 } AMergeContext;
00042
00043 static av_cold void uninit(AVFilterContext *ctx)
00044 {
00045 AMergeContext *am = ctx->priv;
00046 int i, j;
00047
00048 for (i = 0; i < 2; i++)
00049 for (j = 0; j < am->queue[i].nb_buf; j++)
00050 avfilter_unref_buffer(am->queue[i].buf[j]);
00051 }
00052
00053 static int query_formats(AVFilterContext *ctx)
00054 {
00055 AMergeContext *am = ctx->priv;
00056 int64_t inlayout[2], outlayout;
00057 AVFilterFormats *formats;
00058 AVFilterChannelLayouts *layouts;
00059 int i;
00060
00061 for (i = 0; i < 2; i++) {
00062 if (!ctx->inputs[i]->in_channel_layouts ||
00063 !ctx->inputs[i]->in_channel_layouts->nb_channel_layouts) {
00064 av_log(ctx, AV_LOG_ERROR,
00065 "No channel layout for input %d\n", i + 1);
00066 return AVERROR(EINVAL);
00067 }
00068 inlayout[i] = ctx->inputs[i]->in_channel_layouts->channel_layouts[0];
00069 if (ctx->inputs[i]->in_channel_layouts->nb_channel_layouts > 1) {
00070 char buf[256];
00071 av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
00072 av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
00073 }
00074 am->nb_in_ch[i] = av_get_channel_layout_nb_channels(inlayout[i]);
00075 }
00076 if (am->nb_in_ch[0] + am->nb_in_ch[1] > SWR_CH_MAX) {
00077 av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
00078 return AVERROR(EINVAL);
00079 }
00080 if (inlayout[0] & inlayout[1]) {
00081 av_log(ctx, AV_LOG_WARNING,
00082 "Inputs overlap: output layout will be meaningless\n");
00083 for (i = 0; i < am->nb_in_ch[0] + am->nb_in_ch[1]; i++)
00084 am->route[i] = i;
00085 outlayout = av_get_default_channel_layout(am->nb_in_ch[0] +
00086 am->nb_in_ch[1]);
00087 if (!outlayout)
00088 outlayout = ((int64_t)1 << (am->nb_in_ch[0] + am->nb_in_ch[1])) - 1;
00089 } else {
00090 int *route[2] = { am->route, am->route + am->nb_in_ch[0] };
00091 int c, out_ch_number = 0;
00092
00093 outlayout = inlayout[0] | inlayout[1];
00094 for (c = 0; c < 64; c++)
00095 for (i = 0; i < 2; i++)
00096 if ((inlayout[i] >> c) & 1)
00097 *(route[i]++) = out_ch_number++;
00098 }
00099 formats = avfilter_make_format_list(ff_packed_sample_fmts);
00100 avfilter_set_common_sample_formats(ctx, formats);
00101 for (i = 0; i < 2; i++) {
00102 layouts = NULL;
00103 ff_add_channel_layout(&layouts, inlayout[i]);
00104 ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
00105 }
00106 layouts = NULL;
00107 ff_add_channel_layout(&layouts, outlayout);
00108 ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
00109 ff_set_common_samplerates(ctx, ff_all_samplerates());
00110 return 0;
00111 }
00112
00113 static int config_output(AVFilterLink *outlink)
00114 {
00115 AVFilterContext *ctx = outlink->src;
00116 AMergeContext *am = ctx->priv;
00117 int64_t layout;
00118 char name[3][256];
00119 int i;
00120
00121 if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) {
00122 av_log(ctx, AV_LOG_ERROR,
00123 "Inputs must have the same sample rate "
00124 "(%"PRIi64" vs %"PRIi64")\n",
00125 ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate);
00126 return AVERROR(EINVAL);
00127 }
00128 am->bps = av_get_bytes_per_sample(ctx->outputs[0]->format);
00129 outlink->sample_rate = ctx->inputs[0]->sample_rate;
00130 outlink->time_base = ctx->inputs[0]->time_base;
00131 for (i = 0; i < 3; i++) {
00132 layout = (i < 2 ? ctx->inputs[i] : ctx->outputs[0])->channel_layout;
00133 av_get_channel_layout_string(name[i], sizeof(name[i]), -1, layout);
00134 }
00135 av_log(ctx, AV_LOG_INFO,
00136 "in1:%s + in2:%s -> out:%s\n", name[0], name[1], name[2]);
00137 return 0;
00138 }
00139
00140 static int request_frame(AVFilterLink *outlink)
00141 {
00142 AVFilterContext *ctx = outlink->src;
00143 AMergeContext *am = ctx->priv;
00144 int i, ret;
00145
00146 for (i = 0; i < 2; i++)
00147 if (!am->queue[i].nb_samples)
00148 if ((ret = avfilter_request_frame(ctx->inputs[i])) < 0)
00149 return ret;
00150 return 0;
00151 }
00152
00168 static inline void copy_samples(int nb_in_ch[2], int *route, uint8_t *ins[2],
00169 uint8_t **outs, int ns, int bps)
00170 {
00171 int *route_cur;
00172 int i, c;
00173
00174 while (ns--) {
00175 route_cur = route;
00176 for (i = 0; i < 2; i++) {
00177 for (c = 0; c < nb_in_ch[i]; c++) {
00178 memcpy((*outs) + bps * *(route_cur++), ins[i], bps);
00179 ins[i] += bps;
00180 }
00181 }
00182 *outs += (nb_in_ch[0] + nb_in_ch[1]) * bps;
00183 }
00184 }
00185
00186 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00187 {
00188 AVFilterContext *ctx = inlink->dst;
00189 AMergeContext *am = ctx->priv;
00190 AVFilterLink *const outlink = ctx->outputs[0];
00191 int input_number = inlink == ctx->inputs[1];
00192 struct amerge_queue *inq = &am->queue[input_number];
00193 int nb_samples, ns, i;
00194 AVFilterBufferRef *outbuf, **inbuf[2];
00195 uint8_t *ins[2], *outs;
00196
00197 if (inq->nb_buf == QUEUE_SIZE) {
00198 av_log(ctx, AV_LOG_ERROR, "Packet queue overflow; dropped\n");
00199 avfilter_unref_buffer(insamples);
00200 return;
00201 }
00202 inq->buf[inq->nb_buf++] = avfilter_ref_buffer(insamples, AV_PERM_READ |
00203 AV_PERM_PRESERVE);
00204 inq->nb_samples += insamples->audio->nb_samples;
00205 avfilter_unref_buffer(insamples);
00206 if (!am->queue[!input_number].nb_samples)
00207 return;
00208
00209 nb_samples = FFMIN(am->queue[0].nb_samples,
00210 am->queue[1].nb_samples);
00211 outbuf = ff_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE,
00212 nb_samples);
00213 outs = outbuf->data[0];
00214 for (i = 0; i < 2; i++) {
00215 inbuf[i] = am->queue[i].buf;
00216 ins[i] = (*inbuf[i])->data[0] +
00217 am->queue[i].pos * am->nb_in_ch[i] * am->bps;
00218 }
00219 outbuf->pts = (*inbuf[0])->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
00220 (*inbuf[0])->pts +
00221 av_rescale_q(am->queue[0].pos,
00222 (AVRational){ 1, ctx->inputs[0]->sample_rate },
00223 ctx->outputs[0]->time_base);
00224
00225 avfilter_copy_buffer_ref_props(outbuf, *inbuf[0]);
00226 outbuf->audio->nb_samples = nb_samples;
00227 outbuf->audio->channel_layout = outlink->channel_layout;
00228
00229 while (nb_samples) {
00230 ns = nb_samples;
00231 for (i = 0; i < 2; i++)
00232 ns = FFMIN(ns, (*inbuf[i])->audio->nb_samples - am->queue[i].pos);
00233
00234
00235 switch (am->bps) {
00236 case 1:
00237 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 1);
00238 break;
00239 case 2:
00240 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 2);
00241 break;
00242 case 4:
00243 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 4);
00244 break;
00245 default:
00246 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, am->bps);
00247 break;
00248 }
00249
00250 nb_samples -= ns;
00251 for (i = 0; i < 2; i++) {
00252 am->queue[i].nb_samples -= ns;
00253 am->queue[i].pos += ns;
00254 if (am->queue[i].pos == (*inbuf[i])->audio->nb_samples) {
00255 am->queue[i].pos = 0;
00256 avfilter_unref_buffer(*inbuf[i]);
00257 *inbuf[i] = NULL;
00258 inbuf[i]++;
00259 ins[i] = *inbuf[i] ? (*inbuf[i])->data[0] : NULL;
00260 }
00261 }
00262 }
00263 for (i = 0; i < 2; i++) {
00264 int nbufused = inbuf[i] - am->queue[i].buf;
00265 if (nbufused) {
00266 am->queue[i].nb_buf -= nbufused;
00267 memmove(am->queue[i].buf, inbuf[i],
00268 am->queue[i].nb_buf * sizeof(**inbuf));
00269 }
00270 }
00271 ff_filter_samples(ctx->outputs[0], outbuf);
00272 }
00273
00274 AVFilter avfilter_af_amerge = {
00275 .name = "amerge",
00276 .description = NULL_IF_CONFIG_SMALL("Merge two audio streams into "
00277 "a single multi-channel stream."),
00278 .priv_size = sizeof(AMergeContext),
00279 .uninit = uninit,
00280 .query_formats = query_formats,
00281
00282 .inputs = (const AVFilterPad[]) {
00283 { .name = "in1",
00284 .type = AVMEDIA_TYPE_AUDIO,
00285 .filter_samples = filter_samples,
00286 .min_perms = AV_PERM_READ, },
00287 { .name = "in2",
00288 .type = AVMEDIA_TYPE_AUDIO,
00289 .filter_samples = filter_samples,
00290 .min_perms = AV_PERM_READ, },
00291 { .name = NULL }
00292 },
00293 .outputs = (const AVFilterPad[]) {
00294 { .name = "default",
00295 .type = AVMEDIA_TYPE_AUDIO,
00296 .config_props = config_output,
00297 .request_frame = request_frame, },
00298 { .name = NULL }
00299 },
00300 };