LCOV - code coverage report
Current view: top level - libavfilter - af_amerge.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 125 165 75.8 %
Date: 2018-05-20 11:54:08 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : /**
      22             :  * @file
      23             :  * Audio merging filter
      24             :  */
      25             : 
      26             : #define FF_INTERNAL_FIELDS 1
      27             : #include "framequeue.h"
      28             : 
      29             : #include "libavutil/avstring.h"
      30             : #include "libavutil/bprint.h"
      31             : #include "libavutil/channel_layout.h"
      32             : #include "libavutil/opt.h"
      33             : #include "avfilter.h"
      34             : #include "filters.h"
      35             : #include "audio.h"
      36             : #include "internal.h"
      37             : 
      38             : #define SWR_CH_MAX 64
      39             : 
      40             : typedef struct AMergeContext {
      41             :     const AVClass *class;
      42             :     int nb_inputs;
      43             :     int route[SWR_CH_MAX]; /**< channels routing, see copy_samples */
      44             :     int bps;
      45             :     struct amerge_input {
      46             :         int nb_ch;         /**< number of channels for the input */
      47             :     } *in;
      48             : } AMergeContext;
      49             : 
      50             : #define OFFSET(x) offsetof(AMergeContext, x)
      51             : #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      52             : 
      53             : static const AVOption amerge_options[] = {
      54             :     { "inputs", "specify the number of inputs", OFFSET(nb_inputs),
      55             :       AV_OPT_TYPE_INT, { .i64 = 2 }, 1, SWR_CH_MAX, FLAGS },
      56             :     { NULL }
      57             : };
      58             : 
      59             : AVFILTER_DEFINE_CLASS(amerge);
      60             : 
      61           2 : static av_cold void uninit(AVFilterContext *ctx)
      62             : {
      63           2 :     AMergeContext *s = ctx->priv;
      64             :     int i;
      65             : 
      66           6 :     for (i = 0; i < s->nb_inputs; i++) {
      67           4 :         if (ctx->input_pads)
      68           4 :             av_freep(&ctx->input_pads[i].name);
      69             :     }
      70           2 :     av_freep(&s->in);
      71           2 : }
      72             : 
      73           2 : static int query_formats(AVFilterContext *ctx)
      74             : {
      75           2 :     AMergeContext *s = ctx->priv;
      76           2 :     int64_t inlayout[SWR_CH_MAX], outlayout = 0;
      77             :     AVFilterFormats *formats;
      78             :     AVFilterChannelLayouts *layouts;
      79           2 :     int i, ret, overlap = 0, nb_ch = 0;
      80             : 
      81           4 :     for (i = 0; i < s->nb_inputs; i++) {
      82           5 :         if (!ctx->inputs[i]->in_channel_layouts ||
      83           2 :             !ctx->inputs[i]->in_channel_layouts->nb_channel_layouts) {
      84           1 :             av_log(ctx, AV_LOG_WARNING,
      85             :                    "No channel layout for input %d\n", i + 1);
      86           1 :             return AVERROR(EAGAIN);
      87             :         }
      88           2 :         inlayout[i] = ctx->inputs[i]->in_channel_layouts->channel_layouts[0];
      89           2 :         if (ctx->inputs[i]->in_channel_layouts->nb_channel_layouts > 1) {
      90             :             char buf[256];
      91           0 :             av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
      92           0 :             av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
      93             :         }
      94           2 :         s->in[i].nb_ch = FF_LAYOUT2COUNT(inlayout[i]);
      95           2 :         if (s->in[i].nb_ch) {
      96           0 :             overlap++;
      97             :         } else {
      98           2 :             s->in[i].nb_ch = av_get_channel_layout_nb_channels(inlayout[i]);
      99           2 :             if (outlayout & inlayout[i])
     100           1 :                 overlap++;
     101           2 :             outlayout |= inlayout[i];
     102             :         }
     103           2 :         nb_ch += s->in[i].nb_ch;
     104             :     }
     105           1 :     if (nb_ch > SWR_CH_MAX) {
     106           0 :         av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
     107           0 :         return AVERROR(EINVAL);
     108             :     }
     109           1 :     if (overlap) {
     110           1 :         av_log(ctx, AV_LOG_WARNING,
     111             :                "Input channel layouts overlap: "
     112             :                "output layout will be determined by the number of distinct input channels\n");
     113           3 :         for (i = 0; i < nb_ch; i++)
     114           2 :             s->route[i] = i;
     115           1 :         outlayout = av_get_default_channel_layout(nb_ch);
     116           1 :         if (!outlayout && nb_ch)
     117           0 :             outlayout = 0xFFFFFFFFFFFFFFFFULL >> (64 - nb_ch);
     118             :     } else {
     119             :         int *route[SWR_CH_MAX];
     120           0 :         int c, out_ch_number = 0;
     121             : 
     122           0 :         route[0] = s->route;
     123           0 :         for (i = 1; i < s->nb_inputs; i++)
     124           0 :             route[i] = route[i - 1] + s->in[i - 1].nb_ch;
     125           0 :         for (c = 0; c < 64; c++)
     126           0 :             for (i = 0; i < s->nb_inputs; i++)
     127           0 :                 if ((inlayout[i] >> c) & 1)
     128           0 :                     *(route[i]++) = out_ch_number++;
     129             :     }
     130           1 :     formats = ff_make_format_list(ff_packed_sample_fmts_array);
     131           1 :     if ((ret = ff_set_common_formats(ctx, formats)) < 0)
     132           0 :         return ret;
     133           3 :     for (i = 0; i < s->nb_inputs; i++) {
     134           2 :         layouts = NULL;
     135           2 :         if ((ret = ff_add_channel_layout(&layouts, inlayout[i])) < 0)
     136           0 :             return ret;
     137           2 :         if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts)) < 0)
     138           0 :             return ret;
     139             :     }
     140           1 :     layouts = NULL;
     141           1 :     if ((ret = ff_add_channel_layout(&layouts, outlayout)) < 0)
     142           0 :         return ret;
     143           1 :     if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts)) < 0)
     144           0 :         return ret;
     145             : 
     146           1 :     return ff_set_common_samplerates(ctx, ff_all_samplerates());
     147             : }
     148             : 
     149           1 : static int config_output(AVFilterLink *outlink)
     150             : {
     151           1 :     AVFilterContext *ctx = outlink->src;
     152           1 :     AMergeContext *s = ctx->priv;
     153             :     AVBPrint bp;
     154             :     int i;
     155             : 
     156           2 :     for (i = 1; i < s->nb_inputs; i++) {
     157           1 :         if (ctx->inputs[i]->sample_rate != ctx->inputs[0]->sample_rate) {
     158           0 :             av_log(ctx, AV_LOG_ERROR,
     159             :                    "Inputs must have the same sample rate "
     160             :                    "%d for in%d vs %d\n",
     161           0 :                    ctx->inputs[i]->sample_rate, i, ctx->inputs[0]->sample_rate);
     162           0 :             return AVERROR(EINVAL);
     163             :         }
     164             :     }
     165           1 :     s->bps = av_get_bytes_per_sample(ctx->outputs[0]->format);
     166           1 :     outlink->sample_rate = ctx->inputs[0]->sample_rate;
     167           1 :     outlink->time_base   = ctx->inputs[0]->time_base;
     168             : 
     169           1 :     av_bprint_init(&bp, 0, 1);
     170           3 :     for (i = 0; i < s->nb_inputs; i++) {
     171           2 :         av_bprintf(&bp, "%sin%d:", i ? " + " : "", i);
     172           2 :         av_bprint_channel_layout(&bp, -1, ctx->inputs[i]->channel_layout);
     173             :     }
     174           1 :     av_bprintf(&bp, " -> out:");
     175           1 :     av_bprint_channel_layout(&bp, -1, ctx->outputs[0]->channel_layout);
     176           1 :     av_log(ctx, AV_LOG_VERBOSE, "%s\n", bp.str);
     177             : 
     178           1 :     return 0;
     179             : }
     180             : 
     181             : /**
     182             :  * Copy samples from several input streams to one output stream.
     183             :  * @param nb_inputs number of inputs
     184             :  * @param in        inputs; used only for the nb_ch field;
     185             :  * @param route     routing values;
     186             :  *                  input channel i goes to output channel route[i];
     187             :  *                  i <  in[0].nb_ch are the channels from the first output;
     188             :  *                  i >= in[0].nb_ch are the channels from the second output
     189             :  * @param ins       pointer to the samples of each inputs, in packed format;
     190             :  *                  will be left at the end of the copied samples
     191             :  * @param outs      pointer to the samples of the output, in packet format;
     192             :  *                  must point to a buffer big enough;
     193             :  *                  will be left at the end of the copied samples
     194             :  * @param ns        number of samples to copy
     195             :  * @param bps       bytes per sample
     196             :  */
     197         130 : static inline void copy_samples(int nb_inputs, struct amerge_input in[],
     198             :                                 int *route, uint8_t *ins[],
     199             :                                 uint8_t **outs, int ns, int bps)
     200             : {
     201             :     int *route_cur;
     202         130 :     int i, c, nb_ch = 0;
     203             : 
     204         390 :     for (i = 0; i < nb_inputs; i++)
     205         260 :         nb_ch += in[i].nb_ch;
     206      264860 :     while (ns--) {
     207      264600 :         route_cur = route;
     208      793800 :         for (i = 0; i < nb_inputs; i++) {
     209     1058400 :             for (c = 0; c < in[i].nb_ch; c++) {
     210      529200 :                 memcpy((*outs) + bps * *(route_cur++), ins[i], bps);
     211      529200 :                 ins[i] += bps;
     212             :             }
     213             :         }
     214      264600 :         *outs += nb_ch * bps;
     215             :     }
     216         130 : }
     217             : 
     218         130 : static void free_frames(int nb_inputs, AVFrame **input_frames)
     219             : {
     220             :     int i;
     221         390 :     for (i = 0; i < nb_inputs; i++)
     222         260 :         av_frame_free(&input_frames[i]);
     223         130 : }
     224             : 
     225         130 : static int try_push_frame(AVFilterContext *ctx, int nb_samples)
     226             : {
     227         130 :     AMergeContext *s = ctx->priv;
     228         130 :     AVFilterLink *outlink = ctx->outputs[0];
     229             :     int i, ret;
     230         130 :     AVFrame *outbuf, *inbuf[SWR_CH_MAX] = { NULL };
     231             :     uint8_t *outs, *ins[SWR_CH_MAX];
     232             : 
     233         390 :     for (i = 0; i < ctx->nb_inputs; i++) {
     234         260 :         ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &inbuf[i]);
     235         260 :         if (ret < 0) {
     236           0 :             free_frames(i, inbuf);
     237           0 :             return ret;
     238             :         }
     239         260 :         ins[i] = inbuf[i]->data[0];
     240             :     }
     241             : 
     242         130 :     outbuf = ff_get_audio_buffer(ctx->outputs[0], nb_samples);
     243         130 :     if (!outbuf) {
     244           0 :         free_frames(s->nb_inputs, inbuf);
     245           0 :         return AVERROR(ENOMEM);
     246             :     }
     247             : 
     248         130 :     outs = outbuf->data[0];
     249         130 :     outbuf->pts = inbuf[0]->pts;
     250             : 
     251         130 :     outbuf->nb_samples     = nb_samples;
     252         130 :     outbuf->channel_layout = outlink->channel_layout;
     253         130 :     outbuf->channels       = outlink->channels;
     254             : 
     255         390 :     while (nb_samples) {
     256             :         /* Unroll the most common sample formats: speed +~350% for the loop,
     257             :            +~13% overall (including two common decoders) */
     258         130 :         switch (s->bps) {
     259           0 :             case 1:
     260           0 :                 copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, 1);
     261           0 :                 break;
     262         130 :             case 2:
     263         130 :                 copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, 2);
     264         130 :                 break;
     265           0 :             case 4:
     266           0 :                 copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, 4);
     267           0 :                 break;
     268           0 :             default:
     269           0 :                 copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, s->bps);
     270           0 :                 break;
     271             :         }
     272             : 
     273         130 :         nb_samples = 0;
     274             :     }
     275             : 
     276         130 :     free_frames(s->nb_inputs, inbuf);
     277         130 :     return ff_filter_frame(ctx->outputs[0], outbuf);
     278             : }
     279             : 
     280         391 : static int activate(AVFilterContext *ctx)
     281             : {
     282             :     int i, status;
     283             :     int ret, nb_samples;
     284             :     int64_t pts;
     285             : 
     286         391 :     FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
     287             : 
     288         390 :     nb_samples = ff_framequeue_queued_samples(&ctx->inputs[0]->fifo);
     289         649 :     for (i = 1; i < ctx->nb_inputs && nb_samples > 0; i++) {
     290         259 :         nb_samples = FFMIN(ff_framequeue_queued_samples(&ctx->inputs[i]->fifo), nb_samples);
     291             :     }
     292             : 
     293         390 :     if (nb_samples) {
     294         130 :         ret = try_push_frame(ctx, nb_samples);
     295         130 :         if (ret < 0)
     296           0 :             return ret;
     297             :     }
     298             : 
     299         779 :     for (i = 0; i < ctx->nb_inputs; i++) {
     300         649 :         if (ff_framequeue_queued_samples(&ctx->inputs[i]->fifo))
     301         129 :             continue;
     302             : 
     303         520 :         if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
     304           1 :             ff_outlink_set_status(ctx->outputs[0], status, pts);
     305           1 :             return 0;
     306         519 :         } else if (ff_outlink_frame_wanted(ctx->outputs[0])) {
     307         259 :             ff_inlink_request_frame(ctx->inputs[i]);
     308         259 :             return 0;
     309             :         }
     310             :     }
     311             : 
     312         130 :     return 0;
     313             : }
     314             : 
     315           2 : static av_cold int init(AVFilterContext *ctx)
     316             : {
     317           2 :     AMergeContext *s = ctx->priv;
     318             :     int i, ret;
     319             : 
     320           2 :     s->in = av_calloc(s->nb_inputs, sizeof(*s->in));
     321           2 :     if (!s->in)
     322           0 :         return AVERROR(ENOMEM);
     323          12 :     for (i = 0; i < s->nb_inputs; i++) {
     324           4 :         char *name = av_asprintf("in%d", i);
     325           4 :         AVFilterPad pad = {
     326             :             .name             = name,
     327             :             .type             = AVMEDIA_TYPE_AUDIO,
     328             :         };
     329           4 :         if (!name)
     330           0 :             return AVERROR(ENOMEM);
     331           4 :         if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) {
     332           0 :             av_freep(&pad.name);
     333           0 :             return ret;
     334             :         }
     335             :     }
     336           2 :     return 0;
     337             : }
     338             : 
     339             : static const AVFilterPad amerge_outputs[] = {
     340             :     {
     341             :         .name          = "default",
     342             :         .type          = AVMEDIA_TYPE_AUDIO,
     343             :         .config_props  = config_output,
     344             :     },
     345             :     { NULL }
     346             : };
     347             : 
     348             : AVFilter ff_af_amerge = {
     349             :     .name          = "amerge",
     350             :     .description   = NULL_IF_CONFIG_SMALL("Merge two or more audio streams into "
     351             :                                           "a single multi-channel stream."),
     352             :     .priv_size     = sizeof(AMergeContext),
     353             :     .init          = init,
     354             :     .uninit        = uninit,
     355             :     .query_formats = query_formats,
     356             :     .activate      = activate,
     357             :     .inputs        = NULL,
     358             :     .outputs       = amerge_outputs,
     359             :     .priv_class    = &amerge_class,
     360             :     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
     361             : };

Generated by: LCOV version 1.13