00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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
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
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
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
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
00315
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
00348
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
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 };