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 | swap_samplerates_on_filter(graph->filters[i]); | 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 | static void swap_channel_layouts_on_filter(AVFilterContext *filter) | 461 | static void swap_channel_layouts_on_filter(AVFilterContext *filter) |
| 428 | { | 462 | { |
| 429 | AVFilterLink *link = NULL; | 463 | AVFilterLink *link = NULL; |
| 430 | uint64_t chlayout; | 464 | int i, j, k; |
| 431 | int i, j; | ||
| 432 | 465 | ||
| 433 | for (i = 0; i < filter->nb_inputs; i++) { | 466 | for (i = 0; i < filter->nb_inputs; i++) { |
| 434 | link = filter->inputs[i]; | 467 | link = filter->inputs[i]; |
| @@ -440,27 +473,55 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) · 5 unmodified lines | |||
| 440 | if (i == filter->nb_inputs) | 473 | if (i == filter->nb_inputs) |
| 441 | return; | 474 | return; |
| 442 | 475 | ||
| 443 | chlayout = link->out_channel_layouts->channel_layouts[0]; | ||
| 444 | |||
| 445 | for (i = 0; i < filter->nb_outputs; i++) { | 476 | for (i = 0; i < filter->nb_outputs; i++) { |
| 446 | AVFilterLink *outlink = filter->outputs[i]; | 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 | if (outlink->type != AVMEDIA_TYPE_AUDIO || | 480 | if (outlink->type != AVMEDIA_TYPE_AUDIO || |
| 450 | outlink->in_channel_layouts->nb_channel_layouts < 2) | 481 | outlink->in_channel_layouts->nb_channel_layouts < 2) |
| 451 | continue; | 482 | continue; |
| 452 | 483 | ||
| 453 | for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) { | 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 | uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; | 486 | uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; |
| 455 | int matched_channels = av_get_channel_layout_nb_channels(chlayout & | 487 | int in_channels = av_get_channel_layout_nb_channels(in_chlayout); |
| 456 | out_chlayout); | 488 | int out_channels = av_get_channel_layout_nb_channels(out_chlayout); |
| 457 | int extra_channels = av_get_channel_layout_nb_channels(out_chlayout & | 489 | int count_diff = out_channels - in_channels; |
| 458 | (~chlayout)); | 490 | int matched_channels, extra_channels; |
| 459 | int score = 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 | best_score = score; | 522 | best_score = score; |
| 463 | best_idx = j; | 523 | best_idx = j; |
| 524 | best_count_diff = count_diff; | ||
| 464 | } | 525 | } |
| 465 | } | 526 | } |
| 466 | FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], | 527 | FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], |