af_pan: use libswr for rematrixing.
This commit is contained in:
parent
560b224f53
commit
a44b510d56
@ -384,9 +384,6 @@ The channel remapping will be effective if, and only if:
|
|||||||
@itemize
|
@itemize
|
||||||
@item gain coefficients are zeroes or ones,
|
@item gain coefficients are zeroes or ones,
|
||||||
@item only one input per channel output,
|
@item only one input per channel output,
|
||||||
@item the number of output channels is supported by libswresample (16 at the
|
|
||||||
moment)
|
|
||||||
@c if SWR_CH_MAX changes, fix the line above.
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
If all these conditions are satisfied, the filter will notify the user ("Pure
|
If all these conditions are satisfied, the filter will notify the user ("Pure
|
||||||
|
@ -234,18 +234,29 @@ static int config_props(AVFilterLink *link)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// gains are pure, init the channel mapping
|
|
||||||
if (pan->pure_gains) {
|
|
||||||
|
|
||||||
|
/* TODO reindent */
|
||||||
// sanity check; can't be done in query_formats since the inlink
|
// sanity check; can't be done in query_formats since the inlink
|
||||||
// channel layout is unknown at that time
|
// channel layout is unknown at that time
|
||||||
if (pan->nb_input_channels > SWR_CH_MAX) {
|
if (pan->nb_input_channels > SWR_CH_MAX ||
|
||||||
|
pan->nb_output_channels > SWR_CH_MAX) {
|
||||||
av_log(ctx, AV_LOG_ERROR,
|
av_log(ctx, AV_LOG_ERROR,
|
||||||
"libswresample support a maximum of %d channels. "
|
"libswresample support a maximum of %d channels. "
|
||||||
"Feel free to ask for a higher limit.\n", SWR_CH_MAX);
|
"Feel free to ask for a higher limit.\n", SWR_CH_MAX);
|
||||||
return AVERROR_PATCHWELCOME;
|
return AVERROR_PATCHWELCOME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init libswresample context
|
||||||
|
pan->swr = swr_alloc_set_opts(pan->swr,
|
||||||
|
pan->out_channel_layout, link->format, link->sample_rate,
|
||||||
|
link->channel_layout, link->format, link->sample_rate,
|
||||||
|
0, ctx);
|
||||||
|
if (!pan->swr)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
// gains are pure, init the channel mapping
|
||||||
|
if (pan->pure_gains) {
|
||||||
|
|
||||||
// get channel map from the pure gains
|
// get channel map from the pure gains
|
||||||
for (i = 0; i < pan->nb_output_channels; i++) {
|
for (i = 0; i < pan->nb_output_channels; i++) {
|
||||||
int ch_id = -1;
|
int ch_id = -1;
|
||||||
@ -258,19 +269,9 @@ static int config_props(AVFilterLink *link)
|
|||||||
pan->channel_map[i] = ch_id;
|
pan->channel_map[i] = ch_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init libswresample context
|
|
||||||
pan->swr = swr_alloc_set_opts(pan->swr,
|
|
||||||
pan->out_channel_layout, link->format, link->sample_rate,
|
|
||||||
link->channel_layout, link->format, link->sample_rate,
|
|
||||||
0, ctx);
|
|
||||||
if (!pan->swr)
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0);
|
av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0);
|
||||||
av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0);
|
av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0);
|
||||||
swr_set_channel_mapping(pan->swr, pan->channel_map);
|
swr_set_channel_mapping(pan->swr, pan->channel_map);
|
||||||
r = swr_init(pan->swr);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
} else {
|
} else {
|
||||||
// renormalize
|
// renormalize
|
||||||
for (i = 0; i < pan->nb_output_channels; i++) {
|
for (i = 0; i < pan->nb_output_channels; i++) {
|
||||||
@ -289,7 +290,16 @@ static int config_props(AVFilterLink *link)
|
|||||||
for (j = 0; j < pan->nb_input_channels; j++)
|
for (j = 0; j < pan->nb_input_channels; j++)
|
||||||
pan->gain.d[i][j] /= t;
|
pan->gain.d[i][j] /= t;
|
||||||
}
|
}
|
||||||
|
av_opt_set_int(pan->swr, "icl", link->channel_layout, 0);
|
||||||
|
av_opt_set_int(pan->swr, "ocl", pan->out_channel_layout, 0);
|
||||||
|
swr_set_matrix(pan->swr, pan->gain.d[0],
|
||||||
|
pan->gain.d[1] - pan->gain.d[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = swr_init(pan->swr);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
// summary
|
// summary
|
||||||
for (i = 0; i < pan->nb_output_channels; i++) {
|
for (i = 0; i < pan->nb_output_channels; i++) {
|
||||||
cur = buf;
|
cur = buf;
|
||||||
@ -331,30 +341,6 @@ static void filter_samples_channel_mapping(PanContext *pan,
|
|||||||
swr_convert(pan->swr, outsamples->data, n, (void *)insamples->data, n);
|
swr_convert(pan->swr, outsamples->data, n, (void *)insamples->data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filter_samples_panning(PanContext *pan,
|
|
||||||
AVFilterBufferRef *outsamples,
|
|
||||||
AVFilterBufferRef *insamples,
|
|
||||||
int n)
|
|
||||||
{
|
|
||||||
int i, o;
|
|
||||||
|
|
||||||
/* input */
|
|
||||||
const int16_t *in = (int16_t *)insamples->data[0];
|
|
||||||
const int16_t *in_end = in + n * pan->nb_input_channels;
|
|
||||||
|
|
||||||
/* output */
|
|
||||||
int16_t *out = (int16_t *)outsamples->data[0];
|
|
||||||
|
|
||||||
for (; in < in_end; in += pan->nb_input_channels) {
|
|
||||||
for (o = 0; o < pan->nb_output_channels; o++) {
|
|
||||||
int v = 0;
|
|
||||||
for (i = 0; i < pan->nb_input_channels; i++)
|
|
||||||
v += pan->gain.i[o][i] * in[i];
|
|
||||||
*(out++) = v >> 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
|
static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
|
||||||
{
|
{
|
||||||
int n = insamples->audio->nb_samples;
|
int n = insamples->audio->nb_samples;
|
||||||
@ -379,21 +365,12 @@ static int query_formats(AVFilterContext *ctx)
|
|||||||
AVFilterLink *outlink = ctx->outputs[0];
|
AVFilterLink *outlink = ctx->outputs[0];
|
||||||
AVFilterFormats *formats;
|
AVFilterFormats *formats;
|
||||||
|
|
||||||
if (pan->nb_output_channels <= SWR_CH_MAX)
|
/* TODO reindent */
|
||||||
pan->pure_gains = are_gains_pure(pan);
|
pan->pure_gains = are_gains_pure(pan);
|
||||||
if (pan->pure_gains) {
|
|
||||||
/* libswr supports any sample and packing formats */
|
/* libswr supports any sample and packing formats */
|
||||||
avfilter_set_common_sample_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
|
avfilter_set_common_sample_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
|
||||||
avfilter_set_common_packing_formats(ctx, avfilter_make_all_packing_formats());
|
avfilter_set_common_packing_formats(ctx, avfilter_make_all_packing_formats());
|
||||||
pan->filter_samples = filter_samples_channel_mapping;
|
pan->filter_samples = filter_samples_channel_mapping;
|
||||||
} else {
|
|
||||||
const enum AVSampleFormat sample_fmts[] = {AV_SAMPLE_FMT_S16, -1};
|
|
||||||
const int packing_fmts[] = {AVFILTER_PACKED, -1};
|
|
||||||
|
|
||||||
avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts));
|
|
||||||
avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts));
|
|
||||||
pan->filter_samples = filter_samples_panning;
|
|
||||||
}
|
|
||||||
|
|
||||||
// inlink supports any channel layout
|
// inlink supports any channel layout
|
||||||
formats = avfilter_make_all_channel_layouts();
|
formats = avfilter_make_all_channel_layouts();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user