00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00030 #include <stdio.h>
00031 #include "libavutil/avstring.h"
00032 #include "libavutil/opt.h"
00033 #include "libswresample/swresample.h"
00034 #include "avfilter.h"
00035
00036 #define MAX_CHANNELS 63
00037
00038 typedef struct PanContext {
00039 int64_t out_channel_layout;
00040 union {
00041 double d[MAX_CHANNELS][MAX_CHANNELS];
00042
00043 int i[MAX_CHANNELS][MAX_CHANNELS];
00044 } gain;
00045 int64_t need_renorm;
00046 int need_renumber;
00047 int nb_input_channels;
00048 int nb_output_channels;
00049
00050 int pure_gains;
00051 void (*filter_samples)(struct PanContext*,
00052 AVFilterBufferRef*,
00053 AVFilterBufferRef*,
00054 int);
00055
00056
00057 int channel_map[SWR_CH_MAX];
00058 struct SwrContext *swr;
00059 } PanContext;
00060
00061 static int parse_channel_name(char **arg, int *rchannel, int *rnamed)
00062 {
00063 char buf[8];
00064 int len, i, channel_id;
00065 int64_t layout, layout0;
00066
00067 if (sscanf(*arg, " %7[A-Z] %n", buf, &len)) {
00068 layout0 = layout = av_get_channel_layout(buf);
00069 for (i = 32; i > 0; i >>= 1) {
00070 if (layout >= (int64_t)1 << i) {
00071 channel_id += i;
00072 layout >>= i;
00073 }
00074 }
00075 if (channel_id >= MAX_CHANNELS || layout0 != (int64_t)1 << channel_id)
00076 return AVERROR(EINVAL);
00077 *rchannel = channel_id;
00078 *rnamed = 1;
00079 *arg += len;
00080 return 0;
00081 }
00082 if (sscanf(*arg, " c%d %n", &channel_id, &len) &&
00083 channel_id >= 0 && channel_id < MAX_CHANNELS) {
00084 *rchannel = channel_id;
00085 *rnamed = 0;
00086 *arg += len;
00087 return 0;
00088 }
00089 return AVERROR(EINVAL);
00090 }
00091
00092 static void skip_spaces(char **arg)
00093 {
00094 int len = 0;
00095
00096 sscanf(*arg, " %n", &len);
00097 *arg += len;
00098 }
00099
00100 static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
00101 {
00102 PanContext *const pan = ctx->priv;
00103 char *arg, *arg0, *tokenizer, *args = av_strdup(args0);
00104 int out_ch_id, in_ch_id, len, named;
00105 int nb_in_channels[2] = { 0, 0 };
00106 double gain;
00107
00108 if (!args0) {
00109 av_log(ctx, AV_LOG_ERROR,
00110 "pan filter needs a channel layout and a set "
00111 "of channels definitions as parameter\n");
00112 return AVERROR(EINVAL);
00113 }
00114 if (!args)
00115 return AVERROR(ENOMEM);
00116 arg = av_strtok(args, ":", &tokenizer);
00117 pan->out_channel_layout = av_get_channel_layout(arg);
00118 if (!pan->out_channel_layout) {
00119 av_log(ctx, AV_LOG_ERROR, "Unknown channel layout \"%s\"\n", arg);
00120 return AVERROR(EINVAL);
00121 }
00122 pan->nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channel_layout);
00123
00124
00125 while ((arg = arg0 = av_strtok(NULL, ":", &tokenizer))) {
00126
00127 if (parse_channel_name(&arg, &out_ch_id, &named)) {
00128 av_log(ctx, AV_LOG_ERROR,
00129 "Expected out channel name, got \"%.8s\"\n", arg);
00130 return AVERROR(EINVAL);
00131 }
00132 if (named) {
00133 if (!((pan->out_channel_layout >> out_ch_id) & 1)) {
00134 av_log(ctx, AV_LOG_ERROR,
00135 "Channel \"%.8s\" does not exist in the chosen layout\n", arg0);
00136 return AVERROR(EINVAL);
00137 }
00138
00139
00140
00141
00142 out_ch_id = av_get_channel_layout_nb_channels(pan->out_channel_layout & (((int64_t)1 << out_ch_id) - 1));
00143 }
00144 if (out_ch_id < 0 || out_ch_id >= pan->nb_output_channels) {
00145 av_log(ctx, AV_LOG_ERROR,
00146 "Invalid out channel name \"%.8s\"\n", arg0);
00147 return AVERROR(EINVAL);
00148 }
00149 if (*arg == '=') {
00150 arg++;
00151 } else if (*arg == '<') {
00152 pan->need_renorm |= (int64_t)1 << out_ch_id;
00153 arg++;
00154 } else {
00155 av_log(ctx, AV_LOG_ERROR,
00156 "Syntax error after channel name in \"%.8s\"\n", arg0);
00157 return AVERROR(EINVAL);
00158 }
00159
00160 while (1) {
00161 gain = 1;
00162 if (sscanf(arg, " %lf %n* %n", &gain, &len, &len))
00163 arg += len;
00164 if (parse_channel_name(&arg, &in_ch_id, &named)){
00165 av_log(ctx, AV_LOG_ERROR,
00166 "Expected in channel name, got \"%.8s\"\n", arg);
00167 return AVERROR(EINVAL);
00168 }
00169 nb_in_channels[named]++;
00170 if (nb_in_channels[!named]) {
00171 av_log(ctx, AV_LOG_ERROR,
00172 "Can not mix named and numbered channels\n");
00173 return AVERROR(EINVAL);
00174 }
00175 pan->gain.d[out_ch_id][in_ch_id] = gain;
00176 if (!*arg)
00177 break;
00178 if (*arg != '+') {
00179 av_log(ctx, AV_LOG_ERROR, "Syntax error near \"%.8s\"\n", arg);
00180 return AVERROR(EINVAL);
00181 }
00182 arg++;
00183 skip_spaces(&arg);
00184 }
00185 }
00186 pan->need_renumber = !!nb_in_channels[1];
00187
00188 av_free(args);
00189 return 0;
00190 }
00191
00192 static int are_gains_pure(const PanContext *pan)
00193 {
00194 int i, j;
00195
00196 for (i = 0; i < MAX_CHANNELS; i++) {
00197 int nb_gain = 0;
00198
00199 for (j = 0; j < MAX_CHANNELS; j++) {
00200 double gain = pan->gain.d[i][j];
00201
00202
00203
00204 if (gain != 0. && gain != 1.)
00205 return 0;
00206
00207 if (gain && nb_gain++)
00208 return 0;
00209 }
00210 }
00211 return 1;
00212 }
00213
00214 static int config_props(AVFilterLink *link)
00215 {
00216 AVFilterContext *ctx = link->dst;
00217 PanContext *pan = ctx->priv;
00218 char buf[1024], *cur;
00219 int i, j, k, r;
00220 double t;
00221
00222 pan->nb_input_channels = av_get_channel_layout_nb_channels(link->channel_layout);
00223 if (pan->need_renumber) {
00224
00225 for (i = j = 0; i < MAX_CHANNELS; i++) {
00226 if ((link->channel_layout >> i) & 1) {
00227 for (k = 0; k < pan->nb_output_channels; k++)
00228 pan->gain.d[k][j] = pan->gain.d[k][i];
00229 j++;
00230 }
00231 }
00232 }
00233
00234 if (pan->pure_gains) {
00235
00236
00237
00238 if (pan->nb_input_channels > SWR_CH_MAX) {
00239 av_log(ctx, AV_LOG_ERROR,
00240 "libswresample support a maximum of %d channels. "
00241 "Feel free to ask for a higher limit.\n", SWR_CH_MAX);
00242 return AVERROR_PATCHWELCOME;
00243 }
00244
00245
00246 for (i = 0; i < pan->nb_output_channels; i++) {
00247 int ch_id = -1;
00248 for (j = 0; j < pan->nb_input_channels; j++) {
00249 if (pan->gain.d[i][j]) {
00250 ch_id = j;
00251 break;
00252 }
00253 }
00254 pan->channel_map[i] = ch_id;
00255 }
00256
00257
00258 pan->swr = swr_alloc_set_opts(pan->swr,
00259 pan->out_channel_layout, link->format, link->sample_rate,
00260 link->channel_layout, link->format, link->sample_rate,
00261 0, ctx);
00262 if (!pan->swr)
00263 return AVERROR(ENOMEM);
00264 av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0);
00265 av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0);
00266 swr_set_channel_mapping(pan->swr, pan->channel_map);
00267 r = swr_init(pan->swr);
00268 if (r < 0)
00269 return r;
00270 } else {
00271
00272 for (i = 0; i < pan->nb_output_channels; i++) {
00273 if (!((pan->need_renorm >> i) & 1))
00274 continue;
00275 t = 0;
00276 for (j = 0; j < pan->nb_input_channels; j++)
00277 t += pan->gain.d[i][j];
00278 if (t > -1E-5 && t < 1E-5) {
00279
00280 if (t)
00281 av_log(ctx, AV_LOG_WARNING,
00282 "Degenerate coefficients while renormalizing\n");
00283 continue;
00284 }
00285 for (j = 0; j < pan->nb_input_channels; j++)
00286 pan->gain.d[i][j] /= t;
00287 }
00288 }
00289
00290 for (i = 0; i < pan->nb_output_channels; i++) {
00291 cur = buf;
00292 for (j = 0; j < pan->nb_input_channels; j++) {
00293 r = snprintf(cur, buf + sizeof(buf) - cur, "%s%.3g i%d",
00294 j ? " + " : "", pan->gain.d[i][j], j);
00295 cur += FFMIN(buf + sizeof(buf) - cur, r);
00296 }
00297 av_log(ctx, AV_LOG_INFO, "o%d = %s\n", i, buf);
00298 }
00299
00300 if (pan->pure_gains) {
00301 av_log(ctx, AV_LOG_INFO, "Pure channel mapping detected:");
00302 for (i = 0; i < pan->nb_output_channels; i++)
00303 if (pan->channel_map[i] < 0)
00304 av_log(ctx, AV_LOG_INFO, " M");
00305 else
00306 av_log(ctx, AV_LOG_INFO, " %d", pan->channel_map[i]);
00307 av_log(ctx, AV_LOG_INFO, "\n");
00308 return 0;
00309 }
00310
00311 for (i = 0; i < pan->nb_output_channels; i++) {
00312 for (j = 0; j < pan->nb_input_channels; j++) {
00313 if (pan->gain.d[i][j] < -128 || pan->gain.d[i][j] > 128)
00314 av_log(ctx, AV_LOG_WARNING,
00315 "Gain #%d->#%d too large, clamped\n", j, i);
00316 pan->gain.i[i][j] = av_clipf(pan->gain.d[i][j], -128, 128) * 256.0;
00317 }
00318 }
00319 return 0;
00320 }
00321
00322 static void filter_samples_channel_mapping(PanContext *pan,
00323 AVFilterBufferRef *outsamples,
00324 AVFilterBufferRef *insamples,
00325 int n)
00326 {
00327 swr_convert(pan->swr, outsamples->data, n, (void *)insamples->data, n);
00328 }
00329
00330 static void filter_samples_panning(PanContext *pan,
00331 AVFilterBufferRef *outsamples,
00332 AVFilterBufferRef *insamples,
00333 int n)
00334 {
00335 int i, o;
00336
00337
00338 const int16_t *in = (int16_t *)insamples->data[0];
00339 const int16_t *in_end = in + n * pan->nb_input_channels;
00340
00341
00342 int16_t *out = (int16_t *)outsamples->data[0];
00343
00344 for (; in < in_end; in += pan->nb_input_channels) {
00345 for (o = 0; o < pan->nb_output_channels; o++) {
00346 int v = 0;
00347 for (i = 0; i < pan->nb_input_channels; i++)
00348 v += pan->gain.i[o][i] * in[i];
00349 *(out++) = v >> 8;
00350 }
00351 }
00352 }
00353
00354 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00355 {
00356 int n = insamples->audio->nb_samples;
00357 AVFilterLink *const outlink = inlink->dst->outputs[0];
00358 AVFilterBufferRef *outsamples = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, n);
00359 PanContext *pan = inlink->dst->priv;
00360
00361 pan->filter_samples(pan, outsamples, insamples, n);
00362
00363 avfilter_filter_samples(outlink, outsamples);
00364 avfilter_unref_buffer(insamples);
00365 }
00366
00367 static int query_formats(AVFilterContext *ctx)
00368 {
00369 PanContext *pan = ctx->priv;
00370 AVFilterLink *inlink = ctx->inputs[0];
00371 AVFilterLink *outlink = ctx->outputs[0];
00372 AVFilterFormats *formats;
00373
00374 if (pan->nb_output_channels <= SWR_CH_MAX)
00375 pan->pure_gains = are_gains_pure(pan);
00376 if (pan->pure_gains) {
00377
00378 avfilter_set_common_sample_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
00379 avfilter_set_common_packing_formats(ctx, avfilter_make_all_packing_formats());
00380 pan->filter_samples = filter_samples_channel_mapping;
00381 } else {
00382 const enum AVSampleFormat sample_fmts[] = {AV_SAMPLE_FMT_S16, -1};
00383 const int packing_fmts[] = {AVFILTER_PACKED, -1};
00384
00385 avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts));
00386 avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts));
00387 pan->filter_samples = filter_samples_panning;
00388 }
00389
00390
00391 formats = avfilter_make_all_channel_layouts();
00392 avfilter_formats_ref(formats, &inlink->out_chlayouts);
00393
00394
00395 formats = NULL;
00396 avfilter_add_format(&formats, pan->out_channel_layout);
00397 avfilter_formats_ref(formats, &outlink->in_chlayouts);
00398 return 0;
00399 }
00400
00401 static av_cold void uninit(AVFilterContext *ctx)
00402 {
00403 PanContext *pan = ctx->priv;
00404 swr_free(&pan->swr);
00405 }
00406
00407 AVFilter avfilter_af_pan = {
00408 .name = "pan",
00409 .description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."),
00410 .priv_size = sizeof(PanContext),
00411 .init = init,
00412 .uninit = uninit,
00413 .query_formats = query_formats,
00414
00415 .inputs = (const AVFilterPad[]) {
00416 { .name = "default",
00417 .type = AVMEDIA_TYPE_AUDIO,
00418 .config_props = config_props,
00419 .filter_samples = filter_samples,
00420 .min_perms = AV_PERM_READ, },
00421 { .name = NULL}
00422 },
00423 .outputs = (const AVFilterPad[]) {
00424 { .name = "default",
00425 .type = AVMEDIA_TYPE_AUDIO, },
00426 { .name = NULL}
00427 },
00428 };