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.
Showing the changes to libavfilter/avfiltergraph.c (1 of 1 file). Show all
Unified · Split
| @@ -424,11 +424,44 @@ static void swap_samplerates(AVFilterGraph *graph) · 423 unmodified lines | ||
| 424 | 424 | swap_samplerates_on_filter(graph->filters[i]); |
| 425 | 425 | } |
| 426 | 426 | |
| 427 | +#define CH_CENTER_PAIR (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER) | |
| 428 | +#define CH_FRONT_PAIR (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT) | |
| 429 | +#define CH_STEREO_PAIR (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT) | |
| 430 | +#define CH_WIDE_PAIR (AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT) | |
| 431 | +#define CH_SIDE_PAIR (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT) | |
| 432 | +#define CH_DIRECT_PAIR (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT) | |
| 433 | +#define CH_BACK_PAIR (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT) | |
| 434 | + | |
| 435 | +/* allowable substitutions for channel pairs when comparing layouts, | |
| 436 | + * ordered by priority for both values */ | |
| 437 | +static const uint64_t ch_subst[][2] = { | |
| 438 | + { CH_FRONT_PAIR, CH_CENTER_PAIR }, | |
| 439 | + { CH_FRONT_PAIR, CH_WIDE_PAIR }, | |
| 440 | + { CH_FRONT_PAIR, AV_CH_FRONT_CENTER }, | |
| 441 | + { CH_CENTER_PAIR, CH_FRONT_PAIR }, | |
| 442 | + { CH_CENTER_PAIR, CH_WIDE_PAIR }, | |
| 443 | + { CH_CENTER_PAIR, AV_CH_FRONT_CENTER }, | |
| 444 | + { CH_WIDE_PAIR, CH_FRONT_PAIR }, | |
| 445 | + { CH_WIDE_PAIR, CH_CENTER_PAIR }, | |
| 446 | + { CH_WIDE_PAIR, AV_CH_FRONT_CENTER }, | |
| 447 | + { AV_CH_FRONT_CENTER, CH_FRONT_PAIR }, | |
| 448 | + { AV_CH_FRONT_CENTER, CH_CENTER_PAIR }, | |
| 449 | + { AV_CH_FRONT_CENTER, CH_WIDE_PAIR }, | |
| 450 | + { CH_SIDE_PAIR, CH_DIRECT_PAIR }, | |
| 451 | + { CH_SIDE_PAIR, CH_BACK_PAIR }, | |
| 452 | + { CH_SIDE_PAIR, AV_CH_BACK_CENTER }, | |
| 453 | + { CH_BACK_PAIR, CH_DIRECT_PAIR }, | |
| 454 | + { CH_BACK_PAIR, CH_SIDE_PAIR }, | |
| 455 | + { CH_BACK_PAIR, AV_CH_BACK_CENTER }, | |
| 456 | + { AV_CH_BACK_CENTER, CH_BACK_PAIR }, | |
| 457 | + { AV_CH_BACK_CENTER, CH_DIRECT_PAIR }, | |
| 458 | + { AV_CH_BACK_CENTER, CH_SIDE_PAIR }, | |
| 459 | +}; | |
| 460 | + | |
| 427 | 461 | static void swap_channel_layouts_on_filter(AVFilterContext *filter) |
| 428 | 462 | { |
| 429 | 463 | AVFilterLink *link = NULL; |
| 430 | − uint64_t chlayout; | |
| 431 | − int i, j; | |
| 464 | + int i, j, k; | |
| 432 | 465 | |
| 433 | 466 | for (i = 0; i < filter->nb_inputs; i++) { |
| 434 | 467 | link = filter->inputs[i]; |
| @@ -440,27 +473,55 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) · 5 unmodified lines | ||
| 440 | 473 | if (i == filter->nb_inputs) |
| 441 | 474 | return; |
| 442 | 475 | |
| 443 | − chlayout = link->out_channel_layouts->channel_layouts[0]; | |
| 444 | − | |
| 445 | 476 | for (i = 0; i < filter->nb_outputs; i++) { |
| 446 | 477 | AVFilterLink *outlink = filter->outputs[i]; |
| 447 | − int best_idx, best_score = INT_MIN; | |
| 478 | + int best_idx, best_score = INT_MIN, best_count_diff = INT_MAX; | |
| 448 | 479 | |
| 449 | 480 | if (outlink->type != AVMEDIA_TYPE_AUDIO || |
| 450 | 481 | outlink->in_channel_layouts->nb_channel_layouts < 2) |
| 451 | 482 | continue; |
| 452 | 483 | |
| 453 | 484 | for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) { |
| 485 | + uint64_t in_chlayout = link->out_channel_layouts->channel_layouts[0]; | |
| 454 | 486 | uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; |
| 455 | − int matched_channels = av_get_channel_layout_nb_channels(chlayout & | |
| 456 | − out_chlayout); | |
| 457 | − int extra_channels = av_get_channel_layout_nb_channels(out_chlayout & | |
| 458 | − (~chlayout)); | |
| 459 | − int score = matched_channels - extra_channels; | |
| 487 | + int in_channels = av_get_channel_layout_nb_channels(in_chlayout); | |
| 488 | + int out_channels = av_get_channel_layout_nb_channels(out_chlayout); | |
| 489 | + int count_diff = out_channels - in_channels; | |
| 490 | + int matched_channels, extra_channels; | |
| 491 | + int score = 0; | |
| 492 | + | |
| 493 | + /* channel substitution */ | |
| 494 | + for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) { | |
| 495 | + uint64_t cmp0 = ch_subst[k][0]; | |
| 496 | + uint64_t cmp1 = ch_subst[k][1]; | |
| 497 | + if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) && | |
| 498 | + (out_chlayout & cmp1) && (!( in_chlayout & cmp1))) { | |
| 499 | + in_chlayout &= ~cmp0; | |
| 500 | + out_chlayout &= ~cmp1; | |
| 501 | + /* add score for channel match, minus a deduction for | |
| 502 | + having to do the substitution */ | |
| 503 | + score += 10 * av_get_channel_layout_nb_channels(cmp1) - 2; | |
| 504 | + } | |
| 505 | + } | |
| 460 | 506 | |
| 461 | − if (score > best_score) { | |
| 507 | + /* no penalty for LFE channel mismatch */ | |
| 508 | + if ( (in_chlayout & AV_CH_LOW_FREQUENCY) && | |
| 509 | + (out_chlayout & AV_CH_LOW_FREQUENCY)) | |
| 510 | + score += 10; | |
| 511 | + in_chlayout &= ~AV_CH_LOW_FREQUENCY; | |
| 512 | + out_chlayout &= ~AV_CH_LOW_FREQUENCY; | |
| 513 | + | |
| 514 | + matched_channels = av_get_channel_layout_nb_channels(in_chlayout & | |
| 515 | + out_chlayout); | |
| 516 | + extra_channels = av_get_channel_layout_nb_channels(out_chlayout & | |
| 517 | + (~in_chlayout)); | |
| 518 | + score += 10 * matched_channels - 5 * extra_channels; | |
| 519 | + | |
| 520 | + if (score > best_score || | |
| 521 | + (count_diff < best_count_diff && score == best_score)) { | |
| 462 | 522 | best_score = score; |
| 463 | 523 | best_idx = j; |
| 524 | + best_count_diff = count_diff; | |
| 464 | 525 | } |
| 465 | 526 | } |
| 466 | 527 | FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], |