lavfi: better channel layout negotiation
Allow substitution of channel pairs in the input for nearby channel pairs in the output in order to get a closer match. Also weigh LFE channel mismatch differently to favor matching the same layout without LFE over one less channel with LFE.
This commit is contained in:
parent
81f548de57
commit
743f07062a
@ -424,11 +424,44 @@ static void swap_samplerates(AVFilterGraph *graph)
|
||||
swap_samplerates_on_filter(graph->filters[i]);
|
||||
}
|
||||
|
||||
#define CH_CENTER_PAIR (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)
|
||||
#define CH_FRONT_PAIR (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT)
|
||||
#define CH_STEREO_PAIR (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT)
|
||||
#define CH_WIDE_PAIR (AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT)
|
||||
#define CH_SIDE_PAIR (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)
|
||||
#define CH_DIRECT_PAIR (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT)
|
||||
#define CH_BACK_PAIR (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)
|
||||
|
||||
/* allowable substitutions for channel pairs when comparing layouts,
|
||||
* ordered by priority for both values */
|
||||
static const uint64_t ch_subst[][2] = {
|
||||
{ CH_FRONT_PAIR, CH_CENTER_PAIR },
|
||||
{ CH_FRONT_PAIR, CH_WIDE_PAIR },
|
||||
{ CH_FRONT_PAIR, AV_CH_FRONT_CENTER },
|
||||
{ CH_CENTER_PAIR, CH_FRONT_PAIR },
|
||||
{ CH_CENTER_PAIR, CH_WIDE_PAIR },
|
||||
{ CH_CENTER_PAIR, AV_CH_FRONT_CENTER },
|
||||
{ CH_WIDE_PAIR, CH_FRONT_PAIR },
|
||||
{ CH_WIDE_PAIR, CH_CENTER_PAIR },
|
||||
{ CH_WIDE_PAIR, AV_CH_FRONT_CENTER },
|
||||
{ AV_CH_FRONT_CENTER, CH_FRONT_PAIR },
|
||||
{ AV_CH_FRONT_CENTER, CH_CENTER_PAIR },
|
||||
{ AV_CH_FRONT_CENTER, CH_WIDE_PAIR },
|
||||
{ CH_SIDE_PAIR, CH_DIRECT_PAIR },
|
||||
{ CH_SIDE_PAIR, CH_BACK_PAIR },
|
||||
{ CH_SIDE_PAIR, AV_CH_BACK_CENTER },
|
||||
{ CH_BACK_PAIR, CH_DIRECT_PAIR },
|
||||
{ CH_BACK_PAIR, CH_SIDE_PAIR },
|
||||
{ CH_BACK_PAIR, AV_CH_BACK_CENTER },
|
||||
{ AV_CH_BACK_CENTER, CH_BACK_PAIR },
|
||||
{ AV_CH_BACK_CENTER, CH_DIRECT_PAIR },
|
||||
{ AV_CH_BACK_CENTER, CH_SIDE_PAIR },
|
||||
};
|
||||
|
||||
static void swap_channel_layouts_on_filter(AVFilterContext *filter)
|
||||
{
|
||||
AVFilterLink *link = NULL;
|
||||
uint64_t chlayout;
|
||||
int i, j;
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < filter->nb_inputs; i++) {
|
||||
link = filter->inputs[i];
|
||||
@ -440,27 +473,55 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter)
|
||||
if (i == filter->nb_inputs)
|
||||
return;
|
||||
|
||||
chlayout = link->out_channel_layouts->channel_layouts[0];
|
||||
|
||||
for (i = 0; i < filter->nb_outputs; i++) {
|
||||
AVFilterLink *outlink = filter->outputs[i];
|
||||
int best_idx, best_score = INT_MIN;
|
||||
int best_idx, best_score = INT_MIN, best_count_diff = INT_MAX;
|
||||
|
||||
if (outlink->type != AVMEDIA_TYPE_AUDIO ||
|
||||
outlink->in_channel_layouts->nb_channel_layouts < 2)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) {
|
||||
uint64_t in_chlayout = link->out_channel_layouts->channel_layouts[0];
|
||||
uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j];
|
||||
int matched_channels = av_get_channel_layout_nb_channels(chlayout &
|
||||
out_chlayout);
|
||||
int extra_channels = av_get_channel_layout_nb_channels(out_chlayout &
|
||||
(~chlayout));
|
||||
int score = matched_channels - extra_channels;
|
||||
int in_channels = av_get_channel_layout_nb_channels(in_chlayout);
|
||||
int out_channels = av_get_channel_layout_nb_channels(out_chlayout);
|
||||
int count_diff = out_channels - in_channels;
|
||||
int matched_channels, extra_channels;
|
||||
int score = 0;
|
||||
|
||||
if (score > best_score) {
|
||||
/* channel substitution */
|
||||
for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) {
|
||||
uint64_t cmp0 = ch_subst[k][0];
|
||||
uint64_t cmp1 = ch_subst[k][1];
|
||||
if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) &&
|
||||
(out_chlayout & cmp1) && (!( in_chlayout & cmp1))) {
|
||||
in_chlayout &= ~cmp0;
|
||||
out_chlayout &= ~cmp1;
|
||||
/* add score for channel match, minus a deduction for
|
||||
having to do the substitution */
|
||||
score += 10 * av_get_channel_layout_nb_channels(cmp1) - 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* no penalty for LFE channel mismatch */
|
||||
if ( (in_chlayout & AV_CH_LOW_FREQUENCY) &&
|
||||
(out_chlayout & AV_CH_LOW_FREQUENCY))
|
||||
score += 10;
|
||||
in_chlayout &= ~AV_CH_LOW_FREQUENCY;
|
||||
out_chlayout &= ~AV_CH_LOW_FREQUENCY;
|
||||
|
||||
matched_channels = av_get_channel_layout_nb_channels(in_chlayout &
|
||||
out_chlayout);
|
||||
extra_channels = av_get_channel_layout_nb_channels(out_chlayout &
|
||||
(~in_chlayout));
|
||||
score += 10 * matched_channels - 5 * extra_channels;
|
||||
|
||||
if (score > best_score ||
|
||||
(count_diff < best_count_diff && score == best_score)) {
|
||||
best_score = score;
|
||||
best_idx = j;
|
||||
best_count_diff = count_diff;
|
||||
}
|
||||
}
|
||||
FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0],
|
||||
|
Loading…
Reference in New Issue
Block a user