• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavfilter/af_amerge.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
00003  *
00004  * This file is part of FFmpeg.
00005  *
00006  * FFmpeg is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * FFmpeg is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with FFmpeg; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00026 #include "libswresample/swresample.h" // only for SWR_CH_MAX
00027 #include "avfilter.h"
00028 #include "internal.h"
00029 
00030 #define QUEUE_SIZE 16
00031 
00032 typedef struct {
00033     int nb_in_ch[2];       
00034     int route[SWR_CH_MAX]; 
00035     int bps;
00036     struct amerge_queue {
00037         AVFilterBufferRef *buf[QUEUE_SIZE];
00038         int nb_buf, nb_samples, pos;
00039     } queue[2];
00040 } AMergeContext;
00041 
00042 static av_cold void uninit(AVFilterContext *ctx)
00043 {
00044     AMergeContext *am = ctx->priv;
00045     int i, j;
00046 
00047     for (i = 0; i < 2; i++)
00048         for (j = 0; j < am->queue[i].nb_buf; j++)
00049             avfilter_unref_buffer(am->queue[i].buf[j]);
00050 }
00051 
00052 static int query_formats(AVFilterContext *ctx)
00053 {
00054     AMergeContext *am = ctx->priv;
00055     int64_t inlayout[2], outlayout;
00056     const int packing_fmts[] = { AVFILTER_PACKED, -1 };
00057     AVFilterFormats *formats;
00058     int i;
00059 
00060     for (i = 0; i < 2; i++) {
00061         if (!ctx->inputs[i]->in_chlayouts ||
00062             !ctx->inputs[i]->in_chlayouts->format_count) {
00063             av_log(ctx, AV_LOG_ERROR,
00064                    "No channel layout for input %d\n", i + 1);
00065             return AVERROR(EINVAL);
00066         }
00067         inlayout[i] = ctx->inputs[i]->in_chlayouts->formats[0];
00068         if (ctx->inputs[i]->in_chlayouts->format_count > 1) {
00069             char buf[256];
00070             av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
00071             av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
00072         }
00073         am->nb_in_ch[i] = av_get_channel_layout_nb_channels(inlayout[i]);
00074     }
00075     if (am->nb_in_ch[0] + am->nb_in_ch[1] > SWR_CH_MAX) {
00076         av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
00077         return AVERROR(EINVAL);
00078     }
00079     if (inlayout[0] & inlayout[1]) {
00080         av_log(ctx, AV_LOG_WARNING,
00081                "Inputs overlap: output layout will be meaningless\n");
00082         for (i = 0; i < am->nb_in_ch[0] + am->nb_in_ch[1]; i++)
00083             am->route[i] = i;
00084         outlayout = av_get_default_channel_layout(am->nb_in_ch[0] +
00085                                                   am->nb_in_ch[1]);
00086         if (!outlayout)
00087             outlayout = ((int64_t)1 << (am->nb_in_ch[0] + am->nb_in_ch[1])) - 1;
00088     } else {
00089         int *route[2] = { am->route, am->route + am->nb_in_ch[0] };
00090         int c, out_ch_number = 0;
00091 
00092         outlayout = inlayout[0] | inlayout[1];
00093         for (c = 0; c < 64; c++)
00094             for (i = 0; i < 2; i++)
00095                 if ((inlayout[i] >> c) & 1)
00096                     *(route[i]++) = out_ch_number++;
00097     }
00098     formats = avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO);
00099     avfilter_set_common_sample_formats(ctx, formats);
00100     formats = avfilter_make_format_list(packing_fmts);
00101     avfilter_set_common_packing_formats(ctx, formats);
00102     for (i = 0; i < 2; i++) {
00103         formats = NULL;
00104         avfilter_add_format(&formats, inlayout[i]);
00105         avfilter_formats_ref(formats, &ctx->inputs[i]->out_chlayouts);
00106     }
00107     formats = NULL;
00108     avfilter_add_format(&formats, outlayout);
00109     avfilter_formats_ref(formats, &ctx->outputs[0]->in_chlayouts);
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;
00145 
00146     for (i = 0; i < 2; i++)
00147         if (!am->queue[i].nb_samples)
00148             avfilter_request_frame(ctx->inputs[i]);
00149     return 0;
00150 }
00151 
00167 static inline void copy_samples(int nb_in_ch[2], int *route, uint8_t *ins[2],
00168                                 uint8_t **outs, int ns, int bps)
00169 {
00170     int *route_cur;
00171     int i, c;
00172 
00173     while (ns--) {
00174         route_cur = route;
00175         for (i = 0; i < 2; i++) {
00176             for (c = 0; c < nb_in_ch[i]; c++) {
00177                 memcpy((*outs) + bps * *(route_cur++), ins[i], bps);
00178                 ins[i] += bps;
00179             }
00180         }
00181         *outs += (nb_in_ch[0] + nb_in_ch[1]) * bps;
00182     }
00183 }
00184 
00185 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00186 {
00187     AVFilterContext *ctx = inlink->dst;
00188     AMergeContext *am = ctx->priv;
00189     int input_number = inlink == ctx->inputs[1];
00190     struct amerge_queue *inq = &am->queue[input_number];
00191     int nb_samples, ns, i;
00192     AVFilterBufferRef *outbuf, **inbuf[2];
00193     uint8_t *ins[2], *outs;
00194 
00195     if (inq->nb_buf == QUEUE_SIZE) {
00196         av_log(ctx, AV_LOG_ERROR, "Packet queue overflow; dropped\n");
00197         avfilter_unref_buffer(insamples);
00198         return;
00199     }
00200     inq->buf[inq->nb_buf++] = avfilter_ref_buffer(insamples, AV_PERM_READ |
00201                                                              AV_PERM_PRESERVE);
00202     inq->nb_samples += insamples->audio->nb_samples;
00203     avfilter_unref_buffer(insamples);
00204     if (!am->queue[!input_number].nb_samples)
00205         return;
00206 
00207     nb_samples = FFMIN(am->queue[0].nb_samples,
00208                        am->queue[1].nb_samples);
00209     outbuf = avfilter_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE,
00210                                        nb_samples);
00211     outs = outbuf->data[0];
00212     for (i = 0; i < 2; i++) {
00213         inbuf[i] = am->queue[i].buf;
00214         ins[i] = (*inbuf[i])->data[0] +
00215                  am->queue[i].pos * am->nb_in_ch[i] * am->bps;
00216     }
00217     while (nb_samples) {
00218         ns = nb_samples;
00219         for (i = 0; i < 2; i++)
00220             ns = FFMIN(ns, (*inbuf[i])->audio->nb_samples - am->queue[i].pos);
00221         /* Unroll the most common sample formats: speed +~350% for the loop,
00222            +~13% overall (including two common decoders) */
00223         switch (am->bps) {
00224             case 1:
00225                 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 1);
00226                 break;
00227             case 2:
00228                 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 2);
00229                 break;
00230             case 4:
00231                 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, 4);
00232                 break;
00233             default:
00234                 copy_samples(am->nb_in_ch, am->route, ins, &outs, ns, am->bps);
00235                 break;
00236         }
00237 
00238         nb_samples -= ns;
00239         for (i = 0; i < 2; i++) {
00240             am->queue[i].nb_samples -= ns;
00241             am->queue[i].pos += ns;
00242             if (am->queue[i].pos == (*inbuf[i])->audio->nb_samples) {
00243                 am->queue[i].pos = 0;
00244                 avfilter_unref_buffer(*inbuf[i]);
00245                 *inbuf[i] = NULL;
00246                 inbuf[i]++;
00247                 ins[i] = *inbuf[i] ? (*inbuf[i])->data[0] : NULL;
00248             }
00249         }
00250     }
00251     for (i = 0; i < 2; i++) {
00252         int nbufused = inbuf[i] - am->queue[i].buf;
00253         if (nbufused) {
00254             am->queue[i].nb_buf -= nbufused;
00255             memmove(am->queue[i].buf, inbuf[i],
00256                     am->queue[i].nb_buf * sizeof(**inbuf));
00257         }
00258     }
00259     avfilter_filter_samples(ctx->outputs[0], outbuf);
00260 }
00261 
00262 AVFilter avfilter_af_amerge = {
00263     .name          = "amerge",
00264     .description   = NULL_IF_CONFIG_SMALL("Merge two audio streams into "
00265                                           "a single multi-channel stream."),
00266     .priv_size     = sizeof(AMergeContext),
00267     .uninit        = uninit,
00268     .query_formats = query_formats,
00269 
00270     .inputs    = (const AVFilterPad[]) {
00271         { .name             = "in1",
00272           .type             = AVMEDIA_TYPE_AUDIO,
00273           .filter_samples   = filter_samples,
00274           .min_perms        = AV_PERM_READ, },
00275         { .name             = "in2",
00276           .type             = AVMEDIA_TYPE_AUDIO,
00277           .filter_samples   = filter_samples,
00278           .min_perms        = AV_PERM_READ, },
00279         { .name = NULL }
00280     },
00281     .outputs   = (const AVFilterPad[]) {
00282         { .name             = "default",
00283           .type             = AVMEDIA_TYPE_AUDIO,
00284           .config_props     = config_output,
00285           .request_frame    = request_frame, },
00286         { .name = NULL }
00287     },
00288 };
Generated on Fri Feb 1 2013 14:34:48 for FFmpeg by doxygen 1.7.1