libavfilter/asrc_abuffer.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
00003  * Copyright (c) 2011 Mina Nagy Zaki
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00027 #include "libavutil/audioconvert.h"
00028 #include "libavutil/avstring.h"
00029 #include "libavutil/fifo.h"
00030 #include "asrc_abuffer.h"
00031 #include "internal.h"
00032 
00033 typedef struct {
00034     // Audio format of incoming buffers
00035     int sample_rate;
00036     unsigned int sample_format;
00037     int64_t channel_layout;
00038     int packing_format;
00039 
00040     // FIFO buffer of audio buffer ref pointers
00041     AVFifoBuffer *fifo;
00042 
00043     // Normalization filters
00044     AVFilterContext *aconvert;
00045     AVFilterContext *aresample;
00046 } ABufferSourceContext;
00047 
00048 #define FIFO_SIZE 8
00049 
00050 static void buf_free(AVFilterBuffer *ptr)
00051 {
00052     av_free(ptr);
00053     return;
00054 }
00055 
00056 static void set_link_source(AVFilterContext *src, AVFilterLink *link)
00057 {
00058     link->src       = src;
00059     link->srcpad    = &(src->output_pads[0]);
00060     src->outputs[0] = link;
00061 }
00062 
00063 static int reconfigure_filter(ABufferSourceContext *abuffer, AVFilterContext *filt_ctx)
00064 {
00065     int ret;
00066     AVFilterLink * const inlink  = filt_ctx->inputs[0];
00067     AVFilterLink * const outlink = filt_ctx->outputs[0];
00068 
00069     inlink->format         = abuffer->sample_format;
00070     inlink->channel_layout = abuffer->channel_layout;
00071     inlink->planar         = abuffer->packing_format;
00072     inlink->sample_rate    = abuffer->sample_rate;
00073 
00074     filt_ctx->filter->uninit(filt_ctx);
00075     memset(filt_ctx->priv, 0, filt_ctx->filter->priv_size);
00076     if ((ret = filt_ctx->filter->init(filt_ctx, NULL , NULL)) < 0)
00077         return ret;
00078     if ((ret = inlink->srcpad->config_props(inlink)) < 0)
00079         return ret;
00080     return outlink->srcpad->config_props(outlink);
00081 }
00082 
00083 static int insert_filter(ABufferSourceContext *abuffer,
00084                          AVFilterLink *link, AVFilterContext **filt_ctx,
00085                          const char *filt_name)
00086 {
00087     int ret;
00088 
00089     if ((ret = avfilter_open(filt_ctx, avfilter_get_by_name(filt_name), NULL)) < 0)
00090         return ret;
00091 
00092     link->src->outputs[0] = NULL;
00093     if ((ret = avfilter_link(link->src, 0, *filt_ctx, 0)) < 0) {
00094         link->src->outputs[0] = link;
00095         return ret;
00096     }
00097 
00098     set_link_source(*filt_ctx, link);
00099 
00100     if ((ret = reconfigure_filter(abuffer, *filt_ctx)) < 0) {
00101         avfilter_free(*filt_ctx);
00102         return ret;
00103     }
00104 
00105     return 0;
00106 }
00107 
00108 static void remove_filter(AVFilterContext **filt_ctx)
00109 {
00110     AVFilterLink *outlink = (*filt_ctx)->outputs[0];
00111     AVFilterContext *src  = (*filt_ctx)->inputs[0]->src;
00112 
00113     (*filt_ctx)->outputs[0] = NULL;
00114     avfilter_free(*filt_ctx);
00115     *filt_ctx = NULL;
00116 
00117     set_link_source(src, outlink);
00118 }
00119 
00120 static inline void log_input_change(void *ctx, AVFilterLink *link, AVFilterBufferRef *ref)
00121 {
00122     char old_layout_str[16], new_layout_str[16];
00123     av_get_channel_layout_string(old_layout_str, sizeof(old_layout_str),
00124                                  -1, link->channel_layout);
00125     av_get_channel_layout_string(new_layout_str, sizeof(new_layout_str),
00126                                  -1, ref->audio->channel_layout);
00127     av_log(ctx, AV_LOG_INFO,
00128            "Audio input format changed: "
00129            "%s:%s:%d -> %s:%s:%d, normalizing\n",
00130            av_get_sample_fmt_name(link->format),
00131            old_layout_str, (int)link->sample_rate,
00132            av_get_sample_fmt_name(ref->format),
00133            new_layout_str, ref->audio->sample_rate);
00134 }
00135 
00136 int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx,
00137                                         AVFilterBufferRef *samplesref,
00138                                         int av_unused flags)
00139 {
00140     ABufferSourceContext *abuffer = ctx->priv;
00141     AVFilterLink *link;
00142     int ret, logged = 0;
00143 
00144     if (av_fifo_space(abuffer->fifo) < sizeof(samplesref)) {
00145         av_log(ctx, AV_LOG_ERROR,
00146                "Buffering limit reached. Please consume some available frames "
00147                "before adding new ones.\n");
00148         return AVERROR(EINVAL);
00149     }
00150 
00151     // Normalize input
00152 
00153     link = ctx->outputs[0];
00154     if (samplesref->audio->sample_rate != link->sample_rate) {
00155 
00156         log_input_change(ctx, link, samplesref);
00157         logged = 1;
00158 
00159         abuffer->sample_rate = samplesref->audio->sample_rate;
00160 
00161         if (!abuffer->aresample) {
00162             ret = insert_filter(abuffer, link, &abuffer->aresample, "aresample");
00163             if (ret < 0) return ret;
00164         } else {
00165             link = abuffer->aresample->outputs[0];
00166             if (samplesref->audio->sample_rate == link->sample_rate)
00167                 remove_filter(&abuffer->aresample);
00168             else
00169                 if ((ret = reconfigure_filter(abuffer, abuffer->aresample)) < 0)
00170                     return ret;
00171         }
00172     }
00173 
00174     link = ctx->outputs[0];
00175     if (samplesref->format                != link->format         ||
00176         samplesref->audio->channel_layout != link->channel_layout ||
00177         samplesref->audio->planar         != link->planar) {
00178 
00179         if (!logged) log_input_change(ctx, link, samplesref);
00180 
00181         abuffer->sample_format  = samplesref->format;
00182         abuffer->channel_layout = samplesref->audio->channel_layout;
00183         abuffer->packing_format = samplesref->audio->planar;
00184 
00185         if (!abuffer->aconvert) {
00186             ret = insert_filter(abuffer, link, &abuffer->aconvert, "aconvert");
00187             if (ret < 0) return ret;
00188         } else {
00189             link = abuffer->aconvert->outputs[0];
00190             if (samplesref->format                == link->format         &&
00191                 samplesref->audio->channel_layout == link->channel_layout &&
00192                 samplesref->audio->planar         == link->planar
00193                )
00194                 remove_filter(&abuffer->aconvert);
00195             else
00196                 if ((ret = reconfigure_filter(abuffer, abuffer->aconvert)) < 0)
00197                     return ret;
00198         }
00199     }
00200 
00201     if (sizeof(samplesref) != av_fifo_generic_write(abuffer->fifo, &samplesref,
00202                                                     sizeof(samplesref), NULL)) {
00203         av_log(ctx, AV_LOG_ERROR, "Error while writing to FIFO\n");
00204         return AVERROR(EINVAL);
00205     }
00206 
00207     return 0;
00208 }
00209 
00210 int av_asrc_buffer_add_samples(AVFilterContext *ctx,
00211                                uint8_t *data[8], int linesize[8],
00212                                int nb_samples, int sample_rate,
00213                                int sample_fmt, int64_t channel_layout, int planar,
00214                                int64_t pts, int av_unused flags)
00215 {
00216     AVFilterBufferRef *samplesref;
00217 
00218     samplesref = avfilter_get_audio_buffer_ref_from_arrays(
00219                      data, linesize, AV_PERM_WRITE,
00220                      nb_samples,
00221                      sample_fmt, channel_layout, planar);
00222     if (!samplesref)
00223         return AVERROR(ENOMEM);
00224 
00225     samplesref->buf->free  = buf_free;
00226     samplesref->pts = pts;
00227     samplesref->audio->sample_rate = sample_rate;
00228 
00229     return av_asrc_buffer_add_audio_buffer_ref(ctx, samplesref, 0);
00230 }
00231 
00232 int av_asrc_buffer_add_buffer(AVFilterContext *ctx,
00233                               uint8_t *buf, int buf_size, int sample_rate,
00234                               int sample_fmt, int64_t channel_layout, int planar,
00235                               int64_t pts, int av_unused flags)
00236 {
00237     uint8_t *data[8];
00238     int linesize[8];
00239     int nb_channels = av_get_channel_layout_nb_channels(channel_layout),
00240         nb_samples  = buf_size / nb_channels / av_get_bytes_per_sample(sample_fmt);
00241 
00242     av_samples_fill_arrays(data, linesize,
00243                            buf, nb_channels, nb_samples,
00244                            sample_fmt, 16);
00245 
00246     return av_asrc_buffer_add_samples(ctx,
00247                                       data, linesize, nb_samples,
00248                                       sample_rate,
00249                                       sample_fmt, channel_layout, planar,
00250                                       pts, flags);
00251 }
00252 
00253 static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
00254 {
00255     ABufferSourceContext *abuffer = ctx->priv;
00256     char *arg = NULL, *ptr, chlayout_str[16];
00257     char *args = av_strdup(args0);
00258     int ret;
00259 
00260     arg = av_strtok(args, ":", &ptr);
00261 
00262 #define ADD_FORMAT(fmt_name)                                            \
00263     if (!arg)                                                           \
00264         goto arg_fail;                                                  \
00265     if ((ret = ff_parse_##fmt_name(&abuffer->fmt_name, arg, ctx)) < 0) { \
00266         av_freep(&args);                                                \
00267         return ret;                                                     \
00268     }                                                                   \
00269     if (*args)                                                          \
00270         arg = av_strtok(NULL, ":", &ptr)
00271 
00272     ADD_FORMAT(sample_rate);
00273     ADD_FORMAT(sample_format);
00274     ADD_FORMAT(channel_layout);
00275     ADD_FORMAT(packing_format);
00276 
00277     abuffer->fifo = av_fifo_alloc(FIFO_SIZE*sizeof(AVFilterBufferRef*));
00278     if (!abuffer->fifo) {
00279         av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo, filter init failed.\n");
00280         return AVERROR(ENOMEM);
00281     }
00282 
00283     av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str),
00284                                  -1, abuffer->channel_layout);
00285     av_log(ctx, AV_LOG_INFO, "format:%s layout:%s rate:%d\n",
00286            av_get_sample_fmt_name(abuffer->sample_format), chlayout_str,
00287            abuffer->sample_rate);
00288     av_freep(&args);
00289 
00290     return 0;
00291 
00292 arg_fail:
00293     av_log(ctx, AV_LOG_ERROR, "Invalid arguments, must be of the form "
00294                               "sample_rate:sample_fmt:channel_layout:packing\n");
00295     av_freep(&args);
00296     return AVERROR(EINVAL);
00297 }
00298 
00299 static av_cold void uninit(AVFilterContext *ctx)
00300 {
00301     ABufferSourceContext *abuffer = ctx->priv;
00302     av_fifo_free(abuffer->fifo);
00303 }
00304 
00305 static int query_formats(AVFilterContext *ctx)
00306 {
00307     ABufferSourceContext *abuffer = ctx->priv;
00308     AVFilterFormats *formats;
00309 
00310     formats = NULL;
00311     avfilter_add_format(&formats, abuffer->sample_format);
00312     avfilter_set_common_sample_formats(ctx, formats);
00313 
00314     formats = NULL;
00315     avfilter_add_format(&formats, abuffer->channel_layout);
00316     avfilter_set_common_channel_layouts(ctx, formats);
00317 
00318     formats = NULL;
00319     avfilter_add_format(&formats, abuffer->packing_format);
00320     avfilter_set_common_packing_formats(ctx, formats);
00321 
00322     return 0;
00323 }
00324 
00325 static int config_output(AVFilterLink *outlink)
00326 {
00327     ABufferSourceContext *abuffer = outlink->src->priv;
00328     outlink->sample_rate = abuffer->sample_rate;
00329     return 0;
00330 }
00331 
00332 static int request_frame(AVFilterLink *outlink)
00333 {
00334     ABufferSourceContext *abuffer = outlink->src->priv;
00335     AVFilterBufferRef *samplesref;
00336 
00337     if (!av_fifo_size(abuffer->fifo)) {
00338         av_log(outlink->src, AV_LOG_ERROR,
00339                "request_frame() called with no available frames!\n");
00340         return AVERROR(EINVAL);
00341     }
00342 
00343     av_fifo_generic_read(abuffer->fifo, &samplesref, sizeof(samplesref), NULL);
00344     avfilter_filter_samples(outlink, avfilter_ref_buffer(samplesref, ~0));
00345     avfilter_unref_buffer(samplesref);
00346 
00347     return 0;
00348 }
00349 
00350 static int poll_frame(AVFilterLink *outlink)
00351 {
00352     ABufferSourceContext *abuffer = outlink->src->priv;
00353     return av_fifo_size(abuffer->fifo)/sizeof(AVFilterBufferRef*);
00354 }
00355 
00356 AVFilter avfilter_asrc_abuffer = {
00357     .name        = "abuffer",
00358     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
00359     .priv_size   = sizeof(ABufferSourceContext),
00360     .query_formats = query_formats,
00361 
00362     .init        = init,
00363     .uninit      = uninit,
00364 
00365     .inputs      = (const AVFilterPad[]) {{ .name = NULL }},
00366     .outputs     = (const AVFilterPad[]) {{ .name      = "default",
00367                                       .type            = AVMEDIA_TYPE_AUDIO,
00368                                       .request_frame   = request_frame,
00369                                       .poll_frame      = poll_frame,
00370                                       .config_props    = config_output, },
00371                                     { .name = NULL}},
00372 };