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

libavfilter/af_aconvert.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
00003  * Copyright (c) 2011 Stefano Sabatini
00004  * Copyright (c) 2011 Mina Nagy Zaki
00005  *
00006  * This file is part of FFmpeg.
00007  *
00008  * FFmpeg is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * FFmpeg is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with FFmpeg; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00030 #include "libavutil/audioconvert.h"
00031 #include "libavutil/avstring.h"
00032 #include "libavcodec/audioconvert.h"
00033 #include "avfilter.h"
00034 #include "internal.h"
00035 
00036 typedef struct {
00037     enum AVSampleFormat  out_sample_fmt,  in_sample_fmt;   
00038     int64_t              out_chlayout,    in_chlayout;     
00039     int                  out_nb_channels, in_nb_channels;  
00040     enum AVFilterPacking out_packing_fmt, in_packing_fmt;  
00041 
00042     int max_nb_samples;                     
00043     AVFilterBufferRef *mix_samplesref;      
00044     AVFilterBufferRef *out_samplesref;      
00045 
00046     uint8_t *in_mix[8], *out_mix[8];        
00047     uint8_t *packed_data[8];                
00048     int out_strides[8], in_strides[8];      
00049     uint8_t **in_conv, **out_conv;          
00050 
00051     AVAudioConvert *audioconvert_ctx;       
00052 
00053     void (*convert_chlayout)();             
00054 } AConvertContext;
00055 
00056 #define REMATRIX_FUNC_SIG(NAME) static void REMATRIX_FUNC_NAME(NAME) \
00057     (FMT_TYPE *outp[], FMT_TYPE *inp[], int nb_samples, AConvertContext *aconvert)
00058 
00059 #define FMT_TYPE uint8_t
00060 #define REMATRIX_FUNC_NAME(NAME) NAME ## _u8
00061 #include "af_aconvert_rematrix.c"
00062 
00063 #define FMT_TYPE int16_t
00064 #define REMATRIX_FUNC_NAME(NAME) NAME ## _s16
00065 #include "af_aconvert_rematrix.c"
00066 
00067 #define FMT_TYPE int32_t
00068 #define REMATRIX_FUNC_NAME(NAME) NAME ## _s32
00069 #include "af_aconvert_rematrix.c"
00070 
00071 #define FLOATING
00072 
00073 #define FMT_TYPE float
00074 #define REMATRIX_FUNC_NAME(NAME) NAME ## _flt
00075 #include "af_aconvert_rematrix.c"
00076 
00077 #define FMT_TYPE double
00078 #define REMATRIX_FUNC_NAME(NAME) NAME ## _dbl
00079 #include "af_aconvert_rematrix.c"
00080 
00081 #define FMT_TYPE uint8_t
00082 #define REMATRIX_FUNC_NAME(NAME) NAME
00083 REMATRIX_FUNC_SIG(stereo_remix_planar)
00084 {
00085     int size = av_get_bytes_per_sample(aconvert->in_sample_fmt) * nb_samples;
00086 
00087     memcpy(outp[0], inp[0], size);
00088     memcpy(outp[1], inp[aconvert->in_nb_channels == 1 ? 0 : 1], size);
00089 }
00090 
00091 #define REGISTER_FUNC_PACKING(INCHLAYOUT, OUTCHLAYOUT, FUNC, PACKING)   \
00092     {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_U8,  FUNC##_u8},   \
00093     {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_S16, FUNC##_s16},  \
00094     {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_S32, FUNC##_s32},  \
00095     {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_FLT, FUNC##_flt},  \
00096     {INCHLAYOUT, OUTCHLAYOUT, PACKING, AV_SAMPLE_FMT_DBL, FUNC##_dbl},
00097 
00098 #define REGISTER_FUNC(INCHLAYOUT, OUTCHLAYOUT, FUNC)                                \
00099     REGISTER_FUNC_PACKING(INCHLAYOUT, OUTCHLAYOUT, FUNC##_packed, AVFILTER_PACKED)  \
00100     REGISTER_FUNC_PACKING(INCHLAYOUT, OUTCHLAYOUT, FUNC##_planar, AVFILTER_PLANAR)
00101 
00102 static const struct RematrixFunctionInfo {
00103     int64_t in_chlayout, out_chlayout;
00104     int planar, sfmt;
00105     void (*func)();
00106 } rematrix_funcs[] = {
00107     REGISTER_FUNC        (AV_CH_LAYOUT_STEREO,  AV_CH_LAYOUT_5POINT1, stereo_to_surround_5p1)
00108     REGISTER_FUNC        (AV_CH_LAYOUT_5POINT1, AV_CH_LAYOUT_STEREO,  surround_5p1_to_stereo)
00109     REGISTER_FUNC_PACKING(AV_CH_LAYOUT_STEREO,  AV_CH_LAYOUT_MONO,    stereo_to_mono_packed, AVFILTER_PACKED)
00110     REGISTER_FUNC_PACKING(AV_CH_LAYOUT_MONO,    AV_CH_LAYOUT_STEREO,  mono_to_stereo_packed, AVFILTER_PACKED)
00111     REGISTER_FUNC        (0,                    AV_CH_LAYOUT_MONO,    mono_downmix)
00112     REGISTER_FUNC_PACKING(0,                    AV_CH_LAYOUT_STEREO,  stereo_downmix_packed, AVFILTER_PACKED)
00113 
00114     // This function works for all sample formats
00115     {0, AV_CH_LAYOUT_STEREO, AVFILTER_PLANAR, -1, stereo_remix_planar}
00116 };
00117 
00118 static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
00119 {
00120     AConvertContext *aconvert = ctx->priv;
00121     char *arg, *ptr = NULL;
00122     int ret = 0;
00123     char *args = av_strdup(args0);
00124 
00125     aconvert->out_sample_fmt  = AV_SAMPLE_FMT_NONE;
00126     aconvert->out_chlayout    = 0;
00127     aconvert->out_packing_fmt = -1;
00128 
00129     if ((arg = av_strtok(args, ":", &ptr)) && strcmp(arg, "auto")) {
00130         if ((ret = ff_parse_sample_format(&aconvert->out_sample_fmt, arg, ctx)) < 0)
00131             goto end;
00132     }
00133     if ((arg = av_strtok(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
00134         if ((ret = ff_parse_channel_layout(&aconvert->out_chlayout, arg, ctx)) < 0)
00135             goto end;
00136     }
00137     if ((arg = av_strtok(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
00138         if ((ret = ff_parse_packing_format((int *)&aconvert->out_packing_fmt, arg, ctx)) < 0)
00139             goto end;
00140     }
00141 
00142 end:
00143     av_freep(&args);
00144     return ret;
00145 }
00146 
00147 static av_cold void uninit(AVFilterContext *ctx)
00148 {
00149     AConvertContext *aconvert = ctx->priv;
00150     avfilter_unref_buffer(aconvert->mix_samplesref);
00151     avfilter_unref_buffer(aconvert->out_samplesref);
00152     if (aconvert->audioconvert_ctx)
00153         av_audio_convert_free(aconvert->audioconvert_ctx);
00154 }
00155 
00156 static int query_formats(AVFilterContext *ctx)
00157 {
00158     AVFilterFormats *formats = NULL;
00159     AConvertContext *aconvert = ctx->priv;
00160     AVFilterLink *inlink  = ctx->inputs[0];
00161     AVFilterLink *outlink = ctx->outputs[0];
00162 
00163     avfilter_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
00164                          &inlink->out_formats);
00165     if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
00166         formats = NULL;
00167         avfilter_add_format(&formats, aconvert->out_sample_fmt);
00168         avfilter_formats_ref(formats, &outlink->in_formats);
00169     } else
00170         avfilter_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
00171                              &outlink->in_formats);
00172 
00173     avfilter_formats_ref(avfilter_make_all_channel_layouts(),
00174                          &inlink->out_chlayouts);
00175     if (aconvert->out_chlayout != 0) {
00176         formats = NULL;
00177         avfilter_add_format(&formats, aconvert->out_chlayout);
00178         avfilter_formats_ref(formats, &outlink->in_chlayouts);
00179     } else
00180         avfilter_formats_ref(avfilter_make_all_channel_layouts(),
00181                              &outlink->in_chlayouts);
00182 
00183     avfilter_formats_ref(avfilter_make_all_packing_formats(),
00184                          &inlink->out_packing);
00185     if (aconvert->out_packing_fmt != -1) {
00186         formats = NULL;
00187         avfilter_add_format(&formats, aconvert->out_packing_fmt);
00188         avfilter_formats_ref(formats, &outlink->in_packing);
00189     } else
00190         avfilter_formats_ref(avfilter_make_all_packing_formats(),
00191                              &outlink->in_packing);
00192 
00193     return 0;
00194 }
00195 
00196 static int config_output(AVFilterLink *outlink)
00197 {
00198     AVFilterLink *inlink = outlink->src->inputs[0];
00199     AConvertContext *aconvert = outlink->src->priv;
00200     char buf1[64], buf2[64];
00201 
00202     aconvert->in_sample_fmt  = inlink->format;
00203     aconvert->in_packing_fmt = inlink->planar;
00204     if (aconvert->out_packing_fmt == -1)
00205         aconvert->out_packing_fmt = outlink->planar;
00206     aconvert->in_chlayout    = inlink->channel_layout;
00207     aconvert->in_nb_channels =
00208         av_get_channel_layout_nb_channels(inlink->channel_layout);
00209 
00210     /* if not specified in args, use the format and layout of the output */
00211     if (aconvert->out_sample_fmt == AV_SAMPLE_FMT_NONE)
00212         aconvert->out_sample_fmt = outlink->format;
00213     if (aconvert->out_chlayout   == 0)
00214         aconvert->out_chlayout   = outlink->channel_layout;
00215     aconvert->out_nb_channels  =
00216         av_get_channel_layout_nb_channels(outlink->channel_layout);
00217 
00218     av_get_channel_layout_string(buf1, sizeof(buf1),
00219                                  -1, inlink ->channel_layout);
00220     av_get_channel_layout_string(buf2, sizeof(buf2),
00221                                  -1, outlink->channel_layout);
00222     av_log(outlink->src, AV_LOG_INFO,
00223            "fmt:%s cl:%s planar:%i -> fmt:%s cl:%s planar:%i\n",
00224            av_get_sample_fmt_name(inlink ->format), buf1, inlink ->planar,
00225            av_get_sample_fmt_name(outlink->format), buf2, outlink->planar);
00226 
00227     /* compute which channel layout conversion to use */
00228     if (inlink->channel_layout != outlink->channel_layout) {
00229         int i;
00230         for (i = 0; i < sizeof(rematrix_funcs); i++) {
00231             const struct RematrixFunctionInfo *f = &rematrix_funcs[i];
00232             if ((f->in_chlayout  == 0 || f->in_chlayout  == inlink ->channel_layout) &&
00233                 (f->out_chlayout == 0 || f->out_chlayout == outlink->channel_layout) &&
00234                 (f->planar == -1 || f->planar == inlink->planar) &&
00235                 (f->sfmt   == -1 || f->sfmt   == inlink->format)
00236                ) {
00237                 aconvert->convert_chlayout = f->func;
00238                 break;
00239             }
00240         }
00241         if (!aconvert->convert_chlayout) {
00242             av_log(outlink->src, AV_LOG_ERROR,
00243                    "Unsupported channel layout conversion '%s -> %s' requested!\n",
00244                    buf1, buf2);
00245             return AVERROR(EINVAL);
00246         }
00247     }
00248 
00249     return 0;
00250 }
00251 
00252 static int init_buffers(AVFilterLink *inlink, int nb_samples)
00253 {
00254     AConvertContext *aconvert = inlink->dst->priv;
00255     AVFilterLink * const outlink = inlink->dst->outputs[0];
00256     int i, packed_stride = 0;
00257     const unsigned
00258         packing_conv = inlink->planar != outlink->planar &&
00259                        aconvert->out_nb_channels != 1,
00260         format_conv  = inlink->format != outlink->format;
00261     int nb_channels  = aconvert->out_nb_channels;
00262 
00263     uninit(inlink->dst);
00264     aconvert->max_nb_samples = nb_samples;
00265 
00266     if (aconvert->convert_chlayout) {
00267         /* allocate buffer for storing intermediary mixing samplesref */
00268         uint8_t *data[8];
00269         int linesize[8];
00270         int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
00271 
00272         if (av_samples_alloc(data, linesize, nb_channels, nb_samples,
00273                              inlink->format, 16) < 0)
00274             goto fail_no_mem;
00275         aconvert->mix_samplesref =
00276             avfilter_get_audio_buffer_ref_from_arrays(data, linesize, AV_PERM_WRITE,
00277                                                       nb_samples, inlink->format,
00278                                                       outlink->channel_layout,
00279                                                       inlink->planar);
00280         if (!aconvert->mix_samplesref)
00281             goto fail_no_mem;
00282     }
00283 
00284     // if there's a format/packing conversion we need an audio_convert context
00285     if (format_conv || packing_conv) {
00286         aconvert->out_samplesref =
00287             avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
00288         if (!aconvert->out_samplesref)
00289             goto fail_no_mem;
00290 
00291         aconvert->in_strides [0] = av_get_bytes_per_sample(inlink ->format);
00292         aconvert->out_strides[0] = av_get_bytes_per_sample(outlink->format);
00293 
00294         aconvert->out_conv = aconvert->out_samplesref->data;
00295         if (aconvert->mix_samplesref)
00296             aconvert->in_conv = aconvert->mix_samplesref->data;
00297 
00298         if (packing_conv) {
00299             // packed -> planar
00300             if (outlink->planar == AVFILTER_PLANAR) {
00301                 if (aconvert->mix_samplesref)
00302                     aconvert->packed_data[0] = aconvert->mix_samplesref->data[0];
00303                 aconvert->in_conv         = aconvert->packed_data;
00304                 packed_stride             = aconvert->in_strides[0];
00305                 aconvert->in_strides[0]  *= nb_channels;
00306             // planar -> packed
00307             } else {
00308                 aconvert->packed_data[0]  = aconvert->out_samplesref->data[0];
00309                 aconvert->out_conv        = aconvert->packed_data;
00310                 packed_stride             = aconvert->out_strides[0];
00311                 aconvert->out_strides[0] *= nb_channels;
00312             }
00313         } else if (outlink->planar == AVFILTER_PACKED) {
00314             /* If there's no packing conversion, and the stream is packed
00315              * then we treat the entire stream as one big channel
00316              */
00317             nb_channels = 1;
00318         }
00319 
00320         for (i = 1; i < nb_channels; i++) {
00321             aconvert->packed_data[i] = aconvert->packed_data[i-1] + packed_stride;
00322             aconvert->in_strides[i]  = aconvert->in_strides[0];
00323             aconvert->out_strides[i] = aconvert->out_strides[0];
00324         }
00325 
00326         aconvert->audioconvert_ctx =
00327                 av_audio_convert_alloc(outlink->format, nb_channels,
00328                                        inlink->format,  nb_channels, NULL, 0);
00329         if (!aconvert->audioconvert_ctx)
00330             goto fail_no_mem;
00331     }
00332 
00333     return 0;
00334 
00335 fail_no_mem:
00336     av_log(inlink->dst, AV_LOG_ERROR, "Could not allocate memory.\n");
00337     return AVERROR(ENOMEM);
00338 }
00339 
00340 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
00341 {
00342     AConvertContext *aconvert = inlink->dst->priv;
00343     AVFilterBufferRef *curbuf = insamplesref;
00344     AVFilterLink * const outlink = inlink->dst->outputs[0];
00345     int chan_mult;
00346 
00347     /* in/reinint the internal buffers if this is the first buffer
00348      * provided or it is needed to use a bigger one */
00349     if (!aconvert->max_nb_samples ||
00350         (curbuf->audio->nb_samples > aconvert->max_nb_samples))
00351         if (init_buffers(inlink, curbuf->audio->nb_samples) < 0) {
00352             av_log(inlink->dst, AV_LOG_ERROR, "Could not initialize buffers.\n");
00353             return;
00354         }
00355 
00356     /* if channel mixing is required */
00357     if (aconvert->mix_samplesref) {
00358         memcpy(aconvert->in_mix,  curbuf->data, sizeof(aconvert->in_mix));
00359         memcpy(aconvert->out_mix, aconvert->mix_samplesref->data, sizeof(aconvert->out_mix));
00360         aconvert->convert_chlayout(aconvert->out_mix,
00361                                    aconvert->in_mix,
00362                                    curbuf->audio->nb_samples,
00363                                    aconvert);
00364         curbuf = aconvert->mix_samplesref;
00365     }
00366 
00367     if (aconvert->audioconvert_ctx) {
00368         if (!aconvert->mix_samplesref) {
00369             if (aconvert->in_conv == aconvert->packed_data) {
00370                 int i, packed_stride = av_get_bytes_per_sample(inlink->format);
00371                 aconvert->packed_data[0] = curbuf->data[0];
00372                 for (i = 1; i < aconvert->out_nb_channels; i++)
00373                     aconvert->packed_data[i] = aconvert->packed_data[i-1] + packed_stride;
00374             } else {
00375                 aconvert->in_conv = curbuf->data;
00376             }
00377         }
00378 
00379         chan_mult = inlink->planar == outlink->planar && inlink->planar == 0 ?
00380             aconvert->out_nb_channels : 1;
00381 
00382         av_audio_convert(aconvert->audioconvert_ctx,
00383                          (void * const *) aconvert->out_conv,
00384                          aconvert->out_strides,
00385                          (const void * const *) aconvert->in_conv,
00386                          aconvert->in_strides,
00387                          curbuf->audio->nb_samples * chan_mult);
00388 
00389         curbuf = aconvert->out_samplesref;
00390     }
00391 
00392     avfilter_copy_buffer_ref_props(curbuf, insamplesref);
00393     curbuf->audio->channel_layout = outlink->channel_layout;
00394     curbuf->audio->planar         = outlink->planar;
00395 
00396     avfilter_filter_samples(inlink->dst->outputs[0],
00397                             avfilter_ref_buffer(curbuf, ~0));
00398     avfilter_unref_buffer(insamplesref);
00399 }
00400 
00401 AVFilter avfilter_af_aconvert = {
00402     .name          = "aconvert",
00403     .description   = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout:packed_fmt."),
00404     .priv_size     = sizeof(AConvertContext),
00405     .init          = init,
00406     .uninit        = uninit,
00407     .query_formats = query_formats,
00408 
00409     .inputs    = (const AVFilterPad[]) {{ .name      = "default",
00410                                     .type            = AVMEDIA_TYPE_AUDIO,
00411                                     .filter_samples  = filter_samples,
00412                                     .min_perms       = AV_PERM_READ, },
00413                                   { .name = NULL}},
00414     .outputs   = (const AVFilterPad[]) {{ .name      = "default",
00415                                     .type            = AVMEDIA_TYPE_AUDIO,
00416                                     .config_props    = config_output, },
00417                                   { .name = NULL}},
00418 };
Generated on Fri Feb 1 2013 14:34:48 for FFmpeg by doxygen 1.7.1